Merge exported modules with the same public name in generated interface

If a module has the same `public-module-name` as the module being
generated and its import is exported, merge it into the same generated
interface.

Fix various always-imported modules from being printed while here and
update all the tests that checked for them.

Resolves rdar://137887712.
This commit is contained in:
Ben Barham
2025-04-21 11:24:31 -07:00
parent 6735659d39
commit ddddc667c8
35 changed files with 3500 additions and 3640 deletions

View File

@@ -304,6 +304,34 @@ static bool compareSwiftDecls(Decl *LHS, Decl *RHS) {
return LHS->getKind() < RHS->getKind();
}
static bool shouldPrintImport(ImportDecl *ImportD, ModuleDecl *OrigMod,
const clang::Module *OrigClangMod) {
if (ImportD->getAttrs().hasAttribute<ImplementationOnlyAttr>())
return false;
auto *ImportedMod = ImportD->getModule();
if (ImportedMod) {
if (ImportedMod == OrigMod)
return false;
if (ImportedMod->isOnoneSupportModule())
return false;
if (ImportedMod->getName().hasUnderscoredNaming())
return false;
}
if (!OrigClangMod)
return true;
auto ImportedClangMod = ImportD->getClangModule();
if (!ImportedClangMod)
return true;
if (!ImportedClangMod->isSubModule())
return true;
if (ImportedClangMod == OrigClangMod)
return false;
return ImportedClangMod->isSubModuleOf(OrigClangMod);
}
static std::pair<ArrayRef<Decl*>, ArrayRef<Decl*>>
getDeclsFromCrossImportOverlay(ModuleDecl *Overlay, ModuleDecl *Declaring,
SmallVectorImpl<Decl *> &Decls,
@@ -329,7 +357,8 @@ getDeclsFromCrossImportOverlay(ModuleDecl *Overlay, ModuleDecl *Declaring,
// Ignore imports of the underlying module, or any cross-import
// that would map back to it.
if (Imported == Declaring || Imported->isCrossImportOverlayOf(Declaring))
if (!shouldPrintImport(ID, Declaring, nullptr) ||
Imported->isCrossImportOverlayOf(Declaring))
return false;
// Ignore an imports of modules also imported by the underlying module.
@@ -457,19 +486,40 @@ 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
// (excluding the underlying clang module if there is one).
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())
continue;
if (TargetClangMod != nullptr &&
Import.importedModule->findUnderlyingClangModule() == TargetClangMod)
continue;
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);
@@ -482,16 +532,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);
}
}
}
@@ -500,8 +549,7 @@ void swift::ide::printModuleInterface(
}
}
SmallVector<Decl *, 1> Decls;
SmallVector<Decl *, 0> Decls;
for (ModuleDecl *M : ModuleList) {
swift::getTopLevelDeclsForDisplay(M, Decls);
}
@@ -527,42 +575,38 @@ void swift::ide::printModuleInterface(
continue;
}
auto ShouldPrintImport = [&](ImportDecl *ImportD) -> bool {
if (ImportD->getAttrs().hasAttribute<ImplementationOnlyAttr>())
return false;
if (!TargetClangMod)
return true;
if (ImportD->getModule() == TargetMod)
return false;
auto ImportedMod = ImportD->getClangModule();
if (!ImportedMod)
return true;
if (!ImportedMod->isSubModule())
return true;
if (ImportedMod == TargetClangMod)
return false;
return ImportedMod->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 (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 (!shouldPrintImport(ID, TargetMod, TargetClangMod))
continue;
// Erase submodules that are not missing
if (ID->getClangModule())
NoImportSubModules.erase(ID->getClangModule());
if (ID->getImportKind() == ImportKind::Module) {
// Could have a duplicate import from a clang module's overlay or
// because we're merging modules. Skip them.
if (auto *ClangMod = getUnderlyingClangModuleForImport(ID)) {
if (!SeenImportedDecls.insert(ClangMod).second)
continue;
}
ImportDecls.push_back(ID);
if (auto *ImportedMod = ID->getModule()) {
if (!SeenImportedDecls.insert(ImportedMod).second)
continue;
}
} else {
bool AnyNewDecls = false;
for (auto *ImportedDecl : ID->getDecls()) {
AnyNewDecls |= SeenImportedDecls.insert(ImportedDecl).second;
}
if (!AnyNewDecls)
continue;
}
ImportDecls.push_back(ID);
continue;
}
@@ -684,9 +728,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();
}
}
{