@@ -37,23 +37,28 @@ bool areModulesEqual(const ModuleDecl *lhs, const ModuleDecl *rhs, bool ignoreUn
3737
3838SymbolGraphASTWalker::SymbolGraphASTWalker (ModuleDecl &M,
3939 const SmallPtrSet<ModuleDecl *, 4 > ExportedImportedModules,
40+ const llvm::SmallDenseMap<ModuleDecl *, SmallPtrSet<Decl *, 4 >, 4 > QualifiedExportedImports,
4041 const SymbolGraphOptions &Options)
4142 : Options(Options),
4243 M(M),
4344 ExportedImportedModules(ExportedImportedModules),
45+ QualifiedExportedImports(QualifiedExportedImports),
4446 MainGraph(*this , M, None, Ctx) {}
4547
4648// / Get a "sub" symbol graph for the parent module of a type that
4749// / the main module `M` is extending.
4850SymbolGraph *SymbolGraphASTWalker::getModuleSymbolGraph (const Decl *D) {
4951 auto *M = D->getModuleContext ();
5052 const auto *DC = D->getDeclContext ();
53+ const Decl *ExtendedNominal = nullptr ;
5154 while (DC) {
5255 M = DC->getParentModule ();
5356 if (const auto *NTD = dyn_cast_or_null<NominalTypeDecl>(DC->getAsDecl ())) {
5457 DC = NTD->getDeclContext ();
5558 } else if (const auto *Ext = dyn_cast_or_null<ExtensionDecl>(DC->getAsDecl ())) {
5659 DC = Ext->getExtendedNominal ()->getDeclContext ();
60+ if (!ExtendedNominal)
61+ ExtendedNominal = Ext->getExtendedNominal ();
5762 } else {
5863 DC = nullptr ;
5964 }
@@ -67,8 +72,16 @@ SymbolGraph *SymbolGraphASTWalker::getModuleSymbolGraph(const Decl *D) {
6772 // should put actual extensions of that module into the main graph
6873 return &MainGraph;
6974 }
70-
71- if (isExportedImportedModule (M)) {
75+
76+ // Check the module and decl separately since the extension could be from a different module
77+ // than the decl itself.
78+ if (isExportedImportedModule (M) || isQualifiedExportedImport (D)) {
79+ return &MainGraph;
80+ }
81+
82+ if (ExtendedNominal && isFromExportedImportedModule (ExtendedNominal)) {
83+ return &MainGraph;
84+ } else if (!ExtendedNominal && isConsideredExportedImported (D)) {
7285 return &MainGraph;
7386 }
7487
@@ -230,9 +243,49 @@ bool SymbolGraphASTWalker::walkToDeclPre(Decl *D, CharSourceRange Range) {
230243 return true ;
231244}
232245
246+ bool SymbolGraphASTWalker::isConsideredExportedImported (const Decl *D) const {
247+ // First check the decl itself to see if it was directly re-exported.
248+ if (isFromExportedImportedModule (D))
249+ return true ;
250+
251+ const auto *DC = D->getDeclContext ();
252+
253+ // Next, see if the decl is a child symbol of another decl that was re-exported.
254+ if (DC) {
255+ if (const auto *VD = dyn_cast_or_null<ValueDecl>(DC->getAsDecl ())) {
256+ if (isFromExportedImportedModule (VD))
257+ return true ;
258+ }
259+ }
260+
261+ // Finally, check to see if this decl is an extension of something else that was re-exported.
262+ // FIXME: this considers synthesized members of extensions to be valid
263+ const Decl *ExtendedNominal = nullptr ;
264+ while (DC && !ExtendedNominal) {
265+ if (const auto *ED = dyn_cast_or_null<ExtensionDecl>(DC->getAsDecl ())) {
266+ ExtendedNominal = ED->getExtendedNominal ();
267+ } else {
268+ DC = DC->getParent ();
269+ }
270+ }
271+
272+ if (ExtendedNominal && isFromExportedImportedModule (ExtendedNominal)) {
273+ return true ;
274+ }
275+
276+ // If none of the other checks passed, this wasn't from a re-export.
277+ return false ;
278+ }
279+
233280bool SymbolGraphASTWalker::isFromExportedImportedModule (const Decl* D) const {
234281 auto *M = D->getModuleContext ();
235- return isExportedImportedModule (M);
282+ return isQualifiedExportedImport (D) || isExportedImportedModule (M);
283+ }
284+
285+ bool SymbolGraphASTWalker::isQualifiedExportedImport (const Decl *D) const {
286+ return llvm::any_of (QualifiedExportedImports, [&D](const auto &QI) {
287+ return QI.getSecond ().contains (D);
288+ });
236289}
237290
238291bool SymbolGraphASTWalker::isExportedImportedModule (const ModuleDecl *M) const {
0 commit comments