diff --git a/include/swift/AST/Module.h b/include/swift/AST/Module.h index b88d669734467..8d3f45d0ae128 100644 --- a/include/swift/AST/Module.h +++ b/include/swift/AST/Module.h @@ -810,6 +810,14 @@ class FileUnit : public DeclContext { return nullptr; } + /// Returns the name to use when referencing entities in this file. + /// + /// Usually this is the module name itself, but certain Clang features allow + /// substituting another name instead. + virtual StringRef getExportedModuleName() const { + return getParentModule()->getName().str(); + } + /// Traverse the decls within this file. /// /// \returns true if traversal was aborted, false if it completed diff --git a/include/swift/AST/PrintOptions.h b/include/swift/AST/PrintOptions.h index 36704cfacb872..0e1753e392ecc 100644 --- a/include/swift/AST/PrintOptions.h +++ b/include/swift/AST/PrintOptions.h @@ -185,6 +185,12 @@ struct PrintOptions { /// type might be ambiguous. bool FullyQualifiedTypesIfAmbiguous = false; + /// If true, printed module names will use the "exported" name, which may be + /// different from the regular name. + /// + /// \see FileUnit::getExportedModuleName + bool UseExportedModuleNames = false; + /// Print Swift.Array and Swift.Optional with sugared syntax /// ([] and ?), even if there are no sugar type nodes. bool SynthesizeSugarOnTypes = false; diff --git a/include/swift/ClangImporter/ClangModule.h b/include/swift/ClangImporter/ClangModule.h index 2f4e7bfd8ee58..a7f0429fa466b 100644 --- a/include/swift/ClangImporter/ClangModule.h +++ b/include/swift/ClangImporter/ClangModule.h @@ -62,7 +62,7 @@ class ClangModuleUnit final : public LoadedFile { /// Retrieve the "exported" name of the module, which is usually the module /// name, but might be the name of the public module through which this /// (private) module is re-exported. - std::string getExportedModuleName() const; + StringRef getExportedModuleName() const override; virtual bool isSystemModule() const override; diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp index a7ecaee4f5a0c..00227137febec 100644 --- a/lib/AST/ASTPrinter.cpp +++ b/lib/AST/ASTPrinter.cpp @@ -99,6 +99,7 @@ PrintOptions PrintOptions::printParseableInterfaceFile() { result.TypeDefinitions = true; result.PrintIfConfig = false; result.FullyQualifiedTypes = true; + result.UseExportedModuleNames = true; result.AllowNullTypes = false; result.SkipImports = true; result.OmitNameOfInaccessibleProperties = true; @@ -3338,8 +3339,14 @@ class TypePrinter : public TypeVisitor { template void printModuleContext(T *Ty) { - ModuleDecl *Mod = Ty->getDecl()->getModuleContext(); - Printer.printModuleRef(Mod, Mod->getName()); + FileUnit *File = cast(Ty->getDecl()->getModuleScopeContext()); + ModuleDecl *Mod = File->getParentModule(); + + Identifier Name = Mod->getName(); + if (Options.UseExportedModuleNames) + Name = Mod->getASTContext().getIdentifier(File->getExportedModuleName()); + + Printer.printModuleRef(Mod, Name); Printer << "."; } diff --git a/lib/ClangImporter/ClangImporter.cpp b/lib/ClangImporter/ClangImporter.cpp index 751a7db088f8a..6e69708384124 100644 --- a/lib/ClangImporter/ClangImporter.cpp +++ b/lib/ClangImporter/ClangImporter.cpp @@ -3120,7 +3120,7 @@ clang::ASTContext &ClangModuleUnit::getClangASTContext() const { return owner.getClangASTContext(); } -std::string ClangModuleUnit::getExportedModuleName() const { +StringRef ClangModuleUnit::getExportedModuleName() const { if (clangModule && !clangModule->ExportAsModule.empty()) return clangModule->ExportAsModule; diff --git a/lib/Serialization/Deserialization.cpp b/lib/Serialization/Deserialization.cpp index 7feb13dcdaaf1..2f04969a83871 100644 --- a/lib/Serialization/Deserialization.cpp +++ b/lib/Serialization/Deserialization.cpp @@ -1147,7 +1147,7 @@ static bool isReExportedToModule(const ValueDecl *value, = dyn_cast(valueDC->getModuleScopeContext()); if (!fromClangModule) return false; - std::string exportedName = fromClangModule->getExportedModuleName(); + StringRef exportedName = fromClangModule->getExportedModuleName(); auto toClangModule = dyn_cast(expectedModule->getFiles().front()); diff --git a/lib/Serialization/ModuleFile.cpp b/lib/Serialization/ModuleFile.cpp index 2582b9b9bd249..fbc41adea1816 100644 --- a/lib/Serialization/ModuleFile.cpp +++ b/lib/Serialization/ModuleFile.cpp @@ -25,7 +25,6 @@ #include "swift/AST/USRGeneration.h" #include "swift/Basic/Range.h" #include "swift/ClangImporter/ClangImporter.h" -#include "swift/ClangImporter/ClangModule.h" #include "swift/Serialization/BCReadingExtras.h" #include "swift/Serialization/SerializedModuleLoader.h" #include "llvm/ADT/StringExtras.h" @@ -1842,17 +1841,8 @@ void ModuleFile::loadExtensions(NominalTypeDecl *nominal) { } if (nominal->getParent()->isModuleScopeContext()) { - auto parentModule = nominal->getParentModule(); - StringRef moduleName = parentModule->getName().str(); - - // If the originating module is a private module whose interface is - // re-exported via public module, check the name of the public module. - std::string exportedModuleName; - if (auto clangModuleUnit = - dyn_cast(parentModule->getFiles().front())) { - exportedModuleName = clangModuleUnit->getExportedModuleName(); - moduleName = exportedModuleName; - } + auto parentFile = cast(nominal->getParent()); + StringRef moduleName = parentFile->getExportedModuleName(); for (auto item : *iter) { if (item.first != moduleName) diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp index 71c89f2d884a3..5942749968f9d 100644 --- a/lib/Serialization/Serialization.cpp +++ b/lib/Serialization/Serialization.cpp @@ -180,7 +180,7 @@ namespace { int32_t getNameDataForBase(const NominalTypeDecl *nominal, StringRef *dataToWrite = nullptr) { if (nominal->getDeclContext()->isModuleScopeContext()) - return -Serializer.addModuleRef(nominal->getParentModule()); + return -Serializer.addContainingModuleRef(nominal->getDeclContext()); auto &mangledName = MangledNameCache[nominal]; if (mangledName.empty()) @@ -731,7 +731,12 @@ IdentifierID Serializer::addFilename(StringRef filename) { return addUniquedString(filename).second; } -IdentifierID Serializer::addModuleRef(const ModuleDecl *M) { +IdentifierID Serializer::addContainingModuleRef(const DeclContext *DC) { + assert(!isa(DC) && + "References should be to things within modules"); + const FileUnit *file = cast(DC->getModuleScopeContext()); + const ModuleDecl *M = file->getParentModule(); + if (M == this->M) return CURRENT_MODULE_ID; if (M == this->M->getASTContext().TheBuiltinModule) @@ -743,18 +748,10 @@ IdentifierID Serializer::addModuleRef(const ModuleDecl *M) { if (M == clangImporter->getImportedHeaderModule()) return OBJC_HEADER_MODULE_ID; - // If we're referring to a member of a private module that will be - // re-exported via a public module, record the public module's name. - if (auto clangModuleUnit = - dyn_cast(M->getFiles().front())) { - auto exportedModuleName = - M->getASTContext().getIdentifier( - clangModuleUnit->getExportedModuleName()); - return addDeclBaseNameRef(exportedModuleName); - } - - assert(!M->getName().empty()); - return addDeclBaseNameRef(M->getName()); + auto exportedModuleName = file->getExportedModuleName(); + assert(!exportedModuleName.empty()); + auto exportedModuleID = M->getASTContext().getIdentifier(exportedModuleName); + return addDeclBaseNameRef(exportedModuleID); } SILLayoutID Serializer::addSILLayoutRef(SILLayout *layout) { @@ -1650,7 +1647,7 @@ Serializer::writeConformance(ProtocolConformanceRef conformanceRef, abbrCode, addDeclRef(normal->getProtocol()), addDeclRef(normal->getType()->getAnyNominal()), - addModuleRef(normal->getDeclContext()->getParentModule())); + addContainingModuleRef(normal->getDeclContext())); } break; } @@ -1888,14 +1885,13 @@ void Serializer::writeCrossReference(const DeclContext *DC, uint32_t pathLen) { case DeclContextKind::EnumElementDecl: llvm_unreachable("cannot cross-reference this context"); - case DeclContextKind::FileUnit: - DC = cast(DC)->getParentModule(); - LLVM_FALLTHROUGH; - case DeclContextKind::Module: + llvm_unreachable("should only cross-reference something within a file"); + + case DeclContextKind::FileUnit: abbrCode = DeclTypeAbbrCodes[XRefLayout::Code]; XRefLayout::emitRecord(Out, ScratchRecord, abbrCode, - addModuleRef(cast(DC)), pathLen); + addContainingModuleRef(DC), pathLen); break; case DeclContextKind::GenericTypeDecl: { @@ -1932,7 +1928,7 @@ void Serializer::writeCrossReference(const DeclContext *DC, uint32_t pathLen) { genericSig = ext->getGenericSignature()->getCanonicalSignature(); } XRefExtensionPathPieceLayout::emitRecord( - Out, ScratchRecord, abbrCode, addModuleRef(DC->getParentModule()), + Out, ScratchRecord, abbrCode, addContainingModuleRef(DC), addGenericSignatureRef(genericSig)); break; } @@ -2025,7 +2021,7 @@ void Serializer::writeCrossReference(const Decl *D) { unsigned abbrCode; if (auto op = dyn_cast(D)) { - writeCrossReference(op->getModuleContext(), 1); + writeCrossReference(op->getDeclContext(), 1); abbrCode = DeclTypeAbbrCodes[XRefOperatorOrAccessorPathPieceLayout::Code]; auto nameID = addDeclBaseNameRef(op->getName()); @@ -2037,7 +2033,7 @@ void Serializer::writeCrossReference(const Decl *D) { } if (auto prec = dyn_cast(D)) { - writeCrossReference(prec->getModuleContext(), 1); + writeCrossReference(prec->getDeclContext(), 1); abbrCode = DeclTypeAbbrCodes[XRefOperatorOrAccessorPathPieceLayout::Code]; auto nameID = addDeclBaseNameRef(prec->getName()); diff --git a/lib/Serialization/Serialization.h b/lib/Serialization/Serialization.h index 3a9a4f503dab4..3dc4587084b2d 100644 --- a/lib/Serialization/Serialization.h +++ b/lib/Serialization/Serialization.h @@ -540,13 +540,16 @@ class Serializer : public SerializerBase { /// Records the use of the given SILLayout. SILLayoutID addSILLayoutRef(SILLayout *layout); - /// Records the use of the given module. + /// Records the module containing \p DC. /// - /// The module's name will be scheduled for serialization if necessary. + /// The module's name will be scheduled for serialization if necessary. This + /// may not be exactly the same as the name of the module containing DC; + /// instead, it will match the containing file's "exported module name". /// /// \returns The ID for the identifier for the module's name, or one of the /// special module codes defined above. - IdentifierID addModuleRef(const ModuleDecl *M); + /// \see FileUnit::getExportedModuleName + IdentifierID addContainingModuleRef(const DeclContext *DC); /// Write a normal protocol conformance. void writeNormalConformance(const NormalProtocolConformance *conformance); diff --git a/test/ParseableInterface/Inputs/exported-module-name-after/CoreKit.h b/test/ParseableInterface/Inputs/exported-module-name-after/CoreKit.h new file mode 100644 index 0000000000000..1fafb5cf4a456 --- /dev/null +++ b/test/ParseableInterface/Inputs/exported-module-name-after/CoreKit.h @@ -0,0 +1 @@ +#import diff --git a/test/ParseableInterface/Inputs/exported-module-name-after/ExportAsCoreKit.h b/test/ParseableInterface/Inputs/exported-module-name-after/ExportAsCoreKit.h new file mode 100644 index 0000000000000..f078795a60fed --- /dev/null +++ b/test/ParseableInterface/Inputs/exported-module-name-after/ExportAsCoreKit.h @@ -0,0 +1,3 @@ +struct CKThing { + long value; +}; diff --git a/test/ParseableInterface/Inputs/exported-module-name-after/module.modulemap b/test/ParseableInterface/Inputs/exported-module-name-after/module.modulemap new file mode 100644 index 0000000000000..6e2fdfe9d9c9f --- /dev/null +++ b/test/ParseableInterface/Inputs/exported-module-name-after/module.modulemap @@ -0,0 +1,5 @@ +module CoreKit { + header "CoreKit.h" + header "ExportAsCoreKit.h" + export * +} diff --git a/test/ParseableInterface/Inputs/exported-module-name-before/CoreKit.h b/test/ParseableInterface/Inputs/exported-module-name-before/CoreKit.h new file mode 100644 index 0000000000000..1fafb5cf4a456 --- /dev/null +++ b/test/ParseableInterface/Inputs/exported-module-name-before/CoreKit.h @@ -0,0 +1 @@ +#import diff --git a/test/ParseableInterface/Inputs/exported-module-name-before/ExportAsCoreKit.h b/test/ParseableInterface/Inputs/exported-module-name-before/ExportAsCoreKit.h new file mode 100644 index 0000000000000..f078795a60fed --- /dev/null +++ b/test/ParseableInterface/Inputs/exported-module-name-before/ExportAsCoreKit.h @@ -0,0 +1,3 @@ +struct CKThing { + long value; +}; diff --git a/test/ParseableInterface/Inputs/exported-module-name-before/module.modulemap b/test/ParseableInterface/Inputs/exported-module-name-before/module.modulemap new file mode 100644 index 0000000000000..06e552527c312 --- /dev/null +++ b/test/ParseableInterface/Inputs/exported-module-name-before/module.modulemap @@ -0,0 +1,10 @@ +module CoreKit { + header "CoreKit.h" + export * +} + +module ExportAsCoreKit_BAD { + header "ExportAsCoreKit.h" + export_as CoreKit + export * +} diff --git a/test/ParseableInterface/exported-module-name.swift b/test/ParseableInterface/exported-module-name.swift new file mode 100644 index 0000000000000..62a6c3d529458 --- /dev/null +++ b/test/ParseableInterface/exported-module-name.swift @@ -0,0 +1,19 @@ +// RUN: %empty-directory(%t) +// RUN: %target-swift-frontend -typecheck -emit-parseable-module-interface-path %t/CoreKitClient.swiftinterface -module-name CoreKitClient -I %S/Inputs/exported-module-name-before %s +// RUN: %FileCheck -implicit-check-not BAD %s < %t/CoreKitClient.swiftinterface + +// Test that we can rebuild it even when the "export as" module goes away. +// RUN: %target-swift-frontend -build-module-from-parseable-interface -o %t/CoreKitClient.swiftmodule -I %S/Inputs/exported-module-name-after %t/CoreKitClient.swiftinterface + +// CHECK: import CoreKit +import CoreKit + +// CHECK-LABEL: public struct CKThingWrapper : RawRepresentable { +public struct CKThingWrapper: RawRepresentable { + public var rawValue: CKThing + public init(rawValue: CKThing) { + self.rawValue = rawValue + } + // Note that this is CoreKit.CKThing, not ExportAsCoreKit.CKThing + // CHECK: public typealias RawValue = CoreKit.CKThing +} // CHECK: {{^}$}}