39
39
/** A transfer function that accumulates the names of methods called. */
40
40
public class CalledMethodsTransfer extends AccumulationTransfer {
41
41
42
- /**
43
- * {@link #makeExceptionalStores(MethodInvocationNode, TransferInput)} requires a TransferInput,
44
- * but the actual exceptional stores need to be modified in {@link #accumulate(Node,
45
- * TransferResult, String...)}, which only has access to a TransferResult. So this field is set to
46
- * non-null in {@link #visitMethodInvocation(MethodInvocationNode, TransferInput)} via a call to
47
- * {@link #makeExceptionalStores(MethodInvocationNode, TransferInput)} (which reads the CFStores
48
- * from the TransferInput) before the call to accumulate(); accumulate() can then use this field
49
- * to read the CFStores; and then finally this field is then reset to null afterwards to prevent
50
- * it from being used somewhere it shouldn't be.
51
- */
52
- private @ Nullable Map <TypeMirror , AccumulationStore > exceptionalStores ;
53
-
54
42
/**
55
43
* The element for the CalledMethods annotation's value element. Stored in a field in this class
56
44
* to prevent the need to cast to CalledMethods ATF every time it's used.
@@ -118,10 +106,22 @@ protected boolean shouldPerformWholeProgramInference(Tree expressionTree, Tree l
118
106
@ Override
119
107
public TransferResult <AccumulationValue , AccumulationStore > visitMethodInvocation (
120
108
MethodInvocationNode node , TransferInput <AccumulationValue , AccumulationStore > input ) {
121
- exceptionalStores = makeExceptionalStores (node , input );
109
+
110
+ // The call to `super.visitMethodInvocation()` modifies the input store in-place. So if we end
111
+ // up needing to create the exceptional stores, then we'll need this copy taken beforehand.
112
+ AccumulationStore inputStore = input .getRegularStore ().copy ();
113
+
122
114
TransferResult <AccumulationValue , AccumulationStore > superResult =
123
115
super .visitMethodInvocation (node , input );
124
116
117
+ // Ensure that the result has a store for each possible exception. This affects the behavior of
118
+ // accumulate(), which will accumulate values into the result's exceptional stores as well.
119
+ Map <TypeMirror , AccumulationStore > exceptionalStores = superResult .getExceptionalStores ();
120
+ if (exceptionalStores == null ) {
121
+ exceptionalStores = makeExceptionalStores (node , inputStore );
122
+ superResult = superResult .withExceptionalStores (exceptionalStores );
123
+ }
124
+
125
125
ExecutableElement method = TreeUtils .elementFromUse (node .getTree ());
126
126
handleEnsuresCalledMethodsVarargs (node , method , superResult );
127
127
handleEnsuresCalledMethodsOnException (node , method , exceptionalStores );
@@ -134,20 +134,19 @@ public TransferResult<AccumulationValue, AccumulationStore> visitMethodInvocatio
134
134
.adjustMethodNameUsingValueChecker (methodName , node .getTree ());
135
135
accumulate (receiver , superResult , methodName );
136
136
}
137
- TransferResult <AccumulationValue , AccumulationStore > finalResult =
138
- new ConditionalTransferResult <>(
139
- superResult .getResultValue (),
140
- superResult .getThenStore (),
141
- superResult .getElseStore (),
142
- exceptionalStores );
143
- exceptionalStores = null ;
144
- return finalResult ;
137
+ return new ConditionalTransferResult <>(
138
+ superResult .getResultValue (),
139
+ superResult .getThenStore (),
140
+ superResult .getElseStore (),
141
+ exceptionalStores );
145
142
}
146
143
147
144
@ Override
148
145
public void accumulate (
149
146
Node node , TransferResult <AccumulationValue , AccumulationStore > result , String ... values ) {
150
147
super .accumulate (node , result , values );
148
+
149
+ Map <TypeMirror , AccumulationStore > exceptionalStores = result .getExceptionalStores ();
151
150
if (exceptionalStores == null ) {
152
151
return ;
153
152
}
@@ -186,23 +185,21 @@ public void accumulate(
186
185
* node} was definitely called.
187
186
*
188
187
* @param node a method invocation
189
- * @param input the transfer input associated with the method invocation
188
+ * @param inputStore the transfer input associated with the method invocation
190
189
* @return a map from types to stores. The keys are the same keys used by {@link
191
190
* ExceptionBlock#getExceptionalSuccessors()}. The values are copies of the regular store from
192
191
* {@code input}.
193
192
*/
194
193
private Map <TypeMirror , AccumulationStore > makeExceptionalStores (
195
- MethodInvocationNode node , TransferInput < AccumulationValue , AccumulationStore > input ) {
194
+ MethodInvocationNode node , AccumulationStore inputStore ) {
196
195
if (!(node .getBlock () instanceof ExceptionBlock )) {
197
196
// This can happen in some weird (buggy?) cases:
198
197
// see https://github.com/typetools/checker-framework/issues/3585
199
198
return Collections .emptyMap ();
200
199
}
201
200
ExceptionBlock block = (ExceptionBlock ) node .getBlock ();
202
201
Map <TypeMirror , AccumulationStore > result = new LinkedHashMap <>();
203
- block
204
- .getExceptionalSuccessors ()
205
- .forEach ((tm , b ) -> result .put (tm , input .getRegularStore ().copy ()));
202
+ block .getExceptionalSuccessors ().forEach ((tm , b ) -> result .put (tm , inputStore .copy ()));
206
203
return result ;
207
204
}
208
205
0 commit comments