private static boolean isValueOfInvocation(ExpressionTree abstractTypedTree) { if (!abstractTypedTree.is(Kind.METHOD_INVOCATION)) { return false; } Type type = abstractTypedTree.symbolType(); MethodMatcher valueOfMatcher = MethodMatcher.create() .typeDefinition(type.fullyQualifiedName()) .name("valueOf") .addParameter(((JavaType) type).primitiveType().fullyQualifiedName()); return valueOfMatcher.matches((MethodInvocationTree) abstractTypedTree); }
@Override public void visitMethodInvocation(MethodInvocationTree syntaxNode) { final ExpressionTree methodSelect = syntaxNode.methodSelect(); if (isClosingResource(syntaxNode.symbol())) { if (methodSelect.is(Tree.Kind.MEMBER_SELECT)) { final ExpressionTree targetExpression = ((MemberSelectExpressionTree) methodSelect).expression(); if (targetExpression.is(Tree.Kind.IDENTIFIER)) { final IdentifierTree identifier = (IdentifierTree) targetExpression; programState = closeResource(programState, programState.getValue(identifier.symbol())); } else { programState = closeResource(programState, programState.peekValue()); } } } else if (syntaxNode.methodSelect().is(Tree.Kind.MEMBER_SELECT) && isOpeningResultSet(syntaxNode.symbol())) { final SymbolicValue value = getTargetValue(syntaxNode); constraintManager.setValueFactory(new WrappedValueFactory(value)); } else if (isClosingResultSets(syntaxNode.symbol())) { if (methodSelect.is(Tree.Kind.MEMBER_SELECT)) { final SymbolicValue value = getTargetValue(syntaxNode); closeResultSetsRelatedTo(value); } } else { closeArguments(syntaxNode.arguments(), 1); } }
private void addAssignment(ExpressionTree tree) { ExpressionTree variable = ExpressionsHelper.skipParentheses(tree); if (variable.is(Tree.Kind.IDENTIFIER)) { addAssignment((IdentifierTree) variable); } else if (variable.is(Tree.Kind.MEMBER_SELECT)) { addAssignment(((MemberSelectExpressionTree) variable).identifier()); } }
private static List<String> getValueFromExpression(ExpressionTree expression) { List<String> args = Lists.newArrayList(); if (expression.is(Tree.Kind.STRING_LITERAL)) { args.add(LiteralUtils.trimQuotes(((LiteralTree) expression).value())); } else if (expression.is(Tree.Kind.NEW_ARRAY)) { for (ExpressionTree initializer : ((NewArrayTree) expression).initializers()) { args.addAll(getValueFromExpression(initializer)); } } return args; }
@CheckForNull private static Tree getAssignedVariable(ExpressionTree expression) { if (expression.is(Tree.Kind.ARRAY_ACCESS_EXPRESSION)) { return getAssignedVariable(((ArrayAccessExpressionTree) expression).expression()); } IdentifierTree identifier; if (expression.is(Tree.Kind.IDENTIFIER)) { identifier = (IdentifierTree) expression; } else { identifier = ((MemberSelectExpressionTree) expression).identifier(); } return identifier.symbol().declaration(); }
private static ExpressionTree removeParenthesis(ExpressionTree tree) { ExpressionTree result = tree; while (result.is(Tree.Kind.PARENTHESIZED_EXPRESSION)) { result = ((ParenthesizedTree) result).expression(); } return result; }
@Override public void visitMemberSelectExpression(MemberSelectExpressionTree tree) { IdentifierTree identifier = null; ExpressionTree expression = tree.expression(); if (expression.is(Kind.IDENTIFIER)) { identifier = (IdentifierTree) expression; } else if (expression.is(Kind.PARENTHESIZED_EXPRESSION) && ((ParenthesizedTree) expression).expression().is(Kind.IDENTIFIER)) { identifier = (IdentifierTree) ((ParenthesizedTree) expression).expression(); } if (!validUsagesStack.isEmpty() && identifier != null) { Iterator<Collection<IdentifierTree>> iterator = validUsagesStack.iterator(); while (iterator.hasNext()) { iterator.next().remove(identifier); } } super.visitMemberSelectExpression(tree); }
private void addUnboxingIssue(ExpressionTree expressionTree, ExpressionTree expression) { if (expression.is(Tree.Kind.IDENTIFIER)) { IdentifierTree identifier = (IdentifierTree) expression; reportIssue(expressionTree, "Remove the unboxing of \"" + identifier.name() + "\"."); } else { String name = expression.symbolType().name(); reportIssue(expressionTree, "Remove the unboxing from \"" + name + "\"."); } }
private void checkForBoxing(ExpressionTree expression) { if (expression.is(Tree.Kind.NEW_CLASS)) { NewClassTree newClassTree = (NewClassTree) expression; Symbol.TypeSymbol classSymbol = wrapperClassSymbol(newClassTree); if (classSymbol != null) { ExpressionTree boxingArg = newClassTree.arguments().get(0); if (boxingArg.symbolType().isPrimitive()) { addBoxingIssue(newClassTree, classSymbol, boxingArg); } } } else if (expression.is(Tree.Kind.METHOD_INVOCATION)) { MethodInvocationTree methodInvocationTree = (MethodInvocationTree) expression; if (isValueOfInvocation(methodInvocationTree)) { ExpressionTree boxingArg = methodInvocationTree.arguments().get(0); addBoxingIssue(expression, methodInvocationTree.symbol().owner(), boxingArg); } } }
@Override public void visitAssignmentExpression(AssignmentExpressionTree syntaxNode) { final ExpressionTree variable = syntaxNode.variable(); if (variable.is(Tree.Kind.ARRAY_ACCESS_EXPRESSION)) { List<SymbolicValue> stackedValues = programState.peekValues(2); SymbolicValue value = stackedValues.get(1); programState = closeResource(programState, value); } }
@Nullable private State checkAndAdvanceState( MethodInvocationTree mit, State requiredState, State nextState) { ExpressionTree methodSelect = mit.methodSelect(); if (methodSelect.is(Tree.Kind.MEMBER_SELECT)) { ExpressionTree expressionTree = ((MemberSelectExpressionTree) methodSelect).expression(); if (expressionTree.is(Tree.Kind.IDENTIFIER)) { Symbol symbol = ((IdentifierTree) expressionTree).symbol(); Map<Symbol, State> symbolStateMap = symbolStack.peek(); if (symbolStateMap != null && symbolStateMap.containsKey(symbol) && requiredState.equals(symbolStateMap.get(symbol))) { symbolStateMap.put(symbol, nextState); return nextState; } } } return null; }
@Override public void visitAssignmentExpression(AssignmentExpressionTree tree) { super.visitAssignmentExpression(tree); if (isFileCreateTempFile(tree.expression())) { ExpressionTree variable = tree.variable(); if (variable.is(Tree.Kind.IDENTIFIER) && !symbolStack.isEmpty()) { symbolStack.peek().put(((IdentifierTree) variable).symbol(), State.CREATE_TMP_FILE); } } }
private void checkForUnboxing(ExpressionTree expressionTree) { if (!expressionTree.is(Tree.Kind.METHOD_INVOCATION)) { return; } MethodInvocationTree methodInvocationTree = (MethodInvocationTree) expressionTree; if (isUnboxingMethodInvocation(methodInvocationTree)) { ExpressionTree methodSelect = methodInvocationTree.methodSelect(); if (methodSelect.is(Tree.Kind.MEMBER_SELECT)) { MemberSelectExpressionTree memberSelectExpressionTree = (MemberSelectExpressionTree) methodSelect; ExpressionTree unboxedExpression = memberSelectExpressionTree.expression(); String unboxingResultTypeName = methodInvocationTree.symbolType().fullyQualifiedName(); if (unboxingResultTypeName.equals( PRIMITIVE_TYPES_BY_WRAPPER.get(unboxedExpression.symbolType().fullyQualifiedName()))) { addUnboxingIssue(expressionTree, unboxedExpression); } } } }
private static String concatenate(ExpressionTree tree) { Deque<String> pieces = new LinkedList<>(); ExpressionTree expr = tree; while (expr.is(Tree.Kind.MEMBER_SELECT)) { MemberSelectExpressionTree mse = (MemberSelectExpressionTree) expr; pieces.push(mse.identifier().name()); pieces.push("."); expr = mse.expression(); } if (expr.is(Tree.Kind.IDENTIFIER)) { IdentifierTree idt = (IdentifierTree) expr; pieces.push(idt.name()); } StringBuilder sb = new StringBuilder(); for (String piece : pieces) { sb.append(piece); } return sb.toString(); }
@Override public void visitMethodInvocation(MethodInvocationTree tree) { if (TO_STRING_MATCHERS.anyMatch(tree)) { ExpressionTree abstractTypedTree = ((MemberSelectExpressionTree) tree.methodSelect()).expression(); if (abstractTypedTree.is(Kind.NEW_CLASS) || isValueOfInvocation(abstractTypedTree)) { String typeName = abstractTypedTree.symbolType().toString(); createIssue(tree, typeName); } } super.visitMethodInvocation(tree); }
public static boolean areOperandEquivalent( ExpressionTree left, ExpressionTree right, Tree.Kind binaryKind) { if (SyntacticEquivalence.areEquivalent(left, right)) { return true; } // Check other operands if operator is symetric. if (SYMETRIC_OPERATORS.contains(binaryKind) && left.is(binaryKind)) { return areOperandEquivalent(((BinaryExpressionTree) left).leftOperand(), right, binaryKind) || areOperandEquivalent(((BinaryExpressionTree) left).rightOperand(), right, binaryKind); } return false; }
private SymbolicValue getTargetValue(MethodInvocationTree syntaxNode) { final ExpressionTree targetExpression = ((MemberSelectExpressionTree) syntaxNode.methodSelect()).expression(); final SymbolicValue value; if (targetExpression.is(Tree.Kind.IDENTIFIER)) { final IdentifierTree identifier = (IdentifierTree) targetExpression; value = programState.getValue(identifier.symbol()); } else { value = programState.peekValue(); } return value; }
private boolean isQualifiedExcludedType(Tree tree) { if (!tree.is(Kind.MEMBER_SELECT)) { return false; } Deque<String> pieces = new LinkedList<>(); ExpressionTree expr = (MemberSelectExpressionTree) tree; while (expr.is(Tree.Kind.MEMBER_SELECT)) { MemberSelectExpressionTree mse = (MemberSelectExpressionTree) expr; pieces.push(mse.identifier().name()); pieces.push("."); expr = mse.expression(); } if (expr.is(Tree.Kind.IDENTIFIER)) { IdentifierTree idt = (IdentifierTree) expr; pieces.push(idt.name()); } StringBuilder sb = new StringBuilder(); for (String piece : pieces) { sb.append(piece); } return Iterables.contains(exceptions, sb.toString()); }
private static boolean isEqualsMethod(MethodInvocationTree syntaxNode) { if (syntaxNode.arguments().size() == 1) { ExpressionTree methodSelect = syntaxNode.methodSelect(); if (methodSelect.is(Tree.Kind.MEMBER_SELECT)) { MemberSelectExpressionTree expression = (MemberSelectExpressionTree) methodSelect; if ("equals".equals(expression.identifier().name()) && syntaxNode.symbol().isMethodSymbol()) { Symbol.MethodSymbol symbol = (Symbol.MethodSymbol) syntaxNode.symbol(); return symbol.parameterTypes().get(0).is("java.lang.Object"); } } } return false; }
@Override public void visitMethodInvocation(MethodInvocationTree syntaxNode) { if (syntaxNode.methodSelect().is(Tree.Kind.MEMBER_SELECT) && needsClosing(syntaxNode.symbolType())) { final ExpressionTree targetExpression = ((MemberSelectExpressionTree) syntaxNode.methodSelect()).expression(); if (targetExpression.is(Tree.Kind.IDENTIFIER) && !isWithinTryHeader(syntaxNode) && (syntaxNode.symbol().isStatic() || isJdbcResourceCreation(targetExpression))) { programState = programState.addConstraint( programState.peekValue(), new ObjectConstraint(false, false, syntaxNode, Status.OPENED)); } } }
@Override public void visitReturnStatement(ReturnStatementTree syntaxNode) { SymbolicValue currentVal = programState.peekValue(); if (currentVal != null) { final ExpressionTree expression = syntaxNode.expression(); if (expression != null) { if (expression.is(Tree.Kind.IDENTIFIER)) { final IdentifierTree identifier = (IdentifierTree) expression; currentVal = programState.getValue(identifier.symbol()); } else { currentVal = programState.peekValue(); } programState = closeResource(programState, currentVal); } } }
@Override public void visitNewClass(NewClassTree tree) { if (TARGETED_CLASS.contains(getclassName(tree)) && tree.arguments().size() == 1) { ExpressionTree argument = tree.arguments().get(0); if (argument.is(Tree.Kind.CHAR_LITERAL)) { String character = ((LiteralTree) argument).value(); context.reportIssue( this, argument, "Replace the constructor character parameter " + character + " with string parameter " + character.replace("'", "\"") + "."); } } }
private void visitMethodInvocationTree(MethodInvocationTree methodInvocationTree) { if (isValueOfInvocation(methodInvocationTree)) { checkForUnboxing(methodInvocationTree.arguments().get(0)); } else if (isUnboxingMethodInvocation(methodInvocationTree)) { ExpressionTree methodSelect = methodInvocationTree.methodSelect(); if (methodSelect.is(Tree.Kind.MEMBER_SELECT)) { MemberSelectExpressionTree memberSelectExpressionTree = (MemberSelectExpressionTree) methodSelect; checkForBoxing(memberSelectExpressionTree.expression()); } } else { Symbol symbol = methodInvocationTree.symbol(); if (symbol.isMethodSymbol()) { List<Type> parametersTypes = ((Symbol.MethodSymbol) symbol).parameterTypes(); checkMethodInvocationArguments(methodInvocationTree, parametersTypes); } } }
@Override public void leaveNode(Tree tree) { if (hasSemantic()) { if (tree.is(Tree.Kind.METHOD)) { MethodTree method = (MethodTree) tree; if (ModifiersUtils.hasModifier(method.modifiers(), Modifier.NATIVE)) { hasNativeMethod = true; } } else if (tree.is(Tree.Kind.CLASS)) { classes.add((ClassTree) tree); } else if (tree.is(Tree.Kind.EXPRESSION_STATEMENT)) { ExpressionTree expression = ((ExpressionStatementTree) tree).expression(); if (expression.is(ASSIGNMENT_KINDS)) { addAssignment(((AssignmentExpressionTree) expression).variable()); } } else { leaveCompilationUnit(); } } }
private static boolean is0xff(ExpressionTree expression) { return expression.is(Tree.Kind.INT_LITERAL) && "0xff".equals(((LiteralTree) expression).value()); }
private static boolean isFileCreateTempFile(ExpressionTree givenExpression) { ExpressionTree expressionTree = removeParenthesis(givenExpression); return expressionTree.is(Tree.Kind.METHOD_INVOCATION) && FILE_CREATE_TEMP_FILE.matches((MethodInvocationTree) expressionTree); }
private static boolean isEmptyString(ExpressionTree expressionTree) { return expressionTree.is(Kind.STRING_LITERAL) && LiteralUtils.trimQuotes(((LiteralTree) expressionTree).value()).isEmpty(); }