public void testInheritedOuterMethod() { resolveSource( "Test", "class Test { class A { void foo() {} } class B extends A { " + "class Inner { void test() { foo(); } } } }"); TypeDeclaration aNode = (TypeDeclaration) nodesByType.get(ASTNode.TYPE_DECLARATION).get(1); TypeDeclaration bNode = (TypeDeclaration) nodesByType.get(ASTNode.TYPE_DECLARATION).get(2); TypeDeclaration innerNode = (TypeDeclaration) nodesByType.get(ASTNode.TYPE_DECLARATION).get(3); assertFalse(OuterReferenceResolver.needsOuterReference(aNode.resolveBinding())); assertFalse(OuterReferenceResolver.needsOuterReference(bNode.resolveBinding())); assertTrue(OuterReferenceResolver.needsOuterReference(innerNode.resolveBinding())); // B will need an outer reference to Test so it can initialize its // superclass A. List<IVariableBinding> bPath = OuterReferenceResolver.getPath(bNode); assertNotNull(bPath); assertEquals(1, bPath.size()); assertEquals(OuterReferenceResolver.OUTER_PARAMETER, bPath.get(0)); // foo() call will need to get to B's scope to call the inherited method. MethodInvocation fooCall = (MethodInvocation) nodesByType.get(ASTNode.METHOD_INVOCATION).get(0); List<IVariableBinding> fooPath = OuterReferenceResolver.getPath(fooCall); assertNotNull(fooPath); assertEquals(1, fooPath.size()); assertEquals("B", fooPath.get(0).getType().getName()); }
private List<IVariableBinding> getCapturedVariables(ClassInstanceCreation node) { ITypeBinding newType = node.getTypeBinding().getTypeDeclaration(); ITypeBinding owningType = TreeUtil.getOwningType(node).getTypeBinding().getTypeDeclaration(); // Test for the recursive construction of a local class. if (owningType.isEqualTo(newType)) { return OuterReferenceResolver.getInnerFields(newType); } return OuterReferenceResolver.getCapturedVars(newType); }
public void testOuterVarAccess() { resolveSource("Test", "class Test { int i; class Inner { void test() { i++; } } }"); TypeDeclaration innerNode = (TypeDeclaration) nodesByType.get(ASTNode.TYPE_DECLARATION).get(1); assertTrue(OuterReferenceResolver.needsOuterReference(innerNode.resolveBinding())); PostfixExpression increment = (PostfixExpression) nodesByType.get(ASTNode.POSTFIX_EXPRESSION).get(0); List<IVariableBinding> path = OuterReferenceResolver.getPath(increment.getOperand()); assertNotNull(path); assertEquals(2, path.size()); assertEquals("Test", path.get(0).getType().getName()); }
@Override public boolean visit(MethodInvocation node) { List<IVariableBinding> path = OuterReferenceResolver.getPath(node); if (path != null) { node.setExpression(Name.newName(fixPath(path))); } return true; }
public void testAnonymousClassInheritsLocalClassInStaticMethod() { resolveSource( "Test", "class Test { static void test() { class LocalClass {}; new LocalClass() {}; } }"); AnonymousClassDeclaration decl = (AnonymousClassDeclaration) nodesByType.get(ASTNode.ANONYMOUS_CLASS_DECLARATION).get(0); ITypeBinding type = decl.resolveBinding(); assertFalse(OuterReferenceResolver.needsOuterParam(type)); }
@Override public boolean visit(ThisExpression node) { List<IVariableBinding> path = OuterReferenceResolver.getPath(node); if (path != null) { node.replaceWith(Name.newName(fixPath(path))); } else { node.setQualifier(null); } return true; }
@Override public void endVisit(SuperMethodInvocation node) { List<IVariableBinding> path = OuterReferenceResolver.getPath(node); if (path != null) { // We substitute the qualifying type name with the outer variable name. node.setQualifier(Name.newName(fixPath(path))); } else { node.setQualifier(null); } }
@Override public boolean visit(SimpleName node) { List<IVariableBinding> path = OuterReferenceResolver.getPath(node); if (path != null) { if (path.size() == 1 && path.get(0).getConstantValue() != null) { IVariableBinding var = path.get(0); node.replaceWith(TreeUtil.newLiteral(var.getConstantValue())); } else { node.replaceWith(Name.newName(fixPath(path))); } } return true; }
public void testCapturedLocalVariable() { resolveSource( "Test", "class Test { void test(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(); assertFalse(OuterReferenceResolver.needsOuterReference(runnableBinding)); List<IVariableBinding> capturedVars = OuterReferenceResolver.getCapturedVars(runnableBinding); List<IVariableBinding> innerFields = OuterReferenceResolver.getInnerFields(runnableBinding); assertEquals(1, capturedVars.size()); assertEquals(1, innerFields.size()); assertEquals("i", capturedVars.get(0).getName()); assertEquals("val$i", innerFields.get(0).getName()); InfixExpression addition = (InfixExpression) nodesByType.get(ASTNode.INFIX_EXPRESSION).get(0); List<IVariableBinding> iPath = OuterReferenceResolver.getPath(addition.getLeftOperand()); assertNotNull(iPath); assertEquals(1, iPath.size()); assertEquals("val$i", iPath.get(0).getName()); }
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))); }
private void addOuterArg( ClassInstanceCreation node, GeneratedMethodBinding binding, ITypeBinding declaringClass) { ITypeBinding type = node.getTypeBinding().getTypeDeclaration(); if (!OuterReferenceResolver.needsOuterParam(type)) { return; } Expression outerExpr = node.getExpression(); List<IVariableBinding> path = OuterReferenceResolver.getPath(node); Expression outerArg = null; if (outerExpr != null) { node.setExpression(null); outerArg = outerExpr; } else if (path != null) { outerArg = Name.newName(fixPath(path)); } else { outerArg = new ThisExpression(declaringClass); } node.getArguments().add(0, outerArg); binding.addParameter(0, declaringClass); }
@Override protected void tearDown() throws Exception { nodesByType.clear(); OuterReferenceResolver.cleanup(); }
private void resolveSource(String name, String source) { CompilationUnit unit = compileType(name, source); OuterReferenceResolver.resolve(unit); findTypeDeclarations(unit); }