Search in sources :

Example 21 with MethodTree

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

the class FlowExpressions method getParametersOfEnclosingMethod.

/**
 * Returns Receiver objects for the formal parameters of the method in which path is enclosed.
 *
 * @param annotationProvider annotationProvider
 * @param path TreePath that is enclosed by the method
 * @return list of Receiver objects for the formal parameters of the method in which path is
 *     enclosed
 */
public static List<Receiver> getParametersOfEnclosingMethod(AnnotationProvider annotationProvider, TreePath path) {
    MethodTree methodTree = TreeUtils.enclosingMethod(path);
    if (methodTree == null) {
        return null;
    }
    List<Receiver> internalArguments = new ArrayList<>();
    for (VariableTree arg : methodTree.getParameters()) {
        internalArguments.add(internalReprOf(annotationProvider, new LocalVariableNode(arg)));
    }
    return internalArguments;
}
Also used : MethodTree(com.sun.source.tree.MethodTree) ArrayList(java.util.ArrayList) VariableTree(com.sun.source.tree.VariableTree) LocalVariableNode(org.checkerframework.dataflow.cfg.node.LocalVariableNode)

Example 22 with MethodTree

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

the class InterningVisitor method overridesEquals.

// **********************************************************************
// Helper methods
// **********************************************************************
/**
 * Returns true if a class overrides Object.equals
 */
private boolean overridesEquals(ClassTree node) {
    List<? extends Tree> members = node.getMembers();
    for (Tree member : members) {
        if (member instanceof MethodTree) {
            MethodTree mTree = (MethodTree) member;
            ExecutableElement enclosing = TreeUtils.elementFromDeclaration(mTree);
            if (overrides(enclosing, Object.class, "equals")) {
                return true;
            }
        }
    }
    return false;
}
Also used : MethodTree(com.sun.source.tree.MethodTree) ExecutableElement(javax.lang.model.element.ExecutableElement) 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)

Example 23 with MethodTree

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

the class LockVisitor method visitSynchronized.

/**
 * When visiting a synchronized block, issue an error if the expression has a type that
 * implements the java.util.concurrent.locks.Lock interface. This prevents explicit locks from
 * being accidentally used as built-in (monitor) locks. This is important because the Lock
 * Checker does not have a mechanism to separately keep track of the explicit lock and the
 * monitor lock of an expression that implements the Lock interface (i.e. there is a @LockHeld
 * annotation used in dataflow, but there are not distinct @MonitorLockHeld
 * and @ExplicitLockHeld annotations). It is assumed that both kinds of locks will never be held
 * for any expression that implements Lock.
 *
 * <p>Additionally, a synchronized block may not be present in a method that has a @LockingFree
 * guarantee or stronger. An error is issued in this case.
 *
 * @param node the SynchronizedTree for the synchronized block being visited
 */
@Override
public Void visitSynchronized(SynchronizedTree node, Void p) {
    ProcessingEnvironment processingEnvironment = checker.getProcessingEnvironment();
    javax.lang.model.util.Types types = processingEnvironment.getTypeUtils();
    // TODO: make a type declaration annotation for this rather than looking for Lock.class
    // explicitly.
    TypeMirror lockInterfaceTypeMirror = TypesUtils.typeFromClass(Lock.class, types, processingEnvironment.getElementUtils());
    ExpressionTree synchronizedExpression = node.getExpression();
    ensureExpressionIsEffectivelyFinal(synchronizedExpression);
    TypeMirror expressionType = types.erasure(atypeFactory.getAnnotatedType(synchronizedExpression).getUnderlyingType());
    if (types.isSubtype(expressionType, lockInterfaceTypeMirror)) {
        checker.report(Result.failure("explicit.lock.synchronized"), node);
    }
    MethodTree enclosingMethod = TreeUtils.enclosingMethod(atypeFactory.getPath(node));
    ExecutableElement methodElement = null;
    if (enclosingMethod != null) {
        methodElement = TreeUtils.elementFromDeclaration(enclosingMethod);
        SideEffectAnnotation seaOfContainingMethod = atypeFactory.methodSideEffectAnnotation(methodElement, false);
        if (!seaOfContainingMethod.isWeakerThan(SideEffectAnnotation.LOCKINGFREE)) {
            checker.report(Result.failure("synchronized.block.in.lockingfree.method", seaOfContainingMethod), node);
        }
    }
    return super.visitSynchronized(node, p);
}
Also used : AnnotatedTypeMirror(org.checkerframework.framework.type.AnnotatedTypeMirror) TypeMirror(javax.lang.model.type.TypeMirror) MethodTree(com.sun.source.tree.MethodTree) ExecutableElement(javax.lang.model.element.ExecutableElement) ExpressionTree(com.sun.source.tree.ExpressionTree) SideEffectAnnotation(org.checkerframework.checker.lock.LockAnnotatedTypeFactory.SideEffectAnnotation) ProcessingEnvironment(javax.annotation.processing.ProcessingEnvironment)

Example 24 with MethodTree

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

the class LockVisitor method visitMethodInvocation.

/**
 * When visiting a method invocation, issue an error if the side effect annotation on the called
 * method causes the side effect guarantee of the enclosing method to be violated. For example,
 * a method annotated with @ReleasesNoLocks may not call a method annotated
 * with @MayReleaseLocks. Also check that matching @GuardSatisfied(index) on a method's formal
 * receiver/parameters matches those in corresponding locations on the method call site.
 *
 * @param node the MethodInvocationTree of the method call being visited
 */
@Override
public Void visitMethodInvocation(MethodInvocationTree node, Void p) {
    ExecutableElement methodElement = TreeUtils.elementFromUse(node);
    SideEffectAnnotation seaOfInvokedMethod = atypeFactory.methodSideEffectAnnotation(methodElement, false);
    MethodTree enclosingMethod = TreeUtils.enclosingMethod(atypeFactory.getPath(node));
    ExecutableElement enclosingMethodElement = null;
    if (enclosingMethod != null) {
        enclosingMethodElement = TreeUtils.elementFromDeclaration(enclosingMethod);
    }
    if (enclosingMethodElement != null) {
        SideEffectAnnotation seaOfContainingMethod = atypeFactory.methodSideEffectAnnotation(enclosingMethodElement, false);
        if (seaOfInvokedMethod.isWeakerThan(seaOfContainingMethod)) {
            checker.report(Result.failure("method.guarantee.violated", seaOfContainingMethod.getNameOfSideEffectAnnotation(), enclosingMethodElement.toString(), methodElement.toString(), seaOfInvokedMethod.getNameOfSideEffectAnnotation()), node);
        }
    }
    if (methodElement != null) {
        // Handle releasing of explicit locks. Verify that the lock expression is effectively
        // final.
        ExpressionTree recvTree = getReceiverTree(node);
        ensureReceiverOfExplicitUnlockCallIsEffectivelyFinal(node, methodElement, recvTree);
        // Handle acquiring of explicit locks. Verify that the lock expression is effectively
        // final.
        // If the method causes expression "this" or "#1" to be locked, verify that those
        // expressions are effectively final.  TODO: generalize to any expression. This is
        // currently designed only to support methods in ReentrantLock and
        // ReentrantReadWriteLock (which use the "this" expression), as well as Thread.holdsLock
        // (which uses the "#1" expression).
        AnnotationMirror ensuresLockHeldAnno = atypeFactory.getDeclAnnotation(methodElement, EnsuresLockHeld.class);
        List<String> expressions = new ArrayList<>();
        if (ensuresLockHeldAnno != null) {
            expressions.addAll(AnnotationUtils.getElementValueArray(ensuresLockHeldAnno, "value", String.class, false));
        }
        AnnotationMirror ensuresLockHeldIfAnno = atypeFactory.getDeclAnnotation(methodElement, EnsuresLockHeldIf.class);
        if (ensuresLockHeldIfAnno != null) {
            expressions.addAll(AnnotationUtils.getElementValueArray(ensuresLockHeldIfAnno, "expression", String.class, false));
        }
        for (String expr : expressions) {
            if (expr.equals("this")) {
                // are also final. So nothing to be checked for them.
                if (recvTree != null) {
                    ensureExpressionIsEffectivelyFinal(recvTree);
                }
            } else if (expr.equals("#1")) {
                ExpressionTree firstParameter = node.getArguments().get(0);
                if (firstParameter != null) {
                    ensureExpressionIsEffectivelyFinal(firstParameter);
                }
            }
        }
    }
    // Check that matching @GuardSatisfied(index) on a method's formal receiver/parameters
    // matches
    // those in corresponding locations on the method call site.
    Pair<AnnotatedExecutableType, List<AnnotatedTypeMirror>> mfuPair = atypeFactory.methodFromUse(node);
    AnnotatedExecutableType invokedMethod = mfuPair.first;
    List<AnnotatedTypeMirror> requiredArgs = AnnotatedTypes.expandVarArgs(atypeFactory, invokedMethod, node.getArguments());
    // Index on @GuardSatisfied at each location. -1 when no @GuardSatisfied annotation was
    // present.
    // Note that @GuardSatisfied with no index is normally represented as having index -1.
    // We would like to ignore a @GuardSatisfied with no index for these purposes, so if it is
    // encountered we leave its index as -1.
    // The first element of the array is reserved for the receiver.
    int[] guardSatisfiedIndex = // + 1 for the receiver parameter type
    new int[requiredArgs.size() + 1];
    // Retrieve receiver types from method definition and method call
    guardSatisfiedIndex[0] = -1;
    AnnotatedTypeMirror methodDefinitionReceiver = null;
    AnnotatedTypeMirror methodCallReceiver = null;
    ExecutableElement invokedMethodElement = invokedMethod.getElement();
    if (!ElementUtils.isStatic(invokedMethodElement) && invokedMethod.getElement().getKind() != ElementKind.CONSTRUCTOR) {
        methodDefinitionReceiver = invokedMethod.getReceiverType();
        if (methodDefinitionReceiver != null && methodDefinitionReceiver.hasAnnotation(checkerGuardSatisfiedClass)) {
            guardSatisfiedIndex[0] = atypeFactory.getGuardSatisfiedIndex(methodDefinitionReceiver);
            methodCallReceiver = atypeFactory.getReceiverType(node);
        }
    }
    for (int i = 0; i < requiredArgs.size(); i++) {
        guardSatisfiedIndex[i + 1] = -1;
        AnnotatedTypeMirror arg = requiredArgs.get(i);
        if (arg.hasAnnotation(checkerGuardSatisfiedClass)) {
            guardSatisfiedIndex[i + 1] = atypeFactory.getGuardSatisfiedIndex(arg);
        }
    }
    // Combine all of the actual parameters into one list of AnnotationMirrors
    ArrayList<AnnotationMirror> passedArgAnnotations = new ArrayList<>(guardSatisfiedIndex.length);
    passedArgAnnotations.add(methodCallReceiver == null ? null : methodCallReceiver.getAnnotationInHierarchy(atypeFactory.GUARDEDBYUNKNOWN));
    for (ExpressionTree tree : node.getArguments()) {
        passedArgAnnotations.add(atypeFactory.getAnnotatedType(tree).getAnnotationInHierarchy(atypeFactory.GUARDEDBYUNKNOWN));
    }
    for (int i = 0; i < guardSatisfiedIndex.length; i++) {
        if (guardSatisfiedIndex[i] != -1) {
            for (int j = i + 1; j < guardSatisfiedIndex.length; j++) {
                if (guardSatisfiedIndex[i] == guardSatisfiedIndex[j]) {
                    // The @GuardedBy/@GuardSatisfied/@GuardedByUnknown/@GuardedByBottom
                    // annotations must be identical on the corresponding actual parameters.
                    AnnotationMirror arg1Anno = passedArgAnnotations.get(i);
                    AnnotationMirror arg2Anno = passedArgAnnotations.get(j);
                    if (arg1Anno != null && arg2Anno != null) {
                        boolean bothAreGSwithNoIndex = false;
                        if (AnnotationUtils.areSameByClass(arg1Anno, checkerGuardSatisfiedClass) && AnnotationUtils.areSameByClass(arg2Anno, checkerGuardSatisfiedClass)) {
                            if (atypeFactory.getGuardSatisfiedIndex(arg1Anno) == -1 && atypeFactory.getGuardSatisfiedIndex(arg2Anno) == -1) {
                                // Generally speaking, two @GuardSatisfied annotations with no
                                // index are incomparable.
                                // TODO: If they come from the same variable, they are
                                // comparable.  Fix and add a test case.
                                bothAreGSwithNoIndex = true;
                            }
                        }
                        if (bothAreGSwithNoIndex || !(atypeFactory.getQualifierHierarchy().isSubtype(arg1Anno, arg2Anno) || atypeFactory.getQualifierHierarchy().isSubtype(arg2Anno, arg1Anno))) {
                            // TODO: allow these strings to be localized
                            String formalParam1 = null;
                            if (i == 0) {
                                formalParam1 = "The receiver type";
                            } else {
                                formalParam1 = "Parameter #" + // i, not i-1, so the index is 1-based
                                i;
                            }
                            String formalParam2 = // j, not j-1, so the index is 1-based
                            "parameter #" + j;
                            checker.report(Result.failure("guardsatisfied.parameters.must.match", formalParam1, formalParam2, invokedMethod.toString(), guardSatisfiedIndex[i], arg1Anno, arg2Anno), node);
                        }
                    }
                }
            }
        }
    }
    return super.visitMethodInvocation(node, p);
}
Also used : MethodTree(com.sun.source.tree.MethodTree) ExecutableElement(javax.lang.model.element.ExecutableElement) ArrayList(java.util.ArrayList) SideEffectAnnotation(org.checkerframework.checker.lock.LockAnnotatedTypeFactory.SideEffectAnnotation) AnnotatedTypeMirror(org.checkerframework.framework.type.AnnotatedTypeMirror) AnnotationMirror(javax.lang.model.element.AnnotationMirror) AnnotatedExecutableType(org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedExecutableType) ExpressionTree(com.sun.source.tree.ExpressionTree) List(java.util.List) ArrayList(java.util.ArrayList)

Example 25 with MethodTree

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

the class FormatterVisitor method isWrappedFormatCall.

/**
 * Returns true if fc is within a method m annotated as {@code @FormatMethod}, and fc's
 * arguments are m's formal parameters. In other words, fc forwards m's arguments to another
 * format method.
 */
private boolean isWrappedFormatCall(FormatCall fc) {
    MethodTree enclosingMethod = TreeUtils.enclosingMethod(atypeFactory.getPath(fc.node));
    if (enclosingMethod == null) {
        return false;
    }
    ExecutableElement enclosingMethodElement = TreeUtils.elementFromDeclaration(enclosingMethod);
    boolean withinFormatMethod = (atypeFactory.getDeclAnnotation(enclosingMethodElement, FormatMethod.class) != null);
    if (!withinFormatMethod) {
        return false;
    }
    List<? extends ExpressionTree> args = fc.node.getArguments();
    List<? extends VariableTree> params = enclosingMethod.getParameters();
    List<? extends VariableElement> paramElements = enclosingMethodElement.getParameters();
    // Strip off leading Locale arguments.
    if (args.size() > 0 && FormatterTreeUtil.isLocale(args.get(0), atypeFactory)) {
        args = args.subList(1, args.size());
    }
    if (params.size() > 0 && TypesUtils.isDeclaredOfName(paramElements.get(0).asType(), "java.util.Locale")) {
        params = params.subList(1, params.size());
    }
    if (args.size() == params.size()) {
        for (int i = 0; i < args.size(); i++) {
            ExpressionTree arg = args.get(i);
            if (!(arg instanceof IdentifierTree && ((IdentifierTree) arg).getName().equals(params.get(i).getName()))) {
                return false;
            }
        }
    }
    return true;
}
Also used : MethodTree(com.sun.source.tree.MethodTree) ExecutableElement(javax.lang.model.element.ExecutableElement) ExpressionTree(com.sun.source.tree.ExpressionTree) IdentifierTree(com.sun.source.tree.IdentifierTree)

Aggregations

MethodTree (com.sun.source.tree.MethodTree)91 Tree (com.sun.source.tree.Tree)46 ClassTree (com.sun.source.tree.ClassTree)45 VariableTree (com.sun.source.tree.VariableTree)39 ExpressionTree (com.sun.source.tree.ExpressionTree)36 MethodInvocationTree (com.sun.source.tree.MethodInvocationTree)28 MethodSymbol (com.sun.tools.javac.code.Symbol.MethodSymbol)22 LambdaExpressionTree (com.sun.source.tree.LambdaExpressionTree)20 TreePath (com.sun.source.util.TreePath)20 IdentifierTree (com.sun.source.tree.IdentifierTree)19 NewClassTree (com.sun.source.tree.NewClassTree)19 ReturnTree (com.sun.source.tree.ReturnTree)18 ExecutableElement (javax.lang.model.element.ExecutableElement)17 Symbol (com.sun.tools.javac.code.Symbol)16 ArrayList (java.util.ArrayList)15 AssignmentTree (com.sun.source.tree.AssignmentTree)14 BlockTree (com.sun.source.tree.BlockTree)14 CompilationUnitTree (com.sun.source.tree.CompilationUnitTree)14 ConditionalExpressionTree (com.sun.source.tree.ConditionalExpressionTree)14 MemberSelectTree (com.sun.source.tree.MemberSelectTree)14