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);
}
}
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);
}
}
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;
}
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);
}
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;
}
Aggregations