@@ -50,6 +50,8 @@ extension JavaMethodMacro: BodyMacro {
5050 fatalError ( " not a function: \( declaration) " )
5151 }
5252
53+ var resultStatements : [ CodeBlockItemSyntax ] = [ ]
54+
5355 let funcName =
5456 if case . argumentList( let arguments) = node. arguments,
5557 let argument = arguments. first,
@@ -65,7 +67,28 @@ extension JavaMethodMacro: BodyMacro {
6567
6668 let isStatic = node. attributeName. trimmedDescription == " JavaStaticMethod "
6769 let params = funcDecl. signature. parameterClause. parameters
68- let paramNames = params. map { param in param. parameterName? . text ?? " " } . joined ( separator: " , " )
70+
71+ var paramNames : [ String ] = [ ]
72+ for param in params {
73+ guard let name = param. parameterName else {
74+ throw MacroErrors . parameterMustHaveName ( method: funcName, paramSyntax: param. trimmedDescription)
75+ }
76+ if isJNIGenericParameter ( param. type, funcDecl: funcDecl, in: context) {
77+ let erasedName : TokenSyntax = " \( name) $erased "
78+ if param. type. optionalUnwrappedType ( ) != nil {
79+ resultStatements. append (
80+ " let \( erasedName) = \( name) .map { JavaObject(javaHolder: $0.javaHolder) } "
81+ )
82+ } else {
83+ resultStatements. append (
84+ " let \( erasedName) = JavaObject(javaHolder: \( name) .javaHolder) "
85+ )
86+ }
87+ paramNames. append ( erasedName. text)
88+ } else {
89+ paramNames. append ( name. text)
90+ }
91+ }
6992
7093 let genericResultType : String ? =
7194 if case let . argumentList( arguments) = node. arguments,
@@ -106,7 +129,7 @@ extension JavaMethodMacro: BodyMacro {
106129 if paramNames. isEmpty {
107130 parametersAsArgs = " "
108131 } else {
109- parametersAsArgs = " , arguments: \( paramNames) "
132+ parametersAsArgs = " , arguments: \( paramNames. joined ( separator : " , " ) ) "
110133 }
111134
112135 let canRethrowError = funcDecl. signature. effectSpecifiers? . throwsClause != nil
@@ -137,23 +160,60 @@ extension JavaMethodMacro: BodyMacro {
137160 """
138161
139162 if let genericResultType {
140- return [
163+ resultStatements . append (
141164 """
142165 /* convert erased return value to \(raw: genericResultType) */
143166 let result$ = \( resultSyntax)
167+ """
168+ )
169+ resultStatements. append (
170+ """
144171 if let result$ {
145172 return \( raw: genericResultType) (javaThis: result$.javaThis, environment: try! JavaVirtualMachine.shared().environment())
146173 } else {
147174 return nil
148175 }
149176 """
150- ]
177+ )
178+ } else {
179+ // no return type conversions
180+ resultStatements. append ( " return \( resultSyntax) " )
151181 }
152182
153- // no return type conversions
154- return [
155- " return \( resultSyntax) "
156- ]
183+ return resultStatements
184+ }
185+
186+ /// Determines whether an argument is generic in heuristic way.
187+ /// Since Optional does not appear in JNI signatures, it is removed before checking.
188+ /// FIXME: It might be preferable to explicitly specify the type from JavaClass, similar to `typeErasedResult`.
189+ private static func isJNIGenericParameter(
190+ _ type: TypeSyntax ,
191+ funcDecl: FunctionDeclSyntax ,
192+ in context: some MacroExpansionContext
193+ ) -> Bool {
194+ let baseType = type. optionalUnwrappedType ( ) ?? type
195+ guard let identifier = baseType. as ( IdentifierTypeSyntax . self) else {
196+ return false
197+ }
198+ let typeName = identifier. name. text
199+
200+ if let genericParams = funcDecl. genericParameterClause? . parameters {
201+ if genericParams. contains ( where: { $0. name. text == typeName } ) {
202+ return true
203+ }
204+ }
205+
206+ for contextNode in context. lexicalContext {
207+ if let decl = contextNode. asProtocol ( WithGenericParametersSyntax . self) {
208+ if decl. genericParameterClause? . parameters. contains ( where: {
209+ $0. name. text == typeName
210+ } ) == true {
211+ return true
212+ }
213+ }
214+ }
215+
216+ return false
157217 }
158218
159219 /// Bridge an initializer into a call to Java.
@@ -238,4 +298,23 @@ extension TypeSyntaxProtocol {
238298 var typeReferenceString : String {
239299 typeReference. description
240300 }
301+
302+ func optionalUnwrappedType( ) -> TypeSyntax ? {
303+ if let optionalType = self . as ( OptionalTypeSyntax . self) {
304+ return optionalType. wrappedType
305+ }
306+
307+ if let implicitlyUnwrappedType = self . as ( ImplicitlyUnwrappedOptionalTypeSyntax . self) {
308+ return implicitlyUnwrappedType. wrappedType
309+ }
310+
311+ if let identifierType = self . as ( IdentifierTypeSyntax . self) ,
312+ identifierType. name. text == " Optional " ,
313+ let genericArgumentClause = identifierType. genericArgumentClause
314+ {
315+ return genericArgumentClause. arguments. first? . argument. as ( TypeSyntax . self)
316+ }
317+
318+ return nil
319+ }
241320}
0 commit comments