Skip to content

Commit 2c3fff8

Browse files
authored
Initial module qualified lookups (#704)
1 parent dbc911e commit 2c3fff8

5 files changed

Lines changed: 122 additions & 11 deletions

File tree

Sources/JExtractSwiftLib/Swift2JavaTranslator.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ extension Swift2JavaTranslator {
103103
}
104104

105105
package func add(filePath: String, text: String) {
106-
log.info("Adding: \(filePath)")
106+
log.debug("Adding: \(filePath)")
107107
let sourceFileSyntax = Parser.parse(source: text)
108108
self.inputs.append(SwiftJavaInputFile(syntax: sourceFileSyntax, path: filePath))
109109
}

Sources/JExtractSwiftLib/SwiftTypes/SwiftSymbolTable.swift

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -153,11 +153,17 @@ extension SwiftSymbolTable: SwiftSymbolTableProtocol {
153153
}
154154
}
155155

156-
// FIXME: Implement module qualified name lookups. E.g. 'Swift.String'
157-
158156
return nil
159157
}
160158

159+
/// Look for a top-level nominal type in a specific module by name
160+
package func lookupTopLevelNominalType(_ name: String, inModule moduleName: String) -> SwiftNominalTypeDeclaration? {
161+
if moduleName == self.moduleName {
162+
return parsedModule.lookupTopLevelNominalType(name)
163+
}
164+
return importedModules[moduleName]?.lookupTopLevelNominalType(name)
165+
}
166+
161167
// Look for a nested type with the given name.
162168
package func lookupNestedType(_ name: String, parent: SwiftNominalTypeDeclaration) -> SwiftNominalTypeDeclaration? {
163169
if let parsedResult = parsedModule.lookupNestedType(name, parent: parent) {

Sources/JExtractSwiftLib/SwiftTypes/SwiftType.swift

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -353,16 +353,18 @@ extension SwiftType {
353353
self = knownTypes.optionalSugar(try SwiftType(optionalType.wrappedType, lookupContext: lookupContext))
354354

355355
case .memberType(let memberType):
356-
// If the parent type isn't a known module, translate it.
357-
// FIXME: Need a more reasonable notion of which names are module names
358-
// for this to work. What can we query for this information?
356+
// If the parent type is a known module name, perform a module-qualified
357+
// lookup instead of treating the module as a parent type
359358
let parentType: SwiftType?
359+
let moduleName: String?
360360
if let base = memberType.baseType.as(IdentifierTypeSyntax.self),
361361
lookupContext.symbolTable.isModuleName(base.name.trimmedDescription)
362362
{
363363
parentType = nil
364+
moduleName = base.name.trimmedDescription
364365
} else {
365366
parentType = try SwiftType(memberType.baseType, lookupContext: lookupContext)
367+
moduleName = nil
366368
}
367369

368370
// Translate the generic arguments.
@@ -382,7 +384,8 @@ extension SwiftType {
382384
parent: parentType,
383385
name: memberType.name,
384386
genericArguments: genericArgs,
385-
lookupContext: lookupContext
387+
lookupContext: lookupContext,
388+
module: moduleName
386389
)
387390

388391
case .metatypeType(let metatypeType):
@@ -431,7 +434,8 @@ extension SwiftType {
431434
parent: SwiftType?,
432435
name: TokenSyntax,
433436
genericArguments: [SwiftType]?,
434-
lookupContext: SwiftTypeLookupContext
437+
lookupContext: SwiftTypeLookupContext,
438+
module: String? = nil
435439
) throws {
436440
// Look up the imported types by name to resolve it to a nominal type.
437441
let typeDecl: SwiftTypeDeclaration?
@@ -440,6 +444,8 @@ extension SwiftType {
440444
throw TypeTranslationError.unknown(originalType)
441445
}
442446
typeDecl = lookupContext.symbolTable.lookupNestedType(name.text, parent: parentDecl)
447+
} else if let module {
448+
typeDecl = lookupContext.moduleQualifiedLookup(name: name.text, in: module)
443449
} else {
444450
guard let ident = Identifier(name) else {
445451
throw TypeTranslationError.unknown(originalType)

Sources/JExtractSwiftLib/SwiftTypes/SwiftTypeLookupContext.swift

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@
1515
@_spi(Experimental) import SwiftLexicalLookup
1616
import SwiftSyntax
1717

18-
/// Unqualified type lookup manager.
19-
/// All unqualified lookup should be done via this instance. This caches the
18+
/// Type lookup manager.
19+
/// All type lookups should be done via this instance. This caches the
2020
/// association of `Syntax.ID` to `SwiftTypeDeclaration`, and guarantees that
2121
/// there's only one `SwiftTypeDeclaration` per declaration `Syntax`.
2222
class SwiftTypeLookupContext {
@@ -28,6 +28,15 @@ class SwiftTypeLookupContext {
2828
self.symbolTable = symbolTable
2929
}
3030

31+
/// Perform module-qualified type lookup in a specific module
32+
///
33+
/// - Parameters:
34+
/// - name: name to lookup
35+
/// - moduleName: the module to look in
36+
func moduleQualifiedLookup(name: String, in moduleName: String) -> SwiftTypeDeclaration? {
37+
symbolTable.lookupTopLevelNominalType(name, inModule: moduleName)
38+
}
39+
3140
/// Perform unqualified type lookup.
3241
///
3342
/// - Parameters:

Tests/JExtractSwiftTests/SwiftSymbolTableTests.swift

Lines changed: 91 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ struct SwiftSymbolTableSuite {
8181
public struct MyValue {}
8282
}
8383
84-
public func fullyQualifiedType() -> MyModule.MyModule.MyValue
84+
public func fullyQualifiedType() -> MyModule.MyModule.MyValue
8585
""",
8686
mode,
8787
.java,
@@ -92,4 +92,94 @@ struct SwiftSymbolTableSuite {
9292
],
9393
)
9494
}
95+
96+
@Test func moduleScopedLookup() throws {
97+
let sourceFile: SourceFileSyntax = """
98+
public struct MyClass {}
99+
"""
100+
let symbolTable = SwiftSymbolTable.setup(
101+
moduleName: "MyModule",
102+
[
103+
.init(syntax: sourceFile, path: "Fake.swift")
104+
],
105+
config: nil,
106+
log: Logger(label: "swift-java", logLevel: .critical),
107+
)
108+
109+
// Lookup in self-module by qualified name
110+
let myClass = symbolTable.lookupTopLevelNominalType("MyClass", inModule: "MyModule")
111+
#expect(myClass != nil)
112+
#expect(myClass?.qualifiedName == "MyClass")
113+
114+
// Lookup in imported module (Swift)
115+
let swiftInt = symbolTable.lookupTopLevelNominalType("Int", inModule: "Swift")
116+
#expect(swiftInt != nil)
117+
#expect(swiftInt?.qualifiedName == "Int")
118+
119+
// Lookup in unknown module returns nil
120+
let unknown = symbolTable.lookupTopLevelNominalType("Foo", inModule: "NoSuchModule")
121+
#expect(unknown == nil)
122+
}
123+
124+
@Test(arguments: [JExtractGenerationMode.jni, .ffm])
125+
func resolveQualifiedTypesInFunctionSignatures(mode: JExtractGenerationMode) throws {
126+
try assertOutput(
127+
input: """
128+
public struct MySwiftClass {
129+
public init() {}
130+
}
131+
132+
public func factory(len: Swift.Int, cap: Swift.Int) -> MyModule.MySwiftClass
133+
""",
134+
mode,
135+
.java,
136+
swiftModuleName: "MyModule",
137+
detectChunkByInitialLines: 1,
138+
expectedChunks: [
139+
"public static MySwiftClass factory("
140+
],
141+
)
142+
}
143+
144+
@Test(arguments: [JExtractGenerationMode.jni, .ffm])
145+
func resolveQualifiedNestedTypesInFunctionSignatures(mode: JExtractGenerationMode) throws {
146+
try assertOutput(
147+
input: """
148+
public struct MySwiftClass {
149+
public struct Nested {
150+
public init() {}
151+
}
152+
}
153+
154+
public func factory(len: Swift.Int, cap: Swift.Int) -> MyModule.MySwiftClass.Nested
155+
""",
156+
mode,
157+
.java,
158+
swiftModuleName: "MyModule",
159+
detectChunkByInitialLines: 1,
160+
expectedChunks: [
161+
"public static MySwiftClass.Nested factory("
162+
],
163+
)
164+
}
165+
166+
@Test(arguments: [JExtractGenerationMode.jni, .ffm])
167+
func resolveQualifiedTypesShadowingModule(mode: JExtractGenerationMode) throws {
168+
try assertOutput(
169+
input: """
170+
public struct MyModule { // shadowing module MyModule
171+
public init() {}
172+
}
173+
174+
public func factory(len: Swift.Int, cap: Swift.Int) -> MyModule
175+
""",
176+
mode,
177+
.java,
178+
swiftModuleName: "MyModule",
179+
detectChunkByInitialLines: 1,
180+
expectedChunks: [
181+
"public static MyModule factory("
182+
],
183+
)
184+
}
95185
}

0 commit comments

Comments
 (0)