Search in sources :

Example 91 with MethodTree

use of com.sun.source.tree.MethodTree 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;
    }
    TreePath path = getCurrentPath();
    TreePath parentPath = path.getParentPath();
    Tree parent = parentPath.getLeaf();
    // statement in the method.
    if (parent.getKind() == Tree.Kind.RETURN) {
        // ensure the return statement is the first statement in the method
        if (parentPath.getParentPath().getParentPath().getLeaf().getKind() != Tree.Kind.METHOD) {
            return false;
        }
    // maybe set some variables??
    } else if (Heuristics.matchParents(getCurrentPath(), Tree.Kind.IF, Tree.Kind.METHOD)) {
        // Ensure the if statement is the first statement in the method
        // Retrieve the enclosing if statement tree and method tree
        Tree ifStatementTree = null;
        MethodTree methodTree = null;
        // Set ifStatementTree and methodTree
        {
            TreePath ppath = parentPath;
            Tree tree;
            while ((tree = ppath.getLeaf()) != null) {
                if (tree.getKind() == Tree.Kind.IF) {
                    ifStatementTree = tree;
                } else if (tree.getKind() == Tree.Kind.METHOD) {
                    methodTree = (MethodTree) tree;
                    break;
                }
                ppath = ppath.getParentPath();
            }
        }
        assert ifStatementTree != null;
        assert methodTree != null;
        StatementTree firstStmnt = methodTree.getBody().getStatements().get(0);
        assert firstStmnt != null;
        // comparing AST nodes
        @SuppressWarnings("interning:not.interned") boolean notSameNode = firstStmnt != ifStatementTree;
        if (notSameNode) {
            // The if statement is not the first statement in the method.
            return false;
        }
    } else {
        return false;
    }
    ExecutableElement enclosingMethod = TreeUtils.elementFromDeclaration(methodTree);
    assert enclosingMethod != 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().isEmpty()) {
                return false;
            }
            return visit(tree.getStatements().get(0), p);
        }

        @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));
        }
    };
    boolean hasCompareToMethodAnno = atypeFactory.getDeclAnnotation(enclosingMethod, CompareToMethod.class) != null;
    boolean hasEqualsMethodAnno = atypeFactory.getDeclAnnotation(enclosingMethod, EqualsMethod.class) != null;
    int params = enclosingMethod.getParameters().size();
    // "return 0" statement (for the Comparator.compare heuristic).
    if (overrides(enclosingMethod, Comparator.class, "compare") || (hasCompareToMethodAnno && params == 2)) {
        final boolean returnsZero = new Heuristics.Within(new Heuristics.OfKind(Tree.Kind.IF, matcherIfReturnsZero)).match(getCurrentPath());
        if (!returnsZero) {
            return false;
        }
        assert params == 2;
        Element p1 = enclosingMethod.getParameters().get(0);
        Element p2 = enclosingMethod.getParameters().get(1);
        return (p1.equals(lhs) && p2.equals(rhs)) || (p1.equals(rhs) && p2.equals(lhs));
    } else if (overrides(enclosingMethod, Object.class, "equals") || (hasEqualsMethodAnno && params == 1)) {
        assert params == 1;
        Element param = enclosingMethod.getParameters().get(0);
        Element thisElt = getThis(trees.getScope(getCurrentPath()));
        assert thisElt != null;
        return (thisElt.equals(lhs) && param.equals(rhs)) || (thisElt.equals(rhs) && param.equals(lhs));
    } else if (hasEqualsMethodAnno && params == 2) {
        Element p1 = enclosingMethod.getParameters().get(0);
        Element p2 = enclosingMethod.getParameters().get(1);
        return (p1.equals(lhs) && p2.equals(rhs)) || (p1.equals(rhs) && p2.equals(lhs));
    } else if (overrides(enclosingMethod, Comparable.class, "compareTo") || (hasCompareToMethodAnno && params == 1)) {
        final boolean returnsZero = new Heuristics.Within(new Heuristics.OfKind(Tree.Kind.IF, matcherIfReturnsZero)).match(getCurrentPath());
        if (!returnsZero) {
            return false;
        }
        assert params == 1;
        Element param = enclosingMethod.getParameters().get(0);
        Element thisElt = getThis(trees.getScope(getCurrentPath()));
        assert thisElt != null;
        return (thisElt.equals(lhs) && param.equals(rhs)) || (thisElt.equals(rhs) && param.equals(lhs));
    }
    return false;
}
Also used : MethodTree(com.sun.source.tree.MethodTree) Heuristics(org.checkerframework.framework.util.Heuristics) ExecutableElement(javax.lang.model.element.ExecutableElement) TypeElement(javax.lang.model.element.TypeElement) ExecutableElement(javax.lang.model.element.ExecutableElement) Element(javax.lang.model.element.Element) EqualsMethod(org.checkerframework.checker.interning.qual.EqualsMethod) ReturnTree(com.sun.source.tree.ReturnTree) IfTree(com.sun.source.tree.IfTree) Comparator(java.util.Comparator) StatementTree(com.sun.source.tree.StatementTree) TreePath(com.sun.source.util.TreePath) CompareToMethod(org.checkerframework.checker.interning.qual.CompareToMethod) ReturnTree(com.sun.source.tree.ReturnTree) LiteralTree(com.sun.source.tree.LiteralTree) MethodTree(com.sun.source.tree.MethodTree) BinaryTree(com.sun.source.tree.BinaryTree) MethodInvocationTree(com.sun.source.tree.MethodInvocationTree) NewClassTree(com.sun.source.tree.NewClassTree) IdentifierTree(com.sun.source.tree.IdentifierTree) Tree(com.sun.source.tree.Tree) ClassTree(com.sun.source.tree.ClassTree) ConditionalExpressionTree(com.sun.source.tree.ConditionalExpressionTree) IfTree(com.sun.source.tree.IfTree) ExpressionTree(com.sun.source.tree.ExpressionTree) MemberSelectTree(com.sun.source.tree.MemberSelectTree) BlockTree(com.sun.source.tree.BlockTree) StatementTree(com.sun.source.tree.StatementTree) BlockTree(com.sun.source.tree.BlockTree) ConditionalExpressionTree(com.sun.source.tree.ConditionalExpressionTree) ExpressionTree(com.sun.source.tree.ExpressionTree)

Example 92 with MethodTree

use of com.sun.source.tree.MethodTree in project checker-framework by typetools.

the class InitializationAnnotatedTypeFactory method getSelfType.

@Override
public AnnotatedDeclaredType getSelfType(Tree tree) {
    AnnotatedDeclaredType selfType = super.getSelfType(tree);
    TreePath path = getPath(tree);
    AnnotatedDeclaredType enclosing = selfType;
    while (path != null && enclosing != null) {
        TreePath topLevelMemberPath = findTopLevelClassMemberForTree(path);
        if (topLevelMemberPath != null && topLevelMemberPath.getLeaf() != null) {
            Tree topLevelMember = topLevelMemberPath.getLeaf();
            if (topLevelMember.getKind() != Tree.Kind.METHOD || TreeUtils.isConstructor((MethodTree) topLevelMember)) {
                setSelfTypeInInitializationCode(tree, enclosing, topLevelMemberPath);
            }
            path = topLevelMemberPath.getParentPath();
            enclosing = enclosing.getEnclosingType();
        } else {
            break;
        }
    }
    return selfType;
}
Also used : TreePath(com.sun.source.util.TreePath) MethodTree(com.sun.source.tree.MethodTree) AnnotatedDeclaredType(org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedDeclaredType) LiteralTree(com.sun.source.tree.LiteralTree) MemberSelectTree(com.sun.source.tree.MemberSelectTree) MethodTree(com.sun.source.tree.MethodTree) VariableTree(com.sun.source.tree.VariableTree) NewClassTree(com.sun.source.tree.NewClassTree) Tree(com.sun.source.tree.Tree) ClassTree(com.sun.source.tree.ClassTree) ExpressionTree(com.sun.source.tree.ExpressionTree) JCTree(com.sun.tools.javac.tree.JCTree)

Example 93 with MethodTree

use of com.sun.source.tree.MethodTree in project checker-framework by typetools.

the class TypeFromTypeTreeVisitor method getTypeVariableFromDeclaration.

/**
 * If a tree is can be found for the declaration of the type variable {@code type}, then a {@link
 * AnnotatedTypeVariable} is returned with explicit annotations from the type variables declared
 * bounds. If a tree cannot be found, then {@code type}, converted to a use, is returned.
 *
 * @param type type variable used to find declaration tree
 * @param f annotated type factory
 * @return the AnnotatedTypeVariable from the declaration of {@code type} or {@code type} if no
 *     tree is found.
 */
private AnnotatedTypeVariable getTypeVariableFromDeclaration(AnnotatedTypeVariable type, AnnotatedTypeFactory f) {
    TypeVariable typeVar = type.getUnderlyingType();
    TypeParameterElement tpe = (TypeParameterElement) typeVar.asElement();
    Element elt = tpe.getGenericElement();
    if (elt instanceof TypeElement) {
        TypeElement typeElt = (TypeElement) elt;
        int idx = typeElt.getTypeParameters().indexOf(tpe);
        ClassTree cls = (ClassTree) f.declarationFromElement(typeElt);
        if (cls == null || cls.getTypeParameters().isEmpty()) {
            // contains all necessary information and we can return that.
            return type.asUse();
        }
        // will return a declaration ATV.  So change it to a use.
        return visitTypeParameter(cls.getTypeParameters().get(idx), f).asUse();
    } else if (elt instanceof ExecutableElement) {
        ExecutableElement exElt = (ExecutableElement) elt;
        int idx = exElt.getTypeParameters().indexOf(tpe);
        MethodTree meth = (MethodTree) f.declarationFromElement(exElt);
        if (meth == null) {
            // + elt);
            return type.asUse();
        }
        // This works the same as the case above.  Even though `meth` itself is not a
        // type declaration tree, the elements of `meth.getTypeParameters()` still are.
        AnnotatedTypeVariable result = visitTypeParameter(meth.getTypeParameters().get(idx), f).shallowCopy();
        result.setDeclaration(false);
        return result;
    } else if (TypesUtils.isCapturedTypeVariable(typeVar)) {
        // not an element at all, namely Symtab.noSymbol.
        return type.asUse();
    } else {
        throw new BugInCF("TypeFromTree.forTypeVariable: not a supported element: " + elt);
    }
}
Also used : AnnotatedTypeVariable(org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedTypeVariable) TypeVariable(javax.lang.model.type.TypeVariable) MethodTree(com.sun.source.tree.MethodTree) TypeElement(javax.lang.model.element.TypeElement) TypeElement(javax.lang.model.element.TypeElement) ExecutableElement(javax.lang.model.element.ExecutableElement) Element(javax.lang.model.element.Element) TypeParameterElement(javax.lang.model.element.TypeParameterElement) ExecutableElement(javax.lang.model.element.ExecutableElement) ClassTree(com.sun.source.tree.ClassTree) BugInCF(org.checkerframework.javacutil.BugInCF) AnnotatedTypeVariable(org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedTypeVariable) TypeParameterElement(javax.lang.model.element.TypeParameterElement)

Example 94 with MethodTree

use of com.sun.source.tree.MethodTree in project checker-framework by typetools.

the class PropagationTreeAnnotator method visitNewArray.

@Override
public Void visitNewArray(NewArrayTree tree, AnnotatedTypeMirror type) {
    assert type.getKind() == TypeKind.ARRAY : "PropagationTreeAnnotator.visitNewArray: should be an array type";
    AnnotatedTypeMirror componentType = ((AnnotatedArrayType) type).getComponentType();
    // prev is the lub of the initializers if they exist, otherwise the current component type.
    Set<? extends AnnotationMirror> prev = null;
    if (tree.getInitializers() != null && !tree.getInitializers().isEmpty()) {
        // the array.
        for (ExpressionTree init : tree.getInitializers()) {
            AnnotatedTypeMirror initType = atypeFactory.getAnnotatedType(init);
            // initType might be a typeVariable, so use effectiveAnnotations.
            Set<AnnotationMirror> annos = initType.getEffectiveAnnotations();
            prev = (prev == null) ? annos : qualHierarchy.leastUpperBounds(prev, annos);
        }
    } else {
        prev = componentType.getAnnotations();
    }
    assert prev != null : "PropagationTreeAnnotator.visitNewArray: violated assumption about qualifiers";
    TreePath path = atypeFactory.getPath(tree);
    AnnotatedTypeMirror contextType = null;
    if (path != null && path.getParentPath() != null) {
        Tree parentTree = path.getParentPath().getLeaf();
        if (parentTree.getKind() == Kind.ASSIGNMENT) {
            Tree var = ((AssignmentTree) parentTree).getVariable();
            contextType = atypeFactory.getAnnotatedType(var);
        } else if (parentTree.getKind() == Kind.VARIABLE) {
            contextType = atypeFactory.getAnnotatedType(parentTree);
        } else if (parentTree instanceof CompoundAssignmentTree) {
            Tree var = ((CompoundAssignmentTree) parentTree).getVariable();
            contextType = atypeFactory.getAnnotatedType(var);
        } else if (parentTree.getKind() == Kind.RETURN) {
            Tree methodTree = TreePathUtil.enclosingMethodOrLambda(path.getParentPath());
            if (methodTree.getKind() == Kind.METHOD) {
                AnnotatedExecutableType methodType = atypeFactory.getAnnotatedType((MethodTree) methodTree);
                contextType = methodType.getReturnType();
            }
        } else if (parentTree.getKind() == Kind.METHOD_INVOCATION && useAssignmentContext) {
            MethodInvocationTree methodInvocationTree = (MethodInvocationTree) parentTree;
            useAssignmentContext = false;
            AnnotatedExecutableType m;
            try {
                if (atypeFactory.shouldCache && methodInvocationToType.containsKey(methodInvocationTree)) {
                    m = methodInvocationToType.get(methodInvocationTree);
                } else {
                    m = atypeFactory.methodFromUse(methodInvocationTree).executableType;
                    if (atypeFactory.shouldCache) {
                        methodInvocationToType.put(methodInvocationTree, m);
                    }
                }
            } finally {
                useAssignmentContext = true;
            }
            for (int i = 0; i < m.getParameterTypes().size(); i++) {
                // Tree must be exactly the same.
                @SuppressWarnings("interning") boolean foundArgument = methodInvocationTree.getArguments().get(i) == tree;
                if (foundArgument) {
                    contextType = m.getParameterTypes().get(i);
                    break;
                }
            }
        }
    }
    Set<? extends AnnotationMirror> post;
    if (contextType instanceof AnnotatedArrayType) {
        AnnotatedTypeMirror contextComponentType = ((AnnotatedArrayType) contextType).getComponentType();
        // Only compare the qualifiers that existed in the array type.
        // Defaulting wasn't performed yet, so prev might have fewer qualifiers than
        // contextComponentType, which would cause a failure.
        // TODO: better solution?
        boolean prevIsSubtype = true;
        for (AnnotationMirror am : prev) {
            if (contextComponentType.isAnnotatedInHierarchy(am) && !this.qualHierarchy.isSubtype(am, contextComponentType.getAnnotationInHierarchy(am))) {
                prevIsSubtype = false;
            }
        }
        // It fails for array initializer expressions. Those should be handled nicer.
        if (contextComponentType.getKind() == componentType.getKind() && (prev.isEmpty() || (!contextComponentType.getAnnotations().isEmpty() && prevIsSubtype))) {
            post = contextComponentType.getAnnotations();
        } else {
            // The type of the array initializers is incompatible with the context type!
            // Somebody else will complain.
            post = prev;
        }
    } else {
        // No context is available - simply use what we have.
        post = prev;
    }
    // TODO (issue #599): This only works at the top level.  It should work at all levels of
    // the array.
    addAnnoOrBound(componentType, post);
    return null;
}
Also used : MethodTree(com.sun.source.tree.MethodTree) AnnotatedTypeMirror(org.checkerframework.framework.type.AnnotatedTypeMirror) CompoundAssignmentTree(com.sun.source.tree.CompoundAssignmentTree) AnnotatedArrayType(org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedArrayType) AnnotationMirror(javax.lang.model.element.AnnotationMirror) AnnotatedExecutableType(org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedExecutableType) TreePath(com.sun.source.util.TreePath) MethodInvocationTree(com.sun.source.tree.MethodInvocationTree) ExpressionTree(com.sun.source.tree.ExpressionTree) CompoundAssignmentTree(com.sun.source.tree.CompoundAssignmentTree) MethodTree(com.sun.source.tree.MethodTree) BinaryTree(com.sun.source.tree.BinaryTree) UnaryTree(com.sun.source.tree.UnaryTree) MethodInvocationTree(com.sun.source.tree.MethodInvocationTree) AssignmentTree(com.sun.source.tree.AssignmentTree) TypeCastTree(com.sun.source.tree.TypeCastTree) NewArrayTree(com.sun.source.tree.NewArrayTree) Tree(com.sun.source.tree.Tree) ExpressionTree(com.sun.source.tree.ExpressionTree) CompoundAssignmentTree(com.sun.source.tree.CompoundAssignmentTree) AssignmentTree(com.sun.source.tree.AssignmentTree)

Example 95 with MethodTree

use of com.sun.source.tree.MethodTree in project checker-framework by typetools.

the class StringToJavaExpression method atPath.

/**
 * Parses a string as if it were written at {@code localVarPath}.
 *
 * @param expression a Java expression to parse
 * @param localVarPath location at which {@code expression} is parsed
 * @param checker checker used to get the {@link
 *     javax.annotation.processing.ProcessingEnvironment} and current {@link
 *     com.sun.source.tree.CompilationUnitTree}
 * @return a {@code JavaExpression} for {@code expression}
 * @throws JavaExpressionParseException if {@code expression} cannot be parsed
 */
static JavaExpression atPath(String expression, TreePath localVarPath, SourceChecker checker) throws JavaExpressionParseException {
    TypeMirror enclosingType = TreeUtils.typeOf(TreePathUtil.enclosingClass(localVarPath));
    ThisReference thisReference = TreePathUtil.isTreeInStaticScope(localVarPath) ? null : new ThisReference(enclosingType);
    MethodTree methodTree = TreePathUtil.enclosingMethod(localVarPath);
    if (methodTree == null) {
        return JavaExpressionParseUtil.parse(expression, enclosingType, thisReference, null, localVarPath, checker.getPathToCompilationUnit(), checker.getProcessingEnvironment());
    }
    ExecutableElement methodEle = TreeUtils.elementFromDeclaration(methodTree);
    List<FormalParameter> parameters = JavaExpression.getFormalParameters(methodEle);
    JavaExpression javaExpr = JavaExpressionParseUtil.parse(expression, enclosingType, thisReference, parameters, localVarPath, checker.getPathToCompilationUnit(), checker.getProcessingEnvironment());
    List<JavaExpression> paramsAsLocals = JavaExpression.getParametersAsLocalVariables(methodEle);
    return ViewpointAdaptJavaExpression.viewpointAdapt(javaExpr, paramsAsLocals);
}
Also used : FormalParameter(org.checkerframework.dataflow.expression.FormalParameter) JavaExpression(org.checkerframework.dataflow.expression.JavaExpression) ViewpointAdaptJavaExpression(org.checkerframework.dataflow.expression.ViewpointAdaptJavaExpression) TypeMirror(javax.lang.model.type.TypeMirror) MethodTree(com.sun.source.tree.MethodTree) ExecutableElement(javax.lang.model.element.ExecutableElement) ThisReference(org.checkerframework.dataflow.expression.ThisReference)

Aggregations

MethodTree (com.sun.source.tree.MethodTree)127 ClassTree (com.sun.source.tree.ClassTree)66 Tree (com.sun.source.tree.Tree)65 VariableTree (com.sun.source.tree.VariableTree)58 ExpressionTree (com.sun.source.tree.ExpressionTree)54 MethodInvocationTree (com.sun.source.tree.MethodInvocationTree)43 ExecutableElement (javax.lang.model.element.ExecutableElement)39 NewClassTree (com.sun.source.tree.NewClassTree)38 TreePath (com.sun.source.util.TreePath)33 LambdaExpressionTree (com.sun.source.tree.LambdaExpressionTree)32 MemberSelectTree (com.sun.source.tree.MemberSelectTree)28 AnnotationTree (com.sun.source.tree.AnnotationTree)25 IdentifierTree (com.sun.source.tree.IdentifierTree)25 AnnotatedTypeMirror (org.checkerframework.framework.type.AnnotatedTypeMirror)23 ReturnTree (com.sun.source.tree.ReturnTree)22 MethodSymbol (com.sun.tools.javac.code.Symbol.MethodSymbol)22 ArrayList (java.util.ArrayList)22 TypeElement (javax.lang.model.element.TypeElement)21 AssignmentTree (com.sun.source.tree.AssignmentTree)20 ConditionalExpressionTree (com.sun.source.tree.ConditionalExpressionTree)20