Skip to content

Commit 9d83f19

Browse files
add support to getTopLevelDecls for clang submodules
rdar://126031510
1 parent c8a24e5 commit 9d83f19

File tree

10 files changed

+226
-183
lines changed

10 files changed

+226
-183
lines changed

include/swift/AST/ClangNode.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,9 @@ class ClangNode {
9696
/// clang::ImportDecl or null if it's neither.
9797
const clang::Module *getClangModule() const;
9898

99+
/// Returns the owning clang module of this node, if it exists.
100+
const clang::Module *getOwningClangModule() const;
101+
99102
clang::SourceLocation getLocation() const;
100103
clang::SourceRange getSourceRange() const;
101104

lib/AST/Decl.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,16 @@ const clang::Module *ClangNode::getClangModule() const {
128128
return nullptr;
129129
}
130130

131+
const clang::Module *ClangNode::getOwningClangModule() const {
132+
if (auto *M = getAsModule())
133+
return M;
134+
if (auto D = getAsDecl())
135+
return D->getOwningModule();
136+
if (auto MI = getAsModuleMacro())
137+
return MI->getOwningModule();
138+
return nullptr;
139+
}
140+
131141
void ClangNode::dump() const {
132142
if (auto D = getAsDecl())
133143
D->dump();

lib/ClangImporter/ClangImporter.cpp

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3050,6 +3050,15 @@ static bool isDeclaredInModule(const ClangModuleUnit *ModuleFilter,
30503050
if (VD->getModuleContext()->getName().str() == CLANG_HEADER_MODULE_NAME) {
30513051
return true;
30523052
}
3053+
// Because the ClangModuleUnit saved as a decl context will be saved as the top-level module, but
3054+
// the ModuleFilter we're given might be a submodule (if a submodule was passed to
3055+
// getTopLevelDecls, for example), we should compare the underlying Clang modules to determine
3056+
// module membership.
3057+
if (auto ClangNode = VD->getClangNode()) {
3058+
if (auto *ClangModule = ClangNode.getOwningClangModule()) {
3059+
return ModuleFilter->getClangModule() == ClangModule;
3060+
}
3061+
}
30533062
auto ContainingUnit = VD->getDeclContext()->getModuleScopeContext();
30543063
return ModuleFilter == ContainingUnit;
30553064
}
@@ -3222,7 +3231,7 @@ class FilteringDeclaredDeclConsumer : public swift::VisibleDeclConsumer {
32223231
FilteringDeclaredDeclConsumer(swift::VisibleDeclConsumer &consumer,
32233232
const ClangModuleUnit *CMU)
32243233
: NextConsumer(consumer), ModuleFilter(CMU) {
3225-
assert(CMU && CMU->isTopLevel() && "Only top-level modules supported");
3234+
assert(CMU);
32263235
}
32273236

32283237
void foundDecl(ValueDecl *VD, DeclVisibilityKind Reason,
@@ -3596,10 +3605,12 @@ void ClangModuleUnit::getTopLevelDecls(SmallVectorImpl<Decl*> &results) const {
35963605

35973606
// Add the extensions produced by importing categories.
35983607
for (auto category : lookupTable->categories()) {
3599-
if (auto extension = cast_or_null<ExtensionDecl>(
3600-
owner.importDecl(category, owner.CurrentVersion,
3601-
/*UseCanonical*/false))) {
3602-
results.push_back(extension);
3608+
if (category->getOwningModule() == clangModule) {
3609+
if (auto extension = cast_or_null<ExtensionDecl>(
3610+
owner.importDecl(category, owner.CurrentVersion,
3611+
/*UseCanonical*/false))) {
3612+
results.push_back(extension);
3613+
}
36033614
}
36043615
}
36053616

lib/IDE/ModuleInterfacePrinting.cpp

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -446,9 +446,6 @@ void swift::ide::printModuleInterface(
446446
const PrintOptions &Options,
447447
const bool PrintSynthesizedExtensions) {
448448

449-
// Clang submodules aren't handled well by `getDisplayDecls()` (no decls are
450-
// returned), so map them to their top-level module and filter out the extra
451-
// results below.
452449
const clang::Module *TargetClangMod = TargetMod->findUnderlyingClangModule();
453450
ModuleDecl *TopLevelMod = TargetMod->getTopLevelModule();
454451
bool IsSubmodule = TargetMod != TopLevelMod;
@@ -460,8 +457,8 @@ void swift::ide::printModuleInterface(
460457
auto AdjustedOptions = Options;
461458
adjustPrintOptions(AdjustedOptions);
462459

463-
SmallVector<Decl *, 1> Decls;
464-
swift::getTopLevelDeclsForDisplay(TopLevelMod, Decls);
460+
SmallVector<ModuleDecl *, 1> ModuleList;
461+
ModuleList.push_back(TargetMod);
465462

466463
SmallVector<ImportDecl *, 1> ImportDecls;
467464
llvm::DenseSet<const clang::Module *> ClangModulesForImports;
@@ -485,6 +482,10 @@ void swift::ide::printModuleInterface(
485482

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

485+
if (CM != TargetClangMod)
486+
if (auto *OwningModule = Importer.getWrapperForModule(CM))
487+
ModuleList.push_back(OwningModule);
488+
488489
// If we're supposed to visit submodules, add them now.
489490
if (TraversalOptions & ModuleTraversal::VisitSubmodules) {
490491
for (clang::Module * submodule: CM->submodules()) {
@@ -499,6 +500,12 @@ void swift::ide::printModuleInterface(
499500
}
500501
}
501502

503+
SmallVector<Decl *, 1> Decls;
504+
505+
for (ModuleDecl *M : ModuleList) {
506+
swift::getTopLevelDeclsForDisplay(M, Decls);
507+
}
508+
502509
// Collect those submodules that are actually imported but have no import
503510
// decls in the module.
504511
llvm::SmallPtrSet<const clang::Module *, 16> NoImportSubModules;

lib/SymbolGraphGen/SymbolGraph.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
//===----------------------------------------------------------------------===//
1212

1313
#include "clang/AST/DeclObjC.h"
14+
#include "clang/Basic/Module.h"
1415
#include "swift/AST/ASTContext.h"
1516
#include "swift/AST/Comment.h"
1617
#include "swift/AST/Decl.h"
@@ -805,7 +806,15 @@ bool SymbolGraph::isUnconditionallyUnavailableOnAllPlatforms(const Decl *D) cons
805806
bool SymbolGraph::canIncludeDeclAsNode(const Decl *D) const {
806807
// If this decl isn't in this module or module that this module imported with `@_exported`, don't record it,
807808
// as it will appear elsewhere in its module's symbol graph.
808-
if (D->getModuleContext()->getName() != M.getName() && !Walker.isConsideredExportedImported(D)) {
809+
810+
// If a Clang decl was declared in a submodule, the Swift decl's context will still point to the
811+
// top-level module. Instead, we need to probe the owning module on the Clang side, which will
812+
// correctly point to the submodule.
813+
auto RealModuleName = (std::string)D->getModuleContext()->getName();
814+
if (auto *ClangDecl = D->getClangDecl())
815+
if (auto *ClangModule = ClangDecl->getOwningModule())
816+
RealModuleName = ClangModule->Name;
817+
if (RealModuleName != (std::string)M.getName() && !Walker.isConsideredExportedImported(D)) {
809818
return false;
810819
}
811820

lib/SymbolGraphGen/SymbolGraphASTWalker.cpp

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,11 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212

13+
#include "clang/AST/DeclObjC.h"
14+
#include "clang/Basic/Module.h"
1315
#include "llvm/ADT/StringSwitch.h"
16+
#include "swift/AST/ASTContext.h"
17+
#include "swift/AST/ClangModuleLoader.h"
1418
#include "swift/AST/Decl.h"
1519
#include "swift/AST/Module.h"
1620
#include "swift/AST/ProtocolConformance.h"
@@ -57,20 +61,32 @@ SymbolGraphASTWalker::SymbolGraphASTWalker(
5761
QualifiedExportedImports(QualifiedExportedImports),
5862
MainGraph(*this, M, std::nullopt, Ctx) {}
5963

64+
ModuleDecl *SymbolGraphASTWalker::getRealModuleOf(const Decl *D) const {
65+
ModuleDecl *Module = D->getModuleContext();
66+
if (auto *ClangDecl = D->getClangDecl())
67+
if (auto *ClangModule = ClangDecl->getOwningModule())
68+
if (auto *ClangModuleLoader = D->getASTContext().getClangModuleLoader())
69+
if (auto *M = ClangModuleLoader->getWrapperForModule(ClangModule))
70+
Module = M;
71+
72+
return Module;
73+
}
74+
6075
/// Get a "sub" symbol graph for the parent module of a type that
6176
/// the main module `M` is extending.
6277
SymbolGraph *SymbolGraphASTWalker::getModuleSymbolGraph(const Decl *D) {
63-
auto *M = D->getModuleContext();
78+
auto *M = getRealModuleOf(D);
6479
const auto *DC = D->getDeclContext();
6580
SmallVector<const NominalTypeDecl *, 2> ParentTypes = {};
6681
const Decl *ExtendedNominal = nullptr;
6782
while (DC) {
68-
M = DC->getParentModule();
6983
if (const auto *NTD = dyn_cast_or_null<NominalTypeDecl>(DC->getAsDecl())) {
7084
DC = NTD->getDeclContext();
85+
M = getRealModuleOf(NTD);
7186
ParentTypes.push_back(NTD);
7287
} else if (const auto *Ext = dyn_cast_or_null<ExtensionDecl>(DC->getAsDecl())) {
7388
DC = Ext->getExtendedNominal()->getDeclContext();
89+
M = getRealModuleOf(Ext->getExtendedNominal());
7490
if (!ExtendedNominal)
7591
ExtendedNominal = Ext->getExtendedNominal();
7692
} else {

lib/SymbolGraphGen/SymbolGraphASTWalker.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,10 @@ struct SymbolGraphASTWalker : public SourceEntityWalker {
130130
/// extension block symbol, or if its members should be directly associated
131131
/// with its extended nominal.
132132
virtual bool shouldBeRecordedAsExtension(const ExtensionDecl *ED) const;
133+
134+
/// Returns the owning module of the given decl. Loads the module from Clang if necessary, to
135+
/// correctly fetch owning submodules.
136+
virtual ModuleDecl *getRealModuleOf(const Decl *D) const;
133137
};
134138

135139
} // end namespace symbolgraphgen

0 commit comments

Comments
 (0)