Search in sources :

Example 31 with MethodInvocationNode

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

the class MustCallConsistencyAnalyzer method analyze.

/**
 * The main function of the consistency dataflow analysis. The analysis tracks dataflow facts
 * ("Obligations") of type {@link Obligation}, each representing a set of owning resource aliases
 * for some value with a non-empty {@code @MustCall} obligation. The set of tracked Obligations is
 * guaranteed to include at least one Obligation for each actual resource in the program, but
 * might include other, spurious Obligations, too (that is, it is a conservative
 * over-approximation of the true Obligation set).
 *
 * <p>The analysis improves its precision by removing Obligations from tracking when it can prove
 * that they do not represent real resources. For example, it is not necessary to track
 * expressions with empty {@code @MustCall} obligations, because they are trivially fulfilled. Nor
 * is tracking non-owning aliases necessary, because by definition they cannot be used to fulfill
 * must-call obligations.
 *
 * @param cfg the control flow graph of the method to check
 */
// TODO: This analysis is currently implemented directly using a worklist; in the future, it
// should be rewritten to use the dataflow framework of the Checker Framework.
/* package-private */
void analyze(ControlFlowGraph cfg) {
    // The `visited` set contains everything that has been added to the worklist, even if it has not
    // yet been removed and analyzed.
    Set<BlockWithObligations> visited = new HashSet<>();
    Deque<BlockWithObligations> worklist = new ArrayDeque<>();
    // Add any owning parameters to the initial set of variables to track.
    BlockWithObligations entry = new BlockWithObligations(cfg.getEntryBlock(), computeOwningParameters(cfg));
    worklist.add(entry);
    visited.add(entry);
    while (!worklist.isEmpty()) {
        BlockWithObligations current = worklist.remove();
        // A *mutable* set that eventually holds the set of dataflow facts to be propagated to
        // successor blocks. The set is initialized to the current dataflow facts and updated by the
        // methods invoked in the for loop below.
        Set<Obligation> obligations = new LinkedHashSet<>(current.obligations);
        for (Node node : current.block.getNodes()) {
            if (node instanceof AssignmentNode) {
                updateObligationsForAssignment(obligations, (AssignmentNode) node);
            } else if (node instanceof ReturnNode) {
                updateObligationsForOwningReturn(obligations, cfg, (ReturnNode) node);
            } else if (node instanceof MethodInvocationNode || node instanceof ObjectCreationNode) {
                updateObligationsForInvocation(obligations, node);
            }
        // All other types of nodes are ignored. This is safe, because other kinds of
        // nodes cannot create or modify the resource-alias sets that the algorithm is tracking.
        }
        propagateObligationsToSuccessorBlocks(obligations, current.block, visited, worklist);
    }
}
Also used : LinkedHashSet(java.util.LinkedHashSet) AssignmentNode(org.checkerframework.dataflow.cfg.node.AssignmentNode) MethodInvocationNode(org.checkerframework.dataflow.cfg.node.MethodInvocationNode) TypeCastNode(org.checkerframework.dataflow.cfg.node.TypeCastNode) ObjectCreationNode(org.checkerframework.dataflow.cfg.node.ObjectCreationNode) LocalVariableNode(org.checkerframework.dataflow.cfg.node.LocalVariableNode) ThisNode(org.checkerframework.dataflow.cfg.node.ThisNode) AssignmentNode(org.checkerframework.dataflow.cfg.node.AssignmentNode) NullLiteralNode(org.checkerframework.dataflow.cfg.node.NullLiteralNode) FieldAccessNode(org.checkerframework.dataflow.cfg.node.FieldAccessNode) ReturnNode(org.checkerframework.dataflow.cfg.node.ReturnNode) MethodInvocationNode(org.checkerframework.dataflow.cfg.node.MethodInvocationNode) Node(org.checkerframework.dataflow.cfg.node.Node) ArrayDeque(java.util.ArrayDeque) ReturnNode(org.checkerframework.dataflow.cfg.node.ReturnNode) ObjectCreationNode(org.checkerframework.dataflow.cfg.node.ObjectCreationNode) HashSet(java.util.HashSet) LinkedHashSet(java.util.LinkedHashSet)

Example 32 with MethodInvocationNode

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

the class MustCallInferenceLogic method runInference.

/**
 * Runs the inference algorithm on the contents of the {@link #cfg} field.
 *
 * <p>Operationally, it checks method invocations for fields with non-empty @MustCall obligations
 * along all paths to the regular exit point in the method body of the method represented by
 * {@link #cfg}, and updates the {@link #owningFields} set if it discovers an owning field whose
 * must-call obligations were satisfied along one of the checked paths.
 */
void runInference() {
    Set<Block> visited = new HashSet<>();
    Deque<Block> worklist = new ArrayDeque<>();
    Block entry = this.cfg.getEntryBlock();
    worklist.add(entry);
    visited.add(entry);
    while (!worklist.isEmpty()) {
        Block current = worklist.remove();
        for (Node node : current.getNodes()) {
            if (node instanceof MethodInvocationNode) {
                checkForMustCallInvocationOnField((MethodInvocationNode) node);
            }
        }
        propagateRegPaths(current, visited, worklist);
    }
}
Also used : MethodInvocationNode(org.checkerframework.dataflow.cfg.node.MethodInvocationNode) MethodInvocationNode(org.checkerframework.dataflow.cfg.node.MethodInvocationNode) Node(org.checkerframework.dataflow.cfg.node.Node) SingleSuccessorBlock(org.checkerframework.dataflow.cfg.block.SingleSuccessorBlock) Block(org.checkerframework.dataflow.cfg.block.Block) ConditionalBlock(org.checkerframework.dataflow.cfg.block.ConditionalBlock) ArrayDeque(java.util.ArrayDeque) HashSet(java.util.HashSet)

Example 33 with MethodInvocationNode

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

the class ResourceLeakTransfer method visitMethodInvocation.

@Override
public TransferResult<CFValue, CFStore> visitMethodInvocation(final MethodInvocationNode node, final TransferInput<CFValue, CFStore> input) {
    TransferResult<CFValue, CFStore> result = super.visitMethodInvocation(node, input);
    handleCreatesMustCallFor(node, result);
    updateStoreWithTempVar(result, node);
    // If there is a temporary variable for the receiver, update its type.
    Node receiver = node.getTarget().getReceiver();
    MustCallAnnotatedTypeFactory mcAtf = rlTypeFactory.getTypeFactoryOfSubchecker(MustCallChecker.class);
    Node accumulationTarget = mcAtf.getTempVar(receiver);
    if (accumulationTarget != null) {
        String methodName = node.getTarget().getMethod().getSimpleName().toString();
        methodName = rlTypeFactory.adjustMethodNameUsingValueChecker(methodName, node.getTree());
        accumulate(accumulationTarget, result, methodName);
    }
    return result;
}
Also used : CFValue(org.checkerframework.framework.flow.CFValue) CFStore(org.checkerframework.framework.flow.CFStore) TernaryExpressionNode(org.checkerframework.dataflow.cfg.node.TernaryExpressionNode) ObjectCreationNode(org.checkerframework.dataflow.cfg.node.ObjectCreationNode) MethodInvocationNode(org.checkerframework.dataflow.cfg.node.MethodInvocationNode) LocalVariableNode(org.checkerframework.dataflow.cfg.node.LocalVariableNode) SwitchExpressionNode(org.checkerframework.dataflow.cfg.node.SwitchExpressionNode) Node(org.checkerframework.dataflow.cfg.node.Node) MustCallAnnotatedTypeFactory(org.checkerframework.checker.mustcall.MustCallAnnotatedTypeFactory)

Example 34 with MethodInvocationNode

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

the class MustCallConsistencyAnalyzer method shouldTrackInvocationResult.

/**
 * Determines if the result of the given method or constructor invocation node should be tracked
 * in {@code obligations}. In some cases, there is no need to track the result because the
 * must-call obligations are already satisfied in some other way or there cannot possibly be
 * must-call obligations because of the structure of the code.
 *
 * <p>Specifically, an invocation result does NOT need to be tracked if any of the following is
 * true:
 *
 * <ul>
 *   <li>The invocation is a call to a {@code this()} or {@code super()} constructor.
 *   <li>The method's return type is annotated with MustCallAlias and the argument passed in this
 *       invocation in the corresponding position is an owning field.
 *   <li>The method's return type is non-owning, which can either be because the method has no
 *       return type or because the return type is annotated with {@link NotOwning}.
 * </ul>
 *
 * <p>This method can also side-effect {@code obligations}, if node is a super or this constructor
 * call with MustCallAlias annotations, by removing that Obligation.
 *
 * @param obligations the current set of Obligations, which may be side-effected
 * @param node the invocation node to check; must be {@link MethodInvocationNode} or {@link
 *     ObjectCreationNode}
 * @return true iff the result of {@code node} should be tracked in {@code obligations}
 */
private boolean shouldTrackInvocationResult(Set<Obligation> obligations, Node node) {
    Tree callTree = node.getTree();
    if (callTree.getKind() == Tree.Kind.NEW_CLASS) {
        // Constructor results from new expressions are always owning.
        return true;
    }
    // Now callTree.getKind() == Tree.Kind.METHOD_INVOCATION.
    MethodInvocationTree methodInvokeTree = (MethodInvocationTree) callTree;
    if (TreeUtils.isSuperConstructorCall(methodInvokeTree) || TreeUtils.isThisConstructorCall(methodInvokeTree)) {
        List<Node> mustCallAliasArguments = getMustCallAliasArgumentNodes(node);
        // constructor).
        for (Node mustCallAliasArgument : mustCallAliasArguments) {
            if (mustCallAliasArgument instanceof LocalVariableNode) {
                removeObligationsContainingVar(obligations, (LocalVariableNode) mustCallAliasArgument);
            }
        }
        return false;
    }
    return !returnTypeIsMustCallAliasWithUntrackable((MethodInvocationNode) node) && !hasNotOwningReturnType((MethodInvocationNode) node);
}
Also used : MethodInvocationTree(com.sun.source.tree.MethodInvocationTree) TypeCastNode(org.checkerframework.dataflow.cfg.node.TypeCastNode) ObjectCreationNode(org.checkerframework.dataflow.cfg.node.ObjectCreationNode) LocalVariableNode(org.checkerframework.dataflow.cfg.node.LocalVariableNode) ThisNode(org.checkerframework.dataflow.cfg.node.ThisNode) AssignmentNode(org.checkerframework.dataflow.cfg.node.AssignmentNode) NullLiteralNode(org.checkerframework.dataflow.cfg.node.NullLiteralNode) FieldAccessNode(org.checkerframework.dataflow.cfg.node.FieldAccessNode) ReturnNode(org.checkerframework.dataflow.cfg.node.ReturnNode) MethodInvocationNode(org.checkerframework.dataflow.cfg.node.MethodInvocationNode) Node(org.checkerframework.dataflow.cfg.node.Node) MethodInvocationTree(com.sun.source.tree.MethodInvocationTree) MethodTree(com.sun.source.tree.MethodTree) VariableTree(com.sun.source.tree.VariableTree) Tree(com.sun.source.tree.Tree) LocalVariableNode(org.checkerframework.dataflow.cfg.node.LocalVariableNode)

Example 35 with MethodInvocationNode

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

the class TestAccumulationTransfer method visitMethodInvocation.

@Override
public TransferResult<CFValue, CFStore> visitMethodInvocation(final MethodInvocationNode node, final TransferInput<CFValue, CFStore> input) {
    TransferResult<CFValue, CFStore> result = super.visitMethodInvocation(node, input);
    Node receiver = node.getTarget().getReceiver();
    if (receiver != null) {
        String methodName = node.getTarget().getMethod().getSimpleName().toString();
        accumulate(receiver, result, methodName);
    }
    return result;
}
Also used : CFValue(org.checkerframework.framework.flow.CFValue) CFStore(org.checkerframework.framework.flow.CFStore) MethodInvocationNode(org.checkerframework.dataflow.cfg.node.MethodInvocationNode) Node(org.checkerframework.dataflow.cfg.node.Node)

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