Search in sources :

Example 16 with AnnotatedExecutableType

use of org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedExecutableType in project checker-framework by typetools.

the class BaseTypeVisitor method visitLambdaExpression.

@Override
public Void visitLambdaExpression(LambdaExpressionTree node, Void p) {
    Pair<AnnotatedDeclaredType, AnnotatedExecutableType> result = atypeFactory.getFnInterfaceFromTree(node);
    AnnotatedExecutableType functionType = result.second;
    if (node.getBody().getKind() != Tree.Kind.BLOCK) {
        // Check return type for single statement returns here.
        AnnotatedTypeMirror ret = functionType.getReturnType();
        if (ret.getKind() != TypeKind.VOID) {
            visitorState.setAssignmentContext(Pair.of((Tree) node, ret));
            commonAssignmentCheck(ret, (ExpressionTree) node.getBody(), "return.type.incompatible");
        }
    }
    // Check parameters
    for (int i = 0; i < functionType.getParameterTypes().size(); ++i) {
        AnnotatedTypeMirror lambdaParameter = atypeFactory.getAnnotatedType(node.getParameters().get(i));
        commonAssignmentCheck(lambdaParameter, functionType.getParameterTypes().get(i), node.getParameters().get(i), "lambda.param.type.incompatible");
    }
    return super.visitLambdaExpression(node, p);
}
Also used : AnnotatedExecutableType(org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedExecutableType) AnnotatedDeclaredType(org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedDeclaredType) CompoundAssignmentTree(com.sun.source.tree.CompoundAssignmentTree) MethodInvocationTree(com.sun.source.tree.MethodInvocationTree) AssignmentTree(com.sun.source.tree.AssignmentTree) TypeCastTree(com.sun.source.tree.TypeCastTree) LambdaExpressionTree(com.sun.source.tree.LambdaExpressionTree) InstanceOfTree(com.sun.source.tree.InstanceOfTree) ConditionalExpressionTree(com.sun.source.tree.ConditionalExpressionTree) MemberSelectTree(com.sun.source.tree.MemberSelectTree) ThrowTree(com.sun.source.tree.ThrowTree) EnhancedForLoopTree(com.sun.source.tree.EnhancedForLoopTree) ReturnTree(com.sun.source.tree.ReturnTree) UnaryTree(com.sun.source.tree.UnaryTree) VariableTree(com.sun.source.tree.VariableTree) TypeParameterTree(com.sun.source.tree.TypeParameterTree) NewClassTree(com.sun.source.tree.NewClassTree) ParameterizedTypeTree(com.sun.source.tree.ParameterizedTypeTree) Tree(com.sun.source.tree.Tree) ExpressionTree(com.sun.source.tree.ExpressionTree) ArrayAccessTree(com.sun.source.tree.ArrayAccessTree) IdentifierTree(com.sun.source.tree.IdentifierTree) CatchTree(com.sun.source.tree.CatchTree) NewArrayTree(com.sun.source.tree.NewArrayTree) CompilationUnitTree(com.sun.source.tree.CompilationUnitTree) AnnotationTree(com.sun.source.tree.AnnotationTree) MethodTree(com.sun.source.tree.MethodTree) ClassTree(com.sun.source.tree.ClassTree) MemberReferenceTree(com.sun.source.tree.MemberReferenceTree) JCTree(com.sun.tools.javac.tree.JCTree) AnnotatedTypeMirror(org.checkerframework.framework.type.AnnotatedTypeMirror)

Example 17 with AnnotatedExecutableType

use of org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedExecutableType 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 18 with AnnotatedExecutableType

use of org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedExecutableType in project checker-framework by typetools.

the class CFAbstractTransfer method getValueFromFactory.

/**
 * @return the abstract value of a non-leaf tree {@code tree}, as computed by the {@link
 *     AnnotatedTypeFactory}.
 */
protected V getValueFromFactory(Tree tree, Node node) {
    GenericAnnotatedTypeFactory<V, S, T, ? extends CFAbstractAnalysis<V, S, T>> factory = analysis.atypeFactory;
    Tree preTree = analysis.getCurrentTree();
    Pair<Tree, AnnotatedTypeMirror> preCtxt = factory.getVisitorState().getAssignmentContext();
    analysis.setCurrentTree(tree);
    // is there an assignment context node available?
    if (node != null && node.getAssignmentContext() != null) {
        // get the declared type of the assignment context by looking up the
        // assignment context tree's type in the factory while flow is
        // disabled.
        Tree contextTree = node.getAssignmentContext().getContextTree();
        AnnotatedTypeMirror assCtxt = null;
        if (contextTree != null) {
            assCtxt = factory.getAnnotatedTypeLhs(contextTree);
        } else {
            Element assCtxtElement = node.getAssignmentContext().getElementForType();
            if (assCtxtElement != null) {
                // if contextTree is null, use the element to get the type
                assCtxt = factory.getAnnotatedType(assCtxtElement);
            }
        }
        if (assCtxt != null) {
            if (assCtxt instanceof AnnotatedExecutableType) {
                // For a MethodReturnContext, we get the full type of the
                // method, but we only want the return type.
                assCtxt = ((AnnotatedExecutableType) assCtxt).getReturnType();
            }
            factory.getVisitorState().setAssignmentContext(Pair.of(node.getAssignmentContext().getContextTree(), assCtxt));
        }
    }
    AnnotatedTypeMirror at = factory.getAnnotatedType(tree);
    analysis.setCurrentTree(preTree);
    factory.getVisitorState().setAssignmentContext(preCtxt);
    return analysis.createAbstractValue(at);
}
Also used : AnnotatedExecutableType(org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedExecutableType) UnderlyingAST(org.checkerframework.dataflow.cfg.UnderlyingAST) Element(javax.lang.model.element.Element) VariableElement(javax.lang.model.element.VariableElement) ExecutableElement(javax.lang.model.element.ExecutableElement) MethodTree(com.sun.source.tree.MethodTree) VariableTree(com.sun.source.tree.VariableTree) Tree(com.sun.source.tree.Tree) ClassTree(com.sun.source.tree.ClassTree) AnnotatedTypeMirror(org.checkerframework.framework.type.AnnotatedTypeMirror)

Example 19 with AnnotatedExecutableType

use of org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedExecutableType in project checker-framework by typetools.

the class StubParser method processCallableDeclaration.

/**
 * Adds type and declaration annotations from {@code decl}.
 */
private void processCallableDeclaration(CallableDeclaration<?> decl, ExecutableElement elt) {
    // Declaration annotations
    annotateDecl(declAnnos, elt, decl.getAnnotations());
    if (decl.isMethodDeclaration()) {
        // StubParser parses all annotations in type annotation position as type annotations
        annotateDecl(declAnnos, elt, ((MethodDeclaration) decl).getType().getAnnotations());
    }
    addDeclAnnotations(declAnnos, elt);
    AnnotatedExecutableType methodType = atypeFactory.fromElement(elt);
    // Type Parameters
    annotateTypeParameters(decl, elt, atypes, methodType.getTypeVariables(), decl.getTypeParameters());
    typeParameters.addAll(methodType.getTypeVariables());
    // Type annotations
    if (decl.isMethodDeclaration()) {
        annotate(methodType.getReturnType(), ((MethodDeclaration) decl).getType(), decl.getAnnotations());
    } else {
        annotate(methodType.getReturnType(), decl.getAnnotations());
    }
    // Parameters
    processParameters(decl, elt, declAnnos, methodType);
    // Receiver
    if (decl.getReceiverParameter().isPresent() && !decl.getReceiverParameter().get().getAnnotations().isEmpty()) {
        if (methodType.getReceiverType() == null) {
            if (decl.isConstructorDeclaration()) {
                stubWarn("parseParameter: constructor of a top-level class cannot have receiver annotations%n" + "Constructor: %s%n" + "Receiver annotations: %s", methodType, decl.getReceiverParameter().get().getAnnotations());
            } else {
                stubWarn("parseParameter: static methods cannot have receiver annotations%n" + "Method: %s%n" + "Receiver annotations: %s", methodType, decl.getReceiverParameter().get().getAnnotations());
            }
        } else {
            annotate(methodType.getReceiverType(), decl.getReceiverParameter().get().getAnnotations());
        }
    }
    // Store the type.
    putNew(atypes, elt, methodType);
    typeParameters.removeAll(methodType.getTypeVariables());
}
Also used : AnnotatedExecutableType(org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedExecutableType) MethodDeclaration(com.github.javaparser.ast.body.MethodDeclaration)

Example 20 with AnnotatedExecutableType

use of org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedExecutableType in project checker-framework by typetools.

the class AnnotatedTypeCopier method visitExecutable.

@Override
public AnnotatedTypeMirror visitExecutable(AnnotatedExecutableType original, IdentityHashMap<AnnotatedTypeMirror, AnnotatedTypeMirror> originalToCopy) {
    if (originalToCopy.containsKey(original)) {
        return originalToCopy.get(original);
    }
    final AnnotatedExecutableType copy = (AnnotatedExecutableType) AnnotatedTypeMirror.createType(original.getUnderlyingType(), original.atypeFactory, original.isDeclaration());
    maybeCopyPrimaryAnnotations(original, copy);
    originalToCopy.put(original, copy);
    copy.setElement(original.getElement());
    if (original.receiverType != null) {
        copy.receiverType = (AnnotatedDeclaredType) visit(original.receiverType, originalToCopy);
    }
    for (final AnnotatedTypeMirror param : original.paramTypes) {
        copy.paramTypes.add(visit(param, originalToCopy));
    }
    for (final AnnotatedTypeMirror thrown : original.throwsTypes) {
        copy.throwsTypes.add(visit(thrown, originalToCopy));
    }
    copy.returnType = visit(original.returnType, originalToCopy);
    for (final AnnotatedTypeVariable typeVariable : original.typeVarTypes) {
        // This field is needed to identify exactly when the declaration of an executable's
        // type parameter is visited.  When subtypes of this class visit the type parameter's
        // component types, they will likely set visitingExecutableTypeParam to false.
        // Therefore, we set this variable on each iteration of the loop.
        // See TypeVariableSubstitutor.Visitor.visitTypeVariable for an example of this.
        visitingExecutableTypeParam = true;
        copy.typeVarTypes.add((AnnotatedTypeVariable) visit(typeVariable, originalToCopy));
    }
    visitingExecutableTypeParam = false;
    return copy;
}
Also used : AnnotatedExecutableType(org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedExecutableType) AnnotatedTypeVariable(org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedTypeVariable)

Aggregations

AnnotatedExecutableType (org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedExecutableType)42 AnnotatedTypeMirror (org.checkerframework.framework.type.AnnotatedTypeMirror)19 ExecutableElement (javax.lang.model.element.ExecutableElement)17 ArrayList (java.util.ArrayList)15 AnnotatedDeclaredType (org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedDeclaredType)15 ExpressionTree (com.sun.source.tree.ExpressionTree)13 MethodTree (com.sun.source.tree.MethodTree)13 List (java.util.List)13 LambdaExpressionTree (com.sun.source.tree.LambdaExpressionTree)12 MethodInvocationTree (com.sun.source.tree.MethodInvocationTree)12 Tree (com.sun.source.tree.Tree)12 VariableTree (com.sun.source.tree.VariableTree)12 ConditionalExpressionTree (com.sun.source.tree.ConditionalExpressionTree)9 AssignmentTree (com.sun.source.tree.AssignmentTree)7 ClassTree (com.sun.source.tree.ClassTree)7 NewArrayTree (com.sun.source.tree.NewArrayTree)7 ReturnTree (com.sun.source.tree.ReturnTree)7 NewClassTree (com.sun.source.tree.NewClassTree)6 VariableElement (javax.lang.model.element.VariableElement)6 AnnotationTree (com.sun.source.tree.AnnotationTree)5