Search in sources :

Example 36 with AnnotatedExecutableType

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

the class AliasingTransfer method visitMethodInvocation.

/**
 * Case 3: Given a method invocation expression, if the parent of the expression is not a
 * statement, check if there are any arguments of the method call annotated as
 * {@literal @}LeakedToResult and remove it from the store, since it might be leaked.
 */
@Override
public TransferResult<CFValue, CFStore> visitMethodInvocation(MethodInvocationNode n, TransferInput<CFValue, CFStore> in) {
    Tree parent = n.getTreePath().getParentPath().getLeaf();
    boolean parentIsStatement = parent.getKind() == Kind.EXPRESSION_STATEMENT;
    if (!parentIsStatement) {
        ExecutableElement methodElement = TreeUtils.elementFromUse(n.getTree());
        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();
        CFStore store = in.getRegularStore();
        for (int i = 0; i < args.size(); i++) {
            Node arg = args.get(i);
            VariableElement param = params.get(i);
            if (factory.getAnnotatedType(param).hasAnnotation(LeakedToResult.class)) {
                // If argument can leak to result, and parent is not a
                // single statement, remove that node from store.
                store.clearValue(FlowExpressions.internalReprOf(factory, arg));
            }
        }
        // Now, doing the same as above for the receiver parameter
        Node receiver = n.getTarget().getReceiver();
        AnnotatedExecutableType annotatedType = factory.getAnnotatedType(methodElement);
        AnnotatedDeclaredType receiverType = annotatedType.getReceiverType();
        if (receiverType != null && receiverType.hasAnnotation(LeakedToResult.class)) {
            store.clearValue(FlowExpressions.internalReprOf(factory, receiver));
        }
    }
    // pseudo-assignments.
    return super.visitMethodInvocation(n, in);
}
Also used : AnnotatedExecutableType(org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedExecutableType) CFStore(org.checkerframework.framework.flow.CFStore) ExecutableElement(javax.lang.model.element.ExecutableElement) 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) Tree(com.sun.source.tree.Tree) VariableElement(javax.lang.model.element.VariableElement)

Example 37 with AnnotatedExecutableType

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

the class AliasingVisitor method visitMethodInvocation.

/**
 * Checks that if a method call is being invoked inside a constructor with result type
 * {@literal @}Unique, it must not leak the "this" reference. There are 3 ways to make sure that
 * this is not happening:
 *
 * <ol>
 *   <li>{@code this} is not an argument of the method call.
 *   <li>{@code this} is an argument of the method call, but the respective parameter is
 *       annotated as {@literal @}NonLeaked.
 *   <li>{@code this} is an argument of the method call, but the respective parameter is
 *       annotated as {@literal @}LeakedToResult AND the result of the method call is not being
 *       stored (the method call is a statement).
 * </ol>
 *
 * The private method {@code isUniqueCheck} handles cases 2 and 3.
 */
@Override
public Void visitMethodInvocation(MethodInvocationTree node, Void p) {
    // @Unique. We also want to avoid visiting the <init> method.
    if (isInUniqueConstructor(node)) {
        if (TreeUtils.isSuperCall(node)) {
            // Check if a call to super() might create an alias: that
            // happens when the parent's respective constructor is not @Unique.
            AnnotatedTypeMirror superResult = atypeFactory.getAnnotatedType(node);
            if (!superResult.hasAnnotation(Unique.class)) {
                checker.report(Result.failure("unique.leaked"), node);
            }
        } else {
            // TODO: Currently the type of "this" doesn't always return
            // the type of the constructor result, therefore we need
            // this "else" block. Once constructors are implemented
            // correctly we could remove that code below, since the type
            // of "this" in a @Unique constructor will be @Unique.
            Tree parent = getCurrentPath().getParentPath().getLeaf();
            boolean parentIsStatement = parent.getKind() == Kind.EXPRESSION_STATEMENT;
            ExecutableElement methodElement = TreeUtils.elementFromUse(node);
            List<? extends VariableElement> params = methodElement.getParameters();
            List<? extends ExpressionTree> args = node.getArguments();
            assert (args.size() == params.size()) : "Number of arguments in" + " the method call " + node.toString() + " is different from the " + "number of parameters for the method declaration: " + methodElement.getSimpleName().toString();
            for (int i = 0; i < args.size(); i++) {
                // For every argument we check if it is a reference to "this".
                if (TreeUtils.isExplicitThisDereference(args.get(i))) {
                    // If it is a reference to "this", there is still hope that
                    // it is not being leaked (2. and 3. from the javadoc).
                    VariableElement param = params.get(i);
                    boolean hasNonLeaked = atypeFactory.getAnnotatedType(param).hasAnnotation(NonLeaked.class);
                    boolean hasLeakedToResult = atypeFactory.getAnnotatedType(param).hasAnnotation(LeakedToResult.class);
                    isUniqueCheck(node, parentIsStatement, hasNonLeaked, hasLeakedToResult);
                } else {
                // Not possible to leak reference here (case 1. from the javadoc).
                }
            }
            // Now, doing the same as above for the receiver parameter
            AnnotatedExecutableType annotatedType = atypeFactory.getAnnotatedType(methodElement);
            AnnotatedDeclaredType receiverType = annotatedType.getReceiverType();
            if (receiverType != null) {
                boolean hasNonLeaked = receiverType.hasAnnotation(NonLeaked.class);
                boolean hasLeakedToResult = receiverType.hasAnnotation(LeakedToResult.class);
                isUniqueCheck(node, parentIsStatement, hasNonLeaked, hasLeakedToResult);
            }
        }
    }
    return super.visitMethodInvocation(node, p);
}
Also used : AnnotatedExecutableType(org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedExecutableType) ExecutableElement(javax.lang.model.element.ExecutableElement) AnnotatedDeclaredType(org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedDeclaredType) MethodTree(com.sun.source.tree.MethodTree) ExpressionTree(com.sun.source.tree.ExpressionTree) VariableTree(com.sun.source.tree.VariableTree) MethodInvocationTree(com.sun.source.tree.MethodInvocationTree) ThrowTree(com.sun.source.tree.ThrowTree) NewArrayTree(com.sun.source.tree.NewArrayTree) Tree(com.sun.source.tree.Tree) Unique(org.checkerframework.common.aliasing.qual.Unique) VariableElement(javax.lang.model.element.VariableElement) AnnotatedTypeMirror(org.checkerframework.framework.type.AnnotatedTypeMirror)

Example 38 with AnnotatedExecutableType

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

the class BaseTypeVisitor method checkMethodReferenceAsOverride.

/**
 * Check that a method reference is allowed. Using the OverrideChecker class.
 *
 * @param memberReferenceTree the tree for the method reference
 * @return true if the method reference is allowed
 */
protected boolean checkMethodReferenceAsOverride(MemberReferenceTree memberReferenceTree, Void p) {
    Pair<AnnotatedDeclaredType, AnnotatedExecutableType> result = atypeFactory.getFnInterfaceFromTree(memberReferenceTree);
    // The type to which the member reference is assigned -- also known as the target type of the reference.
    AnnotatedDeclaredType functionalInterface = result.first;
    // The type of the single method that is declared by the functional interface.
    AnnotatedExecutableType functionType = result.second;
    // ========= Overriding Type =========
    // This doesn't get the correct type for a "MyOuter.super" based on the receiver of the
    // enclosing method.
    // That is handled separately in method receiver check.
    // The type of the expression or type use, <expression>::method or <type use>::method.
    final ExpressionTree qualifierExpression = memberReferenceTree.getQualifierExpression();
    final ReferenceKind memRefKind = ((JCMemberReference) memberReferenceTree).kind;
    AnnotatedTypeMirror enclosingType;
    if (memberReferenceTree.getMode() == ReferenceMode.NEW || memRefKind == ReferenceKind.UNBOUND || memRefKind == ReferenceKind.STATIC) {
        // The "qualifier expression" is a type tree.
        enclosingType = atypeFactory.getAnnotatedTypeFromTypeTree(qualifierExpression);
    } else {
        // The "qualifier expression" is an expression.
        enclosingType = atypeFactory.getAnnotatedType(qualifierExpression);
    }
    // ========= Overriding Executable =========
    // The ::method element, see JLS 15.13.1 Compile-Time Declaration of a Method Reference
    ExecutableElement compileTimeDeclaration = (ExecutableElement) TreeUtils.elementFromTree(memberReferenceTree);
    if (enclosingType.getKind() == TypeKind.DECLARED && ((AnnotatedDeclaredType) enclosingType).wasRaw()) {
        if (memRefKind == ReferenceKind.UNBOUND) {
            // The method reference is of the form: Type # instMethod
            // and Type is a raw type.
            // If the first parameter of the function type, p1, is a subtype
            // of type, then type should be p1.  This has the effect of "inferring" the
            // class type parameter.
            AnnotatedTypeMirror p1 = functionType.getParameterTypes().get(0);
            TypeMirror asSuper = TypesUtils.asSuper(p1.getUnderlyingType(), enclosingType.getUnderlyingType(), atypeFactory.getProcessingEnv());
            if (asSuper != null) {
                enclosingType = AnnotatedTypes.asSuper(atypeFactory, p1, enclosingType);
            }
        }
    // else method reference is something like ArrayList::new
    // TODO: Use diamond, <>, inference to infer the class type arguments.
    // for now this case is skipped below in checkMethodReferenceInference.
    }
    // The type of the compileTimeDeclaration if it were invoked with a receiver expression
    // of type {@code type}
    AnnotatedExecutableType invocationType = atypeFactory.methodFromUse(memberReferenceTree, compileTimeDeclaration, enclosingType).first;
    if (checkMethodReferenceInference(memberReferenceTree, invocationType, enclosingType)) {
        // #checkMethodReferenceInference issued a warning.
        return true;
    }
    // functionType.getReturnType()
    if (invocationType.getTypeVariables().isEmpty() && !functionType.getTypeVariables().isEmpty()) {
        functionType = functionType.getErased();
    }
    // Use the function type's parameters to resolve polymorphic qualifiers.
    QualifierPolymorphism poly = new QualifierPolymorphism(atypeFactory.getProcessingEnv(), atypeFactory);
    poly.annotate(functionType, invocationType);
    AnnotatedTypeMirror invocationReturnType;
    if (compileTimeDeclaration.getKind() == ElementKind.CONSTRUCTOR) {
        if (enclosingType.getKind() == TypeKind.ARRAY) {
            // Special casing for the return of array constructor
            invocationReturnType = enclosingType;
        } else {
            invocationReturnType = atypeFactory.getResultingTypeOfConstructorMemberReference(memberReferenceTree, invocationType);
        }
    } else {
        invocationReturnType = invocationType.getReturnType();
    }
    AnnotatedTypeMirror functionTypeReturnType = functionType.getReturnType();
    if (functionTypeReturnType.getKind() == TypeKind.VOID) {
        // If the functional interface return type is void, the overriding return
        // type doesn't matter.
        functionTypeReturnType = invocationReturnType;
    }
    // Check the member reference as if invocationType overrides functionType.
    OverrideChecker overrideChecker = createOverrideChecker(memberReferenceTree, invocationType, enclosingType, invocationReturnType, functionType, functionalInterface, functionTypeReturnType);
    return overrideChecker.checkOverride();
}
Also used : AnnotatedExecutableType(org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedExecutableType) QualifierPolymorphism(org.checkerframework.framework.util.QualifierPolymorphism) AnnotatedTypeMirror(org.checkerframework.framework.type.AnnotatedTypeMirror) TypeMirror(javax.lang.model.type.TypeMirror) JCMemberReference(com.sun.tools.javac.tree.JCTree.JCMemberReference) AnnotatedDeclaredType(org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedDeclaredType) ExecutableElement(javax.lang.model.element.ExecutableElement) ReferenceKind(com.sun.tools.javac.tree.JCTree.JCMemberReference.ReferenceKind) LambdaExpressionTree(com.sun.source.tree.LambdaExpressionTree) ConditionalExpressionTree(com.sun.source.tree.ConditionalExpressionTree) ExpressionTree(com.sun.source.tree.ExpressionTree) AnnotatedTypeMirror(org.checkerframework.framework.type.AnnotatedTypeMirror)

Example 39 with AnnotatedExecutableType

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

the class DependentTypesHelper method viewpointAdaptExecutable.

private void viewpointAdaptExecutable(ExpressionTree tree, ExpressionTree receiverTree, AnnotatedExecutableType typeFromUse, List<? extends ExpressionTree> args) {
    Element element = TreeUtils.elementFromUse(tree);
    AnnotatedExecutableType viewpointAdaptedType = (AnnotatedExecutableType) factory.getAnnotatedType(element);
    if (!hasDependentType(viewpointAdaptedType)) {
        return;
    }
    FlowExpressions.Receiver receiver;
    if (receiverTree == null) {
        receiver = FlowExpressions.internalReprOfImplicitReceiver(TreeUtils.elementFromUse(tree));
    } else {
        receiver = FlowExpressions.internalReprOf(factory, receiverTree);
    }
    List<FlowExpressions.Receiver> argReceivers = new ArrayList<>(args.size());
    for (ExpressionTree argTree : args) {
        argReceivers.add(FlowExpressions.internalReprOf(factory, argTree));
    }
    TreePath currentPath = factory.getPath(tree);
    FlowExpressionContext context = new FlowExpressionContext(receiver, argReceivers, factory.getContext());
    // typeForUse cannot be viewpoint adapted directly because it is the type post type variable
    // substitution.  Dependent type annotations on type arguments do not (and cannot) be
    // viewpoint adapted along with the dependent type annotations that are on the method
    // declaration. For example:
    // Map<String, String> map = ...;
    // List<@KeyFor("map") String> list = ...;
    // list.get(0)
    // If the type of List.get is viewpoint adapted for the invocation "list.get(0)", then
    // typeFromUse would be @KeyFor("map") String get(int).
    // Instead, use the type for the method (viewpointAdaptedType) and viewpoint adapt that
    // type.
    // Then copy annotations from the viewpoint adapted type to typeFromUse, if that annotation
    // is not on a type that was substituted for a type variable.
    standardizeDoNotUseLocals(context, currentPath, viewpointAdaptedType);
    new ViewpointAdaptedCopier().visit(viewpointAdaptedType, typeFromUse);
}
Also used : AnnotatedExecutableType(org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedExecutableType) TreePath(com.sun.source.util.TreePath) FlowExpressionContext(org.checkerframework.framework.util.FlowExpressionParseUtil.FlowExpressionContext) TypeElement(javax.lang.model.element.TypeElement) Element(javax.lang.model.element.Element) ArrayList(java.util.ArrayList) FlowExpressions(org.checkerframework.dataflow.analysis.FlowExpressions) Receiver(org.checkerframework.dataflow.analysis.FlowExpressions.Receiver) LambdaExpressionTree(com.sun.source.tree.LambdaExpressionTree) ExpressionTree(com.sun.source.tree.ExpressionTree) Receiver(org.checkerframework.dataflow.analysis.FlowExpressions.Receiver)

Example 40 with AnnotatedExecutableType

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

the class TypeArgInferenceUtil method assignedTo.

/**
 * Returns the annotated type that the leaf of path is assigned to, if it is within an
 * assignment context. Returns the annotated type that the method invocation at the leaf is
 * assigned to. If the result is a primitive, return the boxed version.
 *
 * @return type that path leaf is assigned to
 */
public static AnnotatedTypeMirror assignedTo(AnnotatedTypeFactory atypeFactory, TreePath path) {
    Tree assignmentContext = TreeUtils.getAssignmentContext(path);
    AnnotatedTypeMirror res;
    if (assignmentContext == null) {
        res = null;
    } else if (assignmentContext instanceof AssignmentTree) {
        ExpressionTree variable = ((AssignmentTree) assignmentContext).getVariable();
        res = atypeFactory.getAnnotatedType(variable);
    } else if (assignmentContext instanceof CompoundAssignmentTree) {
        ExpressionTree variable = ((CompoundAssignmentTree) assignmentContext).getVariable();
        res = atypeFactory.getAnnotatedType(variable);
    } else if (assignmentContext instanceof MethodInvocationTree) {
        MethodInvocationTree methodInvocation = (MethodInvocationTree) assignmentContext;
        // TODO move to getAssignmentContext
        if (methodInvocation.getMethodSelect() instanceof MemberSelectTree && ((MemberSelectTree) methodInvocation.getMethodSelect()).getExpression() == path.getLeaf()) {
            return null;
        }
        ExecutableElement methodElt = TreeUtils.elementFromUse(methodInvocation);
        AnnotatedTypeMirror receiver = atypeFactory.getReceiverType(methodInvocation);
        res = assignedToExecutable(atypeFactory, path, methodElt, receiver, methodInvocation.getArguments());
    } else if (assignmentContext instanceof NewArrayTree) {
        // TODO: I left the previous implementation below, it definitely caused infinite loops
        // TODO: if you called it from places like the TreeAnnotator.
        res = null;
    // FIXME: This may cause infinite loop
    // AnnotatedTypeMirror type =
    // atypeFactory.getAnnotatedType((NewArrayTree)assignmentContext);
    // type = AnnotatedTypes.innerMostType(type);
    // return type;
    } else if (assignmentContext instanceof NewClassTree) {
        // This need to be basically like MethodTree
        NewClassTree newClassTree = (NewClassTree) assignmentContext;
        ExecutableElement constructorElt = TreeUtils.constructor(newClassTree);
        AnnotatedTypeMirror receiver = atypeFactory.fromNewClass(newClassTree);
        res = assignedToExecutable(atypeFactory, path, constructorElt, receiver, newClassTree.getArguments());
    } else if (assignmentContext instanceof ReturnTree) {
        HashSet<Kind> kinds = new HashSet<>(Arrays.asList(Kind.LAMBDA_EXPRESSION, Kind.METHOD));
        Tree enclosing = TreeUtils.enclosingOfKind(path, kinds);
        if (enclosing.getKind() == Kind.METHOD) {
            res = (atypeFactory.getAnnotatedType((MethodTree) enclosing)).getReturnType();
        } else {
            Pair<AnnotatedDeclaredType, AnnotatedExecutableType> fninf = atypeFactory.getFnInterfaceFromTree((LambdaExpressionTree) enclosing);
            res = fninf.second.getReturnType();
        }
    } else if (assignmentContext instanceof VariableTree) {
        res = assignedToVariable(atypeFactory, assignmentContext);
    } else {
        ErrorReporter.errorAbort("AnnotatedTypes.assignedTo: shouldn't be here!");
        res = null;
    }
    if (res != null && TypesUtils.isPrimitive(res.getUnderlyingType())) {
        return atypeFactory.getBoxedType((AnnotatedPrimitiveType) res);
    } else {
        return res;
    }
}
Also used : MethodTree(com.sun.source.tree.MethodTree) MemberSelectTree(com.sun.source.tree.MemberSelectTree) ExecutableElement(javax.lang.model.element.ExecutableElement) VariableTree(com.sun.source.tree.VariableTree) NewClassTree(com.sun.source.tree.NewClassTree) ReturnTree(com.sun.source.tree.ReturnTree) AnnotatedTypeMirror(org.checkerframework.framework.type.AnnotatedTypeMirror) CompoundAssignmentTree(com.sun.source.tree.CompoundAssignmentTree) AnnotatedExecutableType(org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedExecutableType) NewArrayTree(com.sun.source.tree.NewArrayTree) MethodInvocationTree(com.sun.source.tree.MethodInvocationTree) Kind(com.sun.source.tree.Tree.Kind) TypeKind(javax.lang.model.type.TypeKind) AnnotatedDeclaredType(org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedDeclaredType) ReturnTree(com.sun.source.tree.ReturnTree) CompoundAssignmentTree(com.sun.source.tree.CompoundAssignmentTree) MethodTree(com.sun.source.tree.MethodTree) VariableTree(com.sun.source.tree.VariableTree) MethodInvocationTree(com.sun.source.tree.MethodInvocationTree) AssignmentTree(com.sun.source.tree.AssignmentTree) NewClassTree(com.sun.source.tree.NewClassTree) LambdaExpressionTree(com.sun.source.tree.LambdaExpressionTree) NewArrayTree(com.sun.source.tree.NewArrayTree) Tree(com.sun.source.tree.Tree) ConditionalExpressionTree(com.sun.source.tree.ConditionalExpressionTree) ExpressionTree(com.sun.source.tree.ExpressionTree) MemberSelectTree(com.sun.source.tree.MemberSelectTree) LambdaExpressionTree(com.sun.source.tree.LambdaExpressionTree) ConditionalExpressionTree(com.sun.source.tree.ConditionalExpressionTree) ExpressionTree(com.sun.source.tree.ExpressionTree) CompoundAssignmentTree(com.sun.source.tree.CompoundAssignmentTree) AssignmentTree(com.sun.source.tree.AssignmentTree) HashSet(java.util.HashSet) LinkedHashSet(java.util.LinkedHashSet)

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