/** * 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)); } }
@Override public void endVisit(TypeDeclaration node) { List<Statement> adjustments = getFieldAdjustments(node); if (adjustments.isEmpty()) { return; } ITypeBinding type = node.getTypeBinding(); ITypeBinding voidType = typeEnv.resolveJavaType("void"); int modifiers = Modifier.PUBLIC | BindingUtil.ACC_SYNTHETIC; IOSMethodBinding methodBinding = IOSMethodBinding.newMethod(JAVA_CLONE_METHOD, modifiers, voidType, type); MethodDeclaration declaration = new MethodDeclaration(methodBinding); node.getBodyDeclarations().add(declaration); Block body = new Block(); declaration.setBody(body); List<Statement> statements = body.getStatements(); ITypeBinding nsObjectType = typeEnv.resolveIOSType("NSObject"); IOSMethodBinding cloneMethod = IOSMethodBinding.newMethod(JAVA_CLONE_METHOD, Modifier.PUBLIC, voidType, nsObjectType); SuperMethodInvocation superCall = new SuperMethodInvocation(cloneMethod); statements.add(new ExpressionStatement(superCall)); statements.addAll(adjustments); }
@Override public boolean visit(MethodDeclaration node) { IMethodBinding binding = node.getMethodBinding(); if (binding.isConstructor()) { List<SingleVariableDeclaration> params = node.getParameters(); if (params.size() > 0) { IVariableBinding firstParam = params.get(0).getVariableBinding(); if (firstParam.getName().equals("outer$")) { outerParam = firstParam; } } } return true; }
public void testVariableDeclarationsInSwitchStatement2() throws IOException { CompilationUnit unit = translateType( "A", "public class A { public void doSomething(int i) { switch (i) { " + "case 1: int j = i * 2; log(j); break; " + "case 2: log(i); break; " + "case 3: log(i); int k = i, l = 42; break; }}" + "private void log(int i) {}}"); TypeDeclaration testType = (TypeDeclaration) unit.getTypes().get(0); MethodDeclaration method = TreeUtil.getMethodDeclarationsList(testType).get(0); List<Statement> stmts = method.getBody().getStatements(); assertEquals(1, stmts.size()); Block block = (Block) stmts.get(0); stmts = block.getStatements(); assertEquals(3, stmts.size()); assertTrue(stmts.get(0) instanceof VariableDeclarationStatement); assertTrue(stmts.get(1) instanceof VariableDeclarationStatement); assertTrue(stmts.get(2) instanceof SwitchStatement); }
/** * Verify that interface methods declaring methods implemented by super-class have a forwarding * method. */ public void testInterfaceOfSuperclassMethodInAnonymousInner() { String source = "interface Equateable { boolean equals(Object o); }" + "public class Test { public void foo() { Equateable e = new Equateable() { }; } } "; CompilationUnit unit = translateType("Test", source); assertEquals(3, unit.getTypes().size()); TypeDeclaration innerType = (TypeDeclaration) unit.getTypes().get(2); assertEquals("$1", innerType.getName().toString()); List<MethodDeclaration> methods = TreeUtil.getMethodDeclarationsList(innerType); assertEquals(2, methods.size()); // isEqual, init MethodDeclaration equalsMethod = methods.get(0); assertEquals("isEqual", equalsMethod.getName().getIdentifier()); assertEquals(1, equalsMethod.getParameters().size()); assertTrue(equalsMethod.getParameters().get(0) instanceof SingleVariableDeclaration); List<Statement> stmts = equalsMethod.getBody().getStatements(); assertEquals(1, stmts.size()); Statement stmt = stmts.get(0); assertTrue(stmt instanceof ReturnStatement); assertTrue(((ReturnStatement) stmt).getExpression() instanceof SuperMethodInvocation); }
/** List has a toArray() method that uses array types. */ public void testAbstractMethodsAddedWithArrayType() { String source = "import java.util.List; public abstract class Test implements List<Object> { " + "public boolean isEmpty() { 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(26, 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("isEmpty")) { 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)); ITypeBinding returnType = m.getReturnType().getTypeBinding(); if (name.equals("toArray")) { assertEquals("IOSObjectArray", returnType.getName()); if (!m.getParameters().isEmpty()) { assertEquals(1, m.getParameters().size()); SingleVariableDeclaration param = m.getParameters().get(0); IVariableBinding paramBinding = param.getVariableBinding(); assertTrue(paramBinding.getType().isArray()); } } } } }
/** 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); } } } }
@Override public boolean visit(MethodDeclaration node) { currentMethod = node.getMethodBinding(); count = 1; return true; }