Search in sources :

Example 91 with TreePath

use of com.sun.source.util.TreePath in project checker-framework by typetools.

the class AnnotatedTypeFactory method getImplicitReceiverType.

// **********************************************************************
// Utilities method for getting specific types from trees or elements
// **********************************************************************
/**
 * Return the implicit receiver type of an expression tree.
 *
 * <p>The result is null for expressions that don't have a receiver, e.g. for a local variable
 * or method parameter access.
 *
 * @param tree the expression that might have an implicit receiver
 * @return the type of the receiver
 */
/*
     * TODO: receiver annotations on outer this.
     * TODO: Better document the difference between getImplicitReceiverType and getSelfType?
     * TODO: this method assumes that the tree is within the current
     * Compilation Unit. This assumption fails in testcase Bug109_A/B, where
     * a chain of dependencies leads into a different compilation unit.
     * I didn't find a way how to handle this better and conservatively
     * return null. See TODO comment below.
     *
     */
protected AnnotatedDeclaredType getImplicitReceiverType(ExpressionTree tree) {
    assert (tree.getKind() == Tree.Kind.IDENTIFIER || tree.getKind() == Tree.Kind.MEMBER_SELECT || tree.getKind() == Tree.Kind.METHOD_INVOCATION || tree.getKind() == Tree.Kind.NEW_CLASS) : "Unexpected tree kind: " + tree.getKind();
    Element element = TreeUtils.elementFromTree(tree);
    assert element != null : "Unexpected null element for tree: " + tree;
    // Return null if the element kind has no receiver.
    if (!ElementUtils.hasReceiver(element)) {
        return null;
    }
    ExpressionTree receiver = TreeUtils.getReceiverTree(tree);
    if (receiver == null) {
        if (isMostEnclosingThisDeref(tree)) {
            // TODO: is this fixed?
            return getSelfType(tree);
        } else {
            TreePath path = getPath(tree);
            if (path == null) {
                // This only arises in the Nullness Checker when substituting rawness.
                return null;
            }
            TypeElement typeElt = ElementUtils.enclosingClass(element);
            if (typeElt == null) {
                ErrorReporter.errorAbort("AnnotatedTypeFactory.getImplicitReceiver: enclosingClass()==null for element: " + element);
            }
            // TODO: method receiver annotations on outer this
            return getEnclosingType(typeElt, tree);
        }
    }
    Element rcvelem = TreeUtils.elementFromTree(receiver);
    assert rcvelem != null : "Unexpected null element for receiver: " + receiver;
    if (!ElementUtils.hasReceiver(rcvelem)) {
        return null;
    }
    if (receiver.getKind() == Tree.Kind.IDENTIFIER && ((IdentifierTree) receiver).getName().contentEquals("this")) {
        // TODO: also "super"?
        return this.getSelfType(tree);
    }
    TypeElement typeElt = ElementUtils.enclosingClass(rcvelem);
    if (typeElt == null) {
        ErrorReporter.errorAbort("AnnotatedTypeFactory.getImplicitReceiver: enclosingClass()==null for element: " + rcvelem);
    }
    AnnotatedDeclaredType type = getAnnotatedType(typeElt);
    // TODO: go through _all_ enclosing methods to see whether any of them has a
    // receiver annotation of the correct type.
    // TODO: Can we reuse getSelfType for outer this accesses?
    AnnotatedDeclaredType methodReceiver = getCurrentMethodReceiver(tree);
    if (shouldTakeFromReceiver(methodReceiver)) {
        // TODO: this only takes the main annotations.
        // What about other annotations (annotations on the type argument, outer types, ...)
        type.clearAnnotations();
        type.addAnnotations(methodReceiver.getAnnotations());
    }
    return type;
}
Also used : TreePath(com.sun.source.util.TreePath) TypeElement(javax.lang.model.element.TypeElement) TypeElement(javax.lang.model.element.TypeElement) Element(javax.lang.model.element.Element) VariableElement(javax.lang.model.element.VariableElement) ExecutableElement(javax.lang.model.element.ExecutableElement) TypeParameterElement(javax.lang.model.element.TypeParameterElement) AnnotatedDeclaredType(org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedDeclaredType) LambdaExpressionTree(com.sun.source.tree.LambdaExpressionTree) ConditionalExpressionTree(com.sun.source.tree.ConditionalExpressionTree) ExpressionTree(com.sun.source.tree.ExpressionTree) IdentifierTree(com.sun.source.tree.IdentifierTree)

Example 92 with TreePath

use of com.sun.source.util.TreePath in project checker-framework by typetools.

the class InitializationAnnotatedTypeFactory method findTopLevelClassMemberForTree.

/**
 * In the first enclosing class, find the top-level member that contains tree. TODO: should we
 * look whether these elements are enclosed within another class that is itself under
 * construction.
 *
 * <p>Are there any other type of top level objects?
 */
private Tree findTopLevelClassMemberForTree(TreePath path) {
    ClassTree enclosingClass = TreeUtils.enclosingClass(path);
    if (enclosingClass != null) {
        List<? extends Tree> classMembers = enclosingClass.getMembers();
        TreePath searchPath = path;
        while (searchPath.getParentPath() != null && searchPath.getParentPath() != enclosingClass) {
            searchPath = searchPath.getParentPath();
            if (classMembers.contains(searchPath.getLeaf())) {
                return searchPath.getLeaf();
            }
        }
    }
    return null;
}
Also used : TreePath(com.sun.source.util.TreePath) NewClassTree(com.sun.source.tree.NewClassTree) ClassTree(com.sun.source.tree.ClassTree)

Example 93 with TreePath

use of com.sun.source.util.TreePath 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);
    Tree topLevelMember = findTopLevelClassMemberForTree(path);
    if (topLevelMember != null) {
        if (topLevelMember.getKind() != Kind.METHOD || TreeUtils.isConstructor((MethodTree) topLevelMember)) {
            setSelfTypeInInitializationCode(tree, selfType, path);
        }
    }
    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) 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 94 with TreePath

use of com.sun.source.util.TreePath 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;
}
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) ReturnTree(com.sun.source.tree.ReturnTree) IfTree(com.sun.source.tree.IfTree) StatementTree(com.sun.source.tree.StatementTree) TreePath(com.sun.source.util.TreePath) 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) 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 95 with TreePath

use of com.sun.source.util.TreePath in project checker-framework by typetools.

the class LockAnnotatedTypeFactory method createDependentTypesHelper.

@Override
protected DependentTypesHelper createDependentTypesHelper() {
    return new DependentTypesHelper(this) {

        @Override
        protected void reportErrors(Tree errorTree, List<DependentTypesError> errors) {
            // If the error message is NOT_EFFECTIVELY_FINAL, then report lock.expression.not
            // .final instead of an expression.unparsable.type.invalid error.
            List<DependentTypesError> superErrors = new ArrayList<>();
            for (DependentTypesError error : errors) {
                if (error.error.equals(NOT_EFFECTIVELY_FINAL)) {
                    checker.report(Result.failure("lock.expression.not.final", error.expression), errorTree);
                } else {
                    superErrors.add(error);
                }
            }
            super.reportErrors(errorTree, superErrors);
        }

        @Override
        protected String standardizeString(String expression, FlowExpressionContext context, TreePath localScope, boolean useLocalScope) {
            if (DependentTypesError.isExpressionError(expression)) {
                return expression;
            }
            // Adds logic to parse <self> expression, which only the Lock Checker uses.
            if (LockVisitor.selfReceiverPattern.matcher(expression).matches()) {
                return expression;
            }
            try {
                FlowExpressions.Receiver result = FlowExpressionParseUtil.parse(expression, context, localScope, useLocalScope);
                if (result == null) {
                    return new DependentTypesError(expression, " ").toString();
                }
                if (!isExpressionEffectivelyFinal(result)) {
                    // NOT_EFFECTIVELY_FINAL error string.
                    return new DependentTypesError(expression, NOT_EFFECTIVELY_FINAL).toString();
                }
                return result.toString();
            } catch (FlowExpressionParseUtil.FlowExpressionParseException e) {
                return new DependentTypesError(expression, e).toString();
            }
        }
    };
}
Also used : FlowExpressionParseUtil(org.checkerframework.framework.util.FlowExpressionParseUtil) FlowExpressionContext(org.checkerframework.framework.util.FlowExpressionParseUtil.FlowExpressionContext) DependentTypesError(org.checkerframework.framework.util.dependenttypes.DependentTypesError) ArrayList(java.util.ArrayList) Receiver(org.checkerframework.dataflow.analysis.FlowExpressions.Receiver) TreePath(com.sun.source.util.TreePath) DependentTypesHelper(org.checkerframework.framework.util.dependenttypes.DependentTypesHelper) MethodInvocationTree(com.sun.source.tree.MethodInvocationTree) VariableTree(com.sun.source.tree.VariableTree) Tree(com.sun.source.tree.Tree) ExpressionTree(com.sun.source.tree.ExpressionTree) FlowExpressions(org.checkerframework.dataflow.analysis.FlowExpressions) List(java.util.List) ArrayList(java.util.ArrayList)

Aggregations

TreePath (com.sun.source.util.TreePath)151 ExpressionTree (com.sun.source.tree.ExpressionTree)60 Tree (com.sun.source.tree.Tree)60 VariableTree (com.sun.source.tree.VariableTree)50 MethodInvocationTree (com.sun.source.tree.MethodInvocationTree)46 MethodTree (com.sun.source.tree.MethodTree)46 ClassTree (com.sun.source.tree.ClassTree)45 MemberSelectTree (com.sun.source.tree.MemberSelectTree)39 IdentifierTree (com.sun.source.tree.IdentifierTree)37 BlockTree (com.sun.source.tree.BlockTree)36 NewClassTree (com.sun.source.tree.NewClassTree)32 StatementTree (com.sun.source.tree.StatementTree)32 JCTree (com.sun.tools.javac.tree.JCTree)31 AssignmentTree (com.sun.source.tree.AssignmentTree)27 BinaryTree (com.sun.source.tree.BinaryTree)27 TypeCastTree (com.sun.source.tree.TypeCastTree)26 ExpressionStatementTree (com.sun.source.tree.ExpressionStatementTree)25 LambdaExpressionTree (com.sun.source.tree.LambdaExpressionTree)25 LiteralTree (com.sun.source.tree.LiteralTree)25 CompoundAssignmentTree (com.sun.source.tree.CompoundAssignmentTree)23