use of com.sun.source.tree.ExpressionTree in project error-prone by google.
the class ChainingConstructorIgnoresParameter method evaluateCallers.
private Description evaluateCallers(MethodSymbol symbol) {
List<VariableTree> paramTypes = paramTypesForMethod.get(symbol);
if (paramTypes == null) {
// We haven't seen the declaration yet. We'll evaluate the call when we do.
return NO_MATCH;
}
for (Caller caller : callersToEvaluate.removeAll(symbol)) {
VisitorState state = caller.state;
MethodInvocationTree invocation = caller.tree;
MethodTree callerConstructor = state.findEnclosing(MethodTree.class);
if (callerConstructor == null) {
// impossible, at least in compilable code?
continue;
}
Map<String, Type> availableParams = indexTypeByName(callerConstructor.getParameters());
/*
* TODO(cpovirk): Better handling of varargs: If the last parameter type is varargs and it is
* called as varargs (rather than by passing an array), then rewrite the parameter types to
* (p0, p1, ..., p[n-2], p[n-1] = element type of varargs parameter if an argument is
* supplied, p[n] = ditto, etc.). For now, we settle for not crashing in the face of a
* mismatch between the number of parameters declared and the number supplied.
*
* (Use MethodSymbol.isVarArgs.)
*/
for (int i = 0; i < paramTypes.size() && i < invocation.getArguments().size(); i++) {
VariableTree formalParam = paramTypes.get(i);
String formalParamName = formalParam.getName().toString();
Type formalParamType = getType(formalParam.getType());
Type availableParamType = availableParams.get(formalParamName);
ExpressionTree actualParam = invocation.getArguments().get(i);
if (/*
* The caller has no param of this type. (Or if it did, we couldn't determine the type.
* Does that ever happen?) If the param doesn't exist, the caller can't be failing to
* pass it.
*/
availableParamType == null || /*
* We couldn't determine the type of the formal parameter. (Does this ever happen?)
*/
formalParamType == null || /*
* The caller is passing the expected parameter (or "ImmutableList.copyOf(parameter),"
* "new File(parameter)," etc.).
*/
referencesIdentifierWithName(formalParamName, actualParam, state)) {
continue;
}
if (state.getTypes().isAssignable(availableParamType, formalParamType)) {
reportMatch(invocation, state, actualParam, formalParamName);
}
/*
* If formal parameter is of an incompatible type, the caller might in theory still intend
* to pass a dervied expression. For example, "Foo(String file)" might intend to call
* "Foo(File file)" by passing "new File(file)." If this comes up in practice, we could
* provide the dummy suggested fix "someExpression(formalParamName)." However, my research
* suggests that this will rarely if ever be what the user wants.
*/
}
}
// All matches are reported through reportMatch calls instead of return values.
return NO_MATCH;
}
use of com.sun.source.tree.ExpressionTree in project error-prone by google.
the class ComparisonContractViolated method matchMethod.
@Override
public Description matchMethod(MethodTree tree, VisitorState state) {
if (tree.getBody() == null) {
return Description.NO_MATCH;
}
// Test that the match is in a Comparable.compareTo or Comparator.compare method.
ClassTree declaringClass = ASTHelpers.findEnclosingNode(state.getPath(), ClassTree.class);
if (!COMPARABLE_CLASS_MATCHER.matches(declaringClass, state) && !COMPARATOR_CLASS_MATCHER.matches(declaringClass, state)) {
return Description.NO_MATCH;
}
if (!COMPARABLE_METHOD_MATCHER.matches(tree, state) && !COMPARATOR_METHOD_MATCHER.matches(tree, state)) {
return Description.NO_MATCH;
}
final Set<ComparisonResult> seenResults = EnumSet.noneOf(ComparisonResult.class);
final TreeVisitor<Void, VisitorState> visitReturnExpression = new SimpleTreeVisitor<Void, VisitorState>() {
@Override
protected Void defaultAction(Tree node, VisitorState state) {
seenResults.add(node.accept(CONSTANT_VISITOR, state));
return null;
}
@Override
public Void visitConditionalExpression(ConditionalExpressionTree node, VisitorState state) {
node.getTrueExpression().accept(this, state);
node.getFalseExpression().accept(this, state);
return null;
}
};
tree.getBody().accept(new TreeScanner<Void, VisitorState>() {
@Override
public Void visitReturn(ReturnTree node, VisitorState state) {
return node.getExpression().accept(visitReturnExpression, state);
}
}, state);
if (seenResults.isEmpty() || seenResults.contains(ComparisonResult.NONCONSTANT)) {
return Description.NO_MATCH;
}
if (!seenResults.contains(ComparisonResult.ZERO)) {
if (tree.getBody().getStatements().size() == 1 && tree.getBody().getStatements().get(0).getKind() == Kind.RETURN) {
ReturnTree returnTree = (ReturnTree) tree.getBody().getStatements().get(0);
if (returnTree.getExpression().getKind() == Kind.CONDITIONAL_EXPRESSION) {
ConditionalExpressionTree condTree = (ConditionalExpressionTree) returnTree.getExpression();
ExpressionTree conditionExpr = condTree.getCondition();
while (conditionExpr instanceof ParenthesizedTree) {
conditionExpr = ((ParenthesizedTree) conditionExpr).getExpression();
}
if (!(conditionExpr instanceof BinaryTree)) {
return describeMatch(tree);
}
ComparisonResult trueConst = condTree.getTrueExpression().accept(CONSTANT_VISITOR, state);
ComparisonResult falseConst = condTree.getFalseExpression().accept(CONSTANT_VISITOR, state);
boolean trueFirst;
if (trueConst == ComparisonResult.NEGATIVE_CONSTANT && falseConst == ComparisonResult.POSITIVE_CONSTANT) {
trueFirst = true;
} else if (trueConst == ComparisonResult.POSITIVE_CONSTANT && falseConst == ComparisonResult.NEGATIVE_CONSTANT) {
trueFirst = false;
} else {
return describeMatch(tree);
}
switch(conditionExpr.getKind()) {
case LESS_THAN:
case LESS_THAN_EQUAL:
break;
case GREATER_THAN:
case GREATER_THAN_EQUAL:
trueFirst = !trueFirst;
break;
default:
return describeMatch(tree);
}
BinaryTree binaryExpr = (BinaryTree) conditionExpr;
Type ty = ASTHelpers.getType(binaryExpr.getLeftOperand());
Types types = Types.instance(state.context);
Symtab symtab = Symtab.instance(state.context);
ExpressionTree first = trueFirst ? binaryExpr.getLeftOperand() : binaryExpr.getRightOperand();
ExpressionTree second = trueFirst ? binaryExpr.getRightOperand() : binaryExpr.getLeftOperand();
String compareType;
if (types.isSameType(ty, symtab.intType)) {
compareType = "Integer";
} else if (types.isSameType(ty, symtab.longType)) {
compareType = "Long";
} else {
return describeMatch(tree);
}
return describeMatch(condTree, SuggestedFix.replace(condTree, String.format("%s.compare(%s, %s)", compareType, state.getSourceForNode(first), state.getSourceForNode(second))));
}
}
return describeMatch(tree);
}
if (COMPARATOR_METHOD_MATCHER.matches(tree, state) && (seenResults.contains(ComparisonResult.NEGATIVE_CONSTANT) != seenResults.contains(ComparisonResult.POSITIVE_CONSTANT))) {
// See e.g. com.google.common.collect.Cut.BelowAll.
return describeMatch(tree);
} else {
return Description.NO_MATCH;
}
}
use of com.sun.source.tree.ExpressionTree in project error-prone by google.
the class ComparisonOutOfRange method describe.
/**
* Suggested fixes are as follows. For the byte case, convert the literal to its byte
* representation. For example, "255" becomes "-1. For the character case, replace the
* comparison with "true"/"false" since it's not clear what was intended and that is
* semantically equivalent.
*
* TODO(eaftan): Suggested fixes don't handle side-effecting expressions, such as
* (d = reader.read()) == -1. Maybe add special case handling for assignments.
*/
public Description describe(BinaryTree tree, VisitorState state) {
List<ExpressionTree> binaryTreeMatches = ASTHelpers.matchBinaryTree(tree, Arrays.asList(Matchers.<ExpressionTree>isInstance(JCLiteral.class), Matchers.<ExpressionTree>anything()), state);
if (binaryTreeMatches == null) {
throw new IllegalStateException("Expected one of the operands to be a literal");
}
JCLiteral literal = (JCLiteral) binaryTreeMatches.get(0);
JCTree nonLiteralOperand = (JCTree) binaryTreeMatches.get(1);
boolean byteMatch = state.getTypes().isSameType(nonLiteralOperand.type, state.getSymtab().byteType);
boolean willEvaluateTo = (tree.getKind() != Kind.EQUAL_TO);
Fix fix;
String customDiagnosticMessage;
if (byteMatch) {
String replacement = Byte.toString(((Number) literal.getValue()).byteValue());
// Correct for poor javac 6 literal parsing.
int actualStart = ASTHelpers.getActualStartPosition(literal, state.getSourceCode());
if (actualStart != literal.getStartPosition()) {
fix = SuggestedFix.replace(literal, replacement, actualStart - literal.getStartPosition(), 0);
} else {
fix = SuggestedFix.replace(literal, replacement);
}
customDiagnosticMessage = String.format(MESSAGE_TEMPLATE, "byte", (int) Byte.MIN_VALUE, (int) Byte.MAX_VALUE, literal.toString(), Boolean.toString(willEvaluateTo));
} else {
fix = SuggestedFix.replace(tree, Boolean.toString(willEvaluateTo));
customDiagnosticMessage = String.format(MESSAGE_TEMPLATE, "char", (int) Character.MIN_VALUE, (int) Character.MAX_VALUE, literal.toString(), Boolean.toString(willEvaluateTo));
}
return buildDescription(tree).addFix(fix).setMessage(customDiagnosticMessage).build();
}
use of com.sun.source.tree.ExpressionTree in project error-prone by google.
the class ConstantOverflow method longFix.
/**
* If the left operand of an int binary expression is an int literal, suggest making it a long.
*/
private Fix longFix(ExpressionTree expr, VisitorState state) {
BinaryTree binExpr = null;
while (expr instanceof BinaryTree) {
binExpr = (BinaryTree) expr;
expr = binExpr.getLeftOperand();
}
if (!(expr instanceof LiteralTree) || expr.getKind() != Kind.INT_LITERAL) {
return null;
}
Type intType = state.getSymtab().intType;
if (!isSameType(getType(binExpr), intType, state)) {
return null;
}
SuggestedFix.Builder fix = SuggestedFix.builder().postfixWith(expr, "L");
Tree parent = state.getPath().getParentPath().getLeaf();
if (parent instanceof VariableTree && isSameType(getType(parent), intType, state)) {
fix.replace(((VariableTree) parent).getType(), "long");
}
return fix.build();
}
use of com.sun.source.tree.ExpressionTree in project error-prone by google.
the class DefaultCharset method handleFileWriter.
private Description handleFileWriter(NewClassTree tree, VisitorState state) {
Iterator<? extends ExpressionTree> it = tree.getArguments().iterator();
Tree fileArg = it.next();
Tree appendMode = it.hasNext() ? it.next() : null;
Tree parent = state.getPath().getParentPath().getLeaf();
Tree toReplace = BUFFERED_WRITER.matches(parent, state) ? parent : tree;
Description.Builder description = buildDescription(tree);
boolean useGuava = shouldUseGuava(state);
for (CharsetFix charset : CharsetFix.values()) {
if (appendMode == null && useGuava) {
description.addFix(guavaFileWriterFix(state, fileArg, toReplace, charset));
} else {
description.addFix(nioFileWriterFix(state, appendMode, fileArg, toReplace, charset, useGuava));
}
}
return description.build();
}
Aggregations