Skip to content

Commit

Permalink
Handle no-receiver expressions in ASTHelpers.getReceiver(ExpressionTree)
Browse files Browse the repository at this point in the history
e.g. invocations of
- instance methods on self
- static methods on own class
- statically-imported methods

RELNOTES: None.
-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=120995869
  • Loading branch information
awturner authored and cushon committed May 3, 2016
1 parent b3a2038 commit b720448
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 12 deletions.
16 changes: 15 additions & 1 deletion core/src/main/java/com/google/errorprone/util/ASTHelpers.java
Expand Up @@ -31,6 +31,7 @@
import com.sun.source.tree.BinaryTree;
import com.sun.source.tree.ClassTree;
import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.IdentifierTree;
import com.sun.source.tree.MemberSelectTree;
import com.sun.source.tree.MethodInvocationTree;
import com.sun.source.tree.MethodTree;
Expand Down Expand Up @@ -285,6 +286,9 @@ public static Type getReturnType(ExpressionTree expressionTree) {
* a.b.foo() ==> type of a.b
* a.bar().foo() ==> type of a.bar()
* this.foo() ==> type of this
* foo() ==> type of this
* TheClass.aStaticMethod() ==> TheClass
* aStaticMethod() ==> type of class in which method is defined
* }
* </pre>
*/
Expand Down Expand Up @@ -313,12 +317,22 @@ public static Type getReceiverType(ExpressionTree expressionTree) {
* a.bar().foo() ==> a.bar()
* a.b.c ==> a.b
* a.b().c ==> a.b()
* this.foo() ==> this
* foo() ==> null
* TheClass.aStaticMethod() ==> TheClass
* aStaticMethod() ==> null
* aStaticallyImportedMethod() ==> null
* }
* </pre>
*/
@Nullable
public static ExpressionTree getReceiver(ExpressionTree expressionTree) {
if (expressionTree instanceof MethodInvocationTree) {
return getReceiver(((MethodInvocationTree) expressionTree).getMethodSelect());
ExpressionTree methodSelect = ((MethodInvocationTree) expressionTree).getMethodSelect();
if (methodSelect instanceof IdentifierTree) {
return null;
}
return getReceiver(methodSelect);
} else if (expressionTree instanceof MemberSelectTree) {
return ((MemberSelectTree) expressionTree).getExpression();
} else {
Expand Down
59 changes: 48 additions & 11 deletions core/src/test/java/com/google/errorprone/util/ASTHelpersTest.java
Expand Up @@ -25,6 +25,7 @@
import com.google.errorprone.VisitorState;
import com.google.errorprone.matchers.CompilerBasedAbstractTest;
import com.google.errorprone.matchers.Matcher;
import com.google.errorprone.matchers.Matchers;
import com.google.errorprone.scanner.Scanner;

import com.sun.source.tree.AnnotationTree;
Expand Down Expand Up @@ -146,6 +147,7 @@ public Void visitLiteral(LiteralTree node, VisitorState state) {
@Test
public void testGetReceiver() {
writeFile("A.java",
"package p;",
"public class A { ",
" public B b;",
" public void foo() {}",
Expand All @@ -154,30 +156,65 @@ public void testGetReceiver() {
" }",
"}");
writeFile("B.java",
"package p;",
"public class B { ",
" public static void bar() {}",
" public void foo() {}",
"}");
writeFile("C.java",
writeFile(
"C.java",
"package p;",
"import static p.B.bar;",
"public class C { ",
" public static void foo() {}",
" public void test() {",
" A a = new A();",
" a.foo();", // a
" a.b.foo();", // a.b
" a.bar().foo();", // a.bar()
" this.test();", // this
" test();", // null
" C.foo();", // C
" foo();", // null
" C c = new C();",
" c.foo();", // c
" bar();", // null
" }",
"}");
assertCompiles(expressionStatementMatches("a.foo()", expressionHasReceiver("a")));
assertCompiles(expressionStatementMatches("a.b.foo()", expressionHasReceiver("a.b")));
assertCompiles(expressionStatementMatches("a.bar().foo()", expressionHasReceiver("a.bar()")));
assertCompiles(expressionStatementMatches("a.foo()", expressionHasReceiverAndType("a", "p.A")));
assertCompiles(
expressionStatementMatches("a.b.foo()", expressionHasReceiverAndType("a.b", "p.B")));
assertCompiles(
expressionStatementMatches(
"a.bar().foo()", expressionHasReceiverAndType("a.bar()", "p.B")));
assertCompiles(
expressionStatementMatches("this.test()", expressionHasReceiverAndType("this", "p.C")));
assertCompiles(expressionStatementMatches("test()", expressionHasReceiverAndType(null, "p.C")));
assertCompiles(expressionStatementMatches("C.foo()", expressionHasReceiverAndType("C", "p.C")));
assertCompiles(expressionStatementMatches("foo()", expressionHasReceiverAndType(null, "p.C")));
assertCompiles(expressionStatementMatches("c.foo()", expressionHasReceiverAndType("c", "p.C")));
assertCompiles(expressionStatementMatches("bar()", expressionHasReceiverAndType(null, "p.B")));
}

private Matcher<ExpressionTree> expressionHasReceiver(final String expectedReceiver) {
return new Matcher<ExpressionTree>() {
@Override
public boolean matches(ExpressionTree t, VisitorState state) {
return ASTHelpers.getReceiver(t).toString().equals(expectedReceiver);
}
};
private Matcher<ExpressionTree> expressionHasReceiverAndType(
final String expectedReceiver, final String expectedType) {
return Matchers.allOf(
new Matcher<ExpressionTree>() {
@Override
public boolean matches(ExpressionTree t, VisitorState state) {
ExpressionTree receiver = ASTHelpers.getReceiver(t);
return expectedReceiver != null
? receiver.toString().equals(expectedReceiver)
: receiver == null;
}
},
new Matcher<ExpressionTree>() {
@Override
public boolean matches(ExpressionTree t, VisitorState state) {
Type type = ASTHelpers.getReceiverType(t);
return state.getTypeFromString(expectedType).equals(type);
}
});
}

private Scanner expressionStatementMatches(final String expectedExpression,
Expand Down

0 comments on commit b720448

Please sign in to comment.