/** Determines if a type can access fields and methods from an outer class. */ public static boolean hasOuterContext(ITypeBinding type) { if (type.getDeclaringClass() == null) { return false; } // Local types can't be declared static, but if the declaring method is // static then the local type is effectively static. IMethodBinding declaringMethod = type.getTypeDeclaration().getDeclaringMethod(); if (declaringMethod != null) { return !BindingUtil.isStatic(declaringMethod); } return !BindingUtil.isStatic(type); }
/** Locate method which matches either Java or Objective C getter name patterns. */ public static IMethodBinding findGetterMethod( String propertyName, ITypeBinding propertyType, ITypeBinding declaringClass) { // Try Objective-C getter naming convention. IMethodBinding getter = BindingUtil.findDeclaredMethod(declaringClass, propertyName); if (getter == null) { // Try Java getter naming conventions. String prefix = BindingUtil.isBoolean(propertyType) ? "is" : "get"; getter = BindingUtil.findDeclaredMethod( declaringClass, prefix + NameTable.capitalize(propertyName)); } return getter; }
@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"); }
/** * Adds a cast check to compareTo methods. This helps Comparable types behave well in sorted * collections which rely on Java's runtime type checking. */ @Override public void endVisit(MethodDeclaration node) { IMethodBinding binding = node.getMethodBinding(); if (!binding.getName().equals("compareTo") || node.getBody() == null) { return; } ITypeBinding comparableType = BindingUtil.findInterface(binding.getDeclaringClass(), "java.lang.Comparable"); if (comparableType == null) { return; } ITypeBinding[] typeArguments = comparableType.getTypeArguments(); ITypeBinding[] parameterTypes = binding.getParameterTypes(); if (typeArguments.length != 1 || parameterTypes.length != 1 || !typeArguments[0].isEqualTo(parameterTypes[0])) { return; } IVariableBinding param = node.getParameters().get(0).getVariableBinding(); FunctionInvocation castCheck = createCastCheck(typeArguments[0], new SimpleName(param)); if (castCheck != null) { node.getBody().getStatements().add(0, new ExpressionStatement(castCheck)); } }
private void initializeCommonJavaTypes() { ITypeBinding charSequence = BindingUtil.findInterface(javaStringType, "java.lang.CharSequence"); javaBindingMap.put("java.lang.CharSequence", charSequence); iosBindingMap.put("JavaLangCharSequence", charSequence); javaBindingMap.put("java.lang.Number", javaNumberType); javaBindingMap.put("java.lang.Throwable", javaThrowableType); }
private List<Statement> getFieldAdjustments(TypeDeclaration node) { List<Statement> adjustments = Lists.newArrayList(); for (VariableDeclarationFragment decl : TreeUtil.getAllFields(node)) { IVariableBinding var = decl.getVariableBinding(); if (BindingUtil.isStatic(var) || var.getType().isPrimitive()) { continue; } boolean isWeak = BindingUtil.isWeakReference(var); boolean isVolatile = BindingUtil.isVolatile(var); if (isWeak && !isVolatile) { adjustments.add(createReleaseStatement(var)); } else if (!isWeak && isVolatile) { adjustments.add(createVolatileRetainStatement(var)); } } return adjustments; }
@Override protected void printStaticFieldGetter(IVariableBinding var) { String name = BindingUtil.isPrimitiveConstant(var) ? NameTable.getPrimitiveConstantName(var) : NameTable.getStaticVarQualifiedName(var); printf("%s {\n return %s;\n}\n\n", staticFieldGetterSignature(var), name); }
@Override public void endVisit(MethodInvocation node) { IMethodBinding binding = node.getMethodBinding(); Expression receiver = node.getExpression(); if (receiver != null && !BindingUtil.isStatic(binding)) { maybeAddCast(receiver, null, true); } maybeCastArguments(node.getArguments(), binding); if (returnValueNeedsIntCast(node)) { addCast(node); } }
public void testCapturedWeakLocalVariable() { resolveSource( "Test", "import com.google.j2objc.annotations.Weak;" + "class Test { void test(@Weak final int i) { Runnable r = new Runnable() { " + "public void run() { int i2 = i + 1; } }; } }"); AnonymousClassDeclaration runnableNode = (AnonymousClassDeclaration) nodesByType.get(ASTNode.ANONYMOUS_CLASS_DECLARATION).get(0); ITypeBinding runnableBinding = runnableNode.resolveBinding(); List<IVariableBinding> innerFields = OuterReferenceResolver.getInnerFields(runnableBinding); assertEquals(1, innerFields.size()); assertTrue(BindingUtil.isWeakReference(innerFields.get(0))); }
// 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); } }
/** * Returns true if the specified binding is of an annotation that has a runtime retention policy. */ public static boolean isRuntimeAnnotation(ITypeBinding binding) { if (binding != null && binding.isAnnotation()) { for (IAnnotationBinding ann : binding.getAnnotations()) { if (ann.getName().equals("Retention")) { IVariableBinding retentionBinding = (IVariableBinding) ann.getDeclaredMemberValuePairs()[0].getValue(); return retentionBinding.getName().equals(RetentionPolicy.RUNTIME.name()); } } if (binding.isNested()) { return BindingUtil.isRuntimeAnnotation(binding.getDeclaringClass()); } } return false; }
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 public void endVisit(CastExpression node) { ITypeBinding type = node.getType().getTypeBinding(); Expression expr = node.getExpression(); ITypeBinding exprType = expr.getTypeBinding(); // TODO(kirbs): Implement correct conversion of Java 8 intersection types to Objective-C. if (node.getType().isIntersectionType() && !Options.isJava8Translator()) { // Technically we can't currently get here, but as we add support and change flags in the // future this should alert us to implement intersection types. assert false : "not implemented yet"; } if (BindingUtil.isFloatingPoint(exprType)) { assert type.isPrimitive(); // Java wouldn't allow a cast from primitive to non-primitive. switch (type.getBinaryName().charAt(0)) { case 'J': node.replaceWith(rewriteFloatToIntegralCast(type, expr, "JreFpToLong", type)); return; case 'C': node.replaceWith(rewriteFloatToIntegralCast(type, expr, "JreFpToChar", type)); return; case 'B': case 'S': case 'I': node.replaceWith( rewriteFloatToIntegralCast(type, expr, "JreFpToInt", typeEnv.resolveJavaType("int"))); return; } // else fall-through. } // Lean on Java's type-checking. if (!type.isPrimitive() && exprType.isAssignmentCompatible(type.getErasure())) { node.replaceWith(TreeUtil.remove(expr)); return; } FunctionInvocation castCheck = createCastCheck(type, expr); if (castCheck != null) { node.setExpression(castCheck); } }
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 boolean apply(Annotation annotation) { return BindingUtil.isRuntimeAnnotation(annotation.getAnnotationBinding()); }
/** Locate method which matches the Java/Objective C setter name pattern. */ public static IMethodBinding findSetterMethod(String propertyName, ITypeBinding declaringClass) { return BindingUtil.findDeclaredMethod( declaringClass, "set" + NameTable.capitalize(propertyName)); }
// 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); }