Skip to content

Commit

Permalink
Fix for #956: detect trait bridge method using annotation
Browse files Browse the repository at this point in the history
  • Loading branch information
eric-milles committed Sep 18, 2019
1 parent c0d4c34 commit a68669a
Show file tree
Hide file tree
Showing 2 changed files with 193 additions and 33 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,125 @@ private void assertExprType(String source, String target, String type) {
//--------------------------------------------------------------------------

@Test
public void testPrivateField() {
public void testPublicMethod() {
String source =
"trait Auditable {\n" +
" boolean check() {\n" +
" true\n" +
" }\n" +
" boolean audit() {\n" +
" if (check()) {\n" +
" ;\n" +
" }\n" +
" }\n" +
"}\n";

assertDeclType(source, "check", "Auditable");
assertExprType(source, "check", "java.lang.Boolean");
}

@Test
public void testPublicMethod2() {
String contents =
"trait A {\n" +
" void method() {}\n" +
"}\n" +
"trait B {\n" +
" void method() {}\n" +
"}\n" +
"class C implements A, B {\n" +
" void something() {\n" +
" method()\n" +
" }\n" +
"}";

assertDeclType(contents, "method", "A");
assertExprType(contents, "method", "java.lang.Void");
}

@Test
public void testPublicMethod3() {
String contents =
"trait A {\n" +
" void method() {}\n" +
"}\n" +
"trait B {\n" +
" void method() {}\n" +
"}\n" +
"class C implements A, B {\n" +
" void something() {\n" +
" A.super.method()\n" +
" }\n" +
"}";

assertDeclType(contents, "method", "A$Trait$Helper");
assertExprType(contents, "method", "java.lang.Void");
}

@Test
public void testPublicMethod4() {
String contents =
"trait A {\n" +
" void method() {}\n" +
"}\n" +
"trait B {\n" +
" void method() {}\n" +
"}\n" +
"class C implements A, B {\n" +
" void something() {\n" +
" B.super.method()\n" +
" }\n" +
"}";

assertDeclType(contents, "method", "B$Trait$Helper");
assertExprType(contents, "method", "java.lang.Void");
}

@Test // https://issues.apache.org/jira/browse/GROOVY-8272
public void testPublicStaticSuperMethod() {
String source =
"trait Checkable {\n" +
" static boolean check() {\n" +
" true\n" +
" }\n" +
"}\n" +
"trait Auditable extends Checkable {\n" +
" boolean audit() {\n" +
" if (check()) {\n" +
" ;\n" +
" }\n" +
" }\n" +
"}\n";

assertDeclType(source, "check", "Checkable");
assertExprType(source, "check", "java.lang.Boolean");
}

@Test
public void testPublicStaticSuperMethod2() {
String source =
"trait Checkable {\n" +
" static boolean check() {\n" +
" true\n" +
" }\n" +
"}\n" +
"trait Auditable extends Checkable {\n" +
" boolean audit() {\n" +
" if (Checkable.super.check()) {\n" +
" ;\n" +
" }\n" +
" }\n" +
"}\n";

assertDeclType(source, "check", "Checkable");
assertExprType(source, "check", "java.lang.Boolean");
}

@Test
public void testPublicField() {
String source =
"trait T {\n" +
" private String field\n" +
" public String field\n" +
" void m() {\n" +
" field\n" +
" }\n" +
Expand All @@ -46,10 +161,26 @@ public void testPrivateField() {
}

@Test
public void testPrivateStaticField() {
public void testPublicField2() {
String source =
"trait T {\n" +
" private static String field\n" +
" public String field\n" +
"}\n" +
"class C implements T {\n" +
" void m() {\n" +
" T__field\n" +
" }\n" +
"}";

assertDeclType(source, "T__field", "T");
assertExprType(source, "T__field", "java.lang.String");
}

@Test
public void testPublicStaticField() {
String source =
"trait T {\n" +
" public static String field\n" +
" void m() {\n" +
" field\n" +
" }\n" +
Expand All @@ -60,10 +191,10 @@ public void testPrivateStaticField() {
}

@Test
public void testPrivateStaticFinalField() {
public void testPublicStaticFinalField() {
String source =
"trait T {\n" +
" private static final String field = 'value'\n" +
" public static final String field = 'value'\n" +
" void m() {\n" +
" field\n" +
" }\n" +
Expand All @@ -73,6 +204,8 @@ public void testPrivateStaticFinalField() {
assertExprType(source, "field", "java.lang.String");
}

//

@Test
public void testPrivateMethod() {
String source =
Expand Down Expand Up @@ -105,6 +238,7 @@ public void testPrivateMethod2() {
" method()\n" +
" }\n" +
"}";

assertDeclType(contents, "method", "A");
assertExprType(contents, "method", "java.lang.Void");
}
Expand All @@ -123,6 +257,7 @@ public void testPrivateMethod3() {
" A.super.method()\n" +
" }\n" +
"}";

assertDeclType(contents, "method", "A$Trait$Helper");
assertExprType(contents, "method", "java.lang.Void");
}
Expand All @@ -141,6 +276,7 @@ public void testPrivateMethod4() {
" B.super.method()\n" +
" }\n" +
"}";

assertDeclType(contents, "method", "B$Trait$Helper");
assertExprType(contents, "method", "java.lang.Void");
}
Expand All @@ -163,43 +299,61 @@ public void testPrivateStaticMethod() {
assertExprType(source, "check", "java.lang.Boolean");
}

@Test // https://issues.apache.org/jira/browse/GROOVY-8272
public void testPublicStaticSuperMethod() {
@Test
public void testPrivateField() {
String source =
"trait Checkable {\n" +
" static boolean check() {\n" +
" true\n" +
"trait T {\n" +
" private String field\n" +
" void m() {\n" +
" field\n" +
" }\n" +
"}\n";

assertDeclType(source, "field", "T");
assertExprType(source, "field", "java.lang.String");
}

@Test
public void testPrivateField2() {
String source =
"trait T {\n" +
" private String field\n" +
"}\n" +
"trait Auditable extends Checkable {\n" +
" boolean audit() {\n" +
" if (check()) {\n" +
" ;\n" +
" }\n" +
"class C implements T {\n" +
" void m() {\n" +
" T__field\n" +
" }\n" +
"}\n";
"}";

assertDeclType(source, "check", "Checkable");
assertExprType(source, "check", "java.lang.Boolean");
assertDeclType(source, "T__field", "T");
assertExprType(source, "T__field", "java.lang.String");
}

@Test
public void testPublicStaticSuperMethod2() {
public void testPrivateStaticField() {
String source =
"trait Checkable {\n" +
" static boolean check() {\n" +
" true\n" +
"trait T {\n" +
" private static String field\n" +
" void m() {\n" +
" field\n" +
" }\n" +
"}\n" +
"trait Auditable extends Checkable {\n" +
" boolean audit() {\n" +
" if (Checkable.super.check()) {\n" +
" ;\n" +
" }\n" +
"}\n";

assertDeclType(source, "field", "T");
assertExprType(source, "field", "java.lang.String");
}

@Test
public void testPrivateStaticFinalField() {
String source =
"trait T {\n" +
" private static final String field = 'value'\n" +
" void m() {\n" +
" field\n" +
" }\n" +
"}\n";

assertDeclType(source, "check", "Checkable");
assertExprType(source, "check", "java.lang.Boolean");
assertDeclType(source, "field", "T");
assertExprType(source, "field", "java.lang.String");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@

import org.codehaus.groovy.ast.ASTNode;
import org.codehaus.groovy.ast.AnnotatedNode;
import org.codehaus.groovy.ast.AnnotationNode;
import org.codehaus.groovy.ast.ClassHelper;
import org.codehaus.groovy.ast.ClassNode;
import org.codehaus.groovy.ast.ConstructorNode;
Expand Down Expand Up @@ -59,6 +60,7 @@
import org.codehaus.groovy.ast.expr.TupleExpression;
import org.codehaus.groovy.ast.expr.VariableExpression;
import org.codehaus.groovy.classgen.asm.OptimizingStatementWriter.StatementMeta;
import org.codehaus.groovy.transform.trait.Traits;
import org.codehaus.jdt.groovy.model.GroovyCompilationUnit;
import org.eclipse.jdt.core.Flags;
import org.eclipse.jdt.groovy.core.util.GroovyUtils;
Expand Down Expand Up @@ -676,8 +678,8 @@ protected MethodNode findMethodDeclaration(final String name, final ClassNode de
List<MethodNode> candidates = getMethods(name, type);
if (!candidates.isEmpty()) {
innerCandidate = findMethodDeclaration0(candidates, argumentTypes, isStaticExpression);
if (innerCandidate.getOriginal() == null) {
innerCandidate = null; // trait bridge
if (isTraitBridge(innerCandidate)) {
continue;
}
if (outerCandidate == null) {
outerCandidate = innerCandidate;
Expand Down Expand Up @@ -969,6 +971,10 @@ protected static boolean isSynthetic(final MethodNode method) {
return method.isSynthetic() || method.getDeclaringClass().equals(VariableScope.CLOSURE_CLASS_NODE);
}

protected static boolean isTraitBridge(final MethodNode method) {
return method.getAnnotations().stream().map(AnnotationNode::getClassNode).anyMatch(Traits.TRAITBRIDGE_CLASSNODE::equals);
}

/**
* Supplements {@link #isTypeCompatible} by supporting unequal lengths and
* tagging Closure -> SAM type as an inexact match.
Expand Down

0 comments on commit a68669a

Please sign in to comment.