Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Second Phase of RLC inference #6278

Merged
merged 182 commits into from
Dec 5, 2023
Merged
Show file tree
Hide file tree
Changes from 169 commits
Commits
Show all changes
182 commits
Select commit Hold shift + click to select a range
695416d
first phase
Nargeshdb May 15, 2023
ab26997
update comments
Nargeshdb May 15, 2023
ad74e0b
Undo wildcard imports
mernst May 15, 2023
1f16be4
Merge ../checker-framework-branch-master into inference-phase-one
mernst May 16, 2023
833231f
Put shorter clauses first
mernst May 16, 2023
22af6f6
address comments
Nargeshdb May 22, 2023
2d23295
address feedbacks
Nargeshdb May 24, 2023
155ded6
address feedbacks
Nargeshdb May 24, 2023
ef2ac88
update shouldPerformWholeProgramInference in MustCallTransfer
Nargeshdb May 24, 2023
6a28bfc
Merge branch 'master' into inference-phase-one
Nargeshdb May 24, 2023
617a7c7
add comments
Nargeshdb May 25, 2023
8f27be1
Merge remote-tracking branch 'origin' into inference-phase-one
Nargeshdb May 25, 2023
e455aa1
Merge branch 'master' into inference-phase-one
Nargeshdb Jun 13, 2023
3a483f5
update
Nargeshdb Jun 16, 2023
2e87329
update comments
Nargeshdb Jun 22, 2023
aae7e30
address Martin's feedback
Nargeshdb Jun 26, 2023
c48227b
address comments
Nargeshdb Jun 29, 2023
d83eb35
address Martin's comments
Nargeshdb Jun 29, 2023
98279da
update java doc for checkMethodInvocation
Nargeshdb Aug 4, 2023
37cd3e2
update
Nargeshdb Aug 4, 2023
9e2cc1a
update java doc for checkMethodInvocation
Nargeshdb Aug 4, 2023
a958009
add a test case
Nargeshdb Apr 28, 2023
f795b0e
update
Nargeshdb Aug 4, 2023
7e678fb
update
Nargeshdb Aug 4, 2023
d32645e
fix deprecation warning
Nargeshdb Aug 8, 2023
ee90781
remove a MustAliasWithDifferentMCSet.java
Nargeshdb Aug 8, 2023
3bd8772
update
Nargeshdb Aug 8, 2023
74cfa33
cleanup
Nargeshdb Aug 11, 2023
6b9f194
handle arguments passed in varArgs position
Nargeshdb Aug 18, 2023
6b787ca
address Martin's feedback
Nargeshdb Aug 18, 2023
7d85c7f
address Martin's feedback
Nargeshdb Aug 18, 2023
3b7d062
update EnsuresCalledMethodsTest
Nargeshdb Aug 19, 2023
421cdbc
remove changes in MCCA
Nargeshdb Aug 22, 2023
bd1372e
pass -AenableWPIForRLC flag to wpi-many test and update manual
Nargeshdb Aug 23, 2023
4993d96
update
Nargeshdb Aug 23, 2023
1849e13
update
Nargeshdb Aug 23, 2023
7dd793a
address Martin's feedback
Nargeshdb Aug 25, 2023
6e518fb
Merge ../checker-framework-branch-master into inference-phase-one
mernst Aug 28, 2023
e5da11a
Documentation tweaks
mernst Aug 28, 2023
6b00ac4
Tweaks
mernst Aug 28, 2023
111c0aa
Documentation improvements
mernst Aug 28, 2023
15097e2
Code review changes
mernst Aug 29, 2023
c968553
Merge ../checker-framework-branch-master into inference-phase-one
mernst Aug 30, 2023
f53afbc
Code review changes
mernst Aug 30, 2023
5216a62
Comment improvements
mernst Aug 30, 2023
885d952
Renaming
mernst Aug 30, 2023
4e9a811
Renaming and comment improvements
mernst Aug 30, 2023
8af4608
Comments
mernst Aug 30, 2023
da6f840
Documentation edits
mernst Aug 30, 2023
6f0ad6e
Code improvements
mernst Aug 30, 2023
16e9687
address Mike's comments (part 1)
Nargeshdb Sep 6, 2023
51cfa50
address Mike's comments
Nargeshdb Sep 7, 2023
3be91db
improve documentation
Nargeshdb Sep 8, 2023
e32a557
Merge ../checker-framework-branch-master into inference-phase-one
mernst Sep 8, 2023
6005941
address Mike's comments
Nargeshdb Sep 14, 2023
ae36399
merge
Nargeshdb Sep 14, 2023
dc24008
Merge ../checker-framework-branch-master into inference-phase-one
mernst Sep 14, 2023
29e941e
Merge ../checker-framework-branch-master into inference-phase-one
mernst Sep 14, 2023
996cce1
Renamings
mernst Sep 14, 2023
e0cb22b
Remove unneeded "Logic"
mernst Sep 15, 2023
998c87a
Merge branch 'inference-phase-one' of github.com:nargeshdb/checker-fr…
mernst Sep 15, 2023
447e1ed
Tweaks
mernst Sep 15, 2023
f4eb105
Tweaks
mernst Sep 15, 2023
a1eb2c1
Renaming, comments
mernst Sep 15, 2023
39c9961
Add import statement
mernst Sep 15, 2023
d4157d0
Merge /scratch/mernst/clones/types/checker-framework-branch-master in…
mernst Sep 16, 2023
4911657
improve documentation and names
Nargeshdb Sep 19, 2023
1ab7ff1
improve comments
Nargeshdb Sep 20, 2023
612ef9d
Merge remote-tracking branch 'origin' into inference-phase-one
Nargeshdb Sep 20, 2023
1299f7a
add more detail about -AenableWpiForRlc
Nargeshdb Sep 20, 2023
372cac3
Merge branch 'master' into inference-phase-one
msridhar Sep 21, 2023
48f5a01
remove static import
msridhar Sep 21, 2023
09fb026
Merge branch 'master' into inference-phase-one
msridhar Sep 23, 2023
2c70b8d
Merge ../checker-framework-branch-master into inference-phase-one
mernst Sep 24, 2023
a6e8546
change AenableWPIForRLC to AenableWpiForRlc
Nargeshdb Sep 25, 2023
12ee23a
revert changes in addOwningToParamsIfDisposedAtAssignment
Nargeshdb Sep 25, 2023
3761941
Compatibility with Java 8; add toString methods
mernst Sep 25, 2023
d7ed3dd
Add diagnostic output
mernst Sep 25, 2023
c6a94f1
Merge branch 'inference-phase-one' of github.com:nargeshdb/checker-fr…
mernst Sep 25, 2023
17b7853
add changes back
Nargeshdb Sep 25, 2023
bc0b737
Merge branch 'master' into inference-phase-one
Nargeshdb Sep 25, 2023
8354a14
improve perf
Nargeshdb Sep 25, 2023
36ddd8e
Merge branch 'master' into inference-phase-one
Nargeshdb Sep 26, 2023
c1c3d7b
make all indexes 1-based
Nargeshdb Sep 26, 2023
f70a11e
fix
Nargeshdb Sep 26, 2023
94bb05f
Merge branch 'inference-phase-one' of github.com:nargeshdb/checker-fr…
mernst Sep 28, 2023
a64af88
Merge ../checker-framework-branch-master into inference-phase-one
mernst Sep 28, 2023
9ffc0a1
Merge branch 'master' into inference-phase-one
msridhar Oct 2, 2023
7110866
fix compile error
msridhar Oct 2, 2023
206643d
Code review changes
mernst Oct 2, 2023
f6e82cc
Merge branch 'inference-phase-one' of github.com:nargeshdb/checker-fr…
mernst Oct 2, 2023
4cda0ed
Brevity
mernst Oct 2, 2023
0bc4ed8
Lazily create HashSet
mernst Oct 2, 2023
5a57c79
Comment tweaks and a renaming
mernst Oct 2, 2023
145bb3e
Reduce duplication in explanation of `-AenableWpiForRlc`
mernst Oct 2, 2023
4caab8a
Comments
mernst Oct 2, 2023
8b6896f
Improve comments
mernst Oct 2, 2023
79e2911
address all feedbacks
Nargeshdb Oct 3, 2023
041fc0a
merge
Nargeshdb Oct 3, 2023
2f6d925
Merge ../checker-framework-branch-master into inference-phase-one
mernst Oct 4, 2023
bbcc548
Merge branch 'inference-phase-one' of github.com:nargeshdb/checker-fr…
mernst Oct 4, 2023
d21d164
update names and docs
Nargeshdb Oct 5, 2023
fa72f43
fix
Nargeshdb Oct 5, 2023
1793e3f
Merge branch 'master' into inference-phase-one
Nargeshdb Oct 5, 2023
ca50189
Update checker/src/main/java/org/checkerframework/checker/resourcelea…
Nargeshdb Oct 7, 2023
61283f1
Update checker/src/main/java/org/checkerframework/checker/resourcelea…
Nargeshdb Oct 7, 2023
cdcb572
Update checker/src/main/java/org/checkerframework/checker/resourcelea…
Nargeshdb Oct 7, 2023
a18c47f
Update checker/src/main/java/org/checkerframework/checker/resourcelea…
Nargeshdb Oct 7, 2023
5a4c853
Update checker/src/main/java/org/checkerframework/checker/resourcelea…
Nargeshdb Oct 7, 2023
39bc3aa
Update checker/src/main/java/org/checkerframework/checker/resourcelea…
Nargeshdb Oct 7, 2023
0155950
update names of methods
Nargeshdb Oct 7, 2023
3f116a1
update comments
msridhar Oct 8, 2023
271d455
address some comments
Nargeshdb Oct 8, 2023
beac03b
Merge branch 'inference-phase-one-2' into inference-phase-one
Nargeshdb Oct 8, 2023
a4ffad6
update
Nargeshdb Oct 9, 2023
a8128d2
address Manu's feedback
Nargeshdb Oct 10, 2023
233d349
Update checker/src/main/java/org/checkerframework/checker/resourcelea…
Nargeshdb Oct 10, 2023
79a6d92
Update checker/src/main/java/org/checkerframework/checker/resourcelea…
Nargeshdb Oct 10, 2023
b473dbc
reformat
Nargeshdb Oct 10, 2023
6c254aa
remove disposedField.clear
Nargeshdb Oct 10, 2023
6be4874
Update checker/src/main/java/org/checkerframework/checker/resourcelea…
Nargeshdb Oct 11, 2023
06900ac
Update checker/src/main/java/org/checkerframework/checker/resourcelea…
Nargeshdb Oct 11, 2023
518a598
Update checker/src/main/java/org/checkerframework/checker/resourcelea…
Nargeshdb Oct 11, 2023
74bf6d2
Update checker/src/main/java/org/checkerframework/checker/resourcelea…
Nargeshdb Oct 11, 2023
ffc2472
imptove comments
Nargeshdb Oct 11, 2023
217e105
update method name
Nargeshdb Oct 11, 2023
3ee6e82
check ownership transfer on object creation node
Nargeshdb Oct 12, 2023
3c7d78a
Merge branch 'master' into inference-phase-one
mernst Oct 12, 2023
13e16da
update
Nargeshdb Oct 12, 2023
8ab8a64
update
Nargeshdb Oct 12, 2023
3acf330
cleanup
Nargeshdb Oct 13, 2023
80323c3
Merge branch 'master' into inference-phase-one
msridhar Oct 13, 2023
f3d465c
Merge branch 'master' into inference-phase-one
msridhar Oct 13, 2023
75f2e84
minor tweaks
msridhar Oct 13, 2023
f089e3c
add annotations after the while loop
Nargeshdb Oct 13, 2023
3a7cfda
Merge branch 'master' into inference-phase-one
msridhar Oct 15, 2023
2b2cca2
improve documentation
Nargeshdb Oct 17, 2023
eb9f86f
update
Nargeshdb Oct 17, 2023
c03056b
improve comments
Nargeshdb Oct 17, 2023
2e3c073
second-phase of inference
Nargeshdb Oct 19, 2023
8bfa69c
merge
Nargeshdb Oct 19, 2023
dd2e68d
reformat
Nargeshdb Oct 19, 2023
8f3debe
refactor
Nargeshdb Oct 20, 2023
8068f05
refactor
Nargeshdb Oct 20, 2023
d2d896b
Merge branch 'inference-phase-one' into inference-phase-two
Nargeshdb Oct 20, 2023
b33b705
add a test
Nargeshdb Oct 23, 2023
d4128a6
remove unneeded changes
Nargeshdb Oct 23, 2023
3b39cbb
update comments
Nargeshdb Oct 24, 2023
f80dcde
Merge branch 'master' into inference-phase-one
Nargeshdb Oct 24, 2023
bf851fc
remove the test
Nargeshdb Oct 24, 2023
a0670c1
Merge branch 'inference-phase-one' into inference-phase-two
Nargeshdb Oct 24, 2023
53e6f05
update comments
Nargeshdb Oct 24, 2023
3011552
add arg
Nargeshdb Oct 24, 2023
67f7b52
1-based map
Nargeshdb Oct 24, 2023
1e5499f
add a test
Nargeshdb Oct 24, 2023
29cfb1f
make debug method static
kelloggm Oct 25, 2023
4b64bf4
Merge branch 'master' into inference-phase-one
Nargeshdb Oct 25, 2023
2ed4210
address feedbacks
Nargeshdb Oct 26, 2023
124f3d0
typo
Nargeshdb Oct 30, 2023
09d1d4e
infer @MCA for receiver
Nargeshdb Oct 31, 2023
7fa1eea
Merge branch 'inference-phase-one' into inference-phase-two
Nargeshdb Oct 31, 2023
1274c9b
merge
Nargeshdb Oct 31, 2023
4f46157
address feedback
Nargeshdb Oct 31, 2023
fe2554c
add a comment
Nargeshdb Nov 1, 2023
e679bfe
update doc
Nargeshdb Nov 2, 2023
4cba487
Merge branch 'master' into inference-phase-two
Nargeshdb Nov 2, 2023
69d8a42
update tests
Nargeshdb Nov 7, 2023
f650990
Merge branch 'master' into inference-phase-two
msridhar Nov 8, 2023
9b46a6d
Merge ../checker-framework-branch-master into inference-phase-two
mernst Nov 13, 2023
6f38468
add comments for test
Nargeshdb Nov 13, 2023
5c86c43
Merge branch 'inference-phase-two' of github.com:nargeshdb/checker-fr…
mernst Nov 14, 2023
8b41fec
Code review changes
mernst Nov 14, 2023
db0ed91
Comments
mernst Nov 14, 2023
7a735cd
Add TODO comments
mernst Nov 14, 2023
d107269
improve comments
Nargeshdb Nov 15, 2023
ea65dc4
address Mike's comments
Nargeshdb Nov 16, 2023
6f4819d
chage disposedFields set to map
Nargeshdb Nov 17, 2023
d8681c0
Merge branch 'master' into inference-phase-two
Nargeshdb Nov 17, 2023
b4e1b2a
Merge ../checker-framework-branch-master into inference-phase-two
mernst Nov 24, 2023
2ba55f1
Merge ../checker-framework-branch-master into inference-phase-two
mernst Dec 4, 2023
324e9f6
Merge branch 'master' into inference-phase-two
msridhar Dec 4, 2023
acc5d3e
remove unneeded resource variable logic
msridhar Dec 4, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1815,7 +1815,7 @@ private List<Node> getMustCallAliasArgumentNodes(Node callNode) {
* @param node a node
* @return either a tempvar for node's content sans typecasts, or node
*/
private Node removeCastsAndGetTmpVarIfPresent(Node node) {
/*package-private*/ Node removeCastsAndGetTmpVarIfPresent(Node node) {
// TODO: Create temp vars for TypeCastNodes as well, so there is no need to explicitly
// remove casts here.
node = NodeUtils.removeCasts(node);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import java.util.Arrays;
import java.util.Collections;
import java.util.Deque;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
Expand All @@ -24,6 +25,8 @@
import javax.lang.model.type.TypeMirror;
import org.checkerframework.checker.calledmethods.qual.EnsuresCalledMethods;
import org.checkerframework.checker.mustcall.qual.InheritableMustCall;
import org.checkerframework.checker.mustcall.qual.MustCallAlias;
import org.checkerframework.checker.mustcall.qual.NotOwning;
import org.checkerframework.checker.mustcall.qual.Owning;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.checkerframework.checker.resourceleak.MustCallConsistencyAnalyzer.BlockWithObligations;
Expand All @@ -40,10 +43,12 @@
import org.checkerframework.dataflow.cfg.block.SingleSuccessorBlock;
import org.checkerframework.dataflow.cfg.node.ArrayCreationNode;
import org.checkerframework.dataflow.cfg.node.AssignmentNode;
import org.checkerframework.dataflow.cfg.node.FieldAccessNode;
import org.checkerframework.dataflow.cfg.node.LocalVariableNode;
import org.checkerframework.dataflow.cfg.node.MethodInvocationNode;
import org.checkerframework.dataflow.cfg.node.Node;
import org.checkerframework.dataflow.cfg.node.ObjectCreationNode;
import org.checkerframework.dataflow.cfg.node.ReturnNode;
import org.checkerframework.dataflow.expression.JavaExpression;
import org.checkerframework.dataflow.expression.LocalVariable;
import org.checkerframework.dataflow.util.NodeUtils;
Expand All @@ -58,7 +63,9 @@
/**
* This class implements the annotation inference algorithm for the Resource Leak Checker. It infers
* annotations such as {@code @}{@link Owning} on owning fields and parameters, {@code @}{@link
* EnsuresCalledMethods} on methods, and {@code @}{@link InheritableMustCall} on class declarations.
* NotOwning} on return types, {@code @}{@link EnsuresCalledMethods} on methods, {@code @}{@link
* MustCallAlias} on parameters and return types, and {@code @}{@link InheritableMustCall} on class
* declarations.
*
* <p>Each instance of this class corresponds to a single control flow graph (CFG), typically
* representing a method.
Expand Down Expand Up @@ -110,6 +117,12 @@ public class MustCallInference {
/** The {@link Owning} annotation. */
protected final AnnotationMirror OWNING;

/** The {@link NotOwning} annotation. */
protected final AnnotationMirror NOTOWNING;

/** The {@link MustCallAlias} annotation. */
protected final AnnotationMirror MUSTCALLALIAS;

/**
* The control flow graph of the current method. There is a separate MustCallInference for each
* method.
Expand All @@ -128,6 +141,13 @@ public class MustCallInference {
/** The element referring to the enclosing class of the current method. */
private final @Nullable TypeElement classElt;

/**
* This map is used to track must-alias relationships between return nodes and method parameters.
* The keys are the obligation of return nodes, and the values are the index of current method
* formal parameter (1-based) that is aliased with the return node.
*/
private final Map<Obligation, Integer> returnNodeToParameterIndexMap = new HashMap<>();

/**
* Creates a MustCallInference instance.
*
Expand All @@ -143,6 +163,10 @@ public class MustCallInference {
this.mcca = mcca;
this.cfg = cfg;
OWNING = AnnotationBuilder.fromClass(this.resourceLeakAtf.getElementUtils(), Owning.class);
NOTOWNING =
AnnotationBuilder.fromClass(this.resourceLeakAtf.getElementUtils(), NotOwning.class);
MUSTCALLALIAS =
AnnotationBuilder.fromClass(this.resourceLeakAtf.getElementUtils(), MustCallAlias.class);
methodTree = ((UnderlyingAST.CFGMethod) cfg.getUnderlyingAST()).getMethod();
methodElt = TreeUtils.elementFromDeclaration(methodTree);
classTree = TreePathUtil.enclosingClass(resourceLeakAtf.getPath(methodTree));
Expand Down Expand Up @@ -216,7 +240,9 @@ private void runInference() {
mcca.updateObligationsWithInvocationResult(obligations, node);
computeOwningFromInvocation(obligations, node);
} else if (node instanceof AssignmentNode) {
analyzeOwnershipTransferAtAssignment(obligations, (AssignmentNode) node);
analyzeAssignmentNode(obligations, (AssignmentNode) node);
} else if (node instanceof ReturnNode) {
analyzeReturnNode(obligations, (ReturnNode) node);
}
}

Expand All @@ -226,10 +252,46 @@ private void runInference() {
addMemberAndClassAnnotations();
}

/**
* Analyzes a return statement and performs two computations:
*
* <ul>
* <li>If the returned expression is a field with non-empty must-call obligations, adds a {@link
* NotOwning} annotation to the return type of the current method. Note the implication: if
* a method returns a field of this class at <i>any</i> return site, the return type is
* inferred to be non-owning.
* <li>Compute the index of the parameter that is an alias of the return node and add it the
* {@link #returnNodeToParameterIndexMap} map. This map will be used later to infer the
* {@link MustCallAlias} annotation for method parameters.
* </ul>
*
* @param obligations set of obligations associated with the current block
* @param node the return node
*/
private void analyzeReturnNode(Set<Obligation> obligations, ReturnNode node) {
Node returnNode = node.getResult();
returnNode = mcca.removeCastsAndGetTmpVarIfPresent(returnNode);
if (resourceLeakAtf.hasEmptyMustCallValue(returnNode.getTree())) {
return;
}

if (returnNode instanceof FieldAccessNode) {
addNotOwning();
msridhar marked this conversation as resolved.
Show resolved Hide resolved
} else if (returnNode instanceof LocalVariableNode) {
Obligation returnNodeObligation =
MustCallConsistencyAnalyzer.getObligationForVar(
obligations, (LocalVariableNode) returnNode);
if (returnNodeObligation != null) {
returnNodeToParameterIndexMap.put(
returnNodeObligation, getIndexOfParam(returnNodeObligation));
}
}
}

/**
* Adds inferred {@literal @Owning} annotations to fields, {@literal @EnsuresCalledMethods}
* annotations to the current method, and {@literal @InheritableMustCall} annotation to the
* enclosing class.
* annotations to the current method, {@literal @MustCallAlias} annotation to the parameter, and
* {@literal @InheritableMustCall} annotation to the enclosing class.
*/
private void addMemberAndClassAnnotations() {
WholeProgramInference wpi = resourceLeakAtf.getWholeProgramInference();
Expand All @@ -241,6 +303,17 @@ private void addMemberAndClassAnnotations() {
addEnsuresCalledMethods();
}

// If all return statements alias the same parameter index, then add the @MustCallAlias
// annotation to that parameter and the return type.
if (!returnNodeToParameterIndexMap.isEmpty()) {
if (returnNodeToParameterIndexMap.values().stream().distinct().count() == 1) {
int indexOfParam = returnNodeToParameterIndexMap.values().iterator().next();
if (indexOfParam > 0) {
addMustCallAlias(indexOfParam);
}
}
}

addOrUpdateClassMustCall();
}

Expand Down Expand Up @@ -323,9 +396,13 @@ private void inferOwningField(Node node, MethodInvocationNode invocation) {
}

/**
* Analyzes an assignment statement and performs three computations:
* Analyzes an assignment statement and performs the following computations:
*
* <ul>
Nargeshdb marked this conversation as resolved.
Show resolved Hide resolved
* <li>If the current method under analysis is a constructor, the left-hand side of the
* assignment is the only owning field of the enclosing class, and the rhs is an alias of a
* formal parameter, it adds an {@code @MustCallAlias} annotation to the formal parameter
* and the result type of the constructor.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this need to be re-done if some other part of the inference discovers an owning field?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It won't be re-done in this iteration, in the next iteration it will infer an @owning annotation if the number of owning fields is greater than 1. I added a new test file(ReplaceMustCallAliasAnnotation.java) to check this scenario.

* <li>If the left-hand side of the assignment is an owning field, and the rhs is an alias of a
* formal parameter, it adds an {@code @Owning} annotation to the formal parameter.
* <li>If the left-hand side of the assignment is a resource variable, and the right-hand side
Expand All @@ -338,13 +415,11 @@ private void inferOwningField(Node node, MethodInvocationNode invocation) {
* @param obligations the set of obligations to update
* @param assignmentNode the assignment statement
*/
private void analyzeOwnershipTransferAtAssignment(
Set<Obligation> obligations, AssignmentNode assignmentNode) {
private void analyzeAssignmentNode(Set<Obligation> obligations, AssignmentNode assignmentNode) {
Node lhs = assignmentNode.getTarget();
Element lhsElement = TreeUtils.elementFromTree(lhs.getTree());
// Use the temporary variable for the rhs if it exists.
Node rhs = NodeUtils.removeCasts(assignmentNode.getExpression());
rhs = mcca.getTempVarOrNode(rhs);
Node rhs = mcca.removeCastsAndGetTmpVarIfPresent(assignmentNode.getExpression());

if (!(rhs instanceof LocalVariableNode)) {
return;
Expand All @@ -368,41 +443,71 @@ private void analyzeOwnershipTransferAtAssignment(
if (!TreeUtils.isConstructor(methodTree)) {
disposedFields.remove((VariableElement) lhsElement);
}
addOwningToParamsIfDisposedAtAssignment(obligations, rhsObligation, rhs);

int paramIndex = getIndexOfParam(rhsObligation);
if (paramIndex == -1) {
// We are only tracking formal parameter aliases. If the rhsObligation is not an alias of
// any of the formal parameters, it won't be present in the obligations set. Thus, skipping
// the rest of this method is fine.
return;
Nargeshdb marked this conversation as resolved.
Show resolved Hide resolved
}

if (TreeUtils.isConstructor(methodTree) && updateOwningFields().size() == 1) {
addMustCallAlias(paramIndex);
mcca.removeObligationsContainingVar(obligations, (LocalVariableNode) rhs);
} else {
addOwningToParam(paramIndex);
mcca.removeObligationsContainingVar(obligations, (LocalVariableNode) rhs);
}

} else if (lhsElement.getKind() == ElementKind.RESOURCE_VARIABLE && mcca.isMustCallClose(rhs)) {
addOwningToParamsIfDisposedAtAssignment(obligations, rhsObligation, rhs);
int paramIndex = getIndexOfParam(rhsObligation);
if (paramIndex > 0) {
addOwningToParam(paramIndex);
}
} else if (lhs instanceof LocalVariableNode) {
LocalVariableNode lhsVar = (LocalVariableNode) lhs;
mcca.updateObligationsForPseudoAssignment(obligations, assignmentNode, lhsVar, rhs);
}
}

/**
* If a must-call obligation of some alias of method parameter p is satisfied during the
* assignment, add an @Owning annotation to p, and remove the rhs node from the obligations set,
* since it no longer needs to be tracked.
* Return the (1-based) index of the method parameter that is an alias of the given {@code
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A parameter can't be an alias of an obligation, only of a node.
Why pass in an obligation here? That is, why not pass in a node?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's because we need to iterate over all the aliases of the given obligation.

* obligation}, if one exists; otherwise, return -1.
*
* @param obligations the set of obligations to update
* @param rhsObligation the obligation associated with the right-hand side of the assignment
* @param rhs the right-hand side of the assignment
* @param obligation the obligation
* @return the index of the current method parameter that is must-aliased to the given obligation,
* if one exists; otherwise, return -1.
*/
private void addOwningToParamsIfDisposedAtAssignment(
Set<Obligation> obligations, Obligation rhsObligation, Node rhs) {
Set<ResourceAlias> rhsAliases = rhsObligation.resourceAliases;
if (rhsAliases.isEmpty()) {
return;
}
private int getIndexOfParam(Obligation obligation) {
Set<ResourceAlias> resourceAliases = obligation.resourceAliases;
List<VariableElement> paramElts =
CollectionsPlume.mapList(TreeUtils::elementFromDeclaration, methodTree.getParameters());
for (ResourceAlias rhsAlias : rhsAliases) {
Element rhsElt = rhsAlias.element;
int i = paramElts.indexOf(rhsElt);
if (i != -1) {
addOwningToParam(i + 1);
mcca.removeObligationsContainingVar(obligations, (LocalVariableNode) rhs);
break;
for (ResourceAlias resourceAlias : resourceAliases) {
int paramIndex = paramElts.indexOf(resourceAlias.element);
if (paramIndex != -1) {
return paramIndex + 1;
}
}

return -1;
}

/** Adds a {@link NotOwning} annotation to the return type of the current method. */
private void addNotOwning() {
WholeProgramInference wpi = resourceLeakAtf.getWholeProgramInference();
wpi.addMethodDeclarationAnnotation(methodElt, NOTOWNING);
Nargeshdb marked this conversation as resolved.
Show resolved Hide resolved
}

/**
* Adds a {@link MustCallAlias} annotation to the formal parameter at the given index.
*
* @param index the index of a formal parameter of the current method (1-based)
*/
private void addMustCallAlias(int index) {
WholeProgramInference wpi = resourceLeakAtf.getWholeProgramInference();
wpi.addMethodDeclarationAnnotation(methodElt, MUSTCALLALIAS);
wpi.addDeclarationAnnotationToFormalParameter(methodElt, index, MUSTCALLALIAS);
}

/**
Expand Down Expand Up @@ -567,7 +672,7 @@ private void computeOwningForArgsOrReceiverOfCall(
}

for (Node argument : mcca.getArgumentsOfInvocation(invocation)) {
Node arg = NodeUtils.removeCasts(argument);
Node arg = mcca.removeCastsAndGetTmpVarIfPresent(argument);
// In the CFG, explicit passing of multiple arguments in the varargs position is represented
// via an ArrayCreationNode. In this case, it checks the called methods set of each argument
// passed in this position.
Expand Down Expand Up @@ -651,14 +756,16 @@ private Set<ResourceAlias> getResourceAliasOfNode(Set<Obligation> obligations, N
}

/**
* Infers @Owning annotations for formal parameters of the enclosing method or fields of the
* enclosing class, as follows:
* Infers @Owning or @MustCallAlias annotations for formal parameters of the enclosing method
* and @Owning annotation for fields of the enclosing class, as follows:
*
* <ul>
* <li>If a formal parameter is passed as an owning parameter, add an @Owning annotation to that
* formal parameter (see {@link #inferOwningParamsViaOwnershipTransfer}).
* <li>It calls {@link #computeOwningForArgsOrReceiverOfCall} to compute @Owning annotations for
* the receiver or arguments of a call by analyzing the called-methods set after the call.
* <li>It calls {@link #computeMustCallAliasFromThisOrSuperCall} to compute @MustCallAlias
* annotation for formal parameters and the result of the constructor.
* </ul>
*
* @param obligations the set of obligations to search in
Expand All @@ -671,11 +778,46 @@ private void computeOwningFromInvocation(Set<Obligation> obligations, Node invoc
// @EnsuresCalledMethods annotations on constructors as we have not observed them in practice.
inferOwningParamsViaOwnershipTransfer(obligations, invocation);
} else if (invocation instanceof MethodInvocationNode) {
computeMustCallAliasFromThisOrSuperCall(obligations, (MethodInvocationNode) invocation);
inferOwningParamsViaOwnershipTransfer(obligations, invocation);
Nargeshdb marked this conversation as resolved.
Show resolved Hide resolved
computeOwningForArgsOrReceiverOfCall(obligations, (MethodInvocationNode) invocation);
}
}

/**
* Adds the @MustCallAlias annotation to a method parameter when it is passed in a @MustCallAlias
* position during a constructor call using {@literal this} or {@literal super}.
*
* @param obligations the set of obligations associated with the current block
* @param node a method invocation node
*/
private void computeMustCallAliasFromThisOrSuperCall(
Set<Obligation> obligations, MethodInvocationNode node) {
if (!TreeUtils.isSuperConstructorCall(node.getTree())
&& !TreeUtils.isThisConstructorCall(node.getTree())) {
return;
}
List<? extends VariableElement> calleeParams = mcca.getParametersOfInvocation(node);
List<Node> arguments = mcca.getArgumentsOfInvocation(node);
for (int i = 0; i < arguments.size(); i++) {
if (!resourceLeakAtf.hasMustCallAlias(calleeParams.get(i))) {
continue;
}

Node arg = mcca.removeCastsAndGetTmpVarIfPresent(arguments.get(i));
Obligation argObligation =
MustCallConsistencyAnalyzer.getObligationForVar(obligations, (LocalVariableNode) arg);
if (argObligation == null) {
return;
}
int index = getIndexOfParam(argObligation);
if (index != -1) {
addMustCallAlias(index);
break;
}
}
}

/**
* Returns the called methods annotation for the given Java expression after the invocation node.
*
Expand Down
Loading