diff --git a/Sources/JExtractSwiftLib/FFM/CDeclLowering/FFMSwift2JavaGenerator+FunctionLowering.swift b/Sources/JExtractSwiftLib/FFM/CDeclLowering/FFMSwift2JavaGenerator+FunctionLowering.swift index 32757a79..9d53b8b5 100644 --- a/Sources/JExtractSwiftLib/FFM/CDeclLowering/FFMSwift2JavaGenerator+FunctionLowering.swift +++ b/Sources/JExtractSwiftLib/FFM/CDeclLowering/FFMSwift2JavaGenerator+FunctionLowering.swift @@ -993,6 +993,14 @@ extension LoweredFunctionSignature { .joined(separator: ", ") resultExpr = "\(callee)(\(raw: arguments))" + case .synthesizedFunction(let function): + switch function { + case .toString: + resultExpr = "String(describing: \(callee))" + case .toDebugString: + resultExpr = "String(reflecting: \(callee))" + } + case .getter: assert(paramExprs.isEmpty) resultExpr = callee diff --git a/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+JavaTranslation.swift b/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+JavaTranslation.swift index cf32a430..5c7d8713 100644 --- a/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+JavaTranslation.swift +++ b/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+JavaTranslation.swift @@ -160,7 +160,7 @@ extension FFMSwift2JavaGenerator { switch decl.apiKind { case .getter, .subscriptGetter: decl.javaGetterName case .setter, .subscriptSetter: decl.javaSetterName - case .function, .initializer, .enumCase: decl.name + case .function, .synthesizedFunction, .initializer, .enumCase: decl.name } // Signature. diff --git a/Sources/JExtractSwiftLib/ImportedDecls.swift b/Sources/JExtractSwiftLib/ImportedDecls.swift index 7bb2f041..1879bc76 100644 --- a/Sources/JExtractSwiftLib/ImportedDecls.swift +++ b/Sources/JExtractSwiftLib/ImportedDecls.swift @@ -17,8 +17,14 @@ import SwiftSyntax /// Any imported (Swift) declaration protocol ImportedDecl: AnyObject {} -package enum SwiftAPIKind { +package enum SynthesizedAPI: Equatable { + case toString + case toDebugString +} + +package enum SwiftAPIKind: Equatable { case function + case synthesizedFunction(SynthesizedAPI) case initializer case getter case setter @@ -182,7 +188,7 @@ public final class ImportedFunc: ImportedDecl, CustomStringConvertible { case .getter: "getter:" case .setter: "setter:" case .enumCase: "case:" - case .function, .initializer: "" + case .function, .synthesizedFunction, .initializer: "" case .subscriptGetter: "subscriptGetter:" case .subscriptSetter: "subscriptSetter:" } diff --git a/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+JavaBindingsPrinting.swift b/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+JavaBindingsPrinting.swift index ffc5fffd..87a5d358 100644 --- a/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+JavaBindingsPrinting.swift +++ b/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+JavaBindingsPrinting.swift @@ -267,9 +267,6 @@ extension JNISwift2JavaGenerator { printer.println() } - printToStringMethods(&printer, decl) - printer.println() - printSpecificTypeHelpers(&printer, decl) printTypeMetadataAddressFunction(&printer, decl) @@ -294,28 +291,6 @@ extension JNISwift2JavaGenerator { } } - private func printToStringMethods(_ printer: inout CodePrinter, _ decl: ImportedNominalType) { - printer.printBraceBlock("public String toString()") { printer in - printer.print( - """ - return $toString(this.$memoryAddress()); - """ - ) - } - printer.print("private static native java.lang.String $toString(long selfPointer);") - - printer.println() - - printer.printBraceBlock("public String toDebugString()") { printer in - printer.print( - """ - return $toDebugString(this.$memoryAddress()); - """ - ) - } - printer.print("private static native java.lang.String $toDebugString(long selfPointer);") - } - private func printHeader(_ printer: inout CodePrinter) { printer.print( """ diff --git a/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+JavaTranslation.swift b/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+JavaTranslation.swift index 436956d2..fc0b0102 100644 --- a/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+JavaTranslation.swift +++ b/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+JavaTranslation.swift @@ -208,7 +208,7 @@ extension JNISwift2JavaGenerator { switch decl.apiKind { case .getter, .subscriptGetter: decl.javaGetterName case .setter, .subscriptSetter: decl.javaSetterName - case .function, .initializer, .enumCase: decl.name + case .function, .synthesizedFunction, .initializer, .enumCase: decl.name } // Swift -> Java diff --git a/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+SwiftThunkPrinting.swift b/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+SwiftThunkPrinting.swift index c12080ee..347d2024 100644 --- a/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+SwiftThunkPrinting.swift +++ b/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+SwiftThunkPrinting.swift @@ -271,7 +271,6 @@ extension JNISwift2JavaGenerator { printer.println() } - printToStringMethods(&printer, type) printSpecificTypeThunks(&printer, type) printTypeMetadataAddressThunk(&printer, type) printer.println() @@ -286,49 +285,6 @@ extension JNISwift2JavaGenerator { try printSwiftInterfaceWrapper(&printer, protocolWrapper) } - private func printToStringMethods(_ printer: inout CodePrinter, _ type: ImportedNominalType) { - let selfPointerParam = JavaParameter(name: "selfPointer", type: .long) - let parentName = type.qualifiedName - - printCDecl( - &printer, - javaMethodName: "$toString", - parentName: type.swiftNominal.qualifiedName, - parameters: [ - selfPointerParam - ], - resultType: .javaLangString - ) { printer in - let selfVar = self.printSelfJLongToUnsafeMutablePointer(&printer, swiftParentName: parentName, selfPointerParam) - - printer.print( - """ - return String(describing: \(selfVar).pointee).getJNIValue(in: environment) - """ - ) - } - - printer.println() - - printCDecl( - &printer, - javaMethodName: "$toDebugString", - parentName: type.swiftNominal.qualifiedName, - parameters: [ - selfPointerParam - ], - resultType: .javaLangString - ) { printer in - let selfVar = self.printSelfJLongToUnsafeMutablePointer(&printer, swiftParentName: parentName, selfPointerParam) - - printer.print( - """ - return String(reflecting: \(selfVar).pointee).getJNIValue(in: environment) - """ - ) - } - } - private func printEnumDiscriminator(_ printer: inout CodePrinter, _ type: ImportedNominalType) { let selfPointerParam = JavaParameter(name: "selfPointer", type: .long) printCDecl( @@ -623,6 +579,14 @@ extension JNISwift2JavaGenerator { .joined(separator: ", ") result = "\(tryClause)\(callee).\(decl.name)(\(downcallArguments))" + case .synthesizedFunction(let function): + switch function { + case .toString: + result = "String(describing: \(callee))" + case .toDebugString: + result = "String(reflecting: \(callee))" + } + case .enumCase: let downcallArguments = zip( decl.functionSignature.parameters, diff --git a/Sources/JExtractSwiftLib/Swift2JavaVisitor.swift b/Sources/JExtractSwiftLib/Swift2JavaVisitor.swift index ff6295bb..9d3a60dd 100644 --- a/Sources/JExtractSwiftLib/Swift2JavaVisitor.swift +++ b/Sources/JExtractSwiftLib/Swift2JavaVisitor.swift @@ -85,6 +85,8 @@ final class Swift2JavaVisitor { for memberItem in node.memberBlock.members { self.visit(decl: memberItem.decl, in: importedNominalType, sourceFilePath: sourceFilePath) } + + self.synthesizeToStringMethods(in: importedNominalType) } func visit( @@ -405,6 +407,46 @@ final class Swift2JavaVisitor { } } } + + private func synthesizeToStringMethods(in imported: ImportedNominalType) { + switch imported.swiftNominal.kind { + case .actor, .class, .enum, .struct: + break + case .protocol: + return + } + + let knownTypes = SwiftKnownTypes(symbolTable: translator.symbolTable) + let toStringFunctionSignature = SwiftFunctionSignature( + selfParameter: .instance(SwiftParameter(convention: .byValue, parameterName: "selfPointer", type: imported.swiftType)), + parameters: [], + result: SwiftResult(convention: .direct, type: knownTypes.string), + effectSpecifiers: [], + genericParameters: [], + genericRequirements: [] + ) + + func makeToStringFunc(name: String, kind: SwiftAPIKind) -> ImportedFunc { + ImportedFunc( + module: translator.swiftModuleName, + swiftDecl: DeclSyntax("func \(raw: name)() -> String"), + name: name, + apiKind: kind, + functionSignature: toStringFunctionSignature + ) + } + + if !imported.methods.contains(where: { + $0.name == "toString" && $0.functionSignature == toStringFunctionSignature + }) { + imported.methods.append(makeToStringFunc(name: "toString", kind: .synthesizedFunction(.toString))) + } + if !imported.methods.contains(where: { + $0.name == "toDebugString" && $0.functionSignature == toStringFunctionSignature + }) { + imported.methods.append(makeToStringFunc(name: "toDebugString", kind: .synthesizedFunction(.toDebugString))) + } + } } extension DeclSyntaxProtocol where Self: WithModifiersSyntax & WithAttributesSyntax { diff --git a/Tests/JExtractSwiftTests/JNI/JNIToStringTests.swift b/Tests/JExtractSwiftTests/JNI/JNIToStringTests.swift index e67561b8..45b67aca 100644 --- a/Tests/JExtractSwiftTests/JNI/JNIToStringTests.swift +++ b/Tests/JExtractSwiftTests/JNI/JNIToStringTests.swift @@ -32,13 +32,11 @@ struct JNIToStringTests { detectChunkByInitialLines: 1, expectedChunks: [ """ - public String toString() { - return $toString(this.$memoryAddress()); + public java.lang.String toString() { + return MyType.$toString(this.$memoryAddress()); } - """, - """ private static native java.lang.String $toString(long selfPointer); - """, + """ ] ) } @@ -55,7 +53,7 @@ struct JNIToStringTests { @_cdecl("Java_com_example_swift_MyType__00024toString__J") public func Java_com_example_swift_MyType__00024toString__J(environment: UnsafeMutablePointer!, thisClass: jclass, selfPointer: jlong) -> jstring? { ... - return String(describing: self$.pointee).getJNIValue(in: environment) + return String(describing: selfPointer$.pointee).getJNIValue(in: environment) } """ ] @@ -71,9 +69,10 @@ struct JNIToStringTests { detectChunkByInitialLines: 1, expectedChunks: [ """ - public String toDebugString() { - return $toDebugString(this.$memoryAddress()); + public java.lang.String toDebugString() { + return MyType.$toDebugString(this.$memoryAddress()); } + private static native java.lang.String $toDebugString(long selfPointer); """ ] ) @@ -91,7 +90,7 @@ struct JNIToStringTests { @_cdecl("Java_com_example_swift_MyType__00024toDebugString__J") public func Java_com_example_swift_MyType__00024toDebugString__J(environment: UnsafeMutablePointer!, thisClass: jclass, selfPointer: jlong) -> jstring? { ... - return String(reflecting: self$.pointee).getJNIValue(in: environment) + return String(reflecting: selfPointer$.pointee).getJNIValue(in: environment) } """ ]