Search in sources :

Example 6 with ReturnTree

use of com.sun.source.tree.ReturnTree in project error-prone by google.

the class FunctionalInterfaceMethodChanged method matchMethod.

@Override
public Description matchMethod(MethodTree tree, VisitorState state) {
    ClassTree enclosingClazz = ASTHelpers.findEnclosingNode(state.getPath(), ClassTree.class);
    if (tree.getModifiers().getFlags().contains(Modifier.DEFAULT) && IS_FUNCTIONAL_INTERFACE.matches(enclosingClazz, state)) {
        Types types = Types.instance(state.context);
        Set<Symbol> functionalSuperInterfaceSams = enclosingClazz.getImplementsClause().stream().filter(t -> IS_FUNCTIONAL_INTERFACE.matches(t, state)).map(ASTHelpers::getSymbol).map(TypeSymbol.class::cast).map(// TypeSymbol to single abstract method of the type
        types::findDescriptorSymbol).collect(toImmutableSet());
        // We designate an override of a superinterface SAM "behavior preserving" if it just
        // calls the SAM of this interface.
        Symbol thisInterfaceSam = types.findDescriptorSymbol(ASTHelpers.getSymbol(enclosingClazz));
        // relatively crude: doesn't verify that the same args are passed in the same order
        // so it can get false positives for behavior-preservingness (false negatives for the check)
        TreeVisitor<Boolean, VisitorState> behaviorPreserving = new SimpleTreeVisitor<Boolean, VisitorState>(false) {

            @Override
            public Boolean visitMethod(MethodTree node, VisitorState state) {
                return node.getBody() != null && node.getBody().accept(this, state);
            }

            @Override
            public Boolean visitBlock(BlockTree node, VisitorState state) {
                return node.getStatements().size() == 1 && Iterables.getOnlyElement(node.getStatements()).accept(this, state);
            }

            @Override
            public Boolean visitExpressionStatement(ExpressionStatementTree node, VisitorState state) {
                return node.getExpression().accept(this, state);
            }

            @Override
            public Boolean visitReturn(ReturnTree node, VisitorState state) {
                return node.getExpression().accept(this, state);
            }

            @Override
            public Boolean visitMethodInvocation(MethodInvocationTree node, VisitorState state) {
                return ASTHelpers.getSymbol(node) == thisInterfaceSam;
            }
        };
        if (!Collections.disjoint(ASTHelpers.findSuperMethods(ASTHelpers.getSymbol(tree), types), functionalSuperInterfaceSams) && !tree.accept(behaviorPreserving, state)) {
            return describeMatch(tree);
        }
    }
    return Description.NO_MATCH;
}
Also used : Types(com.sun.tools.javac.code.Types) MethodTree(com.sun.source.tree.MethodTree) TypeSymbol(com.sun.tools.javac.code.Symbol.TypeSymbol) Symbol(com.sun.tools.javac.code.Symbol) SimpleTreeVisitor(com.sun.source.util.SimpleTreeVisitor) ClassTree(com.sun.source.tree.ClassTree) ExpressionStatementTree(com.sun.source.tree.ExpressionStatementTree) ReturnTree(com.sun.source.tree.ReturnTree) VisitorState(com.google.errorprone.VisitorState) MethodInvocationTree(com.sun.source.tree.MethodInvocationTree) BlockTree(com.sun.source.tree.BlockTree) TypeSymbol(com.sun.tools.javac.code.Symbol.TypeSymbol)

Example 7 with ReturnTree

use of com.sun.source.tree.ReturnTree 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;
    }
}
Also used : Types(com.sun.tools.javac.code.Types) SimpleTreeVisitor(com.sun.source.util.SimpleTreeVisitor) ClassTree(com.sun.source.tree.ClassTree) ParenthesizedTree(com.sun.source.tree.ParenthesizedTree) BinaryTree(com.sun.source.tree.BinaryTree) ConditionalExpressionTree(com.sun.source.tree.ConditionalExpressionTree) ReturnTree(com.sun.source.tree.ReturnTree) Symtab(com.sun.tools.javac.code.Symtab) Type(com.sun.tools.javac.code.Type) VisitorState(com.google.errorprone.VisitorState) ReturnTree(com.sun.source.tree.ReturnTree) LiteralTree(com.sun.source.tree.LiteralTree) MethodTree(com.sun.source.tree.MethodTree) BinaryTree(com.sun.source.tree.BinaryTree) IdentifierTree(com.sun.source.tree.IdentifierTree) Tree(com.sun.source.tree.Tree) ClassTree(com.sun.source.tree.ClassTree) ParenthesizedTree(com.sun.source.tree.ParenthesizedTree) ConditionalExpressionTree(com.sun.source.tree.ConditionalExpressionTree) ExpressionTree(com.sun.source.tree.ExpressionTree) MemberSelectTree(com.sun.source.tree.MemberSelectTree) ConditionalExpressionTree(com.sun.source.tree.ConditionalExpressionTree) ExpressionTree(com.sun.source.tree.ExpressionTree)

Example 8 with ReturnTree

use of com.sun.source.tree.ReturnTree in project error-prone by google.

the class InfiniteRecursion method matchMethod.

@Override
public Description matchMethod(MethodTree tree, VisitorState state) {
    if (tree.getBody() == null || tree.getBody().getStatements().size() != 1) {
        return NO_MATCH;
    }
    Tree statement = TreeInfo.skipParens((JCTree) Iterables.getOnlyElement(tree.getBody().getStatements()));
    ExpressionTree expr = statement.accept(new SimpleTreeVisitor<ExpressionTree, Void>() {

        @Override
        public ExpressionTree visitExpressionStatement(ExpressionStatementTree tree, Void unused) {
            return tree.getExpression();
        }

        @Override
        public ExpressionTree visitReturn(ReturnTree tree, Void unused) {
            return tree.getExpression();
        }
    }, null);
    if (!(expr instanceof MethodInvocationTree)) {
        return NO_MATCH;
    }
    ExpressionTree select = ((MethodInvocationTree) expr).getMethodSelect();
    switch(select.getKind()) {
        case IDENTIFIER:
            break;
        case MEMBER_SELECT:
            ExpressionTree receiver = ((MemberSelectTree) select).getExpression();
            if (receiver.getKind() != Kind.IDENTIFIER) {
                return NO_MATCH;
            }
            if (!((IdentifierTree) receiver).getName().contentEquals("this")) {
                return NO_MATCH;
            }
            break;
        default:
            return NO_MATCH;
    }
    MethodSymbol sym = ASTHelpers.getSymbol(tree);
    if (sym == null || !sym.equals(ASTHelpers.getSymbol(expr))) {
        return NO_MATCH;
    }
    return describeMatch(statement);
}
Also used : MethodSymbol(com.sun.tools.javac.code.Symbol.MethodSymbol) MethodInvocationTree(com.sun.source.tree.MethodInvocationTree) MemberSelectTree(com.sun.source.tree.MemberSelectTree) ReturnTree(com.sun.source.tree.ReturnTree) MethodTree(com.sun.source.tree.MethodTree) ExpressionTree(com.sun.source.tree.ExpressionTree) MemberSelectTree(com.sun.source.tree.MemberSelectTree) JCTree(com.sun.tools.javac.tree.JCTree) ExpressionStatementTree(com.sun.source.tree.ExpressionStatementTree) MethodInvocationTree(com.sun.source.tree.MethodInvocationTree) IdentifierTree(com.sun.source.tree.IdentifierTree) Tree(com.sun.source.tree.Tree) ExpressionTree(com.sun.source.tree.ExpressionTree) ExpressionStatementTree(com.sun.source.tree.ExpressionStatementTree) IdentifierTree(com.sun.source.tree.IdentifierTree) ReturnTree(com.sun.source.tree.ReturnTree)

Aggregations

ReturnTree (com.sun.source.tree.ReturnTree)8 ExpressionTree (com.sun.source.tree.ExpressionTree)6 MethodTree (com.sun.source.tree.MethodTree)6 Tree (com.sun.source.tree.Tree)6 ClassTree (com.sun.source.tree.ClassTree)5 ExpressionStatementTree (com.sun.source.tree.ExpressionStatementTree)5 IdentifierTree (com.sun.source.tree.IdentifierTree)4 LiteralTree (com.sun.source.tree.LiteralTree)4 MemberSelectTree (com.sun.source.tree.MemberSelectTree)4 MethodInvocationTree (com.sun.source.tree.MethodInvocationTree)4 JCTree (com.sun.tools.javac.tree.JCTree)4 AssignmentTree (com.sun.source.tree.AssignmentTree)3 BinaryTree (com.sun.source.tree.BinaryTree)3 BlockTree (com.sun.source.tree.BlockTree)3 CompoundAssignmentTree (com.sun.source.tree.CompoundAssignmentTree)3 ConditionalExpressionTree (com.sun.source.tree.ConditionalExpressionTree)3 NewClassTree (com.sun.source.tree.NewClassTree)3 ParenthesizedTree (com.sun.source.tree.ParenthesizedTree)3 StatementTree (com.sun.source.tree.StatementTree)3 VariableTree (com.sun.source.tree.VariableTree)3