only recurse public-private type aliases from Clang (#79996)

rdar://145980187
This commit is contained in:
QuietMisdreavus
2025-03-31 09:10:58 -06:00
committed by GitHub
parent 96f073d8ba
commit f5c531c8f9
3 changed files with 44 additions and 17 deletions

View File

@@ -335,6 +335,9 @@ bool SymbolGraphASTWalker::walkToDeclPre(Decl *D, CharSourceRange Range) {
}
}
// If this is a Clang typedef of an underlying type that is being hidden (e.g. `typedef struct
// _MyStruct { ... } MyStruct`) then copy in the child symbols from the underlying type to the
// type alias.
if (const auto *TD = dyn_cast_or_null<TypeAliasDecl>(VD)) {
const auto InnerType = TD->getUnderlyingType();
if (NominalTypeDecl *NTD = InnerType->getAnyNominal()) {
@@ -342,8 +345,18 @@ bool SymbolGraphASTWalker::walkToDeclPre(Decl *D, CharSourceRange Range) {
// otherwise isn't being shown
if (isOurModule(NTD->getModuleContext()) &&
!SG->canIncludeDeclAsNode(NTD)) {
PublicPrivateTypeAliases.insert_or_assign(NTD, TD);
synthesizeChildSymbols(NTD, TD);
// We specifically only want to look for underlying types that are "embedded" in the typedef
// definition, so let's pull out the Clang decl and check for that
if (NTD->hasClangNode()) {
if (const auto *ClangDecl = NTD->getClangNode().getAsDecl()) {
if (const auto *ClangTagDecl = dyn_cast<clang::TagDecl>(ClangDecl)) {
if (ClangTagDecl->isEmbeddedInDeclarator()) {
PublicPrivateTypeAliases.insert_or_assign(NTD, TD);
synthesizeChildSymbols(NTD, TD);
}
}
}
}
}
}
}

View File

@@ -10,21 +10,7 @@
// _InnerType's type name should only appear in quotes like this once, in the declaration for OuterType
// INNER-COUNT-1: "_InnerType"
// _InnerType.someFunc() as synthesized on OuterType
// CHECK-DAG: "precise": "s:15HiddenTypeAlias06_InnerB0C8someFuncyyF::SYNTHESIZED::s:15HiddenTypeAlias05OuterB0a"
// someFunc is a member of OuterType
// CHECK-DAG: "kind": "memberOf",{{[[:space:]]*}}"source": "s:15HiddenTypeAlias06_InnerB0C8someFuncyyF::SYNTHESIZED::s:15HiddenTypeAlias05OuterB0a",{{[[:space:]]*}}"target": "s:15HiddenTypeAlias05OuterB0a"
// OuterType conforms to SomeProtocol
// CHECK-DAG: "kind": "conformsTo",{{[[:space:]]*}}"source": "s:15HiddenTypeAlias05OuterB0a",{{[[:space:]]*}}"target": "s:15HiddenTypeAlias12SomeProtocolP"
// OuterType "inherits from" BaseType
// CHECK-DAG: "kind": "inheritsFrom",{{[[:space:]]*}}"source": "s:15HiddenTypeAlias05OuterB0a",{{[[:space:]]*}}"target": "s:15HiddenTypeAlias04BaseB0C"
// bonusFunc as a synthesized member of OuterType
// CHECK-DAG: "precise": "s:15HiddenTypeAlias12SomeProtocolPAAE9bonusFuncyyF::SYNTHESIZED::s:15HiddenTypeAlias05OuterB0a",
// CHECK-DAG: "kind": "memberOf",{{[[:space:]]*}}"source": "s:15HiddenTypeAlias12SomeProtocolPAAE9bonusFuncyyF::SYNTHESIZED::s:15HiddenTypeAlias05OuterB0a",{{[[:space:]]*}}"target": "s:15HiddenTypeAlias05OuterB0a",
// CHECK-NOT: someFunc
public protocol SomeProtocol {}

View File

@@ -0,0 +1,28 @@
// RUN: %empty-directory(%t)
// RUN: %target-build-swift %s -module-name HiddenTypeAliasRecursive -emit-module -emit-module-path %t/
// RUN: %target-swift-symbolgraph-extract -module-name HiddenTypeAliasRecursive -I %t -pretty-print -output-dir %t -v
// RUN: %FileCheck %s --input-file %t/HiddenTypeAliasRecursive.symbols.json
// Ensure that mutually-recursive public-private type aliases don't cause infinite recursion in
// SymbolGraphGen when generating symbol graphs. (rdar://145980187)
// HiddenClassB is not referenced by any public symbol, so it shouldn't appear in any symbol graph
// CHECK-NOT: HiddenClassB
// HiddenClassA should only appear one time: in the declaration for PublicAlias
// CHECK-COUNT-1: HiddenClassA
// CHECK-NOT: HiddenClassA
@_documentation(visibility: private)
public class HiddenClassA {
public typealias ProblematicA = HiddenClassB
public func funcA() {}
}
@_documentation(visibility: private)
public class HiddenClassB {
public typealias ProblematicB = HiddenClassA
public func funcB() {}
}
public typealias PublicAlias = HiddenClassA