use of com.sun.source.tree.ExpressionTree 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.source.tree.ExpressionTree 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.source.tree.ExpressionTree in project error-prone by google.
the class IsLoggableTagLength method matchMethodInvocation.
@Override
public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) {
if (!IS_LOGGABLE_CALL.matches(tree, state)) {
return NO_MATCH;
}
ExpressionTree tagArg = tree.getArguments().get(0);
// Check for constant value.
String tagConstantValue = ASTHelpers.constValue(tagArg, String.class);
if (tagConstantValue != null) {
return isValidTag(tagConstantValue) ? NO_MATCH : describeMatch(tagArg);
}
// Check for class literal simple name (e.g. MyClass.class.getSimpleName().
ExpressionTree tagExpr = tagArg;
// If the tag argument is a final field, retrieve the initializer.
if (kindIs(IDENTIFIER).matches(tagArg, state)) {
VariableTree declaredField = findEnclosingIdentifier((IdentifierTree) tagArg, state);
if (declaredField == null || !hasModifier(FINAL).matches(declaredField, state)) {
return NO_MATCH;
}
tagExpr = declaredField.getInitializer();
}
if (GET_SIMPLE_NAME_CALL.matches(tagExpr, state) && RECEIVER_IS_CLASS_LITERAL.matches((MethodInvocationTree) tagExpr, state)) {
String tagName = getSymbol(getReceiver(getReceiver(tagExpr))).getSimpleName().toString();
return isValidTag(tagName) ? NO_MATCH : describeMatch(tagArg);
}
return NO_MATCH;
}
use of com.sun.source.tree.ExpressionTree 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.source.tree.ExpressionTree in project error-prone by google.
the class IncompatibleArgumentType method reportAnyViolations.
private void reportAnyViolations(List<? extends ExpressionTree> arguments, List<RequiredType> requiredTypesAtCallSite, VisitorState state) {
Types types = state.getTypes();
for (int i = 0; i < requiredTypesAtCallSite.size(); i++) {
RequiredType requiredType = requiredTypesAtCallSite.get(i);
if (requiredType == null) {
continue;
}
ExpressionTree argument = arguments.get(i);
Type argType = ASTHelpers.getType(argument);
if (requiredType.type() != null && !types.isCastable(argType, types.erasure(ASTHelpers.getUpperBound(requiredType.type(), types)))) {
// Report a violation for this type
state.reportMatch(describeViolation(argument, argType, requiredType.type(), types));
}
}
}
Aggregations