use of com.sun.tools.javac.tree.JCTree.JCFieldAccess in project error-prone by google.
the class ASTHelpers method sameVariable.
/**
* Determines whether two expressions refer to the same variable. Note that returning false
* doesn't necessarily mean the expressions do *not* refer to the same field. We don't attempt
* to do any complex analysis here, just catch the obvious cases.
*/
public static boolean sameVariable(ExpressionTree expr1, ExpressionTree expr2) {
// Throw up our hands if we're not comparing identifiers and/or field accesses.
if ((expr1.getKind() != Kind.IDENTIFIER && expr1.getKind() != Kind.MEMBER_SELECT) || (expr2.getKind() != Kind.IDENTIFIER && expr2.getKind() != Kind.MEMBER_SELECT)) {
return false;
}
Symbol sym1 = getSymbol(expr1);
Symbol sym2 = getSymbol(expr2);
if (sym1 == null) {
throw new IllegalStateException("Couldn't get symbol for " + expr1);
} else if (sym2 == null) {
throw new IllegalStateException("Couldn't get symbol for " + expr2);
}
if (expr1.getKind() == Kind.IDENTIFIER && expr2.getKind() == Kind.IDENTIFIER) {
// foo == foo?
return sym1.equals(sym2);
} else if (expr1.getKind() == Kind.MEMBER_SELECT && expr2.getKind() == Kind.MEMBER_SELECT) {
// foo.baz.bar == foo.baz.bar?
return sym1.equals(sym2) && sameVariable(((JCFieldAccess) expr1).selected, ((JCFieldAccess) expr2).selected);
} else {
// this.foo == foo?
ExpressionTree selected = null;
if (expr1.getKind() == Kind.IDENTIFIER) {
selected = ((JCFieldAccess) expr2).selected;
} else {
selected = ((JCFieldAccess) expr1).selected;
}
// TODO(eaftan): really shouldn't be relying on .toString()
return selected.toString().equals("this") && sym1.equals(sym2);
}
}
use of com.sun.tools.javac.tree.JCTree.JCFieldAccess in project error-prone by google.
the class Matchers method receiverSameAsArgument.
/**
* Matches when the receiver of an instance method is the same reference as a particular argument to the method.
* For example, receiverSameAsArgument(1) would match {@code obj.method("", obj)}
*
* @param argNum The number of the argument to compare against (zero-based.
*/
public static Matcher<? super MethodInvocationTree> receiverSameAsArgument(final int argNum) {
return new Matcher<MethodInvocationTree>() {
@Override
public boolean matches(MethodInvocationTree t, VisitorState state) {
List<? extends ExpressionTree> args = t.getArguments();
if (args.size() <= argNum) {
return false;
}
ExpressionTree arg = args.get(argNum);
JCExpression methodSelect = (JCExpression) t.getMethodSelect();
if (methodSelect instanceof JCFieldAccess) {
JCFieldAccess fieldAccess = (JCFieldAccess) methodSelect;
return ASTHelpers.sameVariable(fieldAccess.getExpression(), arg);
} else if (methodSelect instanceof JCIdent) {
// A bare method call: "equals(foo)". Receiver is implicitly "this".
return "this".equals(arg.toString());
}
return false;
}
};
}
use of com.sun.tools.javac.tree.JCTree.JCFieldAccess in project error-prone by google.
the class SelfAssignment method describeForAssignment.
/**
* We expect that the lhs is a field and the rhs is an identifier, specifically
* a parameter to the method. We base our suggested fixes on this expectation.
*
* Case 1: If lhs is a field and rhs is an identifier, find a method parameter
* of the same type and similar name and suggest it as the rhs. (Guess that they
* have misspelled the identifier.)
*
* Case 2: If lhs is a field and rhs is not an identifier, find a method parameter
* of the same type and similar name and suggest it as the rhs.
*
* Case 3: If lhs is not a field and rhs is an identifier, find a class field
* of the same type and similar name and suggest it as the lhs.
*
* Case 4: Otherwise suggest deleting the assignment.
*/
public Description describeForAssignment(AssignmentTree assignmentTree, VisitorState state) {
// the statement that is the parent of the self-assignment expression
Tree parent = state.getPath().getParentPath().getLeaf();
// default fix is to delete assignment
Fix fix = SuggestedFix.delete(parent);
ExpressionTree lhs = assignmentTree.getVariable();
ExpressionTree rhs = assignmentTree.getExpression();
// if this is a method invocation, they must be calling checkNotNull()
if (assignmentTree.getExpression().getKind() == METHOD_INVOCATION) {
// change the default fix to be "checkNotNull(x)" instead of "x = checkNotNull(x)"
fix = SuggestedFix.replace(assignmentTree, rhs.toString());
// new rhs is first argument to checkNotNull()
rhs = stripCheckNotNull(rhs, state);
}
if (lhs.getKind() == MEMBER_SELECT) {
// rhs should be either identifier or field access
assert (rhs.getKind() == IDENTIFIER || rhs.getKind() == MEMBER_SELECT);
// get current name of rhs
String rhsName = null;
if (rhs.getKind() == IDENTIFIER) {
rhsName = ((JCIdent) rhs).name.toString();
} else if (rhs.getKind() == MEMBER_SELECT) {
rhsName = ((JCFieldAccess) rhs).name.toString();
}
// find method parameters of the same type
Type type = ((JCFieldAccess) lhs).type;
TreePath path = state.getPath();
while (path != null && path.getLeaf().getKind() != METHOD) {
path = path.getParentPath();
}
JCMethodDecl method = (JCMethodDecl) path.getLeaf();
int minEditDistance = Integer.MAX_VALUE;
String replacement = null;
for (JCVariableDecl var : method.params) {
if (var.type == type) {
int editDistance = EditDistance.getEditDistance(rhsName, var.name.toString());
if (editDistance < minEditDistance) {
// pick one with minimum edit distance
minEditDistance = editDistance;
replacement = var.name.toString();
}
}
}
if (replacement != null) {
// suggest replacing rhs with the parameter
fix = SuggestedFix.replace(rhs, replacement);
}
} else if (rhs.getKind() == IDENTIFIER) {
// lhs should be identifier
assert (lhs.getKind() == IDENTIFIER);
// get current name of lhs
String lhsName = ((JCIdent) rhs).name.toString();
// find class instance fields of the same type
Type type = ((JCIdent) lhs).type;
TreePath path = state.getPath();
while (path != null && !(path.getLeaf() instanceof JCClassDecl)) {
path = path.getParentPath();
}
if (path == null) {
throw new IllegalStateException("Expected to find an enclosing class declaration");
}
JCClassDecl klass = (JCClassDecl) path.getLeaf();
int minEditDistance = Integer.MAX_VALUE;
String replacement = null;
for (JCTree member : klass.getMembers()) {
if (member.getKind() == VARIABLE) {
JCVariableDecl var = (JCVariableDecl) member;
if (!Flags.isStatic(var.sym) && var.type == type) {
int editDistance = EditDistance.getEditDistance(lhsName, var.name.toString());
if (editDistance < minEditDistance) {
// pick one with minimum edit distance
minEditDistance = editDistance;
replacement = var.name.toString();
}
}
}
}
if (replacement != null) {
// suggest replacing lhs with the field
fix = SuggestedFix.replace(lhs, "this." + replacement);
}
}
return describeMatch(assignmentTree, fix);
}
use of com.sun.tools.javac.tree.JCTree.JCFieldAccess in project error-prone by google.
the class ProtoFieldNullComparison method getMethodName.
private static String getMethodName(ExpressionTree tree) {
MethodInvocationTree method = (MethodInvocationTree) tree;
ExpressionTree expressionTree = method.getMethodSelect();
JCFieldAccess access = (JCFieldAccess) expressionTree;
return access.sym.getQualifiedName().toString();
}
use of com.sun.tools.javac.tree.JCTree.JCFieldAccess in project error-prone by google.
the class ProtoFieldPreconditionsCheckNotNull method isGetMethodInvocation.
private static boolean isGetMethodInvocation(ExpressionTree tree, VisitorState state) {
if (tree.getKind() == Tree.Kind.METHOD_INVOCATION) {
MethodInvocationTree method = (MethodInvocationTree) tree;
if (!method.getArguments().isEmpty()) {
return false;
}
if (returnsListMatcher.matches(method, state)) {
return false;
}
ExpressionTree expressionTree = method.getMethodSelect();
if (expressionTree instanceof JCFieldAccess) {
JCFieldAccess access = (JCFieldAccess) expressionTree;
String methodName = access.sym.getQualifiedName().toString();
return isFieldGetMethod(methodName);
}
return true;
}
return false;
}
Aggregations