Skip to content

When qualifying Clang types with a module, make sure we choose a visible module #32465

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
Dec 11, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion include/swift/AST/PrintOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -550,7 +550,8 @@ struct PrintOptions {
/// attributes.
///
/// \see swift::emitSwiftInterface
static PrintOptions printSwiftInterfaceFile(bool preferTypeRepr,
static PrintOptions printSwiftInterfaceFile(ModuleDecl *ModuleToPrint,
bool preferTypeRepr,
bool printFullConvention,
bool printSPIs);

Expand Down
93 changes: 89 additions & 4 deletions lib/AST/ASTPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,14 +107,16 @@ static bool contributesToParentTypeStorage(const AbstractStorageDecl *ASD) {
return !ND->isResilient() && ASD->hasStorage() && !ASD->isStatic();
}

PrintOptions PrintOptions::printSwiftInterfaceFile(bool preferTypeRepr,
PrintOptions PrintOptions::printSwiftInterfaceFile(ModuleDecl *ModuleToPrint,
bool preferTypeRepr,
bool printFullConvention,
bool printSPIs) {
PrintOptions result;
result.IsForSwiftInterface = true;
result.PrintLongAttrsOnSeparateLines = true;
result.TypeDefinitions = true;
result.PrintIfConfig = false;
result.CurrentModule = ModuleToPrint;
result.FullyQualifiedTypes = true;
result.UseExportedModuleNames = true;
result.AllowNullTypes = false;
Expand Down Expand Up @@ -3648,6 +3650,8 @@ class TypePrinter : public TypeVisitor<TypePrinter> {

ASTPrinter &Printer;
const PrintOptions &Options;
Optional<llvm::DenseMap<const clang::Module *, ModuleDecl *>>
VisibleClangModules;

void printGenericArgs(ArrayRef<Type> Args) {
if (Args.empty())
Expand Down Expand Up @@ -3678,7 +3682,7 @@ class TypePrinter : public TypeVisitor<TypePrinter> {
}
}

/// Determinee whether the given type has a simple representation
/// Determine whether the given type has a simple representation
/// under the current print options.
bool isSimpleUnderPrintOptions(Type T) {
if (auto typealias = dyn_cast<TypeAliasType>(T.getPointer())) {
Expand All @@ -3700,19 +3704,100 @@ class TypePrinter : public TypeVisitor<TypePrinter> {
return T->hasSimpleTypeRepr();
}

/// Computes the map that is cached by `getVisibleClangModules()`.
/// Do not call directly.
llvm::DenseMap<const clang::Module *, ModuleDecl *>
computeVisibleClangModules() {
assert(Options.CurrentModule &&
"CurrentModule needs to be set to determine imported Clang modules");

llvm::DenseMap<const clang::Module *, ModuleDecl *> Result;

// For the current module, consider both private and public imports.
ModuleDecl::ImportFilter Filter = ModuleDecl::ImportFilterKind::Exported;
Filter |= ModuleDecl::ImportFilterKind::Default;
Filter |= ModuleDecl::ImportFilterKind::SPIAccessControl;
SmallVector<ImportedModule, 4> Imports;
Options.CurrentModule->getImportedModules(Imports, Filter);

SmallVector<ModuleDecl *, 4> ModulesToProcess;
for (const auto &Import : Imports) {
ModulesToProcess.push_back(Import.importedModule);
}

SmallPtrSet<ModuleDecl *, 4> Processed;
while (!ModulesToProcess.empty()) {
ModuleDecl *Mod = ModulesToProcess.back();
ModulesToProcess.pop_back();

if (!Processed.insert(Mod).second)
continue;

if (const clang::Module *ClangModule = Mod->findUnderlyingClangModule())
Result[ClangModule] = Mod;

// For transitive imports, consider only public imports.
Imports.clear();
Mod->getImportedModules(Imports, ModuleDecl::ImportFilterKind::Exported);
for (const auto &Import : Imports) {
ModulesToProcess.push_back(Import.importedModule);
}
}

return Result;
}

/// Returns all Clang modules that are visible from `Options.CurrentModule`.
/// This includes any modules that are imported transitively through public
/// (`@_exported`) imports.
///
/// The returned map associates each visible Clang module with the
/// corresponding Swift module.
const llvm::DenseMap<const clang::Module *, ModuleDecl *> &
getVisibleClangModules() {
if (!VisibleClangModules) {
VisibleClangModules = computeVisibleClangModules();
}
return *VisibleClangModules;
}

template <typename T>
void printModuleContext(T *Ty) {
FileUnit *File = cast<FileUnit>(Ty->getDecl()->getModuleScopeContext());
ModuleDecl *Mod = File->getParentModule();
StringRef ExportedModuleName = File->getExportedModuleName();

// Clang declarations need special treatment: Multiple Clang modules can
// contain the same declarations from a textually included header, but not
// all of these modules may be visible. We therefore need to make sure we
// choose a module that is visible from the current module. This is possible
// only if we know what the current module is.
const clang::Decl *ClangDecl = Ty->getDecl()->getClangDecl();
if (ClangDecl && Options.CurrentModule) {
for (auto *Redecl : ClangDecl->redecls()) {
clang::Module *ClangModule =
Redecl->getOwningModule()->getTopLevelModule();
if (!ClangModule)
continue;

if (ModuleDecl *VisibleModule =
getVisibleClangModules().lookup(ClangModule)) {
Mod = VisibleModule;
ExportedModuleName = ClangModule->ExportAsModule;
break;
}
}
}

if (Options.MapCrossImportOverlaysToDeclaringModule) {
if (ModuleDecl *Declaring = Mod->getDeclaringModuleIfCrossImportOverlay())
Mod = Declaring;
}

Identifier Name = Mod->getName();
if (Options.UseExportedModuleNames)
Name = Mod->getASTContext().getIdentifier(File->getExportedModuleName());
if (Options.UseExportedModuleNames && !ExportedModuleName.empty()) {
Name = Mod->getASTContext().getIdentifier(ExportedModuleName);
}

Printer.printModuleRef(Mod, Name);
Printer << ".";
Expand Down
2 changes: 1 addition & 1 deletion lib/Frontend/ModuleInterfaceSupport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -517,7 +517,7 @@ bool swift::emitSwiftInterface(raw_ostream &out,
printImports(out, Opts, M);

const PrintOptions printOptions = PrintOptions::printSwiftInterfaceFile(
Opts.PreserveTypesAsWritten, Opts.PrintFullConvention, Opts.PrintSPIs);
M, Opts.PreserveTypesAsWritten, Opts.PrintFullConvention, Opts.PrintSPIs);
InheritedProtocolCollector::PerTypeMap inheritedProtocolMap;

SmallVector<Decl *, 16> topLevelDecls;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
@_spi(dummy) import HelperModule

public func funcTakingForeignStruct(_ param: ForeignStruct) {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// This tests verifies that SPI visible modules are understood by the machinery
// that produces .swiftinterface files.
//
// See the documentation for the print-qualified-clang-types.swift test next to
// this one for more context.

// RUN: %empty-directory(%t)
// RUN: mkdir %t/helper_module %t/spi_main_module
// RUN: %target-swift-frontend -enable-library-evolution -swift-version 5 -emit-module -o %t/helper_module/HelperModule.swiftmodule %S/Inputs/HelperModule.swift -I %S/Inputs
// RUN: %target-swift-frontend -enable-library-evolution -swift-version 5 -emit-module -o %t/spi_main_module/SpiMainModule.swiftmodule -emit-module-interface-path %t/spi_main_module/SpiMainModule.swiftinterface -I %t/helper_module %S/Inputs/SpiMainModule.swift -I %S/Inputs
// RUN: %FileCheck --input-file=%t/spi_main_module/SpiMainModule.swiftinterface %s
// RUN: %target-swift-frontend -typecheck -swift-version 5 %t/spi_main_module/SpiMainModule.swiftinterface -I %t/helper_module -I %S/Inputs

// CHECK: public func funcTakingForeignStruct(_ param: ForeignB.ForeignStruct)
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,3 @@
// RUN: %target-swift-frontend -typecheck -swift-version 5 %t/main_module/MainModule.swiftinterface -I %t/helper_module -I %S/Inputs

// CHECK: public func funcTakingForeignStruct(_ param: ForeignB.ForeignStruct)

// REQUIRES: SR-13032