Skip to content

Merge exported modules with the same public name in generated interface #80958

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

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
7 changes: 5 additions & 2 deletions include/swift/IDE/ModuleInterfacePrinting.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,14 @@ namespace ide {
/// Flags used when traversing a module for printing.
enum class ModuleTraversal : unsigned {
/// Visit modules even if their contents wouldn't be visible to name lookup.
VisitHidden = 0x01,
VisitHidden = 0x01,
/// Visit submodules.
VisitSubmodules = 0x02,
/// Skip the declarations in a Swift overlay module.
SkipOverlay = 0x04,
SkipOverlay = 0x04,
/// Visit exported modules where their public module name matches the current
/// module.
VisitMatchingExported = 0x08,
};

/// Options used to describe the traversal of a module for printing.
Expand Down
116 changes: 78 additions & 38 deletions lib/IDE/ModuleInterfacePrinting.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -457,19 +457,34 @@ void swift::ide::printModuleInterface(
auto AdjustedOptions = Options;
adjustPrintOptions(AdjustedOptions);

llvm::DenseSet<const void *> SeenImportedDecls;
SmallVector<ModuleDecl *, 1> ModuleList;
ModuleList.push_back(TargetMod);
SeenImportedDecls.insert(TargetMod);

SmallVector<ImportDecl *, 1> ImportDecls;
llvm::DenseSet<const clang::Module *> ClangModulesForImports;
SmallVector<Decl *, 1> SwiftDecls;
SmallVector<ImportDecl *, 0> ImportDecls;
SmallVector<Decl *, 0> SwiftDecls;
llvm::DenseMap<const clang::Module *,
SmallVector<std::pair<Decl *, clang::SourceLocation>, 1>>
ClangDecls;
SmallVector<std::pair<Decl *, clang::SourceLocation>, 0>>
ClangDecls;

// Add exported modules that have the same public module name as this module
if (TraversalOptions & ModuleTraversal::VisitMatchingExported) {
SmallVector<ImportedModule> Imports;
TargetMod->getImportedModules(Imports,
ModuleDecl::ImportFilterKind::Exported);
for (ImportedModule Import : Imports) {
if (Import.importedModule->getPublicModuleName(
/*onlyIfImported=*/false) == TargetMod->getName()) {
ModuleList.push_back(Import.importedModule);
SeenImportedDecls.insert(Import.importedModule);
}
}
}

// If we're printing recursively, find all of the submodules to print.
if (TargetClangMod) {
if (TraversalOptions) {
// Add clang submodules if they're being visited
if (TraversalOptions & ModuleTraversal::VisitSubmodules) {
SmallVector<const clang::Module *, 8> Worklist;
SmallPtrSet<const clang::Module *, 8> Visited;
Worklist.push_back(TargetClangMod);
Expand All @@ -482,16 +497,15 @@ void swift::ide::printModuleInterface(

ClangDecls.insert({ CM, {} });

if (CM != TargetClangMod)
if (auto *OwningModule = Importer.getWrapperForModule(CM))
if (CM != TargetClangMod) {
if (auto *OwningModule = Importer.getWrapperForModule(CM)) {
ModuleList.push_back(OwningModule);
}
}

// If we're supposed to visit submodules, add them now.
if (TraversalOptions & ModuleTraversal::VisitSubmodules) {
for (clang::Module * submodule: CM->submodules()) {
if (Visited.insert(submodule).second) {
Worklist.push_back(submodule);
}
for (clang::Module *submodule : CM->submodules()) {
if (Visited.insert(submodule).second) {
Worklist.push_back(submodule);
}
}
}
Expand All @@ -500,8 +514,7 @@ void swift::ide::printModuleInterface(
}
}

SmallVector<Decl *, 1> Decls;

SmallVector<Decl *, 0> Decls;
for (ModuleDecl *M : ModuleList) {
swift::getTopLevelDeclsForDisplay(M, Decls);
}
Expand Down Expand Up @@ -531,38 +544,62 @@ void swift::ide::printModuleInterface(
if (ImportD->getAttrs().hasAttribute<ImplementationOnlyAttr>())
return false;

auto *ImportedMod = ImportD->getModule();
if (ImportedMod) {
if (ImportedMod == TargetMod)
return false;
if (ImportedMod->isOnoneSupportModule())
return false;
if (ImportedMod->getName().hasUnderscoredNaming())
return false;
}

if (!TargetClangMod)
return true;
if (ImportD->getModule() == TargetMod)
return false;

auto ImportedMod = ImportD->getClangModule();
if (!ImportedMod)
auto ImportedClangMod = ImportD->getClangModule();
if (!ImportedClangMod)
return true;
if (!ImportedMod->isSubModule())
if (!ImportedClangMod->isSubModule())
return true;
if (ImportedMod == TargetClangMod)
if (ImportedClangMod == TargetClangMod)
return false;
return ImportedMod->isSubModuleOf(TargetClangMod);
return ImportedClangMod->isSubModuleOf(TargetClangMod);
};

if (auto ID = dyn_cast<ImportDecl>(D)) {
if (ShouldPrintImport(ID)) {
if (ID->getClangModule())
// Erase those submodules that are not missing.
NoImportSubModules.erase(ID->getClangModule());
if (!ShouldPrintImport(ID))
continue;

// Erase submodules that are not missing
if (ID->getClangModule())
NoImportSubModules.erase(ID->getClangModule());

// If we're merging multiple modules together, skip duplicate imports
if (ModuleList.size() > 1) {
if (ID->getImportKind() == ImportKind::Module) {
// Make sure we don't print duplicate imports, due to getting imports
// for both a clang module and its overlay.
if (auto *ClangMod = getUnderlyingClangModuleForImport(ID)) {
auto P = ClangModulesForImports.insert(ClangMod);
bool IsNew = P.second;
if (!IsNew)
continue;
if (!SeenImportedDecls.insert(ID->getModule()).second)
continue;
} else {
bool AnyNewDecls = false;
for (auto *ImportedDecl : ID->getDecls()) {
AnyNewDecls |= SeenImportedDecls.insert(ImportedDecl).second;
}
if (!AnyNewDecls)
continue;
}
}

if (ID->getImportKind() == ImportKind::Module) {
// Could have a duplicate import from a clang module's overlay, skip it
if (auto *ClangMod = getUnderlyingClangModuleForImport(ID)) {
if (!SeenImportedDecls.insert(ClangMod).second)
continue;
}
ImportDecls.push_back(ID);
}

ImportDecls.push_back(ID);

continue;
}

Expand Down Expand Up @@ -684,9 +721,12 @@ void swift::ide::printModuleInterface(

// Imports from the stdlib are internal details that don't need to be exposed.
if (!TargetMod->isStdlibModule()) {
for (auto *D : ImportDecls)
for (auto *D : ImportDecls) {
PrintDecl(D);
Printer.printNewline();
}
if (!ImportDecls.empty()) {
Printer.printNewline();
}
}

{
Expand Down
44 changes: 44 additions & 0 deletions test/SourceKit/InterfaceGen/gen_public_module_name.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// RUN: %empty-directory(%t)
// RUN: split-file %s %t

// RUN: %target-swift-frontend %t/common.swift \
// RUN: -module-name Common \
// RUN: -emit-module-path %t/Common.swiftmodule \
// RUN: -emit-module-interface-path %t/Common.swiftinterface \
// RUN: -enable-library-evolution -swift-version 6

// RUN: %target-swift-frontend %t/modimpl.swift -I %t \
// RUN: -module-name BestModImpl \
// RUN: -emit-module-path %t/BestModImpl.swiftmodule \
// RUN: -emit-module-interface-path %t/BestModImpl.swiftinterface \
// RUN: -enable-library-evolution -swift-version 6 \
// RUN: -public-module-name BestMod

// RUN: %target-swift-frontend %t/mod.swift -I %t \
// RUN: -module-name BestMod \
// RUN: -emit-module-path %t/BestMod.swiftmodule \
// RUN: -emit-module-interface-path %t/BestMod.swiftinterface \
// RUN: -enable-library-evolution -swift-version 6

// RUN: %sourcekitd-test -req=interface-gen -module BestMod -- -swift-version 6 -I %t -target %target-triple &> %t/BestMod.generatedinterface
// RUN: %FileCheck -input-file=%t/BestMod.generatedinterface %s

//--- common.swift
public struct CommonType {}

//--- modimpl.swift
import struct Common.CommonType

public func fromModImpl() {}

//--- mod.swift
@_exported import BestModImpl
import struct Common.CommonType

public func fromMod() {}

// CHECK-NOT: import BestModImpl
// CHECK: import struct Common.CommonType
// CHECK-NOT: import
// CHECK: func fromMod()
// CHECK: func fromModImpl()
5 changes: 4 additions & 1 deletion tools/SourceKit/lib/SwiftLang/SwiftEditorInterfaceGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -387,8 +387,11 @@ static bool getModuleInterfaceInfo(
Options.SkipInlineCXXNamespace = true;
}
}
// Skip submodules but include any exported modules that have the same public
// module name as this module.
ModuleTraversalOptions TraversalOptions =
std::nullopt; // Don't print submodules.
ModuleTraversal::VisitMatchingExported;

SmallString<128> Text;
llvm::raw_svector_ostream OS(Text);
AnnotatingPrinter Printer(Info, OS);
Expand Down