Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ struct SwiftModuleSymbolTable: SwiftSymbolTableProtocol {
/// type name to the nominal type declaration.
var nestedTypes: [SwiftNominalTypeDeclaration: [String: SwiftNominalTypeDeclaration]] = [:]

/// The nested typealias declarations defined within this module. The map itself is indexed
/// by the nominal type declaration, and each entry is a map from the nested typealias
/// name to the typealias declaration.
var nestedTypeAliases: [SwiftNominalTypeDeclaration: [String: SwiftTypeAliasDeclaration]] = [:]

/// Look for a top-level type with the given name.
func lookupTopLevelNominalType(_ name: String) -> SwiftNominalTypeDeclaration? {
topLevelTypes[name]
Expand All @@ -51,6 +56,11 @@ struct SwiftModuleSymbolTable: SwiftSymbolTableProtocol {
nestedTypes[parent]?[name]
}

// Look for a nested typealias with the given name.
func lookupNestedTypealias(_ name: String, parent: SwiftNominalTypeDeclaration) -> SwiftTypeAliasDeclaration? {
nestedTypeAliases[parent]?[name]
}

func isAlternative(for moduleName: String) -> Bool {
alternativeModules.flatMap { $0.moduleNames.contains(moduleName) } ?? false
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ extension SwiftParsedModuleSymbolTableBuilder {

if let nominalTypeNode = decl.asNominal {
self.handle(sourceFilePath: sourceFilePath, nominalTypeDecl: nominalTypeNode, parent: nil)
} else if let typeAliasNode = decl.as(TypeAliasDeclSyntax.self) {
self.handle(sourceFilePath: sourceFilePath, typeAliasDecl: typeAliasNode, parent: nil)
} else if let extensionNode = decl.as(ExtensionDeclSyntax.self) {
self.handle(extensionDecl: extensionNode, sourceFilePath: sourceFilePath)
} else if let ifConfigNode = decl.as(IfConfigDeclSyntax.self) {
Expand Down Expand Up @@ -113,7 +115,9 @@ extension SwiftParsedModuleSymbolTableBuilder {
) {
// If we have already recorded a nominal type with the name in this module,
// it's an invalid redeclaration.
if let _ = symbolTable.lookupType(node.name.text, parent: parent) {
if symbolTable.lookupType(node.name.text, parent: parent) != nil
|| symbolTable.lookupTypealias(node.name.text, parent: parent) != nil
{
log?.debug("Failed to add a decl into symbol table: redeclaration; " + node.nameForDebug)
return
}
Expand All @@ -137,6 +141,31 @@ extension SwiftParsedModuleSymbolTableBuilder {
self.handle(sourceFilePath: sourceFilePath, memberBlock: node.memberBlock, parent: nominalTypeDecl)
}

mutating func handle(
sourceFilePath: String,
typeAliasDecl node: TypeAliasDeclSyntax,
parent: SwiftNominalTypeDeclaration?
) {
if symbolTable.lookupType(node.name.text, parent: parent) != nil
|| symbolTable.lookupTypealias(node.name.text, parent: parent) != nil
{
log?.debug("Failed to add a decl into symbol table: redeclaration; " + node.nameForDebug)
return
}

let typeAliasDecl = SwiftTypeAliasDeclaration(
sourceFilePath: sourceFilePath,
moduleName: moduleName,
node: node
)

if let parent {
symbolTable.nestedTypeAliases[parent, default: [:]][typeAliasDecl.name] = typeAliasDecl
} else {
symbolTable.topLevelTypeAliases[typeAliasDecl.name] = typeAliasDecl
}
}

mutating func handle(
sourceFilePath: String,
memberBlock node: MemberBlockSyntax,
Expand All @@ -146,9 +175,10 @@ extension SwiftParsedModuleSymbolTableBuilder {
// Find any nested types within this nominal type and add them.
if let nominalMember = member.decl.asNominal {
self.handle(sourceFilePath: sourceFilePath, nominalTypeDecl: nominalMember, parent: parent)
} else if let typeAliasMember = member.decl.as(TypeAliasDeclSyntax.self) {
self.handle(sourceFilePath: sourceFilePath, typeAliasDecl: typeAliasMember, parent: parent)
}
}

}

mutating func handle(
Expand Down
40 changes: 33 additions & 7 deletions Sources/JExtractSwiftLib/SwiftTypes/SwiftSymbolTable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,14 @@ package protocol SwiftSymbolTableProtocol {
/// return nominal types within this module.
func lookupTopLevelNominalType(_ name: String) -> SwiftNominalTypeDeclaration?

/// Look for a top-level typealias with the given name.
func lookupTopLevelTypealias(_ name: String) -> SwiftTypeAliasDeclaration?

// Look for a nested type with the given name.
func lookupNestedType(_ name: String, parent: SwiftNominalTypeDeclaration) -> SwiftNominalTypeDeclaration?

/// Look for a top-level typealias with the given name.
func lookupTopLevelTypealias(_ name: String) -> SwiftTypeAliasDeclaration?
// Look for a nested typealias with the given name.
func lookupNestedTypealias(_ name: String, parent: SwiftNominalTypeDeclaration) -> SwiftTypeAliasDeclaration?
}

extension SwiftSymbolTableProtocol {
Expand All @@ -42,6 +45,14 @@ extension SwiftSymbolTableProtocol {

return lookupTopLevelNominalType(name)
}

package func lookupTypealias(_ name: String, parent: SwiftNominalTypeDeclaration?) -> SwiftTypeAliasDeclaration? {
if let parent {
return lookupNestedTypealias(name, parent: parent)
}

return lookupTopLevelTypealias(name)
}
}

package class SwiftSymbolTable {
Expand Down Expand Up @@ -167,6 +178,21 @@ extension SwiftSymbolTable: SwiftSymbolTableProtocol {
return importedModules[moduleName]?.lookupTopLevelNominalType(name)
}

/// Look for a top-level typealias with the given name.
package func lookupTopLevelTypealias(_ name: String) -> SwiftTypeAliasDeclaration? {
if let parsedResult = parsedModule.lookupTopLevelTypealias(name) {
return parsedResult
}

for importedModule in prioritySortedImportedModules {
if let result = importedModule.lookupTopLevelTypealias(name) {
return result
}
}

return nil
}

// Look for a nested type with the given name.
package func lookupNestedType(_ name: String, parent: SwiftNominalTypeDeclaration) -> SwiftNominalTypeDeclaration? {
if let parsedResult = parsedModule.lookupNestedType(name, parent: parent) {
Expand All @@ -182,14 +208,14 @@ extension SwiftSymbolTable: SwiftSymbolTableProtocol {
return nil
}

/// Look for a top-level typealias with the given name.
package func lookupTopLevelTypealias(_ name: String) -> SwiftTypeAliasDeclaration? {
if let parsedResult = parsedModule.lookupTopLevelTypealias(name) {
// Look for a nested typealias with the given name.
package func lookupNestedTypealias(_ name: String, parent: SwiftNominalTypeDeclaration) -> SwiftTypeAliasDeclaration? {
if let parsedResult = parsedModule.lookupNestedTypealias(name, parent: parent) {
return parsedResult
}

for importedModule in prioritySortedImportedModules {
if let result = importedModule.lookupTopLevelTypealias(name) {
for importedModule in importedModules.values {
if let result = importedModule.lookupNestedTypealias(name, parent: parent) {
return result
}
}
Expand Down
4 changes: 3 additions & 1 deletion Sources/JExtractSwiftLib/SwiftTypes/SwiftType.swift
Original file line number Diff line number Diff line change
Expand Up @@ -443,7 +443,9 @@ extension SwiftType {
guard let parentDecl = parent.asNominalTypeDeclaration else {
throw TypeTranslationError.unknown(originalType)
}
typeDecl = lookupContext.symbolTable.lookupNestedType(name.text, parent: parentDecl)
typeDecl =
lookupContext.symbolTable.lookupNestedType(name.text, parent: parentDecl)
?? lookupContext.symbolTable.lookupNestedTypealias(name.text, parent: parentDecl)
} else if let module {
typeDecl = lookupContext.moduleQualifiedLookup(name: name.text, in: module)
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ class SwiftTypeLookupContext {
if let found = symbolTable.lookupNestedType(name.name, parent: nominalDecl) {
return found
}
if let found = symbolTable.lookupNestedTypealias(name.name, parent: nominalDecl) {
return found
}
}

case .lookForGenericParameters(let extensionNode):
Expand Down
101 changes: 95 additions & 6 deletions Tests/JExtractSwiftTests/TypealiasResolutionTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -226,14 +226,21 @@ struct TypealiasResolutionTests {
}

public typealias FishBox = Box<Fish>
public func makeFishBox() -> FishBox {
.init()
}
"""#

var config = Configuration()
config.swiftModule = "SwiftModule"
let translator = Swift2JavaTranslator(config: config)
try translator.analyze(path: "/fake/Fake.swift", text: input)

#expect(translator.importedTypes["FishBox"] != nil, "FishBox specialization should still register")
try assertOutput(
input: input,
.jni,
.java,
detectChunkByInitialLines: 1,
expectedChunks: [
"public final class FishBox implements JNISwiftInstance {",
"public static Box<Fish> makeFishBox(",
],
)
}

// ==== -----------------------------------------------------------------------
Expand Down Expand Up @@ -405,4 +412,86 @@ struct TypealiasResolutionTests {
#expect(nominal.nominalTypeDecl.name == "Optional")
#expect(nominal.genericArguments?.first?.description == "Int64")
}

// ==== -----------------------------------------------------------------------
// MARK: Nested typealiases

@Test("Typealias nested inside a type resolves correctly")
func nestedTypealiasResolves() throws {
let input =
#"""
public struct Foo {
public typealias ID = Int
public var id: ID
}

public func useFooID(value: Foo.ID) -> Foo.ID {
value
}
"""#

try assertOutput(
input: input,
.jni,
.swift,
detectChunkByInitialLines: 2,
expectedChunks: [
#"""
@_cdecl("Java_com_example_swift_Foo__00024getId__J")
public func Java_com_example_swift_Foo__00024getId__J(environment: UnsafeMutablePointer<JNIEnv?>!, thisClass: jclass, selfPointer: jlong) -> jlong {
"""#,
#"""
@_cdecl("Java_com_example_swift_Foo__00024setId__JJ")
public func Java_com_example_swift_Foo__00024setId__JJ(environment: UnsafeMutablePointer<JNIEnv?>!, thisClass: jclass, newValue: jlong, selfPointer: jlong) {
"""#,
],
)

try assertOutput(
input: input,
.jni,
.java,
detectChunkByInitialLines: 2,
expectedChunks: [
"""
public long getId()
""",
"""
public void setId(long newValue)
""",
"""
public static long useFooID(long value)
""",
],
)
}

@Test("Nested typealias used in an extension of that typealias's RHS resolves")
func useNestedTypealiasFromExtension() throws {
let input =
#"""
public typealias MyEnumAlt = Never

extension MyStruct.MyEnumAlt {
public func methodInExtension() {}
}

public struct MyStruct {
public enum MyEnum {}
public typealias MyEnumAlt = MyEnum
}
"""#

try assertOutput(
input: input,
.ffm,
.java,
expectedChunks: [
#"""
private static final MemorySegment ADDR =
SwiftModule.findOrThrow("swiftjava_SwiftModule_MyStruct_MyEnum_methodInExtension");
"""#
],
)
}
}
Loading