diff --git a/Sources/JavaKitMacros/JavaFieldMacro.swift b/Sources/JavaKitMacros/JavaFieldMacro.swift index 7f60f26d..29eb966c 100644 --- a/Sources/JavaKitMacros/JavaFieldMacro.swift +++ b/Sources/JavaKitMacros/JavaFieldMacro.swift @@ -33,6 +33,11 @@ extension JavaFieldMacro: AccessorMacro { return [] } + let isStatic = node.attributeName.trimmedDescription == "JavaStaticField" + guard !isStatic || isInJavaClassContext(context: context) else { + throw MacroExpansionErrorMessage("Cannot use @JavaStaticField outside of a JavaClass instance") + } + // Dig out the Java field name, if provided. Otherwise, use the name as written. let fieldName = if case .argumentList(let arguments) = node.arguments, @@ -79,4 +84,14 @@ extension JavaFieldMacro: AccessorMacro { return accessors } + + private static func isInJavaClassContext(context: some MacroExpansionContext) -> Bool { + for lexicalContext in context.lexicalContext { + if let classSyntax = lexicalContext.as(ExtensionDeclSyntax.self) { + return classSyntax.extendedType.trimmedDescription.starts(with: "JavaClass") + } + } + + return false + } } diff --git a/Tests/JavaKitMacroTests/JavaClassMacroTests.swift b/Tests/JavaKitMacroTests/JavaClassMacroTests.swift index e639800b..1dc08ba8 100644 --- a/Tests/JavaKitMacroTests/JavaClassMacroTests.swift +++ b/Tests/JavaKitMacroTests/JavaClassMacroTests.swift @@ -23,9 +23,64 @@ class JavaKitMacroTests: XCTestCase { static let javaKitMacros: [String: any Macro.Type] = [ "JavaClass": JavaClassMacro.self, "JavaMethod": JavaMethodMacro.self, - "JavaField": JavaFieldMacro.self + "JavaField": JavaFieldMacro.self, + "JavaStaticField": JavaFieldMacro.self ] + func testJavaStaticMethodFailure() throws { + assertMacroExpansion( + """ + @JavaClass("org.swift.example.HelloWorld") + public class HelloWorld { + @JavaStaticField + public var test: String + } + """, + expandedSource: """ + + public class HelloWorld { + public var test: String + + /// The full Java class name for this Swift type. + open override class var fullJavaClassName: String { + "org.swift.example.HelloWorld" + } + + public required init(javaHolder: JavaObjectHolder) { + super.init(javaHolder: javaHolder) + } + } + """, + diagnostics: [DiagnosticSpec(message: "Cannot use @JavaStaticField outside of a JavaClass instance", line: 3, column: 5)], + macros: Self.javaKitMacros + ) + } + + func testJavaStaticMethodSuccess() throws { + assertMacroExpansion( + """ + extension JavaClass { + @JavaStaticField + public var test: String + } + """, + expandedSource: """ + + extension JavaClass { + public var test: String { + get { + self[javaFieldName: "test", fieldType: String.self] + } + set { + self[javaFieldName: "test", fieldType: String.self] = newValue + } + } + } + """, + macros: Self.javaKitMacros + ) + } + func testJavaClass() throws { assertMacroExpansion(""" @JavaClass("org.swift.example.HelloWorld")