Skip to content

Commit b7079f4

Browse files
add "public type alias" support for more symbol relationships
1 parent 28c5c4f commit b7079f4

File tree

3 files changed

+78
-38
lines changed

3 files changed

+78
-38
lines changed

lib/SymbolGraphGen/SymbolGraph.cpp

Lines changed: 50 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,18 @@ void SymbolGraph::recordEdge(Symbol Source,
232232

233233
void SymbolGraph::recordMemberRelationship(Symbol S) {
234234
const auto *DC = S.getLocalSymbolDecl()->getDeclContext();
235+
const ValueDecl *ParentDecl = DC->getSelfNominalTypeDecl();
236+
if (!ParentDecl) {
237+
// If we couldn't look up the type the member is declared on (e.g.
238+
// because the member is declared in an extension whose extended type
239+
// doesn't exist), don't record a memberOf relationship.
240+
return;
241+
}
242+
if (const auto *PublicDecl = Walker.PublicPrivateTypeAliases[ParentDecl]) {
243+
// If our member target is a private type that has a public type alias,
244+
// point the membership to that type alias instead.
245+
ParentDecl = PublicDecl;
246+
}
235247
switch (DC->getContextKind()) {
236248
case DeclContextKind::GenericTypeDecl:
237249
case DeclContextKind::ExtensionDecl:
@@ -250,13 +262,6 @@ void SymbolGraph::recordMemberRelationship(Symbol S) {
250262
return;
251263
}
252264

253-
if (DC->getSelfNominalTypeDecl() == nullptr) {
254-
// If we couldn't look up the type the member is declared on (e.g.
255-
// because the member is declared in an extension whose extended type
256-
// doesn't exist), don't record a memberOf relationship.
257-
return;
258-
}
259-
260265
// If this is an extension to an external type, we use the extension
261266
// symbol itself as the target.
262267
if (auto const *Extension =
@@ -268,22 +273,8 @@ void SymbolGraph::recordMemberRelationship(Symbol S) {
268273
}
269274
}
270275

271-
if (Walker.PublicPrivateTypeAliases.contains(
272-
DC->getSelfNominalTypeDecl())) {
273-
// If our member target is a private type that has a public type alias,
274-
// point the membership to that type alias instead.
275-
return recordEdge(
276-
S,
277-
Symbol(
278-
this,
279-
Walker.PublicPrivateTypeAliases[DC->getSelfNominalTypeDecl()],
280-
nullptr),
281-
RelationshipKind::MemberOf());
282-
} else {
283-
return recordEdge(S,
284-
Symbol(this, DC->getSelfNominalTypeDecl(), nullptr),
285-
RelationshipKind::MemberOf());
286-
}
276+
return recordEdge(S, Symbol(this, ParentDecl, nullptr),
277+
RelationshipKind::MemberOf());
287278
case swift::DeclContextKind::AbstractClosureExpr:
288279
case swift::DeclContextKind::SerializedAbstractClosure:
289280
case swift::DeclContextKind::Initializer:
@@ -335,7 +326,16 @@ void SymbolGraph::recordConformanceSynthesizedMemberRelationships(Symbol S) {
335326
bool dropSynthesizedMembers = !Walker.Options.EmitSynthesizedMembers ||
336327
Walker.Options.SkipProtocolImplementations;
337328

338-
const auto D = S.getLocalSymbolDecl();
329+
const auto *D = S.getLocalSymbolDecl();
330+
331+
// If this symbol is a public type alias to a private symbol, collect
332+
// synthesized members for the underlying type.
333+
if (const auto *TD = dyn_cast<TypeAliasDecl>(D)) {
334+
const auto *NTD = TD->getUnderlyingType()->getAnyNominal();
335+
if (NTD && Walker.PublicPrivateTypeAliases[NTD] == D)
336+
D = NTD;
337+
}
338+
339339
const NominalTypeDecl *OwningNominal = nullptr;
340340
if (const auto *ThisNominal = dyn_cast<NominalTypeDecl>(D)) {
341341
OwningNominal = ThisNominal;
@@ -421,7 +421,11 @@ void SymbolGraph::recordConformanceSynthesizedMemberRelationships(Symbol S) {
421421
continue;
422422
}
423423

424-
Symbol Source(this, SynthMember, OwningNominal);
424+
const ValueDecl *BaseDecl = OwningNominal;
425+
if (Walker.PublicPrivateTypeAliases.contains(BaseDecl))
426+
BaseDecl = Walker.PublicPrivateTypeAliases[BaseDecl];
427+
428+
Symbol Source(this, SynthMember, BaseDecl);
425429

426430
if (auto *InheritedDecl = Source.getInheritedDecl()) {
427431
if (auto *ParentDecl =
@@ -439,7 +443,7 @@ void SymbolGraph::recordConformanceSynthesizedMemberRelationships(Symbol S) {
439443
}
440444
}
441445

442-
auto ExtendedSG = Walker.getModuleSymbolGraph(OwningNominal);
446+
auto ExtendedSG = Walker.getModuleSymbolGraph(BaseDecl);
443447

444448
ExtendedSG->Nodes.insert(Source);
445449

@@ -452,7 +456,15 @@ void SymbolGraph::recordConformanceSynthesizedMemberRelationships(Symbol S) {
452456

453457
void
454458
SymbolGraph::recordInheritanceRelationships(Symbol S) {
455-
const auto D = S.getLocalSymbolDecl();
459+
const auto *D = S.getLocalSymbolDecl();
460+
461+
// If this is a public type alias for a private symbol, gather inheritance
462+
// for the underlying type instead.
463+
if (const auto *TD = dyn_cast<TypeAliasDecl>(D)) {
464+
const auto *NTD = TD->getUnderlyingType()->getAnyNominal();
465+
if (NTD && Walker.PublicPrivateTypeAliases[NTD] == D)
466+
D = NTD;
467+
}
456468

457469
ClassDecl *Super = nullptr;
458470
if (auto *CD = dyn_cast<ClassDecl>(D))
@@ -461,8 +473,7 @@ SymbolGraph::recordInheritanceRelationships(Symbol S) {
461473
Super = PD->getSuperclassDecl();
462474

463475
if (Super) {
464-
recordEdge(Symbol(this, cast<ValueDecl>(D), nullptr),
465-
Symbol(this, Super, nullptr),
476+
recordEdge(S, Symbol(this, Super, nullptr),
466477
RelationshipKind::InheritsFrom());
467478
}
468479
}
@@ -541,7 +552,16 @@ void SymbolGraph::recordOptionalRequirementRelationships(Symbol S) {
541552
}
542553

543554
void SymbolGraph::recordConformanceRelationships(Symbol S) {
544-
const auto D = S.getLocalSymbolDecl();
555+
const auto *D = S.getLocalSymbolDecl();
556+
557+
// If this is a public type alias for a private symbol, gather conformances
558+
// for the underlying type instead.
559+
if (const auto *TD = dyn_cast<TypeAliasDecl>(D)) {
560+
const auto *NTD = TD->getUnderlyingType()->getAnyNominal();
561+
if (NTD && Walker.PublicPrivateTypeAliases[NTD] == D)
562+
D = NTD;
563+
}
564+
545565
if (const auto *NTD = dyn_cast<NominalTypeDecl>(D)) {
546566
if (auto *PD = dyn_cast<ProtocolDecl>(NTD)) {
547567
for (auto *inherited : PD->getAllInheritedProtocols()) {

lib/SymbolGraphGen/SymbolGraphASTWalker.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,11 +60,11 @@ struct SymbolGraphASTWalker : public SourceEntityWalker {
6060
llvm::StringMap<SymbolGraph *> ExtendedModuleGraphs;
6161

6262
/// A temporary pointer to a base decl when crawling symbols to synthesize.
63-
const ValueDecl *BaseDecl;
63+
const ValueDecl *BaseDecl = nullptr;
6464

6565
/// A temporary pointer to the top-level decl being crawled when synthesizing
6666
/// child symbols.
67-
const Decl *SynthesizedChildrenBaseDecl;
67+
const Decl *SynthesizedChildrenBaseDecl = nullptr;
6868

6969
/// Maps any internal symbol with a public type alias of that symbol.
7070
llvm::DenseMap<const ValueDecl *, const ValueDecl *> PublicPrivateTypeAliases;

test/SymbolGraph/Relationships/Synthesized/HiddenTypeAlias.swift

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,39 @@
11
// RUN: %empty-directory(%t)
22
// RUN: %target-build-swift %s -module-name HiddenTypeAlias -emit-module -emit-module-path %t/
3-
// RUN: %target-swift-symbolgraph-extract -module-name HiddenTypeAlias -I %t -pretty-print -output-dir %t
3+
// RUN: %target-swift-symbolgraph-extract -module-name HiddenTypeAlias -I %t -pretty-print -output-dir %t -v
44
// RUN: %FileCheck %s --input-file %t/HiddenTypeAlias.symbols.json
55

66
// Ensure that public type aliases of effectively-private symbols inherit the child symbols of the
77
// inner type.
88

9-
// CHECK-NOT: "OuterType._InnerType"
10-
// CHECK-DAG: "title": "OuterType"
9+
// _InnerType's type name should only appear in quotes like this once, in the declaration for OuterType
10+
// CHECK-COUNT-1: "_InnerType"
1111

12-
// CHECK-DAG: "precise": "s:15HiddenTypeAlias06_InnerB0V8someFuncyyF::SYNTHESIZED::s:15HiddenTypeAlias05OuterB0a"
12+
// _InnerType.someFunc() as synthesized on OuterType
13+
// CHECK-DAG: "precise": "s:15HiddenTypeAlias06_InnerB0C8someFuncyyF::SYNTHESIZED::s:15HiddenTypeAlias05OuterB0a"
1314

14-
// CHECK-DAG: "kind": "memberOf",{{[[:space:]]*}}"source": "s:15HiddenTypeAlias06_InnerB0V8someFuncyyF::SYNTHESIZED::s:15HiddenTypeAlias05OuterB0a",{{[[:space:]]*}}"target": "s:15HiddenTypeAlias05OuterB0a"
15+
// someFunc is a member of OuterType
16+
// CHECK-DAG: "kind": "memberOf",{{[[:space:]]*}}"source": "s:15HiddenTypeAlias06_InnerB0C8someFuncyyF::SYNTHESIZED::s:15HiddenTypeAlias05OuterB0a",{{[[:space:]]*}}"target": "s:15HiddenTypeAlias05OuterB0a"
1517

16-
public struct _InnerType {
18+
// OuterType conforms to SomeProtocol
19+
// CHECK-DAG: "kind": "conformsTo",{{[[:space:]]*}}"source": "s:15HiddenTypeAlias05OuterB0a",{{[[:space:]]*}}"target": "s:15HiddenTypeAlias12SomeProtocolP"
20+
21+
// OuterType "inherits from" BaseType
22+
// CHECK-DAG: "kind": "inheritsFrom",{{[[:space:]]*}}"source": "s:15HiddenTypeAlias05OuterB0a",{{[[:space:]]*}}"target": "s:15HiddenTypeAlias04BaseB0C"
23+
24+
// bonusFunc as a synthesized member of OuterType
25+
// CHECK-DAG: "precise": "s:15HiddenTypeAlias12SomeProtocolPAAE9bonusFuncyyF::SYNTHESIZED::s:15HiddenTypeAlias05OuterB0a",
26+
// CHECK-DAG: "kind": "memberOf",{{[[:space:]]*}}"source": "s:15HiddenTypeAlias12SomeProtocolPAAE9bonusFuncyyF::SYNTHESIZED::s:15HiddenTypeAlias05OuterB0a",{{[[:space:]]*}}"target": "s:15HiddenTypeAlias05OuterB0a",
27+
28+
public protocol SomeProtocol {}
29+
30+
extension SomeProtocol {
31+
public func bonusFunc() {}
32+
}
33+
34+
public class BaseType {}
35+
36+
public class _InnerType: BaseType, SomeProtocol {
1737
public func someFunc() {}
1838
}
1939

0 commit comments

Comments
 (0)