Search in sources :

Example 26 with MethodInvocationNode

use of org.checkerframework.dataflow.cfg.node.MethodInvocationNode in project checker-framework by typetools.

the class AccumulationTransfer method accumulate.

/**
 * Updates the estimate of how many things {@code node} has accumulated.
 *
 * <p>If the node is an invocation of a method that returns its receiver, then its receiver's type
 * will also be updated. In a chain of method calls, this process will continue backward as long
 * as each receiver is itself a receiver-returning method invocation.
 *
 * <p>For example, suppose {@code node} is the expression {@code a.b().c()}, the new value (added
 * by the accumulation analysis because of the {@code .c()} call) is "foo", and b and c return
 * their receiver. This method will directly update the estimate of {@code a.b().c()} to include
 * "foo". In addition, the estimates for the expressions {@code a.b()} and {@code a} would have
 * their estimates updated to include "foo", because c and b (respectively) return their
 * receivers. Note that due to what kind of values can be held in the store, this information is
 * lost outside the method chain. That is, the returns-receiver propagated information is lost
 * outside the expression in which the returns-receiver method invocations are nested.
 *
 * <p>As a concrete example, consider the Called Methods accumulation checker: if {@code build}
 * requires a, b, and c to be called, then {@code foo.a().b().c().build();} will typecheck (they
 * are in one fluent method chain), but {@code foo.a().b().c(); foo.build();} will not -- the
 * store does not keep the information that a, b, and c have been called outside the chain. {@code
 * foo}'s type will be {@code CalledMethods("a")}, because only {@code a()} was called directly on
 * {@code foo}. For such code to typecheck, the Called Methods accumulation checker uses an
 * additional rule: the return type of a receiver-returning method {@code rr()} is {@code
 * CalledMethods("rr")}. This rule is implemented directly in the {@link
 * org.checkerframework.framework.type.treeannotator.TreeAnnotator} subclass defined in the Called
 * Methods type factory.
 *
 * @param node the node whose estimate should be expanded
 * @param result the transfer result containing the store to be modified
 * @param values the new accumulation values
 */
public void accumulate(Node node, TransferResult<CFValue, CFStore> result, String... values) {
    List<String> valuesAsList = Arrays.asList(values);
    // If dataflow has already recorded information about the target, fetch it and integrate
    // it into the list of values in the new annotation.
    JavaExpression target = JavaExpression.fromNode(node);
    if (CFAbstractStore.canInsertJavaExpression(target)) {
        CFValue flowValue = result.getRegularStore().getValue(target);
        if (flowValue != null) {
            Set<AnnotationMirror> flowAnnos = flowValue.getAnnotations();
            assert flowAnnos.size() <= 1;
            for (AnnotationMirror anno : flowAnnos) {
                if (atypeFactory.isAccumulatorAnnotation(anno)) {
                    List<String> oldFlowValues = atypeFactory.getAccumulatedValues(anno);
                    if (!oldFlowValues.isEmpty()) {
                        // valuesAsList cannot have its length changed -- it is backed by an
                        // array -- but if oldFlowValues is not empty, it is a new, modifiable list.
                        oldFlowValues.addAll(valuesAsList);
                        valuesAsList = oldFlowValues;
                    }
                }
            }
        }
    }
    AnnotationMirror newAnno = atypeFactory.createAccumulatorAnnotation(valuesAsList);
    insertIntoStores(result, target, newAnno);
    Tree tree = node.getTree();
    if (tree != null && tree.getKind() == Tree.Kind.METHOD_INVOCATION) {
        Node receiver = ((MethodInvocationNode) node).getTarget().getReceiver();
        if (receiver != null && atypeFactory.returnsThis((MethodInvocationTree) tree)) {
            accumulate(receiver, result, values);
        }
    }
}
Also used : CFValue(org.checkerframework.framework.flow.CFValue) AnnotationMirror(javax.lang.model.element.AnnotationMirror) JavaExpression(org.checkerframework.dataflow.expression.JavaExpression) MethodInvocationTree(com.sun.source.tree.MethodInvocationTree) MethodInvocationNode(org.checkerframework.dataflow.cfg.node.MethodInvocationNode) Node(org.checkerframework.dataflow.cfg.node.Node) MethodInvocationTree(com.sun.source.tree.MethodInvocationTree) Tree(com.sun.source.tree.Tree)

Example 27 with MethodInvocationNode

use of org.checkerframework.dataflow.cfg.node.MethodInvocationNode 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() == Tree.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 + " is different from the" + " number of parameters for the method declaration: " + methodElement.getSimpleName();
        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(JavaExpression.fromNode(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(JavaExpression.fromNode(receiver));
        }
    }
    // If parent is a statement, processPostconditions will handle the 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) ObjectCreationNode(org.checkerframework.dataflow.cfg.node.ObjectCreationNode) MethodInvocationNode(org.checkerframework.dataflow.cfg.node.MethodInvocationNode) AssignmentNode(org.checkerframework.dataflow.cfg.node.AssignmentNode) 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 28 with MethodInvocationNode

use of org.checkerframework.dataflow.cfg.node.MethodInvocationNode in project checker-framework by typetools.

the class AliasingTransfer method visitAssignment.

/**
 * Case 1: For every assignment, the LHS is refined if the RHS has type {@literal @}Unique and is
 * a method invocation or a new class instance.
 */
@Override
public TransferResult<CFValue, CFStore> visitAssignment(AssignmentNode n, TransferInput<CFValue, CFStore> in) {
    Node rhs = n.getExpression();
    Tree treeRhs = rhs.getTree();
    AnnotatedTypeMirror rhsType = factory.getAnnotatedType(treeRhs);
    if (rhsType.hasAnnotation(Unique.class) && (rhs instanceof MethodInvocationNode || rhs instanceof ObjectCreationNode)) {
        // Do normal refinement.
        return super.visitAssignment(n, in);
    }
    // Widen the type of the rhs if the RHS's declared type wasn't @Unique.
    JavaExpression rhsExpr = JavaExpression.fromNode(rhs);
    in.getRegularStore().clearValue(rhsExpr);
    return new RegularTransferResult<>(null, in.getRegularStore());
}
Also used : JavaExpression(org.checkerframework.dataflow.expression.JavaExpression) MethodInvocationNode(org.checkerframework.dataflow.cfg.node.MethodInvocationNode) ObjectCreationNode(org.checkerframework.dataflow.cfg.node.ObjectCreationNode) MethodInvocationNode(org.checkerframework.dataflow.cfg.node.MethodInvocationNode) AssignmentNode(org.checkerframework.dataflow.cfg.node.AssignmentNode) Node(org.checkerframework.dataflow.cfg.node.Node) ObjectCreationNode(org.checkerframework.dataflow.cfg.node.ObjectCreationNode) Tree(com.sun.source.tree.Tree) Unique(org.checkerframework.common.aliasing.qual.Unique) AnnotatedTypeMirror(org.checkerframework.framework.type.AnnotatedTypeMirror) RegularTransferResult(org.checkerframework.dataflow.analysis.RegularTransferResult)

Example 29 with MethodInvocationNode

use of org.checkerframework.dataflow.cfg.node.MethodInvocationNode in project checker-framework by typetools.

the class NullnessTransfer method visitMethodInvocation.

/*
   * Provided that m is of a type that implements interface java.util.Map:
   * <ul>
   * <li>Given a call m.get(k), if k is @KeyFor("m") and m's value type is @NonNull,
   *     then the result is @NonNull in the thenStore and elseStore of the transfer result.
   * </ul>
   */
@Override
public TransferResult<NullnessValue, NullnessStore> visitMethodInvocation(MethodInvocationNode n, TransferInput<NullnessValue, NullnessStore> in) {
    TransferResult<NullnessValue, NullnessStore> result = super.visitMethodInvocation(n, in);
    // Make receiver non-null.
    Node receiver = n.getTarget().getReceiver();
    makeNonNull(result, receiver);
    // For all formal parameters with a non-null annotation, make the actual argument non-null.
    // The point of this is to prevent cascaded errors -- the Nullness Checker will issue a
    // warning for the method invocation, but not for subsequent uses of the argument.  See test
    // case FlowNullness.java.
    MethodInvocationTree tree = n.getTree();
    ExecutableElement method = TreeUtils.elementFromUse(tree);
    AnnotatedExecutableType methodType = nullnessTypeFactory.getAnnotatedType(method);
    List<AnnotatedTypeMirror> methodParams = methodType.getParameterTypes();
    List<? extends ExpressionTree> methodArgs = tree.getArguments();
    for (int i = 0; i < methodParams.size() && i < methodArgs.size(); ++i) {
        if (methodParams.get(i).hasAnnotation(NONNULL)) {
            makeNonNull(result, n.getArgument(i));
        }
    }
    // the map, and the map's value type is not @Nullable.
    if (keyForTypeFactory != null && keyForTypeFactory.isMapGet(n)) {
        String mapName = JavaExpression.fromNode(receiver).toString();
        AnnotatedTypeMirror receiverType = nullnessTypeFactory.getReceiverType(n.getTree());
        if (keyForTypeFactory.isKeyForMap(mapName, methodArgs.get(0)) && !hasNullableValueType(receiverType)) {
            makeNonNull(result, n);
            refineToNonNull(result);
        }
    }
    return result;
}
Also used : AnnotatedExecutableType(org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedExecutableType) MethodInvocationTree(com.sun.source.tree.MethodInvocationTree) InstanceOfNode(org.checkerframework.dataflow.cfg.node.InstanceOfNode) MethodAccessNode(org.checkerframework.dataflow.cfg.node.MethodAccessNode) NullLiteralNode(org.checkerframework.dataflow.cfg.node.NullLiteralNode) FieldAccessNode(org.checkerframework.dataflow.cfg.node.FieldAccessNode) ArrayAccessNode(org.checkerframework.dataflow.cfg.node.ArrayAccessNode) ReturnNode(org.checkerframework.dataflow.cfg.node.ReturnNode) MethodInvocationNode(org.checkerframework.dataflow.cfg.node.MethodInvocationNode) ThrowNode(org.checkerframework.dataflow.cfg.node.ThrowNode) Node(org.checkerframework.dataflow.cfg.node.Node) ExecutableElement(javax.lang.model.element.ExecutableElement) AnnotatedTypeMirror(org.checkerframework.framework.type.AnnotatedTypeMirror)

Example 30 with MethodInvocationNode

use of org.checkerframework.dataflow.cfg.node.MethodInvocationNode in project checker-framework by typetools.

the class MustCallConsistencyAnalyzer method getParametersOfInvocation.

/**
 * Get the elements representing the formal parameters of a method or constructor, from an
 * invocation of that method or constructor.
 *
 * @param node a method invocation or object creation node
 * @return a list of the declarations of the formal parameters of the method or constructor being
 *     invoked
 */
private List<? extends VariableElement> getParametersOfInvocation(Node node) {
    ExecutableElement executableElement;
    if (node instanceof MethodInvocationNode) {
        MethodInvocationNode invocationNode = (MethodInvocationNode) node;
        executableElement = TreeUtils.elementFromUse(invocationNode.getTree());
    } else if (node instanceof ObjectCreationNode) {
        executableElement = TreeUtils.elementFromUse(((ObjectCreationNode) node).getTree());
    } else {
        throw new TypeSystemError("unexpected node type " + node.getClass());
    }
    return executableElement.getParameters();
}
Also used : MethodInvocationNode(org.checkerframework.dataflow.cfg.node.MethodInvocationNode) ExecutableElement(javax.lang.model.element.ExecutableElement) ObjectCreationNode(org.checkerframework.dataflow.cfg.node.ObjectCreationNode) TypeSystemError(org.checkerframework.javacutil.TypeSystemError)

Aggregations

MethodInvocationNode (org.checkerframework.dataflow.cfg.node.MethodInvocationNode)42 Node (org.checkerframework.dataflow.cfg.node.Node)38 FieldAccessNode (org.checkerframework.dataflow.cfg.node.FieldAccessNode)21 ObjectCreationNode (org.checkerframework.dataflow.cfg.node.ObjectCreationNode)16 ExecutableElement (javax.lang.model.element.ExecutableElement)15 AssignmentNode (org.checkerframework.dataflow.cfg.node.AssignmentNode)15 MethodAccessNode (org.checkerframework.dataflow.cfg.node.MethodAccessNode)14 LocalVariableNode (org.checkerframework.dataflow.cfg.node.LocalVariableNode)13 ClassNameNode (org.checkerframework.dataflow.cfg.node.ClassNameNode)12 ReturnNode (org.checkerframework.dataflow.cfg.node.ReturnNode)12 ArrayCreationNode (org.checkerframework.dataflow.cfg.node.ArrayCreationNode)11 GreaterThanNode (org.checkerframework.dataflow.cfg.node.GreaterThanNode)11 GreaterThanOrEqualNode (org.checkerframework.dataflow.cfg.node.GreaterThanOrEqualNode)11 LessThanNode (org.checkerframework.dataflow.cfg.node.LessThanNode)11 LessThanOrEqualNode (org.checkerframework.dataflow.cfg.node.LessThanOrEqualNode)11 StringConversionNode (org.checkerframework.dataflow.cfg.node.StringConversionNode)11 MethodInvocationTree (com.sun.source.tree.MethodInvocationTree)10 ArrayAccessNode (org.checkerframework.dataflow.cfg.node.ArrayAccessNode)10 CFStore (org.checkerframework.framework.flow.CFStore)10 CFValue (org.checkerframework.framework.flow.CFValue)10