forked from typetools/checker-framework
-
Notifications
You must be signed in to change notification settings - Fork 0
/
ResourceLeakTransfer.java
152 lines (137 loc) · 6.64 KB
/
ResourceLeakTransfer.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
package org.checkerframework.checker.resourceleak;
import java.util.List;
import javax.lang.model.element.AnnotationMirror;
import org.checkerframework.checker.calledmethods.CalledMethodsTransfer;
import org.checkerframework.checker.mustcall.CreatesMustCallForElementSupplier;
import org.checkerframework.checker.mustcall.MustCallAnnotatedTypeFactory;
import org.checkerframework.checker.mustcall.MustCallChecker;
import org.checkerframework.dataflow.analysis.TransferInput;
import org.checkerframework.dataflow.analysis.TransferResult;
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.SwitchExpressionNode;
import org.checkerframework.dataflow.cfg.node.TernaryExpressionNode;
import org.checkerframework.dataflow.expression.JavaExpression;
import org.checkerframework.framework.flow.CFStore;
import org.checkerframework.framework.flow.CFValue;
import org.checkerframework.javacutil.TypesUtils;
/** The transfer function for the resource-leak extension to the called-methods type system. */
public class ResourceLeakTransfer extends CalledMethodsTransfer {
/**
* Shadowed because we must dispatch to the Resource Leak Checker's version of
* getTypefactoryOfSubchecker to get the correct MustCallAnnotatedTypeFactory.
*/
private final ResourceLeakAnnotatedTypeFactory rlTypeFactory;
/**
* Create a new resource leak transfer function.
*
* @param analysis the analysis. Its type factory must be a {@link
* ResourceLeakAnnotatedTypeFactory}.
*/
public ResourceLeakTransfer(final ResourceLeakAnalysis analysis) {
super(analysis);
this.rlTypeFactory = (ResourceLeakAnnotatedTypeFactory) analysis.getTypeFactory();
}
@Override
public TransferResult<CFValue, CFStore> visitTernaryExpression(
TernaryExpressionNode node, TransferInput<CFValue, CFStore> input) {
TransferResult<CFValue, CFStore> result = super.visitTernaryExpression(node, input);
if (!TypesUtils.isPrimitiveOrBoxed(node.getType())) {
// Add the synthetic variable created during CFG construction to the temporary
// variable map (rather than creating a redundant temp var)
rlTypeFactory.addTempVar(node.getTernaryExpressionVar(), node.getTree());
}
return result;
}
@Override
public TransferResult<CFValue, CFStore> visitSwitchExpressionNode(
SwitchExpressionNode node, TransferInput<CFValue, CFStore> input) {
TransferResult<CFValue, CFStore> result = super.visitSwitchExpressionNode(node, input);
if (!TypesUtils.isPrimitiveOrBoxed(node.getType())) {
// Add the synthetic variable created during CFG construction to the temporary
// variable map (rather than creating a redundant temp var)
rlTypeFactory.addTempVar(node.getSwitchExpressionVar(), node.getTree());
}
return result;
}
@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;
}
/**
* Clears the called-methods store of all information about the target if an @CreatesMustCallFor
* method is invoked and the type factory can create obligations. Otherwise, does nothing.
*
* @param n a method invocation
* @param result the transfer result whose stores should be cleared of information
*/
private void handleCreatesMustCallFor(
MethodInvocationNode n, TransferResult<CFValue, CFStore> result) {
if (!rlTypeFactory.canCreateObligations()) {
return;
}
List<JavaExpression> targetExprs =
CreatesMustCallForElementSupplier.getCreatesMustCallForExpressions(
n, rlTypeFactory, rlTypeFactory);
AnnotationMirror defaultType = rlTypeFactory.top;
for (JavaExpression targetExpr : targetExprs) {
CFValue defaultTypeValue =
analysis.createSingleAnnotationValue(defaultType, targetExpr.getType());
if (result.containsTwoStores()) {
result.getThenStore().replaceValue(targetExpr, defaultTypeValue);
result.getElseStore().replaceValue(targetExpr, defaultTypeValue);
} else {
result.getRegularStore().replaceValue(targetExpr, defaultTypeValue);
}
}
}
@Override
public TransferResult<CFValue, CFStore> visitObjectCreation(
ObjectCreationNode node, TransferInput<CFValue, CFStore> input) {
TransferResult<CFValue, CFStore> result = super.visitObjectCreation(node, input);
updateStoreWithTempVar(result, node);
return result;
}
/**
* This method either creates or looks up the temp var t for node, and then updates the store to
* give t the same type as node. Temporary variables are supported for expressions throughout this
* checker (and the Must Call Checker) to enable refinement of their types. See the documentation
* of {@link MustCallConsistencyAnalyzer} for more details.
*
* @param node the node to be assigned to a temporary variable
* @param result the transfer result containing the store to be modified
*/
public void updateStoreWithTempVar(TransferResult<CFValue, CFStore> result, Node node) {
// Must-call obligations on primitives are not supported.
if (!TypesUtils.isPrimitiveOrBoxed(node.getType())) {
MustCallAnnotatedTypeFactory mcAtf =
rlTypeFactory.getTypeFactoryOfSubchecker(MustCallChecker.class);
LocalVariableNode temp = mcAtf.getTempVar(node);
if (temp != null) {
rlTypeFactory.addTempVar(temp, node.getTree());
JavaExpression localExp = JavaExpression.fromNode(temp);
AnnotationMirror anm =
rlTypeFactory
.getAnnotatedType(node.getTree())
.getAnnotationInHierarchy(rlTypeFactory.top);
insertIntoStores(result, localExp, anm == null ? rlTypeFactory.top : anm);
}
}
}
}