Search in sources :

Example 11 with AnnotatedExecutableType

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

the class AliasingTransfer method processPostconditions.

/**
 * Handling pseudo-assignments. Called by {@code CFAbstractTransfer.visitMethodInvocation()}.
 *
 * <p>Case 2: Given a method call, traverses all formal parameters of the method declaration,
 * and if it doesn't have the {@literal @}NonLeaked or {@literal @}LeakedToResult annotations,
 * we remove the node of the respective argument in the method call from the store. If parameter
 * has {@literal @}LeakedToResult, {@code visitMethodInvocation()} handles it.
 */
@Override
protected void processPostconditions(MethodInvocationNode n, CFStore store, ExecutableElement methodElement, Tree tree) {
    super.processPostconditions(n, store, methodElement, tree);
    if (TreeUtils.isEnumSuper(n.getTree())) {
        // Skipping the init() method for enums.
        return;
    }
    List<Node> args = n.getArguments();
    List<? extends VariableElement> params = methodElement.getParameters();
    assert (args.size() == params.size()) : "Number of arguments in " + "the method call " + n.toString() + " is different from the" + " number of parameters for the method declaration: " + methodElement.getSimpleName().toString();
    AnnotatedExecutableType annotatedType = factory.getAnnotatedType(methodElement);
    List<AnnotatedTypeMirror> paramTypes = annotatedType.getParameterTypes();
    for (int i = 0; i < args.size(); i++) {
        Node arg = args.get(i);
        AnnotatedTypeMirror paramType = paramTypes.get(i);
        if (!paramType.hasAnnotation(NonLeaked.class) && !paramType.hasAnnotation(LeakedToResult.class)) {
            store.clearValue(FlowExpressions.internalReprOf(factory, arg));
        }
    }
    // Now, doing the same as above for the receiver parameter
    Node receiver = n.getTarget().getReceiver();
    AnnotatedDeclaredType receiverType = annotatedType.getReceiverType();
    if (receiverType != null && !receiverType.hasAnnotation(LeakedToResult.class) && !receiverType.hasAnnotation(NonLeaked.class)) {
        store.clearValue(FlowExpressions.internalReprOf(factory, receiver));
    }
}
Also used : AnnotatedExecutableType(org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedExecutableType) AssignmentNode(org.checkerframework.dataflow.cfg.node.AssignmentNode) ObjectCreationNode(org.checkerframework.dataflow.cfg.node.ObjectCreationNode) MethodInvocationNode(org.checkerframework.dataflow.cfg.node.MethodInvocationNode) Node(org.checkerframework.dataflow.cfg.node.Node) AnnotatedDeclaredType(org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedDeclaredType) LeakedToResult(org.checkerframework.common.aliasing.qual.LeakedToResult) AnnotatedTypeMirror(org.checkerframework.framework.type.AnnotatedTypeMirror)

Example 12 with AnnotatedExecutableType

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

the class BaseTypeVisitor method visitAnnotation.

/* TODO: something similar to visitReturn should be done.
     * public Void visitThrow(ThrowTree node, Void p) {
     * return super.visitThrow(node, p);
     * }
     */
/**
 * Ensure that the annotation arguments comply to their declarations. This needs some special
 * casing, as annotation arguments form special trees.
 */
@Override
public Void visitAnnotation(AnnotationTree node, Void p) {
    List<? extends ExpressionTree> args = node.getArguments();
    if (args.isEmpty()) {
        // Nothing to do if there are no annotation arguments.
        return null;
    }
    TypeElement anno = (TypeElement) TreeInfo.symbol((JCTree) node.getAnnotationType());
    Name annoName = anno.getQualifiedName();
    if (annoName.contentEquals(DefaultQualifier.class.getName()) || annoName.contentEquals(SuppressWarnings.class.getName())) {
        // Skip these two annotations, as we don't care about the arguments to them.
        return null;
    }
    // Mapping from argument simple name to its annotated type.
    Map<String, AnnotatedTypeMirror> annoTypes = new HashMap<>();
    for (Element encl : ElementFilter.methodsIn(anno.getEnclosedElements())) {
        AnnotatedExecutableType exeatm = (AnnotatedExecutableType) atypeFactory.getAnnotatedType(encl);
        AnnotatedTypeMirror retty = exeatm.getReturnType();
        annoTypes.put(encl.getSimpleName().toString(), retty);
    }
    for (ExpressionTree arg : args) {
        if (!(arg instanceof AssignmentTree)) {
            // TODO: when can this happen?
            continue;
        }
        AssignmentTree at = (AssignmentTree) arg;
        // we don't have a type for annotations.
        if (at.getExpression().getKind() == Tree.Kind.ANNOTATION) {
            visitAnnotation((AnnotationTree) at.getExpression(), p);
            continue;
        }
        if (at.getExpression().getKind() == Tree.Kind.NEW_ARRAY) {
            NewArrayTree nat = (NewArrayTree) at.getExpression();
            boolean isAnno = false;
            for (ExpressionTree init : nat.getInitializers()) {
                if (init.getKind() == Tree.Kind.ANNOTATION) {
                    visitAnnotation((AnnotationTree) init, p);
                    isAnno = true;
                }
            }
            if (isAnno) {
                continue;
            }
        }
        AnnotatedTypeMirror expected = annoTypes.get(at.getVariable().toString());
        Pair<Tree, AnnotatedTypeMirror> preAssCtxt = visitorState.getAssignmentContext();
        {
            // Determine and set the new assignment context.
            ExpressionTree var = at.getVariable();
            assert var instanceof IdentifierTree : "Expected IdentifierTree as context. Found: " + var;
            AnnotatedTypeMirror meth = atypeFactory.getAnnotatedType(var);
            assert meth instanceof AnnotatedExecutableType : "Expected AnnotatedExecutableType as context. Found: " + meth;
            AnnotatedTypeMirror newctx = ((AnnotatedExecutableType) meth).getReturnType();
            visitorState.setAssignmentContext(Pair.of((Tree) null, newctx));
        }
        try {
            AnnotatedTypeMirror actual = atypeFactory.getAnnotatedType(at.getExpression());
            if (expected.getKind() != TypeKind.ARRAY) {
                // Expected is not an array -> direct comparison.
                commonAssignmentCheck(expected, actual, at.getExpression(), "annotation.type.incompatible");
            } else {
                if (actual.getKind() == TypeKind.ARRAY) {
                    // Both actual and expected are arrays.
                    commonAssignmentCheck(expected, actual, at.getExpression(), "annotation.type.incompatible");
                } else {
                    // The declaration is an array type, but just a single
                    // element is given.
                    commonAssignmentCheck(((AnnotatedArrayType) expected).getComponentType(), actual, at.getExpression(), "annotation.type.incompatible");
                }
            }
        } finally {
            visitorState.setAssignmentContext(preAssCtxt);
        }
    }
    return null;
}
Also used : HashMap(java.util.HashMap) 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) JCTree(com.sun.tools.javac.tree.JCTree) IdentifierTree(com.sun.source.tree.IdentifierTree) AnnotatedTypeMirror(org.checkerframework.framework.type.AnnotatedTypeMirror) Name(javax.lang.model.element.Name) AnnotatedExecutableType(org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedExecutableType) NewArrayTree(com.sun.source.tree.NewArrayTree) LambdaExpressionTree(com.sun.source.tree.LambdaExpressionTree) ConditionalExpressionTree(com.sun.source.tree.ConditionalExpressionTree) ExpressionTree(com.sun.source.tree.ExpressionTree) 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) CompoundAssignmentTree(com.sun.source.tree.CompoundAssignmentTree) AssignmentTree(com.sun.source.tree.AssignmentTree)

Example 13 with AnnotatedExecutableType

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

the class BaseTypeVisitor method visitMethodInvocation.

/**
 * Performs a method invocation check.
 *
 * <p>An invocation of a method, m, on the receiver, r is valid only if:
 *
 * <ul>
 *   <li>passed arguments are subtypes of corresponding m parameters
 *   <li>r is a subtype of m receiver type
 *   <li>if m is generic, passed type arguments are subtypes of m type variables
 * </ul>
 */
@Override
public Void visitMethodInvocation(MethodInvocationTree node, Void p) {
    // hard to check), also see CFGBuilder.visitMethodInvocation.
    if (TreeUtils.elementFromUse(node) == null || TreeUtils.isEnumSuper(node)) {
        return super.visitMethodInvocation(node, p);
    }
    if (shouldSkipUses(node)) {
        return super.visitMethodInvocation(node, p);
    }
    Pair<AnnotatedExecutableType, List<AnnotatedTypeMirror>> mfuPair = atypeFactory.methodFromUse(node);
    AnnotatedExecutableType invokedMethod = mfuPair.first;
    List<AnnotatedTypeMirror> typeargs = mfuPair.second;
    if (!atypeFactory.ignoreUninferredTypeArguments) {
        for (AnnotatedTypeMirror typearg : typeargs) {
            if (typearg.getKind() == TypeKind.WILDCARD && ((AnnotatedWildcardType) typearg).isUninferredTypeArgument()) {
                checker.report(Result.failure("type.arguments.not.inferred", invokedMethod.getElement().getSimpleName()), node);
                // only issue error once per method
                break;
            }
        }
    }
    List<AnnotatedTypeParameterBounds> paramBounds = new ArrayList<>();
    for (AnnotatedTypeVariable param : invokedMethod.getTypeVariables()) {
        paramBounds.add(param.getBounds());
    }
    checkTypeArguments(node, paramBounds, typeargs, node.getTypeArguments());
    List<AnnotatedTypeMirror> params = AnnotatedTypes.expandVarArgs(atypeFactory, invokedMethod, node.getArguments());
    checkArguments(params, node.getArguments());
    checkVarargs(invokedMethod, node);
    if (isVectorCopyInto(invokedMethod)) {
        typeCheckVectorCopyIntoArgument(node, params);
    }
    ExecutableElement invokedMethodElement = invokedMethod.getElement();
    if (!ElementUtils.isStatic(invokedMethodElement) && !TreeUtils.isSuperCall(node)) {
        checkMethodInvocability(invokedMethod, node);
    }
    // check precondition annotations
    checkPreconditions(node, contractsUtils.getPreconditions(invokedMethodElement));
    // Do not call super, as that would observe the arguments without
    // a set assignment context.
    scan(node.getMethodSelect(), p);
    // super.visitMethodInvocation(node, p);
    return null;
}
Also used : AnnotatedTypeParameterBounds(org.checkerframework.framework.type.AnnotatedTypeParameterBounds) AnnotatedExecutableType(org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedExecutableType) ExecutableElement(javax.lang.model.element.ExecutableElement) ArrayList(java.util.ArrayList) ArrayList(java.util.ArrayList) List(java.util.List) AnnotatedTypeMirror(org.checkerframework.framework.type.AnnotatedTypeMirror) AnnotatedTypeVariable(org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedTypeVariable)

Example 14 with AnnotatedExecutableType

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

the class BaseTypeVisitor method visitMethod.

/**
 * Performs pseudo-assignment check: checks that the method obeys override and subtype rules to
 * all overridden methods.
 *
 * <p>The override rule specifies that a method, m1, may override a method m2 only if:
 *
 * <ul>
 *   <li>m1 return type is a subtype of m2
 *   <li>m1 receiver type is a supertype of m2
 *   <li>m1 parameters are supertypes of corresponding m2 parameters
 * </ul>
 *
 * Also, it issues a "missing.this" error for static method annotated receivers.
 */
@Override
public Void visitMethod(MethodTree node, Void p) {
    // We copy the result from getAnnotatedType to ensure that
    // circular types (e.g. K extends Comparable<K>) are represented
    // by circular AnnotatedTypeMirrors, which avoids problems with
    // later checks.
    // TODO: Find a cleaner way to ensure circular AnnotatedTypeMirrors.
    AnnotatedExecutableType methodType = atypeFactory.getAnnotatedType(node).deepCopy();
    AnnotatedDeclaredType preMRT = visitorState.getMethodReceiver();
    MethodTree preMT = visitorState.getMethodTree();
    visitorState.setMethodReceiver(methodType.getReceiverType());
    visitorState.setMethodTree(node);
    ExecutableElement methodElement = TreeUtils.elementFromDeclaration(node);
    try {
        if (TreeUtils.isAnonymousConstructor(node)) {
            // We shouldn't dig deeper
            return null;
        }
        // check method purity if needed
        {
            boolean anyPurityAnnotation = PurityUtils.hasPurityAnnotation(atypeFactory, node);
            boolean checkPurityAlways = checker.hasOption("suggestPureMethods");
            boolean checkPurityAnnotations = checker.hasOption("checkPurityAnnotations");
            if (checkPurityAnnotations && (anyPurityAnnotation || checkPurityAlways)) {
                // check "no" purity
                List<Pure.Kind> kinds = PurityUtils.getPurityKinds(atypeFactory, node);
                // @Deterministic makes no sense for a void method or constructor
                boolean isDeterministic = kinds.contains(Pure.Kind.DETERMINISTIC);
                if (isDeterministic) {
                    if (TreeUtils.isConstructor(node)) {
                        checker.report(Result.warning("purity.deterministic.constructor"), node);
                    } else if (TreeUtils.typeOf(node.getReturnType()).getKind() == TypeKind.VOID) {
                        checker.report(Result.warning("purity.deterministic.void.method"), node);
                    }
                }
                // Report errors if necessary.
                PurityResult r = PurityChecker.checkPurity(atypeFactory.getPath(node.getBody()), atypeFactory, checker.hasOption("assumeSideEffectFree"));
                if (!r.isPure(kinds)) {
                    reportPurityErrors(r, node, kinds);
                }
                // as such (if the feature is activated).
                if (checkPurityAlways) {
                    Collection<Pure.Kind> additionalKinds = new HashSet<>(r.getTypes());
                    additionalKinds.removeAll(kinds);
                    if (TreeUtils.isConstructor(node)) {
                        additionalKinds.remove(Pure.Kind.DETERMINISTIC);
                    }
                    if (!additionalKinds.isEmpty()) {
                        if (additionalKinds.size() == 2) {
                            checker.report(Result.warning("purity.more.pure", node.getName()), node);
                        } else if (additionalKinds.contains(Pure.Kind.SIDE_EFFECT_FREE)) {
                            checker.report(Result.warning("purity.more.sideeffectfree", node.getName()), node);
                        } else if (additionalKinds.contains(Pure.Kind.DETERMINISTIC)) {
                            checker.report(Result.warning("purity.more.deterministic", node.getName()), node);
                        } else {
                            assert false : "BaseTypeVisitor reached undesirable state";
                        }
                    }
                }
            }
        }
        // Passing the whole method/constructor validates the return type
        validateTypeOf(node);
        // Validate types in throws clauses
        for (ExpressionTree thr : node.getThrows()) {
            validateTypeOf(thr);
        }
        if (atypeFactory.getDependentTypesHelper() != null) {
            atypeFactory.getDependentTypesHelper().checkMethod(node, methodType);
        }
        AnnotatedDeclaredType enclosingType = (AnnotatedDeclaredType) atypeFactory.getAnnotatedType(methodElement.getEnclosingElement());
        // Find which method this overrides!
        Map<AnnotatedDeclaredType, ExecutableElement> overriddenMethods = AnnotatedTypes.overriddenMethods(elements, atypeFactory, methodElement);
        for (Map.Entry<AnnotatedDeclaredType, ExecutableElement> pair : overriddenMethods.entrySet()) {
            AnnotatedDeclaredType overriddenType = pair.getKey();
            AnnotatedExecutableType overriddenMethod = AnnotatedTypes.asMemberOf(types, atypeFactory, overriddenType, pair.getValue());
            if (!checkOverride(node, enclosingType, overriddenMethod, overriddenType)) {
                // the same method, not adding any value. See Issue 373.
                break;
            }
        }
        return super.visitMethod(node, p);
    } finally {
        boolean abstractMethod = methodElement.getModifiers().contains(Modifier.ABSTRACT) || methodElement.getModifiers().contains(Modifier.NATIVE);
        // check well-formedness of pre/postcondition
        List<String> formalParamNames = new ArrayList<>();
        for (VariableTree param : node.getParameters()) {
            formalParamNames.add(param.getName().toString());
        }
        checkContractsAtMethodDeclaration(node, methodElement, formalParamNames, abstractMethod);
        visitorState.setMethodReceiver(preMRT);
        visitorState.setMethodTree(preMT);
    }
}
Also used : PurityResult(org.checkerframework.dataflow.util.PurityChecker.PurityResult) MethodTree(com.sun.source.tree.MethodTree) ExecutableElement(javax.lang.model.element.ExecutableElement) ArrayList(java.util.ArrayList) VariableTree(com.sun.source.tree.VariableTree) AnnotatedExecutableType(org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedExecutableType) AnnotatedDeclaredType(org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedDeclaredType) Collection(java.util.Collection) LambdaExpressionTree(com.sun.source.tree.LambdaExpressionTree) ConditionalExpressionTree(com.sun.source.tree.ConditionalExpressionTree) ExpressionTree(com.sun.source.tree.ExpressionTree) ArrayList(java.util.ArrayList) List(java.util.List) Map(java.util.Map) HashMap(java.util.HashMap) Pure(org.checkerframework.dataflow.qual.Pure)

Example 15 with AnnotatedExecutableType

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

the class BaseTypeVisitor method visitNewClass.

/**
 * Performs a new class invocation check.
 *
 * <p>An invocation of a constructor, c, is valid only if:
 *
 * <ul>
 *   <li>passed arguments are subtypes of corresponding c parameters
 *   <li>if c is generic, passed type arguments are subtypes of c type variables
 * </ul>
 */
@Override
public Void visitNewClass(NewClassTree node, Void p) {
    if (checker.shouldSkipUses(TreeUtils.constructor(node))) {
        return super.visitNewClass(node, p);
    }
    Pair<AnnotatedExecutableType, List<AnnotatedTypeMirror>> fromUse = atypeFactory.constructorFromUse(node);
    AnnotatedExecutableType constructor = fromUse.first;
    List<AnnotatedTypeMirror> typeargs = fromUse.second;
    List<? extends ExpressionTree> passedArguments = node.getArguments();
    List<AnnotatedTypeMirror> params = AnnotatedTypes.expandVarArgs(atypeFactory, constructor, passedArguments);
    checkArguments(params, passedArguments);
    checkVarargs(constructor, node);
    List<AnnotatedTypeParameterBounds> paramBounds = new ArrayList<>();
    for (AnnotatedTypeVariable param : constructor.getTypeVariables()) {
        paramBounds.add(param.getBounds());
    }
    checkTypeArguments(node, paramBounds, typeargs, node.getTypeArguments());
    boolean valid = validateTypeOf(node);
    if (valid) {
        AnnotatedDeclaredType dt = atypeFactory.getAnnotatedType(node);
        if (atypeFactory.getDependentTypesHelper() != null) {
            atypeFactory.getDependentTypesHelper().checkType(dt, node);
        }
        checkConstructorInvocation(dt, constructor, node);
    }
    // Do not call super, as that would observe the arguments without
    // a set assignment context.
    scan(node.getEnclosingExpression(), p);
    scan(node.getIdentifier(), p);
    scan(node.getClassBody(), p);
    return null;
}
Also used : AnnotatedTypeParameterBounds(org.checkerframework.framework.type.AnnotatedTypeParameterBounds) AnnotatedExecutableType(org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedExecutableType) AnnotatedDeclaredType(org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedDeclaredType) ArrayList(java.util.ArrayList) ArrayList(java.util.ArrayList) List(java.util.List) AnnotatedTypeMirror(org.checkerframework.framework.type.AnnotatedTypeMirror) 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