use of com.sun.source.tree.LiteralTree in project error-prone by google.
the class PreconditionsInvalidPlaceholder method describe.
public Description describe(MethodInvocationTree t, VisitorState state) {
LiteralTree formatTree = (LiteralTree) t.getArguments().get(1);
String fixedFormatString = BAD_PLACEHOLDER_REGEX.matcher(state.getSourceForNode((JCTree) formatTree)).replaceAll("%s");
if (expectedArguments(fixedFormatString) == t.getArguments().size() - 2) {
return describeMatch(formatTree, SuggestedFix.replace(formatTree, fixedFormatString));
} else {
int missing = t.getArguments().size() - 2 - expectedArguments(fixedFormatString);
StringBuilder builder = new StringBuilder(fixedFormatString);
builder.deleteCharAt(builder.length() - 1);
builder.append(" [%s");
for (int i = 1; i < missing; i++) {
builder.append(", %s");
}
builder.append("]\"");
return describeMatch(t, SuggestedFix.replace(formatTree, builder.toString()));
}
}
use of com.sun.source.tree.LiteralTree in project checker-framework by typetools.
the class FlowExpressions method internalReprOf.
/**
* We ignore operations such as widening and narrowing when computing the internal
* representation.
*
* @return the internal representation (as {@link Receiver}) of any {@link ExpressionTree}.
* Might contain {@link Unknown}.
*/
public static Receiver internalReprOf(AnnotationProvider provider, ExpressionTree receiverTree, boolean allowNonDeterministic) {
Receiver receiver;
switch(receiverTree.getKind()) {
case ARRAY_ACCESS:
ArrayAccessTree a = (ArrayAccessTree) receiverTree;
Receiver arrayAccessExpression = internalReprOf(provider, a.getExpression());
Receiver index = internalReprOf(provider, a.getIndex());
receiver = new ArrayAccess(TreeUtils.typeOf(a), arrayAccessExpression, index);
break;
case BOOLEAN_LITERAL:
case CHAR_LITERAL:
case DOUBLE_LITERAL:
case FLOAT_LITERAL:
case INT_LITERAL:
case LONG_LITERAL:
case NULL_LITERAL:
case STRING_LITERAL:
LiteralTree vn = (LiteralTree) receiverTree;
receiver = new ValueLiteral(TreeUtils.typeOf(receiverTree), vn.getValue());
break;
case NEW_ARRAY:
NewArrayTree newArrayTree = (NewArrayTree) receiverTree;
List<Receiver> dimensions = new ArrayList<>();
if (newArrayTree.getDimensions() != null) {
for (ExpressionTree dimension : newArrayTree.getDimensions()) {
dimensions.add(internalReprOf(provider, dimension, allowNonDeterministic));
}
}
List<Receiver> initializers = new ArrayList<>();
if (newArrayTree.getInitializers() != null) {
for (ExpressionTree initializer : newArrayTree.getInitializers()) {
initializers.add(internalReprOf(provider, initializer, allowNonDeterministic));
}
}
receiver = new ArrayCreation(TreeUtils.typeOf(receiverTree), dimensions, initializers);
break;
case METHOD_INVOCATION:
MethodInvocationTree mn = (MethodInvocationTree) receiverTree;
ExecutableElement invokedMethod = TreeUtils.elementFromUse(mn);
if (PurityUtils.isDeterministic(provider, invokedMethod) || allowNonDeterministic) {
List<Receiver> parameters = new ArrayList<>();
for (ExpressionTree p : mn.getArguments()) {
parameters.add(internalReprOf(provider, p));
}
Receiver methodReceiver;
if (ElementUtils.isStatic(invokedMethod)) {
methodReceiver = new ClassName(TreeUtils.typeOf(mn.getMethodSelect()));
} else {
ExpressionTree methodReceiverTree = TreeUtils.getReceiverTree(mn);
if (methodReceiverTree != null) {
methodReceiver = internalReprOf(provider, methodReceiverTree);
} else {
methodReceiver = internalReprOfImplicitReceiver(invokedMethod);
}
}
TypeMirror type = TreeUtils.typeOf(mn);
receiver = new MethodCall(type, invokedMethod, methodReceiver, parameters);
} else {
receiver = null;
}
break;
case MEMBER_SELECT:
receiver = internalReprOfMemberSelect(provider, (MemberSelectTree) receiverTree);
break;
case IDENTIFIER:
IdentifierTree identifierTree = (IdentifierTree) receiverTree;
TypeMirror typeOfId = TreeUtils.typeOf(identifierTree);
if (identifierTree.getName().contentEquals("this") || identifierTree.getName().contentEquals("super")) {
receiver = new ThisReference(typeOfId);
break;
}
Element ele = TreeUtils.elementFromUse(identifierTree);
switch(ele.getKind()) {
case LOCAL_VARIABLE:
case RESOURCE_VARIABLE:
case EXCEPTION_PARAMETER:
case PARAMETER:
receiver = new LocalVariable(ele);
break;
case FIELD:
// Implicit access expression, such as "this" or a class name
Receiver fieldAccessExpression;
TypeMirror enclosingType = ElementUtils.enclosingClass(ele).asType();
if (ElementUtils.isStatic(ele)) {
fieldAccessExpression = new ClassName(enclosingType);
} else {
fieldAccessExpression = new ThisReference(enclosingType);
}
receiver = new FieldAccess(fieldAccessExpression, typeOfId, (VariableElement) ele);
break;
case CLASS:
case ENUM:
case ANNOTATION_TYPE:
case INTERFACE:
receiver = new ClassName(ele.asType());
break;
default:
receiver = null;
}
break;
default:
receiver = null;
}
if (receiver == null) {
receiver = new Unknown(TreeUtils.typeOf(receiverTree));
}
return receiver;
}
use of com.sun.source.tree.LiteralTree in project checker-framework by typetools.
the class InterningVisitor method suppressEarlyCompareTo.
/**
* Pattern matches to prevent false positives of the form {@code (a == b || a.compareTo(b) ==
* 0)}. Returns true iff the given node fits this pattern.
*
* @return true iff the node fits the pattern (a == b || a.compareTo(b) == 0)
*/
private boolean suppressEarlyCompareTo(final BinaryTree node) {
// Only handle == binary trees
if (node.getKind() != Tree.Kind.EQUAL_TO) {
return false;
}
Tree left = TreeUtils.skipParens(node.getLeftOperand());
Tree right = TreeUtils.skipParens(node.getRightOperand());
// Only valid if we're comparing identifiers.
if (!(left.getKind() == Tree.Kind.IDENTIFIER && right.getKind() == Tree.Kind.IDENTIFIER)) {
return false;
}
final Element lhs = TreeUtils.elementFromUse((IdentifierTree) left);
final Element rhs = TreeUtils.elementFromUse((IdentifierTree) right);
// looking for ((a == b || a.compareTo(b) == 0)
Heuristics.Matcher matcherEqOrCompareTo = new Heuristics.Matcher() {
@Override
public Boolean visitBinary(BinaryTree tree, Void p) {
if (tree.getKind() == Tree.Kind.EQUAL_TO) {
// a.compareTo(b) == 0
ExpressionTree leftTree = // looking for a.compareTo(b) or
tree.getLeftOperand();
// b.compareTo(a)
// looking for 0
ExpressionTree rightTree = tree.getRightOperand();
if (rightTree.getKind() != Tree.Kind.INT_LITERAL) {
return false;
}
LiteralTree rightLiteral = (LiteralTree) rightTree;
if (!rightLiteral.getValue().equals(0)) {
return false;
}
return visit(leftTree, p);
} else {
// a == b || a.compareTo(b) == 0
// looking for a==b
ExpressionTree leftTree = tree.getLeftOperand();
ExpressionTree rightTree = // looking for a.compareTo(b) == 0
tree.getRightOperand();
// or b.compareTo(a) == 0
if (leftTree != node) {
return false;
}
if (rightTree.getKind() != Tree.Kind.EQUAL_TO) {
return false;
}
return visit(rightTree, p);
}
}
@Override
public Boolean visitMethodInvocation(MethodInvocationTree tree, Void p) {
if (!isInvocationOfCompareTo(tree)) {
return false;
}
List<? extends ExpressionTree> args = tree.getArguments();
if (args.size() != 1) {
return false;
}
ExpressionTree arg = args.get(0);
if (arg.getKind() != Tree.Kind.IDENTIFIER) {
return false;
}
Element argElt = TreeUtils.elementFromUse(arg);
ExpressionTree exp = tree.getMethodSelect();
if (exp.getKind() != Tree.Kind.MEMBER_SELECT) {
return false;
}
MemberSelectTree member = (MemberSelectTree) exp;
if (member.getExpression().getKind() != Tree.Kind.IDENTIFIER) {
return false;
}
Element refElt = TreeUtils.elementFromUse(member.getExpression());
if (!((refElt.equals(lhs) && argElt.equals(rhs)) || ((refElt.equals(rhs) && argElt.equals(lhs))))) {
return false;
}
return true;
}
};
boolean okay = Heuristics.Matchers.withIn(Heuristics.Matchers.ofKind(Tree.Kind.CONDITIONAL_OR, matcherEqOrCompareTo)).match(getCurrentPath());
return okay;
}
use of com.sun.source.tree.LiteralTree in project checker-framework by typetools.
the class InterningVisitor method suppressInsideComparison.
/**
* Pattern matches particular comparisons to avoid common false positives in the {@link
* Comparable#compareTo(Object)} and {@link Object#equals(Object)}.
*
* <p>Specifically, this method tests if: the comparison is a == comparison, it is the test of
* an if statement that's the first statement in the method, and one of the following is true:
*
* <ol>
* <li>the method overrides {@link Comparator#compare}, the "then" branch of the if statement
* returns zero, and the comparison tests equality of the method's two parameters
* <li>the method overrides {@link Object#equals(Object)} and the comparison tests "this"
* against the method's parameter
* <li>the method overrides {@link Comparable#compareTo(Object)}, the "then" branch of the if
* statement returns zero, and the comparison tests "this" against the method's parameter
* </ol>
*
* @param node the comparison to check
* @return true if one of the supported heuristics is matched, false otherwise
*/
// TODO: handle != comparisons too!
// TODO: handle more methods, such as early return from addAll when this == arg
private boolean suppressInsideComparison(final BinaryTree node) {
// Only handle == binary trees
if (node.getKind() != Tree.Kind.EQUAL_TO) {
return false;
}
Tree left = node.getLeftOperand();
Tree right = node.getRightOperand();
// Only valid if we're comparing identifiers.
if (!(left.getKind() == Tree.Kind.IDENTIFIER && right.getKind() == Tree.Kind.IDENTIFIER))
return false;
// parens and blocks), terminate.
if (!Heuristics.matchParents(getCurrentPath(), Tree.Kind.IF, Tree.Kind.METHOD)) {
return false;
}
// Ensure the if statement is the first statement in the method
TreePath parentPath = getCurrentPath().getParentPath();
// Retrieve the enclosing if statement tree and method tree
Tree tree, ifStatementTree = null;
MethodTree methodTree = null;
while ((tree = parentPath.getLeaf()) != null) {
if (tree.getKind() == Tree.Kind.IF) {
ifStatementTree = tree;
} else if (tree.getKind() == Tree.Kind.METHOD) {
methodTree = (MethodTree) tree;
break;
}
parentPath = parentPath.getParentPath();
}
// The call to Heuristics.matchParents already ensured there is an enclosing if statement
assert ifStatementTree != null;
// The call to Heuristics.matchParents already ensured there is an enclosing method
assert methodTree != null;
StatementTree stmnt = methodTree.getBody().getStatements().get(0);
// The call to Heuristics.matchParents already ensured the enclosing method has at least one statement (an if statement) in the body
assert stmnt != null;
if (stmnt != ifStatementTree) {
// The if statement is not the first statement in the method.
return false;
}
ExecutableElement enclosing = TreeUtils.elementFromDeclaration(visitorState.getMethodTree());
assert enclosing != null;
final Element lhs = TreeUtils.elementFromUse((IdentifierTree) left);
final Element rhs = TreeUtils.elementFromUse((IdentifierTree) right);
// Matcher to check for if statement that returns zero
Heuristics.Matcher matcherIfReturnsZero = new Heuristics.Matcher() {
@Override
public Boolean visitIf(IfTree tree, Void p) {
return visit(tree.getThenStatement(), p);
}
@Override
public Boolean visitBlock(BlockTree tree, Void p) {
if (tree.getStatements().size() > 0) {
return visit(tree.getStatements().get(0), p);
}
return false;
}
@Override
public Boolean visitReturn(ReturnTree tree, Void p) {
ExpressionTree expr = tree.getExpression();
return (expr != null && expr.getKind() == Tree.Kind.INT_LITERAL && ((LiteralTree) expr).getValue().equals(0));
}
};
// "return 0" statement (for the Comparator.compare heuristic).
if (overrides(enclosing, Comparator.class, "compare")) {
final boolean returnsZero = Heuristics.Matchers.withIn(Heuristics.Matchers.ofKind(Tree.Kind.IF, matcherIfReturnsZero)).match(getCurrentPath());
if (!returnsZero) {
return false;
}
assert enclosing.getParameters().size() == 2;
Element p1 = enclosing.getParameters().get(0);
Element p2 = enclosing.getParameters().get(1);
return (p1.equals(lhs) && p2.equals(rhs)) || (p2.equals(lhs) && p1.equals(rhs));
} else if (overrides(enclosing, Object.class, "equals")) {
assert enclosing.getParameters().size() == 1;
Element param = enclosing.getParameters().get(0);
Element thisElt = getThis(trees.getScope(getCurrentPath()));
assert thisElt != null;
return (thisElt.equals(lhs) && param.equals(rhs)) || (param.equals(lhs) && thisElt.equals(rhs));
} else if (overrides(enclosing, Comparable.class, "compareTo")) {
final boolean returnsZero = Heuristics.Matchers.withIn(Heuristics.Matchers.ofKind(Tree.Kind.IF, matcherIfReturnsZero)).match(getCurrentPath());
if (!returnsZero) {
return false;
}
assert enclosing.getParameters().size() == 1;
Element param = enclosing.getParameters().get(0);
Element thisElt = getThis(trees.getScope(getCurrentPath()));
assert thisElt != null;
return (thisElt.equals(lhs) && param.equals(rhs)) || (param.equals(lhs) && thisElt.equals(rhs));
}
return false;
}
use of com.sun.source.tree.LiteralTree in project checker-framework by typetools.
the class RegexVisitor method visitMethodInvocation.
/**
* Case 1: Don't require a Regex annotation on the String argument to Pattern.compile if the
* Pattern.LITERAL flag is passed.
*/
@Override
public Void visitMethodInvocation(MethodInvocationTree node, Void p) {
ProcessingEnvironment env = checker.getProcessingEnvironment();
if (TreeUtils.isMethodInvocation(node, patternCompile, env)) {
ExpressionTree flagParam = node.getArguments().get(1);
if (flagParam.getKind() == Kind.MEMBER_SELECT) {
MemberSelectTree memSelect = (MemberSelectTree) flagParam;
if (TreeUtils.isSpecificFieldAccess(memSelect, patternLiteral)) {
// This is a call to Pattern.compile with the Pattern.LITERAL
// flag so the first parameter doesn't need to be a
// @Regex String. Don't call the super method to skip checking
// if the first parameter is a @Regex String, but make sure to
// still recurse on all of the different parts of the method call.
Void r = scan(node.getTypeArguments(), p);
r = reduce(scan(node.getMethodSelect(), p), r);
r = reduce(scan(node.getArguments(), p), r);
return r;
}
}
} else if (TreeUtils.isMethodInvocation(node, matchResultEnd, env) || TreeUtils.isMethodInvocation(node, matchResultGroup, env) || TreeUtils.isMethodInvocation(node, matchResultStart, env)) {
/**
* Case 3: Checks calls to {@code MatchResult.start}, {@code MatchResult.end} and {@code
* MatchResult.group} to ensure that a valid group number is passed.
*/
ExpressionTree group = node.getArguments().get(0);
if (group.getKind() == Kind.INT_LITERAL) {
LiteralTree literal = (LiteralTree) group;
int paramGroups = (Integer) literal.getValue();
ExpressionTree receiver = TreeUtils.getReceiverTree(node);
if (receiver == null) {
// is out of the scope of this checker.
return super.visitMethodInvocation(node, p);
}
int annoGroups = 0;
AnnotatedTypeMirror receiverType = atypeFactory.getAnnotatedType(receiver);
if (receiverType != null && receiverType.hasAnnotation(Regex.class)) {
annoGroups = atypeFactory.getGroupCount(receiverType.getAnnotation(Regex.class));
}
if (paramGroups > annoGroups) {
checker.report(Result.failure("group.count.invalid", paramGroups, annoGroups, receiver), group);
}
} else {
checker.report(Result.warning("group.count.unknown"), group);
}
}
return super.visitMethodInvocation(node, p);
}
Aggregations