private void printTypeAnnotationsMethod(AbstractTypeDeclaration decl) {
   List<Annotation> runtimeAnnotations = ASTUtil.getRuntimeAnnotations(ASTUtil.getModifiers(decl));
   if (runtimeAnnotations.size() > 0) {
     println("+ (IOSObjectArray *)__annotations {");
     printAnnotationCreate(runtimeAnnotations);
   }
 }
  @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 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);
   }
 }
 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 void printFieldAnnotationMethods(List<FieldDeclaration> fields) {
   for (FieldDeclaration field : fields) {
     List<Annotation> runtimeAnnotations =
         ASTUtil.getRuntimeAnnotations(ASTUtil.getModifiers(field));
     if (runtimeAnnotations.size() > 0) {
       for (VariableDeclarationFragment var : ASTUtil.getFragments(field)) {
         printf("+ (IOSObjectArray *)__annotations_%s_ {\n", var.getName().getIdentifier());
         printAnnotationCreate(runtimeAnnotations);
       }
     }
   }
 }
  private void printImports(CompilationUnit node) {
    ImplementationImportCollector collector = new ImplementationImportCollector();
    collector.collect(node, getSourceFileName());
    Set<Import> imports = collector.getImports();

    if (!imports.isEmpty()) {
      Set<String> includeStmts = Sets.newTreeSet();
      for (Import imp : imports) {
        includeStmts.add(String.format("#include \"%s.h\"", imp.getImportFileName()));
      }
      for (String stmt : includeStmts) {
        println(stmt);
      }

      // Print native includes.
      int endOfImportText =
          node.types().isEmpty()
              ? node.getLength()
              : ((ASTNode) node.types().get(0)).getStartPosition();
      for (Comment c : ASTUtil.getCommentList(node)) {
        int start = c.getStartPosition();
        if (start >= endOfImportText) {
          break;
        }
        if (c instanceof BlockComment) {
          String nativeImport = extractNativeCode(start, c.getLength(), true);
          if (nativeImport != null) { // if it has a JSNI section
            println(nativeImport.trim());
          }
        }
      }

      newline();
    }
  }
 /** Finds all block comments and associates them with their containing type. */
 private void findBlockComments(CompilationUnit unit, List<AbstractTypeDeclaration> types) {
   List<Comment> comments = ASTUtil.getCommentList(unit);
   for (Comment comment : comments) {
     if (!comment.isBlockComment()) {
       continue;
     }
     int commentPos = comment.getStartPosition();
     AbstractTypeDeclaration containingType = null;
     int containingTypePos = -1;
     for (AbstractTypeDeclaration type : types) {
       int typePos = type.getStartPosition();
       if (typePos < 0) {
         continue;
       }
       int typeEnd = typePos + type.getLength();
       if (commentPos > typePos && commentPos < typeEnd && typePos > containingTypePos) {
         containingType = type;
         containingTypePos = typePos;
       }
     }
     if (containingType != null) {
       blockComments.put(containingType, comment);
     }
   }
 }
  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 List<VariableDeclarationFragment> getProperties(FieldDeclaration[] fields) {
   List<VariableDeclarationFragment> properties = Lists.newArrayList();
   for (FieldDeclaration field : fields) {
     if (!Modifier.isStatic(field.getModifiers())) {
       properties.addAll(ASTUtil.getFragments(field));
     }
   }
   return properties;
 }
 @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");
 }
 @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";
   }
 }
 public void generate(CompilationUnit unit) {
   println(J2ObjC.getFileHeader(getSourceFileName()));
   List<AbstractTypeDeclaration> typesToGenerate = collectTypes(unit);
   if (!typesToGenerate.isEmpty()) {
     findBlockComments(unit, typesToGenerate);
     findInvokedConstructors(unit);
     printStart(getSourceFileName());
     printImports(unit);
     pushIgnoreDeprecatedDeclarationsPragma();
     for (AbstractTypeDeclaration type : typesToGenerate) {
       generate(type);
     }
     popIgnoreDeprecatedDeclarationsPragma();
   } else {
     // Print a dummy C function so compiled object file is valid.
     List<AbstractTypeDeclaration> types = ASTUtil.getTypes(unit);
     if (!types.isEmpty()) {
       printf("void %s_unused() {}\n", NameTable.getFullName(types.get(0)));
     }
   }
   save(unit);
 }
 // 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();
   }
 }
  @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");
  }