Skip to content

Commit 7eae31b

Browse files
committed
register nested types declared inside #if blocks in the symbol table
Cherry-picked from swiftlang#823 (ktoso). Nested type/typealias members wrapped in an #if/#else were never visited when building the per-parent nested-type map, since the member-walk only checked for a direct nominal or typealias decl and skipped IfConfigDeclSyntax entirely - so such a type was invisible to lookups needing its parent, same class of symptom as the extension-declared case fixed in cf5bd53, but a genuinely separate gap (verified empirically: this PR alone, without cf5bd53, does not fix the original extension-based repro - the two fixes are complementary, not overlapping).
1 parent 6f82991 commit 7eae31b

2 files changed

Lines changed: 164 additions & 5 deletions

File tree

‎Sources/SwiftExtract/SwiftTypes/SwiftParsedModuleSymbolTableBuilder.swift‎

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -174,11 +174,37 @@ extension SwiftParsedModuleSymbolTableBuilder {
174174
parent: SwiftNominalTypeDeclaration
175175
) {
176176
for member in node.members {
177-
// Find any nested types within this nominal type and add them.
178-
if let nominalMember = member.decl.asNominal {
179-
self.handle(sourceFilePath: sourceFilePath, nominalTypeDecl: nominalMember, parent: parent)
180-
} else if let typeAliasMember = member.decl.as(TypeAliasDeclSyntax.self) {
181-
self.handle(sourceFilePath: sourceFilePath, typeAliasDecl: typeAliasMember, parent: parent)
177+
self.handle(sourceFilePath: sourceFilePath, memberDecl: member.decl, parent: parent)
178+
}
179+
}
180+
181+
/// Add a nested type declaration to the symbol table.
182+
package mutating func handle(
183+
sourceFilePath: String,
184+
memberDecl decl: DeclSyntax,
185+
parent: SwiftNominalTypeDeclaration
186+
) {
187+
if let nominalMember = decl.asNominal {
188+
self.handle(sourceFilePath: sourceFilePath, nominalTypeDecl: nominalMember, parent: parent)
189+
} else if let typeAliasMember = decl.as(TypeAliasDeclSyntax.self) {
190+
self.handle(sourceFilePath: sourceFilePath, typeAliasDecl: typeAliasMember, parent: parent)
191+
} else if let ifConfigNode = decl.as(IfConfigDeclSyntax.self) {
192+
let (clause, _) = ifConfigNode.activeClause(in: buildConfig)
193+
if let clause, let elements = clause.elements {
194+
switch elements {
195+
case .decls(let memberBlock):
196+
for memberItem in memberBlock {
197+
self.handle(sourceFilePath: sourceFilePath, memberDecl: memberItem.decl, parent: parent)
198+
}
199+
case .statements(let codeBlock):
200+
for codeItem in codeBlock {
201+
if let declNode = codeItem.item.as(DeclSyntax.self) {
202+
self.handle(sourceFilePath: sourceFilePath, memberDecl: declNode, parent: parent)
203+
}
204+
}
205+
default:
206+
break
207+
}
182208
}
183209
}
184210
}

‎Tests/JExtractSwiftTests/JNI/JNINestedTypesTests.swift‎

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,139 @@ struct JNINestedTypesTests {
102102
)
103103
}
104104

105+
@Test("Import: shadowed nested type name")
106+
func shadowedNestedTypeName_java() throws {
107+
// A nested type whose name shadows a type of the same name in an outer
108+
// scope must resolve to the innermost declaration.
109+
try assertOutput(
110+
input: """
111+
public struct Outer: Sendable, Codable {
112+
public enum Kind: Sendable, Codable {
113+
case alpha
114+
case beta
115+
}
116+
117+
public struct Inner: Sendable, Codable {
118+
public enum Kind: Sendable, Codable {
119+
case one
120+
case two
121+
}
122+
123+
public var kind: Kind // Outer.Inner.Kind
124+
}
125+
126+
public var kind: Kind // Outer.Kind
127+
public var inner: Inner
128+
}
129+
""",
130+
.jni,
131+
.java,
132+
detectChunkByInitialLines: 1,
133+
expectedChunks: [
134+
// The `Inner.kind` property must reference `Outer.Inner.Kind`, not `Outer.Kind`.
135+
"""
136+
public Outer.Inner.Kind getKind(SwiftArena swiftArena) {
137+
return Outer.Inner.Kind.wrapMemoryAddressUnsafe(Outer.Inner.$getKind(this.$memoryAddress()), swiftArena);
138+
""",
139+
"""
140+
public void setKind(Outer.Inner.Kind newValue) {
141+
Outer.Inner.$setKind(newValue.$memoryAddress(), this.$memoryAddress());
142+
""",
143+
// The outer `kind` must reference `Outer.Kind`.
144+
"""
145+
public Outer.Kind getKind(SwiftArena swiftArena) {
146+
return Outer.Kind.wrapMemoryAddressUnsafe(Outer.$getKind(this.$memoryAddress()), swiftArena);
147+
""",
148+
]
149+
)
150+
}
151+
152+
@Test("Import: shadowed nested type name inside #if")
153+
func shadowedNestedTypeName_ifConfig_java() throws {
154+
try assertOutput(
155+
input: """
156+
public struct Outer {
157+
#if SOME_FLAG
158+
public enum Kind {
159+
case alphaX
160+
}
161+
#else
162+
public enum Kind {
163+
case alpha
164+
case beta
165+
}
166+
#endif
167+
168+
public struct Inner {
169+
#if SOME_FLAG
170+
public enum Kind {
171+
case oneX
172+
}
173+
#else
174+
public enum Kind {
175+
case one
176+
case two
177+
}
178+
#endif
179+
180+
public var kind: Kind // Outer.Inner.Kind
181+
}
182+
183+
public var kind: Kind // Outer.Kind
184+
public var inner: Inner
185+
}
186+
""",
187+
.jni,
188+
.java,
189+
detectChunkByInitialLines: 1,
190+
expectedChunks: [
191+
"""
192+
public Outer.Inner.Kind getKind(SwiftArena swiftArena) {
193+
return Outer.Inner.Kind.wrapMemoryAddressUnsafe(Outer.Inner.$getKind(this.$memoryAddress()), swiftArena);
194+
""",
195+
"""
196+
public void setKind(Outer.Inner.Kind newValue) {
197+
Outer.Inner.$setKind(newValue.$memoryAddress(), this.$memoryAddress());
198+
""",
199+
]
200+
)
201+
}
202+
203+
@Test("Import: shadowed nested type name in deeper nesting")
204+
func shadowedNestedTypeName_deep_java() throws {
205+
try assertOutput(
206+
input: """
207+
public struct DiscordChannel {
208+
public struct Kind {
209+
public init() {}
210+
}
211+
212+
public struct Message {
213+
public struct MessageReference {
214+
public struct Kind {
215+
public init() {}
216+
}
217+
public var kind: Kind
218+
}
219+
}
220+
}
221+
""",
222+
.jni,
223+
.java,
224+
detectChunkByInitialLines: 1,
225+
expectedChunks: [
226+
// The `MessageReference.kind` property must reference the deeply nested
227+
// `DiscordChannel.Message.MessageReference.Kind`, not `DiscordChannel.Kind`.
228+
"""
229+
public DiscordChannel.Message.MessageReference.Kind getKind(SwiftArena swiftArena) {
230+
""",
231+
"""
232+
public void setKind(DiscordChannel.Message.MessageReference.Kind newValue) {
233+
""",
234+
]
235+
)
236+
}
237+
105238
@Test("Import: nested in enum")
106239
func nestedEnums_java() throws {
107240
try assertOutput(

0 commit comments

Comments
 (0)