@Override protected void generate(AnnotationTypeDeclaration node) { syncLineNumbers(node.getName()); // avoid doc-comment String typeName = NameTable.getFullName(node); printf("@implementation %s\n", typeName); if (BindingUtil.isRuntimeAnnotation(Types.getTypeBinding(node))) { List<AnnotationTypeMemberDeclaration> members = Lists.newArrayList(); for (BodyDeclaration decl : ASTUtil.getBodyDeclarations(node)) { if (decl instanceof AnnotationTypeMemberDeclaration) { members.add((AnnotationTypeMemberDeclaration) decl); } } printAnnotationProperties(members); if (!members.isEmpty()) { printAnnotationConstructor(Types.getTypeBinding(node)); } printAnnotationAccessors(members); } List<FieldDeclaration> fields = ASTUtil.getFieldDeclarations(node); List<IVariableBinding> fieldsNeedingAccessors = getStaticFieldsNeedingAccessors(fields, /* isInterface */ true); printStaticVars(fields, /* isInterface */ true); printStaticFieldAccessors(fieldsNeedingAccessors, Collections.<MethodDeclaration>emptyList()); println("- (IOSClass *)annotationType {"); printf(" return [IOSClass classWithProtocol:@protocol(%s)];\n", typeName); println("}\n"); if (!Options.stripReflection()) { printTypeAnnotationsMethod(node); printMetadata(node); } println("@end\n"); }
private Statement createInnerConstructorInvocation(MethodDeclaration m) { ConstructorInvocation invocation = m.getAST().newConstructorInvocation(); Types.addBinding(invocation, Types.getBinding(m)); for (SingleVariableDeclaration param : ASTUtil.getParameters(m)) { SimpleName paramName = param.getName(); IVariableBinding paramBinding = Types.getVariableBinding(paramName); SimpleName argName = m.getAST().newSimpleName(paramName.getIdentifier()); Types.addBinding(argName, paramBinding); ASTUtil.getArguments(invocation).add(argName); } return invocation; }
private String generateMethodBody(MethodDeclaration m) { String methodBody; if (Modifier.isNative(m.getModifiers())) { if (hasNativeCode(m, true)) { methodBody = extractNativeMethodBody(m); } else if (Options.generateNativeStubs()) { return generateNativeStub(m); } else { return null; } } else if (Modifier.isAbstract(m.getModifiers())) { // Generate a body which throws a NSInvalidArgumentException. String body = "{\n // can't call an abstract method\n " + "[self doesNotRecognizeSelector:_cmd];\n "; if (!Types.isVoidType(m.getReturnType2())) { body += "return 0;\n"; // Never executes, but avoids a gcc warning. } return body + "}"; } else { // generate a normal method body methodBody = generateStatement(m.getBody(), false); } boolean isStatic = (m.getModifiers() & Modifier.STATIC) != 0; boolean isSynchronized = (m.getModifiers() & Modifier.SYNCHRONIZED) != 0; if (isStatic && isSynchronized) { methodBody = "{\n@synchronized([self class]) {\n" + methodBody + "}\n}\n"; } else if (isSynchronized) { methodBody = "{\n@synchronized(self) {\n" + methodBody + "}\n}\n"; } return methodBody; }
public IOSMethod(String s, IMethodBinding binding, ITypeBinding returnType, AST ast) { if (s.endsWith(";")) { s = s.substring(0, s.length() - 1); } int i = s.indexOf(' '); String className = s.substring(0, i); IOSTypeBinding clazz = Types.resolveIOSType(className); if (clazz == null) { clazz = new IOSTypeBinding(className, false); } declaringClass = clazz.getName(); s = s.substring(i + 1); parameters = Lists.newArrayList(); i = s.indexOf(':'); if (i > 0) { // if there are parameters name = s.substring(0, i); String[] argDefs = splitParameterString(s); for (i = 0; i < argDefs.length; i++) { IOSParameter param = new IOSParameter(argDefs[i], i, ast); parameters.add(param); if (param.isVarArgs()) { varArgs = true; break; } } } else { name = s; } this.binding = new IOSMethodBinding(name, binding, clazz, returnType, varArgs); }
@Override protected void printStaticConstructorDeclaration(MethodDeclaration m) { String className = NameTable.getFullName(Types.getMethodBinding(m).getDeclaringClass()); StringBuffer sb = new StringBuffer(); sb.append("{\nif (self == [" + className + " class]) {\n"); for (Statement statement : ASTUtil.getStatements(m.getBody())) { sb.append(generateStatement(statement, false)); } sb.append("}\n}"); print("+ (void)initialize " + reindent(sb.toString()) + "\n\n"); }
private void printMethodAnnotationMethods(List<MethodDeclaration> methods) { for (MethodDeclaration method : methods) { List<Annotation> runtimeAnnotations = ASTUtil.getRuntimeAnnotations(ASTUtil.getModifiers(method)); if (runtimeAnnotations.size() > 0) { printf( "+ (IOSObjectArray *)__annotations_%s {\n", methodKey(Types.getMethodBinding(method))); printAnnotationCreate(runtimeAnnotations); } printParameterAnnotationMethods(method); } }
// Prints an annotation's values as a constructor argument list. If // the annotation type declares default values, then for any value that // isn't specified in the annotation will use the default. private void printAnnotationParameters(Annotation annotation) { IAnnotationBinding binding = Types.getAnnotationBinding(annotation); IMemberValuePairBinding[] valueBindings = BindingUtil.getSortedMemberValuePairs(binding); for (int i = 0; i < valueBindings.length; i++) { if (i > 0) { print(' '); } IMemberValuePairBinding valueBinding = valueBindings[i]; print(i == 0 ? "With" : "with"); printf("%s:", NameTable.capitalize(valueBinding.getName())); Object value = valueBinding.getValue(); printAnnotationValue(annotation.getAST(), value); } }
private void printMethodsAndOcni( AbstractTypeDeclaration typeNode, Iterable<MethodDeclaration> methods, Iterable<Comment> comments) { Set<String> methodsPrinted = Sets.newHashSet(); Iterator<MethodDeclaration> methodsIter = methods.iterator(); Iterator<Comment> commentsIter = comments.iterator(); MethodDeclaration nextMethod = methodsIter.hasNext() ? methodsIter.next() : null; Comment nextComment = commentsIter.hasNext() ? commentsIter.next() : null; int minPos = 0; while (nextMethod != null || nextComment != null) { int methodStartPos = nextMethod != null ? nextMethod.getStartPosition() : Integer.MAX_VALUE; if (methodStartPos < 0) { methodStartPos = minPos; } int commentStartPos = nextComment != null ? nextComment.getStartPosition() : Integer.MAX_VALUE; if (methodStartPos < commentStartPos) { assert nextMethod != null; printMethod(nextMethod); minPos = methodStartPos + nextMethod.getLength(); nextMethod = methodsIter.hasNext() ? methodsIter.next() : null; } else { assert nextComment != null; if (commentStartPos > minPos) { String nativeCode = extractNativeCode(commentStartPos, nextComment.getLength()); if (nativeCode != null) { nativeCode = reindent(nativeCode.trim()); findMethodSignatures(nativeCode, methodsPrinted); print(nativeCode + "\n\n"); } } nextComment = commentsIter.hasNext() ? commentsIter.next() : null; } } // If the type implements Iterable and there's no existing implementation // for NSFastEnumeration's protocol method, then add the default // implementation. if (BindingUtil.findInterface(Types.getTypeBinding(typeNode), "java.lang.Iterable") != null && !methodsPrinted.contains("countByEnumeratingWithState:objects:count:")) { print( "- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state " + "objects:(__unsafe_unretained id *)stackbuf count:(NSUInteger)len {\n" + " return JreDefaultFastEnumeration(self, state, stackbuf, len);\n}\n\n"); } }
@Override protected String constructorDeclaration(MethodDeclaration m) { String methodBody; IMethodBinding binding = Types.getMethodBinding(m); boolean memDebug = Options.memoryDebug(); List<Statement> statements = ASTUtil.getStatements(m.getBody()); if (binding.getDeclaringClass().isEnum()) { return enumConstructorDeclaration(m, statements, binding); } StringBuffer sb = new StringBuffer("{\n"); int constructorIdx = findConstructorInvocation(statements); int idx = 0; while (idx < constructorIdx) { sb.append(generateStatement(statements.get(idx++), false)); } String superCall = idx == constructorIdx ? generateStatement(statements.get(idx++), false) : "[super init]"; if (idx >= statements.size()) { sb.append("return "); if (memDebug) { sb.append("JreMemDebugAdd("); } sb.append(superCall).append(memDebug ? ");\n}" : ";\n}"); } else { sb.append("if (self = ").append(superCall).append(") {\n"); while (idx < statements.size()) { sb.append(generateStatement(statements.get(idx++), false)); } if (memDebug) { sb.append("JreMemDebugAdd(self);\n"); } sb.append("}\nreturn self;\n}"); } methodBody = sb.toString(); if (invokedConstructors.contains(methodKey(binding))) { return super.constructorDeclaration(m, true) + " " + reindent(methodBody) + "\n\n" + super.constructorDeclaration(m, false) + " {\n return " + generateStatement(createInnerConstructorInvocation(m), false) + ";\n}\n\n"; } else { return super.constructorDeclaration(m, false) + " " + reindent(methodBody) + "\n\n"; } }
private void printParameterAnnotationMethods(MethodDeclaration method) { List<SingleVariableDeclaration> params = ASTUtil.getParameters(method); // Quick test to see if there are any parameter annotations. boolean hasAnnotations = false; for (SingleVariableDeclaration param : params) { List<Annotation> runtimeAnnotations = ASTUtil.getRuntimeAnnotations(ASTUtil.getModifiers(param)); if (runtimeAnnotations.size() > 0) { hasAnnotations = true; break; } } if (hasAnnotations) { // Print array of arrays, with an element in the outer array for each parameter. printf( "+ (IOSObjectArray *)__annotations_%s_params {\n", methodKey(Types.getMethodBinding(method))); print(" return [IOSObjectArray arrayWithObjects:(id[]) { "); for (int i = 0; i < params.size(); i++) { if (i > 0) { print(", "); } SingleVariableDeclaration param = params.get(i); List<Annotation> runtimeAnnotations = ASTUtil.getRuntimeAnnotations(ASTUtil.getModifiers(param)); if (runtimeAnnotations.size() > 0) { print("[IOSObjectArray arrayWithObjects:(id[]) { "); printAnnotations(runtimeAnnotations); printf( " } count:%d type:[IOSClass classWithProtocol:" + "@protocol(JavaLangAnnotationAnnotation)]]", runtimeAnnotations.size()); } else { print( "[IOSObjectArray arrayWithLength:0 " + "type:[IOSClass classWithProtocol:@protocol(JavaLangAnnotationAnnotation)]]"); } } printf( " } count:%d type:[IOSClass classWithProtocol:" + "@protocol(JavaLangAnnotationAnnotation)]];\n}\n", params.size()); } }
private void printMethods(TypeDeclaration node) { printMethodsAndOcni(node, Arrays.asList(node.getMethods()), blockComments.get(node)); // If node implements CharSequence, add forwarding method from the // sequenceDescription method to description (toString()). See // JavaToIOSMethodTranslator.loadCharSequenceMethods() for details. ITypeBinding binding = Types.getTypeBinding(node); for (ITypeBinding interfaze : binding.getInterfaces()) { if (interfaze.getQualifiedName().equals("java.lang.CharSequence")) { println("- (NSString *)description {\n return [self sequenceDescription];\n}\n"); } } List<VariableDeclarationFragment> properties = getProperties(node.getFields()); if (properties.size() > 0) { printStrongReferencesMethod(properties); } }
private void printAnnotationAccessors(List<AnnotationTypeMemberDeclaration> members) { int nPrinted = 0; for (AnnotationTypeMemberDeclaration member : members) { Expression deflt = member.getDefault(); if (deflt != null) { ITypeBinding type = Types.getTypeBinding(member.getType()); String typeString = NameTable.getSpecificObjCType(type); String propertyName = NameTable.getName(member.getName()); printf("+ (%s)%sDefault {\n", typeString, propertyName); printf(" return %s;\n", generateExpression(deflt)); println("}\n"); nPrinted++; } } if (nPrinted > 0) { newline(); } }
private void printAnnotations(List<Annotation> runtimeAnnotations) { boolean first = true; for (Annotation annotation : runtimeAnnotations) { if (first) { first = false; } else { print(", "); } if (Options.useReferenceCounting()) { print('['); } printf("[[%s alloc] init", NameTable.getFullName(Types.getTypeBinding(annotation))); printAnnotationParameters(annotation); print(']'); if (Options.useReferenceCounting()) { print(" autorelease]"); } } }
/** Verifies that abstract methods to implement an interface are added to an abstract class. */ public void testAbstractMethodsAdded() { String source = "import java.util.Iterator; public abstract class Test implements Iterator<Test> { " + "public boolean hasNext() { return true; } }"; CompilationUnit unit = translateType("Test", source); List<AbstractTypeDeclaration> types = unit.getTypes(); assertEquals(1, types.size()); assertTrue(types.get(0) instanceof TypeDeclaration); TypeDeclaration testType = (TypeDeclaration) types.get(0); List<MethodDeclaration> methods = TreeUtil.getMethodDeclarationsList(testType); assertEquals(4, methods.size()); // verify added methods are abstract, and that existing method wasn't changed for (MethodDeclaration m : methods) { int modifiers = m.getModifiers(); String name = m.getName().getIdentifier(); if (name.equals("hasNext")) { assertFalse(Modifier.isAbstract(modifiers)); } else if (name.equals(NameTable.FINALIZE_METHOD) || name.equals(NameTable.DEALLOC_METHOD) || name.equals(NameTable.INIT_NAME)) { // it's ok. } else { // it's an added method assertTrue(Modifier.isAbstract(modifiers)); assertEquals(0, m.getParameters().size()); if (name.equals("next")) { assertEquals(testType.getTypeBinding(), m.getReturnType().getTypeBinding()); } else if (name.equals("remove")) { ITypeBinding voidType = Types.resolveJavaType("void"); assertEquals(voidType, m.getReturnType().getTypeBinding()); } else { fail("unknown method added: " + name); } } } }
// We generate the runtime debug method +memDebugStaticReferences. // This method will return an array of NSNumber containing pointers (casted into unsigned long) // to the objects referenced by a class variable with a strong reference. // It will be useful for debug purpose. // // Arrays returned by -memDebugStaticReferences and -memDebugStaticReferencesNames (see below) // must be the same size. // // In case of a Java enum, valuesVarNameis the name of the array of enum values. private void printStaticReferencesMethod(List<FieldDeclaration> fields, String valuesVarName) { if (Options.memoryDebug()) { if (!Options.useReferenceCounting()) { println("+ (NSArray *)memDebugStaticReferences {"); println(" return nil;"); println("}"); return; } println("+ (NSArray *)memDebugStaticReferences {"); println(" NSMutableArray *result = [NSMutableArray array];"); for (FieldDeclaration f : fields) { if (Modifier.isStatic(f.getModifiers())) { for (VariableDeclarationFragment var : ASTUtil.getFragments(f)) { IVariableBinding binding = Types.getVariableBinding(var); // All non-primitive static variables are strong references. if (!binding.getType().isPrimitive()) { String name = NameTable.getStaticVarQualifiedName(binding); println( String.format( " [result addObject:[JreMemDebugStrongReference " + "strongReferenceWithObject:%s name:@\"%s\"]];", name, name)); } } } } if (valuesVarName != null) { println( String.format( " [result addObject:[JreMemDebugStrongReference " + "strongReferenceWithObject:%s name:@\"enumValues\"]];", valuesVarName)); } println(" return result;"); println("}\n"); } }
private void printStaticVars(List<FieldDeclaration> fields, boolean isInterface) { boolean hadStaticVar = false; for (FieldDeclaration f : fields) { if (Modifier.isStatic(f.getModifiers()) || isInterface) { for (VariableDeclarationFragment var : ASTUtil.getFragments(f)) { IVariableBinding binding = Types.getVariableBinding(var); if (!BindingUtil.isPrimitiveConstant(binding)) { String name = NameTable.getStaticVarQualifiedName(binding); String objcType = NameTable.getObjCType(binding.getType()); Expression initializer = var.getInitializer(); if (initializer != null) { printf("static %s %s = %s;\n", objcType, name, generateExpression(initializer)); } else { printf("static %s %s;\n", objcType, name); } hadStaticVar = true; } } } } if (hadStaticVar) { newline(); } }
public NullLiteral() { super(Types.resolveJavaType("java.lang.Object")); }
// Returns whether the property is a strong reference. private boolean isStrongReferenceProperty(VariableDeclarationFragment property) { IVariableBinding varBinding = Types.getVariableBinding(property); ITypeBinding type = Types.getTypeBinding(property); return !type.isPrimitive() && !BindingUtil.isWeakReference(varBinding); }
@Override protected void generate(EnumDeclaration node) { List<EnumConstantDeclaration> constants = ASTUtil.getEnumConstants(node); List<MethodDeclaration> methods = Lists.newArrayList(); List<FieldDeclaration> fields = Lists.newArrayList(); MethodDeclaration initializeMethod = null; for (BodyDeclaration decl : ASTUtil.getBodyDeclarations(node)) { if (decl instanceof FieldDeclaration) { fields.add((FieldDeclaration) decl); } else if (decl instanceof MethodDeclaration) { MethodDeclaration md = (MethodDeclaration) decl; if (md.getName().getIdentifier().equals("initialize")) { initializeMethod = md; } else { methods.add(md); } } } syncLineNumbers(node.getName()); // avoid doc-comment String typeName = NameTable.getFullName(node); newline(); for (EnumConstantDeclaration constant : constants) { IVariableBinding var = Types.getVariableBinding(constant.getName()); printf("static %s *%s;\n", typeName, NameTable.getStaticVarQualifiedName(var)); } printf("IOSObjectArray *%s_values;\n", typeName); newline(); printf("@implementation %s\n\n", typeName); printStaticVars(fields, /* isInterface */ false); printStaticReferencesMethod(fields, typeName + "_values"); for (EnumConstantDeclaration constant : constants) { String name = NameTable.getName(constant.getName()); printf("+ (%s *)%s {\n", typeName, name); printf(" return %s_%s;\n", typeName, name); println("}"); } newline(); // Enum constants needs to implement NSCopying. Being singletons, they // can just return self, as long the retain count is incremented. String selfString = Options.useReferenceCounting() ? "[self retain]" : "self"; printf("- (id)copyWithZone:(NSZone *)zone {\n return %s;\n}\n\n", selfString); printStaticFieldAccessors(fields, methods, /* isInterface */ false); printMethodsAndOcni(node, methods, blockComments.get(node)); printf("+ (void)initialize {\n if (self == [%s class]) {\n", typeName); for (int i = 0; i < constants.size(); i++) { EnumConstantDeclaration constant = constants.get(i); List<Expression> args = ASTUtil.getArguments(constant); String name = NameTable.getName(constant.getName()); String constantTypeName = NameTable.getFullName(Types.getMethodBinding(constant).getDeclaringClass()); printf(" %s_%s = [[%s alloc] init", typeName, name, constantTypeName); if (args.isEmpty()) { print("With"); } else { print( StatementGenerator.generateArguments( Types.getMethodBinding(constant), args, fieldHiders, getBuilder().getSourcePosition())); print(" with"); } printf("NSString:@\"%s\" withInt:%d];\n", name, i); } printf(" %s_values = [[IOSObjectArray alloc] initWithObjects:(id[]){ ", typeName); for (EnumConstantDeclaration constant : constants) { printf("%s_%s, ", typeName, NameTable.getName(constant.getName())); } printf( "nil } count:%d type:[IOSClass classWithClass:[%s class]]];\n", constants.size(), typeName); if (initializeMethod != null) { for (Statement s : ASTUtil.getStatements(initializeMethod.getBody())) { printf( " %s", StatementGenerator.generate(s, fieldHiders, false, getBuilder().getSourcePosition())); } } println(" }\n}\n"); // Print generated values and valueOf methods. println("+ (IOSObjectArray *)values {"); printf(" return [IOSObjectArray arrayWithArray:%s_values];\n", typeName); println("}\n"); printf("+ (%s *)valueOfWithNSString:(NSString *)name {\n", typeName); printf(" for (int i = 0; i < [%s_values count]; i++) {\n", typeName); printf(" %s *e = %s_values->buffer_[i];\n", typeName, typeName); printf(" if ([name isEqual:[e name]]) {\n"); printf(" return e;\n"); printf(" }\n"); printf(" }\n"); if (Options.useReferenceCounting()) { printf( " @throw [[[JavaLangIllegalArgumentException alloc] initWithNSString:name]" + " autorelease];\n"); } else { printf(" @throw [[JavaLangIllegalArgumentException alloc] initWithNSString:name];\n"); } printf(" return nil;\n"); println("}\n"); if (!Options.stripReflection()) { printTypeAnnotationsMethod(node); printMetadata(node); } println("@end"); }
private String generateNativeStub(MethodDeclaration m) { IMethodBinding binding = Types.getMethodBinding(m); String methodName = NameTable.getName(binding); return String.format("{\n @throw \"%s method not implemented\";\n}", methodName); }
@Override protected String getParameterName(SingleVariableDeclaration param) { String name = super.getParameterName(param); IVariableBinding binding = Types.getVariableBinding(param); return binding != null && fieldHiders.contains(binding) ? name + "Arg" : name; }