diff --git a/jre_emul/Classes/J2ObjC_common.h b/jre_emul/Classes/J2ObjC_common.h index 0c3d98f71d..c882754222 100644 --- a/jre_emul/Classes/J2ObjC_common.h +++ b/jre_emul/Classes/J2ObjC_common.h @@ -340,34 +340,38 @@ FOUNDATION_EXPORT Class _Nullable objc_opt_class(id _Nullable obj); #ifdef J2OBJC_STRICT_FIELD_ASSIGN -#define J2OBJC_FIELD_SETTER(CLASS, FIELD, TYPE) \ - __attribute__((unused)) static inline TYPE CLASS##_set_##FIELD(CLASS *instance, TYPE value) { \ - return JreStrictFieldStrongAssign(&instance->FIELD, value); \ +#define J2OBJC_FIELD_SETTER(CLASS, FIELD, ...) \ + __attribute__((unused)) static inline __VA_ARGS__ CLASS##_set_##FIELD(CLASS *instance, \ + __VA_ARGS__ value) { \ + return JreStrictFieldStrongAssign(&instance->FIELD, value); \ } #else // J2OBJC_STRICT_FIELD_ASSIGN #if __has_feature(objc_arc) -#define J2OBJC_FIELD_SETTER(CLASS, FIELD, TYPE) \ - __attribute__((unused)) static inline TYPE CLASS##_set_##FIELD(CLASS *instance, TYPE value) { \ - return instance->FIELD = value; \ +#define J2OBJC_FIELD_SETTER(CLASS, FIELD, ...) \ + __attribute__((unused)) static inline __VA_ARGS__ CLASS##_set_##FIELD(CLASS *instance, \ + __VA_ARGS__ value) { \ + return instance->FIELD = value; \ } #else -#define J2OBJC_FIELD_SETTER(CLASS, FIELD, TYPE) \ - __attribute__((unused)) static inline TYPE CLASS##_set_##FIELD(CLASS *instance, TYPE value) { \ - return JreStrongAssign(&instance->FIELD, value); \ - }\ - __attribute__((unused)) static inline TYPE CLASS##_setAndConsume_##FIELD( \ - CLASS *instance, NS_RELEASES_ARGUMENT TYPE value) { \ - return JreStrongAssignAndConsume(&instance->FIELD, value); \ +#define J2OBJC_FIELD_SETTER(CLASS, FIELD, ...) \ + __attribute__((unused)) static inline __VA_ARGS__ CLASS##_set_##FIELD(CLASS *instance, \ + __VA_ARGS__ value) { \ + return JreStrongAssign(&instance->FIELD, value); \ + } \ + __attribute__((unused)) static inline __VA_ARGS__ CLASS##_setAndConsume_##FIELD( \ + CLASS *instance, NS_RELEASES_ARGUMENT __VA_ARGS__ value) { \ + return JreStrongAssignAndConsume(&instance->FIELD, value); \ } #endif #endif // J2OBJC_STRICT_FIELD_ASSIGN -#define J2OBJC_VOLATILE_FIELD_SETTER(CLASS, FIELD, TYPE) \ - __attribute__((unused)) static inline TYPE CLASS##_set_##FIELD(CLASS *instance, TYPE value) { \ - return JreVolatileStrongAssign(&instance->FIELD, value); \ +#define J2OBJC_VOLATILE_FIELD_SETTER(CLASS, FIELD, ...) \ + __attribute__((unused)) static inline __VA_ARGS__ CLASS##_set_##FIELD(CLASS *instance, \ + __VA_ARGS__ value) { \ + return JreVolatileStrongAssign(&instance->FIELD, value); \ } /*! diff --git a/jre_emul/Classes/J2ObjC_header.h b/jre_emul/Classes/J2ObjC_header.h index 41d8791abb..fc4345e5fd 100644 --- a/jre_emul/Classes/J2ObjC_header.h +++ b/jre_emul/Classes/J2ObjC_header.h @@ -44,25 +44,25 @@ CF_EXTERN_C_END * @param FIELD The name of the static variable prefixed with an underscore. * @param TYPE The type of the static variable. */ -#define J2OBJC_STATIC_FIELD_BASIC_GETTER(CLASS, FIELD, TYPE) \ - __attribute__((always_inline)) inline TYPE CLASS##_get##FIELD(void) { \ - CLASS##_initialize(); \ - return CLASS##FIELD; \ +#define J2OBJC_STATIC_FIELD_BASIC_GETTER(CLASS, FIELD, ...) \ + __attribute__((always_inline)) inline __VA_ARGS__ CLASS##_get##FIELD(void) { \ + CLASS##_initialize(); \ + return CLASS##FIELD; \ } -#define J2OBJC_STATIC_FIELD_PRIMITIVE_REF_GETTER(CLASS, FIELD, TYPE) \ - __attribute__((always_inline)) inline TYPE *CLASS##_getRef##FIELD(void) { \ - CLASS##_initialize(); \ - return &CLASS##FIELD; \ +#define J2OBJC_STATIC_FIELD_PRIMITIVE_REF_GETTER(CLASS, FIELD, ...) \ + __attribute__((always_inline)) inline __VA_ARGS__ *CLASS##_getRef##FIELD(void) { \ + CLASS##_initialize(); \ + return &CLASS##FIELD; \ } -#define J2OBJC_STATIC_FIELD_PRIMITIVE_VOLATILE_GETTER(CLASS, FIELD, TYPE) \ - __attribute__((always_inline)) inline TYPE CLASS##_get##FIELD(void) { \ - CLASS##_initialize(); \ - return __c11_atomic_load(&CLASS##FIELD, __ATOMIC_SEQ_CST); \ +#define J2OBJC_STATIC_FIELD_PRIMITIVE_VOLATILE_GETTER(CLASS, FIELD, ...) \ + __attribute__((always_inline)) inline __VA_ARGS__ CLASS##_get##FIELD(void) { \ + CLASS##_initialize(); \ + return __c11_atomic_load(&CLASS##FIELD, __ATOMIC_SEQ_CST); \ } -#define J2OBJC_STATIC_FIELD_OBJ_VOLATILE_GETTER(CLASS, FIELD, TYPE) \ - __attribute__((always_inline)) inline TYPE CLASS##_get##FIELD(void) { \ - CLASS##_initialize(); \ - return JreLoadVolatileId(&CLASS##FIELD); \ +#define J2OBJC_STATIC_FIELD_OBJ_VOLATILE_GETTER(CLASS, FIELD, ...) \ + __attribute__((always_inline)) inline __VA_ARGS__ CLASS##_get##FIELD(void) { \ + CLASS##_initialize(); \ + return JreLoadVolatileId(&CLASS##FIELD); \ } /*! @@ -79,38 +79,39 @@ CF_EXTERN_C_END * @param FIELD The name of the static variable prefixed with an underscore. * @param TYPE The type of the static variable. */ -#define J2OBJC_STATIC_FIELD_PRIMITIVE_SETTER(CLASS, FIELD, TYPE) \ - __attribute__((always_inline)) inline TYPE CLASS##_set##FIELD(TYPE value) { \ - CLASS##_initialize(); \ - return CLASS##FIELD = value; \ +#define J2OBJC_STATIC_FIELD_PRIMITIVE_SETTER(CLASS, FIELD, ...) \ + __attribute__((always_inline)) inline __VA_ARGS__ CLASS##_set##FIELD(__VA_ARGS__ value) { \ + CLASS##_initialize(); \ + return CLASS##FIELD = value; \ } -#define J2OBJC_STATIC_FIELD_PRIMITIVE_VOLATILE_SETTER(CLASS, FIELD, TYPE) \ - __attribute__((always_inline)) inline TYPE CLASS##_set##FIELD(TYPE value) { \ - CLASS##_initialize(); \ - __c11_atomic_store(&CLASS##FIELD, value, __ATOMIC_SEQ_CST); \ - return value; \ +#define J2OBJC_STATIC_FIELD_PRIMITIVE_VOLATILE_SETTER(CLASS, FIELD, ...) \ + __attribute__((always_inline)) inline __VA_ARGS__ CLASS##_set##FIELD(__VA_ARGS__ value) { \ + CLASS##_initialize(); \ + __c11_atomic_store(&CLASS##FIELD, value, __ATOMIC_SEQ_CST); \ + return value; \ } #if __has_feature(objc_arc) -#define J2OBJC_STATIC_FIELD_OBJ_SETTER(CLASS, FIELD, TYPE) \ - __attribute__((always_inline)) inline TYPE CLASS##_set##FIELD(TYPE value) { \ - CLASS##_initialize(); \ - return CLASS##FIELD = value; \ +#define J2OBJC_STATIC_FIELD_OBJ_SETTER(CLASS, FIELD, ...) \ + __attribute__((always_inline)) inline __VA_ARGS__ CLASS##_set##FIELD(__VA_ARGS__ value) { \ + CLASS##_initialize(); \ + return CLASS##FIELD = value; \ } #else -#define J2OBJC_STATIC_FIELD_OBJ_SETTER(CLASS, FIELD, TYPE) \ - __attribute__((always_inline)) inline TYPE CLASS##_set##FIELD(TYPE value) { \ - CLASS##_initialize(); \ - return JreStrongAssign(&CLASS##FIELD, value); \ - } \ - __attribute__((always_inline)) inline TYPE CLASS##_setAndConsume##FIELD(TYPE value) { \ - CLASS##_initialize(); \ - return JreStrongAssignAndConsume(&CLASS##FIELD, value); \ +#define J2OBJC_STATIC_FIELD_OBJ_SETTER(CLASS, FIELD, ...) \ + __attribute__((always_inline)) inline __VA_ARGS__ CLASS##_set##FIELD(__VA_ARGS__ value) { \ + CLASS##_initialize(); \ + return JreStrongAssign(&CLASS##FIELD, value); \ + } \ + __attribute__((always_inline)) inline __VA_ARGS__ CLASS##_setAndConsume##FIELD( \ + __VA_ARGS__ value) { \ + CLASS##_initialize(); \ + return JreStrongAssignAndConsume(&CLASS##FIELD, value); \ } #endif -#define J2OBJC_STATIC_FIELD_OBJ_VOLATILE_SETTER(CLASS, FIELD, TYPE) \ - __attribute__((always_inline)) inline TYPE CLASS##_set##FIELD(TYPE value) { \ - CLASS##_initialize(); \ - return JreVolatileStrongAssign(&CLASS##FIELD, value); \ +#define J2OBJC_STATIC_FIELD_OBJ_VOLATILE_SETTER(CLASS, FIELD, ...) \ + __attribute__((always_inline)) inline __VA_ARGS__ CLASS##_set##FIELD(__VA_ARGS__ value) { \ + CLASS##_initialize(); \ + return JreVolatileStrongAssign(&CLASS##FIELD, value); \ } /*! @@ -131,25 +132,27 @@ CF_EXTERN_C_END * @param TYPE The type of the static variable. */ // Java constants do not cause static initialization. -#define J2OBJC_STATIC_FIELD_CONSTANT(CLASS, FIELD, TYPE) \ - __attribute__((always_inline)) inline TYPE CLASS##_get_##FIELD(void) { return CLASS##_##FIELD; } -#define J2OBJC_STATIC_FIELD_PRIMITIVE(CLASS, FIELD, TYPE) \ - J2OBJC_STATIC_FIELD_BASIC_GETTER(CLASS, _##FIELD, TYPE) \ - J2OBJC_STATIC_FIELD_PRIMITIVE_SETTER(CLASS, _##FIELD, TYPE) \ - J2OBJC_STATIC_FIELD_PRIMITIVE_REF_GETTER(CLASS, _##FIELD, TYPE) -#define J2OBJC_STATIC_FIELD_PRIMITIVE_VOLATILE(CLASS, FIELD, TYPE) \ - J2OBJC_STATIC_FIELD_PRIMITIVE_VOLATILE_GETTER(CLASS, _##FIELD, TYPE) \ - J2OBJC_STATIC_FIELD_PRIMITIVE_VOLATILE_SETTER(CLASS, _##FIELD, TYPE) -#define J2OBJC_STATIC_FIELD_PRIMITIVE_FINAL(CLASS, FIELD, TYPE) \ - J2OBJC_STATIC_FIELD_BASIC_GETTER(CLASS, _##FIELD, TYPE) -#define J2OBJC_STATIC_FIELD_OBJ(CLASS, FIELD, TYPE) \ - J2OBJC_STATIC_FIELD_BASIC_GETTER(CLASS, _##FIELD, TYPE) \ - J2OBJC_STATIC_FIELD_OBJ_SETTER(CLASS, _##FIELD, TYPE) -#define J2OBJC_STATIC_FIELD_OBJ_VOLATILE(CLASS, FIELD, TYPE) \ - J2OBJC_STATIC_FIELD_OBJ_VOLATILE_GETTER(CLASS, _##FIELD, TYPE) \ - J2OBJC_STATIC_FIELD_OBJ_VOLATILE_SETTER(CLASS, _##FIELD, TYPE) -#define J2OBJC_STATIC_FIELD_OBJ_FINAL(CLASS, FIELD, TYPE) \ - J2OBJC_STATIC_FIELD_BASIC_GETTER(CLASS, _##FIELD, TYPE) +#define J2OBJC_STATIC_FIELD_CONSTANT(CLASS, FIELD, ...) \ + __attribute__((always_inline)) inline __VA_ARGS__ CLASS##_get_##FIELD(void) { \ + return CLASS##_##FIELD; \ + } +#define J2OBJC_STATIC_FIELD_PRIMITIVE(CLASS, FIELD, ...) \ + J2OBJC_STATIC_FIELD_BASIC_GETTER(CLASS, _##FIELD, __VA_ARGS__) \ + J2OBJC_STATIC_FIELD_PRIMITIVE_SETTER(CLASS, _##FIELD, __VA_ARGS__) \ + J2OBJC_STATIC_FIELD_PRIMITIVE_REF_GETTER(CLASS, _##FIELD, __VA_ARGS__) +#define J2OBJC_STATIC_FIELD_PRIMITIVE_VOLATILE(CLASS, FIELD, ...) \ + J2OBJC_STATIC_FIELD_PRIMITIVE_VOLATILE_GETTER(CLASS, _##FIELD, __VA_ARGS__) \ + J2OBJC_STATIC_FIELD_PRIMITIVE_VOLATILE_SETTER(CLASS, _##FIELD, __VA_ARGS__) +#define J2OBJC_STATIC_FIELD_PRIMITIVE_FINAL(CLASS, FIELD, ...) \ + J2OBJC_STATIC_FIELD_BASIC_GETTER(CLASS, _##FIELD, __VA_ARGS__) +#define J2OBJC_STATIC_FIELD_OBJ(CLASS, FIELD, ...) \ + J2OBJC_STATIC_FIELD_BASIC_GETTER(CLASS, _##FIELD, __VA_ARGS__) \ + J2OBJC_STATIC_FIELD_OBJ_SETTER(CLASS, _##FIELD, __VA_ARGS__) +#define J2OBJC_STATIC_FIELD_OBJ_VOLATILE(CLASS, FIELD, ...) \ + J2OBJC_STATIC_FIELD_OBJ_VOLATILE_GETTER(CLASS, _##FIELD, __VA_ARGS__) \ + J2OBJC_STATIC_FIELD_OBJ_VOLATILE_SETTER(CLASS, _##FIELD, __VA_ARGS__) +#define J2OBJC_STATIC_FIELD_OBJ_FINAL(CLASS, FIELD, ...) \ + J2OBJC_STATIC_FIELD_BASIC_GETTER(CLASS, _##FIELD, __VA_ARGS__) /*! * Defines the getter for an enum constant. For enum class "FooEnum" and constant "BAR" diff --git a/translator/src/main/java/com/google/devtools/j2objc/gen/PropertyGenerator.java b/translator/src/main/java/com/google/devtools/j2objc/gen/PropertyGenerator.java index 96de135a89..904e491fbd 100644 --- a/translator/src/main/java/com/google/devtools/j2objc/gen/PropertyGenerator.java +++ b/translator/src/main/java/com/google/devtools/j2objc/gen/PropertyGenerator.java @@ -213,7 +213,16 @@ private String getStringRepresentation(Set attributes) { buffer.append('(').append(PropertyAnnotation.toAttributeString(attributes)).append(") "); } - String objcType = nameTable.getObjCType(varType); + TypeElement declaringClass = ElementUtil.getDeclaringClass(varElement); + boolean allowGenerics = !typeUtil.isProtoClass(varType); + boolean enableGenerics = + allowGenerics + && (options.asObjCGenericDecl() + || TypeUtil.hasGenerateObjectiveCGenerics(varType) + || (declaringClass != null + && TypeUtil.hasGenerateObjectiveCGenerics(declaringClass))) + && (declaringClass == null || !TypeUtil.isInterface(declaringClass.asType())); + String objcType = nameTable.getObjCTypeDeclaration(varType, enableGenerics, declaringClass); buffer.append(objcType); if (!objcType.endsWith("*")) { buffer.append(' '); diff --git a/translator/src/main/java/com/google/devtools/j2objc/gen/TypeDeclarationGenerator.java b/translator/src/main/java/com/google/devtools/j2objc/gen/TypeDeclarationGenerator.java index 79179710a3..405bce13f9 100644 --- a/translator/src/main/java/com/google/devtools/j2objc/gen/TypeDeclarationGenerator.java +++ b/translator/src/main/java/com/google/devtools/j2objc/gen/TypeDeclarationGenerator.java @@ -358,7 +358,14 @@ protected void printStaticAccessors() { VariableElement var = fragment.getVariableElement(); TypeMirror type = var.asType(); String accessorName = nameTable.getStaticAccessorName(var); - String objcType = paddedType(nameTable.getObjCTypeDeclaration(type), var).trim(); + boolean allowGenerics = !typeUtil.isProtoClass(type); + boolean enableGenerics = + allowGenerics + && (generateObjectiveCGenerics(type) + || generateObjectiveCGenerics(typeElement.asType())); + String objcType = + paddedType(nameTable.getObjCTypeDeclaration(type, enableGenerics, typeElement), var) + .trim(); TypeElement declaringClass = ElementUtil.getDeclaringClass(var); String baseName = nameTable.getVariableBaseName(var); ExecutableElement getter = @@ -579,7 +586,12 @@ protected void printStaticFieldDeclaration( private void printStaticFieldFullDeclaration(VariableDeclarationFragment fragment) { VariableElement var = fragment.getVariableElement(); boolean isVolatile = ElementUtil.isVolatile(var); - String objcType = nameTable.getObjCTypeDeclaration(var.asType()); + boolean allowGenerics = !typeUtil.isProtoClass(var.asType()); + boolean enableGenerics = + allowGenerics + && (generateObjectiveCGenerics(var.asType()) + || generateObjectiveCGenerics(typeElement.asType())); + String objcType = nameTable.getObjCTypeDeclaration(var.asType(), enableGenerics, typeElement); String objcTypePadded = paddedType(objcType, var); String declType = paddedType(getDeclarationType(var), var); String name = nameTable.getVariableShortName(var); @@ -610,8 +622,11 @@ private void printStaticFieldFullDeclaration(VariableDeclarationFragment fragmen printStaticFieldDeclaration( fragment, UnicodeUtils.format("%s%s_%s", declType, typeName, name)); } - printf( - "J2OBJC_STATIC_FIELD%s(%s, %s, %s)\n", qualifiers, typeName, name, objcTypePadded.trim()); + String macroTypeArg = objcTypePadded.trim(); + if (macroTypeArg.contains(",")) { + macroTypeArg = "J2OBJC_ARG(" + macroTypeArg + ')'; + } + printf("J2OBJC_STATIC_FIELD%s(%s, %s, %s)\n", qualifiers, typeName, name, macroTypeArg); } // Overridden in TypePrivateDeclarationGenerator diff --git a/translator/src/main/java/com/google/devtools/j2objc/gen/TypeImplementationGenerator.java b/translator/src/main/java/com/google/devtools/j2objc/gen/TypeImplementationGenerator.java index 92d8debeb2..e0472713c9 100644 --- a/translator/src/main/java/com/google/devtools/j2objc/gen/TypeImplementationGenerator.java +++ b/translator/src/main/java/com/google/devtools/j2objc/gen/TypeImplementationGenerator.java @@ -297,7 +297,14 @@ private void printStaticFieldExterns() { } for (VariableDeclarationFragment fragment : getStaticFields()) { VariableElement var = fragment.getVariableElement(); - String objcTypePadded = paddedType(nameTable.getObjCTypeDeclaration(var.asType()), var); + boolean allowGenerics = !typeUtil.isProtoClass(var.asType()); + boolean enableGenerics = + allowGenerics + && (generateObjectiveCGenerics(var.asType()) + || generateObjectiveCGenerics(typeElement.asType())); + String objcTypePadded = + paddedType( + nameTable.getObjCTypeDeclaration(var.asType(), enableGenerics, typeElement), var); String name = nameTable.getVariableShortName(var); newline(); printf("extern %s%s_get_%s(void);\n", objcTypePadded, typeName, name); diff --git a/translator/src/main/java/com/google/devtools/j2objc/types/HeaderImportCollector.java b/translator/src/main/java/com/google/devtools/j2objc/types/HeaderImportCollector.java index 78072b1e19..10bbce4e89 100644 --- a/translator/src/main/java/com/google/devtools/j2objc/types/HeaderImportCollector.java +++ b/translator/src/main/java/com/google/devtools/j2objc/types/HeaderImportCollector.java @@ -143,8 +143,11 @@ public boolean visit(AnnotationTypeMemberDeclaration node) { @Override public boolean visit(FieldDeclaration node) { - if (filter.include(node) && includeInnerTypes) { + if (filter.include(node)) { addForwardDecl(node.getTypeMirror()); + for (TypeMirror fieldGeneric : objCForwardDeclaredGenericParameters(node.getTypeMirror())) { + addForwardDecl(fieldGeneric); + } } return false; } diff --git a/translator/src/test/java/com/google/devtools/j2objc/gen/GenerateObjectiveCGenericsTest.java b/translator/src/test/java/com/google/devtools/j2objc/gen/GenerateObjectiveCGenericsTest.java index c08641f380..dbb9a9355e 100644 --- a/translator/src/test/java/com/google/devtools/j2objc/gen/GenerateObjectiveCGenericsTest.java +++ b/translator/src/test/java/com/google/devtools/j2objc/gen/GenerateObjectiveCGenericsTest.java @@ -422,4 +422,25 @@ public void testProtoDeclaration() throws IOException { assertInTranslation(testHeader, "@interface ComGoogleProtobufTest : NSObject"); assertInTranslation(testHeader, "- (id)getWithId:(id)input;"); } + + public void testStaticPropertyGenerics() throws IOException { + options.setClassProperties(true); + addSourceFile( + "import com.google.j2objc.annotations.GenerateObjectiveCGenerics; " + + "@GenerateObjectiveCGenerics " + + "public class Box {}", + "Box.java"); + addSourceFile( + "import com.google.j2objc.annotations.GenerateObjectiveCGenerics; " + + "@GenerateObjectiveCGenerics " + + "public class Test {" + + " public static final Box STRING_BOX = new Box<>();" + + "}", + "Test.java"); + + String testSystemHeader = translateSourceFile("Test", "Test.h"); + assertInTranslation( + testSystemHeader, "@property (readonly, class, strong) Box *STRING_BOX"); + assertInTranslation(testSystemHeader, "inline Box *Test_get_STRING_BOX(void);"); + } }