@@ -37,23 +37,28 @@ bool areModulesEqual(const ModuleDecl *lhs, const ModuleDecl *rhs, bool ignoreUn
37
37
38
38
SymbolGraphASTWalker::SymbolGraphASTWalker (ModuleDecl &M,
39
39
const SmallPtrSet<ModuleDecl *, 4 > ExportedImportedModules,
40
+ const llvm::SmallDenseMap<ModuleDecl *, SmallPtrSet<Decl *, 4 >, 4 > QualifiedExportedImports,
40
41
const SymbolGraphOptions &Options)
41
42
: Options(Options),
42
43
M(M),
43
44
ExportedImportedModules(ExportedImportedModules),
45
+ QualifiedExportedImports(QualifiedExportedImports),
44
46
MainGraph(*this , M, None, Ctx) {}
45
47
46
48
// / Get a "sub" symbol graph for the parent module of a type that
47
49
// / the main module `M` is extending.
48
50
SymbolGraph *SymbolGraphASTWalker::getModuleSymbolGraph (const Decl *D) {
49
51
auto *M = D->getModuleContext ();
50
52
const auto *DC = D->getDeclContext ();
53
+ const Decl *ExtendedNominal = nullptr ;
51
54
while (DC) {
52
55
M = DC->getParentModule ();
53
56
if (const auto *NTD = dyn_cast_or_null<NominalTypeDecl>(DC->getAsDecl ())) {
54
57
DC = NTD->getDeclContext ();
55
58
} else if (const auto *Ext = dyn_cast_or_null<ExtensionDecl>(DC->getAsDecl ())) {
56
59
DC = Ext->getExtendedNominal ()->getDeclContext ();
60
+ if (!ExtendedNominal)
61
+ ExtendedNominal = Ext->getExtendedNominal ();
57
62
} else {
58
63
DC = nullptr ;
59
64
}
@@ -67,8 +72,16 @@ SymbolGraph *SymbolGraphASTWalker::getModuleSymbolGraph(const Decl *D) {
67
72
// should put actual extensions of that module into the main graph
68
73
return &MainGraph;
69
74
}
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)) {
72
85
return &MainGraph;
73
86
}
74
87
@@ -230,9 +243,49 @@ bool SymbolGraphASTWalker::walkToDeclPre(Decl *D, CharSourceRange Range) {
230
243
return true ;
231
244
}
232
245
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
+
233
280
bool SymbolGraphASTWalker::isFromExportedImportedModule (const Decl* D) const {
234
281
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
+ });
236
289
}
237
290
238
291
bool SymbolGraphASTWalker::isExportedImportedModule (const ModuleDecl *M) const {
0 commit comments