Skip to content

Commit

Permalink
Generate all types, ensuring that every type has a class accessor.
Browse files Browse the repository at this point in the history
Refactors annotation type generation so that fields and reflective data is available even for non-runtime annotations.
	Change on 2015/01/16 by kstanger <kstanger@google.com>
-------------
Created by MOE: http://code.google.com/p/moe-java
MOE_MIGRATED_REVID=84140260
  • Loading branch information
kstanger authored and tomball committed Jan 29, 2015
1 parent b8c628b commit 3801343
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 72 deletions.
Expand Up @@ -215,11 +215,12 @@ protected void generate(AnnotationTypeDeclaration node) {
}
println("\n@end");

Iterable<IVariableBinding> staticFields = getStaticFieldsNeedingAccessors(node);

if (isRuntime || !Iterables.isEmpty(staticFields)) {
if (isRuntime || hasInitializeMethod(node)) {
// Print annotation implementation interface.
printf("\n@interface %s : NSObject < %s >", typeName, typeName);
printf("\n@interface %s : NSObject", typeName);
if (isRuntime) {
printf(" < %s >", typeName);
}
if (isRuntime && !members.isEmpty()) {
println(" {\n @private");
printAnnotationVariables(members);
Expand All @@ -230,10 +231,10 @@ protected void generate(AnnotationTypeDeclaration node) {
newline();
}
println("\n@end");
printStaticInitFunction(node);
for (IVariableBinding field : staticFields) {
printStaticField(field);
}
}
printStaticInitFunction(node);
for (IVariableBinding field : getStaticFieldsNeedingAccessors(node)) {
printStaticField(field);
}
}

Expand Down
Expand Up @@ -92,29 +92,28 @@ protected String getSuffix() {
public void generate() {
CompilationUnit unit = getUnit();
println(J2ObjC.getFileHeader(unit.getSourceFileFullPath()));
List<AbstractTypeDeclaration> typesToGenerate = collectTypes(unit);
if (!typesToGenerate.isEmpty()) {
List<AbstractTypeDeclaration> types = unit.getTypes();
if (!types.isEmpty()) {
findInvokedConstructors(unit);
printStart(unit.getSourceFileFullPath());
printImports(unit);
printIgnoreIncompletePragmas(unit);
pushIgnoreDeprecatedDeclarationsPragma();
printFinalFunctionDecls(typesToGenerate);
printClassExtensions(typesToGenerate);
for (AbstractTypeDeclaration type : typesToGenerate) {
printFinalFunctionDecls(types);
printClassExtensions(types);
for (AbstractTypeDeclaration type : types) {
generate(type);
newline();
ITypeBinding binding = type.getTypeBinding();
printf("J2OBJC_%s_TYPE_LITERAL_SOURCE(%s)\n",
binding.isInterface() ? "INTERFACE": "CLASS", NameTable.getFullName(binding));
binding.isInterface() ? "INTERFACE" : "CLASS", NameTable.getFullName(binding));
}
popIgnoreDeprecatedDeclarationsPragma();
} else if (unit.getMainTypeName().endsWith(NameTable.PACKAGE_INFO_MAIN_TYPE)
&& unit.getPackage().getAnnotations().size() > 0) {
generate(unit.getPackage());
} else {
// Print a dummy C function so compiled object file is valid.
List<AbstractTypeDeclaration> types = unit.getTypes();
if (!types.isEmpty()) {
printf("void %s_unused() {}\n", NameTable.getFullName(types.get(0).getTypeBinding()));
}
Expand All @@ -134,37 +133,6 @@ private void printIgnoreIncompletePragmas(CompilationUnit unit) {
}
}

private List<AbstractTypeDeclaration> collectTypes(CompilationUnit unit) {
final List<AbstractTypeDeclaration> types = Lists.newArrayList();
unit.accept(new TreeVisitor() {
@Override
public boolean visit(TypeDeclaration node) {
if (!node.isInterface()
|| !Iterables.isEmpty(getStaticFieldsNeedingInitialization(node))
|| TranslationUtil.needsReflection(node)) {
types.add(node);
}
return false;
}

@Override
public boolean visit(EnumDeclaration node) {
types.add(node); // always print enums
return false;
}

@Override
public boolean visit(AnnotationTypeDeclaration node) {
if (BindingUtil.isRuntimeAnnotation(node.getTypeBinding())
|| !Iterables.isEmpty(getStaticFieldsNeedingInitialization(node))) {
types.add(node);
}
return false;
}
});
return types;
}

private String parameterKey(IMethodBinding method) {
StringBuilder sb = new StringBuilder();
ITypeBinding[] parameterTypes = method.getParameterTypes();
Expand Down Expand Up @@ -226,31 +194,41 @@ public void generate(TypeDeclaration node) {

@Override
protected void generate(AnnotationTypeDeclaration node) {
syncLineNumbers(node.getName()); // avoid doc-comment

boolean isRuntime = BindingUtil.isRuntimeAnnotation(node.getTypeBinding());
boolean hasInitMethod = hasInitializeMethod(node);
boolean needsReflection = TranslationUtil.needsReflection(node);
String typeName = NameTable.getFullName(node.getTypeBinding());
List<MethodDeclaration> methods = TreeUtil.getMethodDeclarationsList(node);
printInitFlagDefinition(node);
printf("\n@implementation %s\n", typeName);
if (BindingUtil.isRuntimeAnnotation(node.getTypeBinding())) {
List<AnnotationTypeMemberDeclaration> members = Lists.newArrayList(
Iterables.filter(node.getBodyDeclarations(), AnnotationTypeMemberDeclaration.class));
printAnnotationProperties(members);
if (!members.isEmpty()) {
printAnnotationConstructor(node.getTypeBinding());
}
printAnnotationAccessors(members);

if (needsReflection && !isRuntime && !hasInitMethod) {
printf("\n@interface %s : NSObject\n@end\n", typeName);
}

printInitFlagDefinition(node);
printStaticVars(node);
println("\n- (IOSClass *)annotationType {");
printf(" return [IOSClass classFromProtocol:@protocol(%s)];\n", typeName);
println("}");
printMethods(methods);
if (TranslationUtil.needsReflection(node)) {
printTypeAnnotationsMethod(node);
printMetadata(node);

if (isRuntime || hasInitMethod || needsReflection) {
syncLineNumbers(node.getName()); // avoid doc-comment
printf("\n@implementation %s\n", typeName);

if (isRuntime) {
List<AnnotationTypeMemberDeclaration> members = Lists.newArrayList(
Iterables.filter(node.getBodyDeclarations(), AnnotationTypeMemberDeclaration.class));
printAnnotationProperties(members);
if (!members.isEmpty()) {
printAnnotationConstructor(node.getTypeBinding());
}
printAnnotationAccessors(members);
println("\n- (IOSClass *)annotationType {");
printf(" return [IOSClass classFromProtocol:@protocol(%s)];\n", typeName);
println("}");
}
printInitializeMethod(node);
if (needsReflection) {
printTypeAnnotationsMethod(node);
printMetadata(node);
}
println("\n@end");
}
println("\n@end");
}

private void printAnnotationConstructor(ITypeBinding annotation) {
Expand Down
Expand Up @@ -17,6 +17,7 @@
package com.google.devtools.j2objc.types;

import com.google.common.collect.Sets;
import com.google.devtools.j2objc.ast.AbstractTypeDeclaration;
import com.google.devtools.j2objc.ast.Annotation;
import com.google.devtools.j2objc.ast.AnnotationTypeDeclaration;
import com.google.devtools.j2objc.ast.AnnotationTypeMemberDeclaration;
Expand All @@ -37,6 +38,7 @@
import com.google.devtools.j2objc.ast.MethodInvocation;
import com.google.devtools.j2objc.ast.Name;
import com.google.devtools.j2objc.ast.NormalAnnotation;
import com.google.devtools.j2objc.ast.PackageDeclaration;
import com.google.devtools.j2objc.ast.QualifiedName;
import com.google.devtools.j2objc.ast.SimpleName;
import com.google.devtools.j2objc.ast.SingleMemberAnnotation;
Expand All @@ -52,6 +54,7 @@
import com.google.devtools.j2objc.ast.VariableDeclarationStatement;
import com.google.devtools.j2objc.util.BindingUtil;
import com.google.devtools.j2objc.util.NameTable;
import com.google.devtools.j2objc.util.TranslationUtil;

import org.eclipse.jdt.core.dom.IAnnotationBinding;
import org.eclipse.jdt.core.dom.IBinding;
Expand Down Expand Up @@ -369,7 +372,15 @@ public boolean visit(VariableDeclarationStatement node) {

private boolean visitAnnotation(Annotation node) {
IAnnotationBinding binding = node.getAnnotationBinding();
if (!BindingUtil.isRuntimeAnnotation(binding)) {
boolean needsReflection = false;
AbstractTypeDeclaration owningType = TreeUtil.getOwningType(node);
if (owningType != null) {
needsReflection = TranslationUtil.needsReflection(owningType);
} else {
needsReflection = TranslationUtil.needsReflection(
TreeUtil.getNearestAncestorWithType(PackageDeclaration.class, node));
}
if (!BindingUtil.isRuntimeAnnotation(binding) || !needsReflection) {
return false;
}
for (IMemberValuePairBinding memberValuePair : binding.getAllMemberValuePairs()) {
Expand Down
Expand Up @@ -65,8 +65,8 @@ public void testHeaderFileMapping() throws IOException {
addSourceFile("package unit.mapping.custom; public class Test { }",
"unit/mapping/custom/Test.java");
String translation = translateSourceFile(
"import unit.mapping.custom.Test; " +
"public class MyTest { MyTest(Test u) {}}",
"import unit.mapping.custom.Test; "
+ "public class MyTest { MyTest(Test u) {}}",
"MyTest", "MyTest.m");
assertTranslation(translation, "#include \"my/mapping/custom/Test.h\"");
}
Expand Down Expand Up @@ -284,7 +284,7 @@ public void testEmptyInterfaceGenerationNoMetadata() throws IOException {
String translation = translateSourceFile(
"package foo; public interface Compatible {}",
"Compatible", "foo/Compatible.m");
assertTranslation(translation, "void FooCompatible_unused() {}");
assertNotInTranslation(translation, "@interface");
}

public void testEmptyInterfaceGeneration() throws IOException {
Expand Down Expand Up @@ -686,11 +686,11 @@ public void testAnnotationWithField() throws IOException {
String translation = translateSourceFile(
"@interface Test { String FOO = \"foo\"; int I = 5; }", "Test", "Test.h");
assertTranslation(translation, "#define Test_I 5");
assertTranslation(translation, "@interface Test : NSObject < Test >");
assertTranslation(translation, "FOUNDATION_EXPORT NSString *Test_FOO_;");
assertTranslation(translation, "J2OBJC_STATIC_FIELD_GETTER(Test, FOO_, NSString *)");
translation = getTranslatedFile("Test.m");
assertTranslation(translation, "NSString * Test_FOO_ = @\"foo\";");
assertTranslation(translation, "@interface Test : NSObject");
}

public void testPackageInfoAnnotationAndDoc() throws IOException {
Expand Down

0 comments on commit 3801343

Please sign in to comment.