Search in sources :

Example 76 with AnnotatedTypeMirror

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

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

the class LockVisitor method visitVariable.

@Override
public Void visitVariable(VariableTree node, Void p) {
    // visit a variable declaration
    // A user may not annotate a primitive type, a boxed primitive type or a String
    // with any qualifier from the @GuardedBy hierarchy.
    // They are immutable, so there is no need to guard them.
    TypeMirror tm = TreeUtils.typeOf(node);
    if (TypesUtils.isBoxedPrimitive(tm) || TypesUtils.isPrimitive(tm) || TypesUtils.isString(tm)) {
        AnnotatedTypeMirror atm = atypeFactory.getAnnotatedType(node);
        if (atm.hasExplicitAnnotationRelaxed(atypeFactory.GUARDSATISFIED) || atm.hasExplicitAnnotationRelaxed(atypeFactory.GUARDEDBY) || atm.hasExplicitAnnotation(atypeFactory.GUARDEDBYUNKNOWN) || atm.hasExplicitAnnotation(atypeFactory.GUARDEDBYBOTTOM)) {
            checker.report(Result.failure("immutable.type.guardedby"), node);
        }
    }
    issueErrorIfMoreThanOneGuardedByAnnotationPresent(node);
    return super.visitVariable(node, p);
}
Also used : AnnotatedTypeMirror(org.checkerframework.framework.type.AnnotatedTypeMirror) TypeMirror(javax.lang.model.type.TypeMirror) AnnotatedTypeMirror(org.checkerframework.framework.type.AnnotatedTypeMirror)

Example 78 with AnnotatedTypeMirror

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

the class CollectionToArrayHeuristics method setComponentNullness.

/**
 * Sets the nullness of the component of the array type.
 *
 * @param isNonNull indicates which annotation ({@code NonNull} or {@code Nullable}) should be
 *     inserted
 * @param type the array type
 */
private void setComponentNullness(boolean isNonNull, AnnotatedTypeMirror type) {
    assert type.getKind() == TypeKind.ARRAY;
    AnnotatedTypeMirror compType = ((AnnotatedArrayType) type).getComponentType();
    compType.replaceAnnotation(isNonNull ? atypeFactory.NONNULL : atypeFactory.NULLABLE);
}
Also used : AnnotatedArrayType(org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedArrayType) AnnotatedTypeMirror(org.checkerframework.framework.type.AnnotatedTypeMirror)

Example 79 with AnnotatedTypeMirror

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

the class KeyForPropagator method propagate.

/**
 * Propagate annotations from the type arguments of one type to another. Which type is the
 * source and destination of the annotations depends on the direction parameter. Only @KeyFor
 * annotations are propagated and only if the type to which it would be propagated contains
 * an @UnknownKeyFor or contains no key for annotations of any kind. If any of the type
 * arguments are wildcards than they are ignored.
 *
 * <p>Note the primary annotations of subtype/supertype are not used.
 *
 * <p>Simple Example:
 *
 * <pre>{@code
 * typeOf(subtype) = ArrayList<@KeyFor("a") String>
 * typeOf(supertype) = List<@UnknownKeyFor String>
 * direction = TO_SUPERTYPE
 * }</pre>
 *
 * The type of supertype after propagate would be: {@code List<@KeyFor("a") String>}
 *
 * <p>A more complex example would be:
 *
 * <pre>{@code
 * typeOf(subtype) = HashMap<@UnknownKeyFor String, @KeyFor("b") List<@KeyFor("c") String>>
 * typeOf(supertype) = Map<@KeyFor("a") String, @KeyFor("b") List<@KeyFor("c") String>>
 * direction = TO_SUBTYPE
 * }</pre>
 *
 * The type of subtype after propagate would be: {@code HashMap<@KeyFor("a")
 * String, @KeyFor("b") List<@KeyFor("c") String>>}
 */
public void propagate(final AnnotatedDeclaredType subtype, final AnnotatedDeclaredType supertype, PropagationDirection direction, final AnnotatedTypeFactory typeFactory) {
    final TypeElement subtypeElement = (TypeElement) subtype.getUnderlyingType().asElement();
    final TypeElement supertypeElement = (TypeElement) supertype.getUnderlyingType().asElement();
    final Types types = typeFactory.getProcessingEnv().getTypeUtils();
    // Note: The right hand side of this or expression will cover raw types
    if (subtype.getTypeArguments().isEmpty()) {
        return;
    }
    // In either case, there is no reason to propagate
    if (supertype.getTypeArguments().isEmpty()) {
        return;
    }
    Set<Pair<Integer, Integer>> typeParamMappings = TypeArgumentMapper.mapTypeArgumentIndices(subtypeElement, supertypeElement, types);
    KeyForPropagationMerger merger = new KeyForPropagationMerger(typeFactory.getProcessingEnv());
    final List<AnnotatedTypeMirror> subtypeArgs = subtype.getTypeArguments();
    final List<AnnotatedTypeMirror> supertypeArgs = supertype.getTypeArguments();
    for (final Pair<Integer, Integer> path : typeParamMappings) {
        final AnnotatedTypeMirror subtypeArg = subtypeArgs.get(path.first);
        final AnnotatedTypeMirror supertypeArg = supertypeArgs.get(path.second);
        if (subtypeArg.getKind() == TypeKind.WILDCARD || supertypeArg.getKind() == TypeKind.WILDCARD) {
            continue;
        }
        switch(direction) {
            case TO_SUBTYPE:
                merger.visit(supertypeArg, subtypeArg);
                break;
            case TO_SUPERTYPE:
                merger.visit(subtypeArg, supertypeArg);
                break;
            case BOTH:
                // note if they both have an annotation nothing will happen
                merger.visit(subtypeArg, supertypeArg);
                merger.visit(supertypeArg, subtypeArg);
                break;
        }
    }
}
Also used : Types(javax.lang.model.util.Types) TypeElement(javax.lang.model.element.TypeElement) AnnotatedTypeMirror(org.checkerframework.framework.type.AnnotatedTypeMirror) Pair(org.checkerframework.javacutil.Pair)

Example 80 with AnnotatedTypeMirror

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

the class NullnessAnnotatedTypeFactory method getMethodReturnType.

@Override
public AnnotatedTypeMirror getMethodReturnType(MethodTree m, ReturnTree r) {
    AnnotatedTypeMirror result = super.getMethodReturnType(m, r);
    replacePolyQualifier(result, r);
    return result;
}
Also used : AnnotatedTypeMirror(org.checkerframework.framework.type.AnnotatedTypeMirror)

Aggregations

AnnotatedTypeMirror (org.checkerframework.framework.type.AnnotatedTypeMirror)188 AnnotationMirror (javax.lang.model.element.AnnotationMirror)42 ExpressionTree (com.sun.source.tree.ExpressionTree)32 AnnotatedDeclaredType (org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedDeclaredType)27 Tree (com.sun.source.tree.Tree)25 AnnotatedTypeVariable (org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedTypeVariable)25 VariableTree (com.sun.source.tree.VariableTree)22 ArrayList (java.util.ArrayList)22 AnnotatedExecutableType (org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedExecutableType)21 MethodTree (com.sun.source.tree.MethodTree)20 TypeVariable (javax.lang.model.type.TypeVariable)19 MethodInvocationTree (com.sun.source.tree.MethodInvocationTree)18 AnnotatedArrayType (org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedArrayType)17 LambdaExpressionTree (com.sun.source.tree.LambdaExpressionTree)16 TypeMirror (javax.lang.model.type.TypeMirror)16 VariableElement (javax.lang.model.element.VariableElement)15 ConditionalExpressionTree (com.sun.source.tree.ConditionalExpressionTree)13 MemberSelectTree (com.sun.source.tree.MemberSelectTree)13 NewClassTree (com.sun.source.tree.NewClassTree)13 Element (javax.lang.model.element.Element)13