Skip to content

Commit 93ec262

Browse files
authored
Make the RLC an empty aggregate checker calling the RLCCalledMethodsChecker
1 parent 1679b9c commit 93ec262

13 files changed

Lines changed: 428 additions & 192 deletions

File tree

checker/src/main/java/org/checkerframework/checker/mustcall/MustCallAnnotatedTypeFactory.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,15 @@ public ExecutableElement getMustCallValueElement() {
346346
return mustCallValueElement;
347347
}
348348

349+
/**
350+
* Returns the {@link InheritableMustCall#value} element.
351+
*
352+
* @return the {@link InheritableMustCall#value} element
353+
*/
354+
public ExecutableElement getInheritableMustCallValueElement() {
355+
return inheritableMustCallValueElement;
356+
}
357+
349358
/** Support @InheritableMustCall meaning @MustCall on all subtype elements. */
350359
private class MustCallDefaultQualifierForUseTypeAnnotator
351360
extends DefaultQualifierForUseTypeAnnotator {

checker/src/main/java/org/checkerframework/checker/resourceleak/MustCallConsistencyAnalyzer.java

Lines changed: 81 additions & 97 deletions
Large diffs are not rendered by default.

checker/src/main/java/org/checkerframework/checker/resourceleak/MustCallInference.java

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import org.checkerframework.checker.resourceleak.MustCallConsistencyAnalyzer.MethodExitKind;
3434
import org.checkerframework.checker.resourceleak.MustCallConsistencyAnalyzer.Obligation;
3535
import org.checkerframework.checker.resourceleak.MustCallConsistencyAnalyzer.ResourceAlias;
36+
import org.checkerframework.checker.rlccalledmethods.RLCCalledMethodsAnnotatedTypeFactory;
3637
import org.checkerframework.common.accumulation.AccumulationStore;
3738
import org.checkerframework.common.accumulation.AccumulationValue;
3839
import org.checkerframework.common.wholeprograminference.WholeProgramInference;
@@ -69,9 +70,9 @@
6970
*
7071
* <p>Each instance of this class corresponds to a single control flow graph (CFG), typically
7172
* representing a method. The entry method of this class is {@link
72-
* #runMustCallInference(ResourceLeakAnnotatedTypeFactory, ControlFlowGraph,
73+
* #runMustCallInference(RLCCalledMethodsAnnotatedTypeFactory, ControlFlowGraph,
7374
* MustCallConsistencyAnalyzer)}, invoked from the {@link
74-
* ResourceLeakAnnotatedTypeFactory#postAnalyze} method when Whole Program Inference is enabled.
75+
* RLCCalledMethodsAnnotatedTypeFactory#postAnalyze} method when Whole Program Inference is enabled.
7576
*
7677
* <p>The algorithm determines if the @MustCall obligation of a field is satisfied along some path
7778
* leading to the regular exit point of the method. If the obligation is satisfied, the algorithm
@@ -120,7 +121,7 @@ public class MustCallInference {
120121
/**
121122
* The type factory for the Resource Leak Checker, which is used to access the Must Call Checker.
122123
*/
123-
private final ResourceLeakAnnotatedTypeFactory resourceLeakAtf;
124+
private final RLCCalledMethodsAnnotatedTypeFactory resourceLeakAtf;
124125

125126
/** The MustCallConsistencyAnalyzer. */
126127
private final MustCallConsistencyAnalyzer mcca;
@@ -172,7 +173,7 @@ public class MustCallInference {
172173
* @param mcca the MustCallConsistencyAnalyzer
173174
*/
174175
/*package-private*/ MustCallInference(
175-
ResourceLeakAnnotatedTypeFactory resourceLeakAtf,
176+
RLCCalledMethodsAnnotatedTypeFactory resourceLeakAtf,
176177
ControlFlowGraph cfg,
177178
MustCallConsistencyAnalyzer mcca) {
178179
this.resourceLeakAtf = resourceLeakAtf;
@@ -198,15 +199,15 @@ public class MustCallInference {
198199

199200
/**
200201
* Creates a MustCallInference instance and runs the inference algorithm. This method is called by
201-
* the {@link ResourceLeakAnnotatedTypeFactory#postAnalyze} method if Whole Program Inference is
202-
* enabled.
202+
* the {@link RLCCalledMethodsAnnotatedTypeFactory#postAnalyze} method if Whole Program Inference
203+
* is enabled.
203204
*
204205
* @param resourceLeakAtf the type factory
205206
* @param cfg the control flow graph of the method to check
206207
* @param mcca the MustCallConsistencyAnalyzer
207208
*/
208-
/*package-private*/ static void runMustCallInference(
209-
ResourceLeakAnnotatedTypeFactory resourceLeakAtf,
209+
public static void runMustCallInference(
210+
RLCCalledMethodsAnnotatedTypeFactory resourceLeakAtf,
210211
ControlFlowGraph cfg,
211212
MustCallConsistencyAnalyzer mcca) {
212213
MustCallInference mustCallInferenceLogic = new MustCallInference(resourceLeakAtf, cfg, mcca);
@@ -248,7 +249,7 @@ private void runInference() {
248249
// before the checking phase. However, calling
249250
// updateObligationsWithInvocationResult() will not have any side effects on the
250251
// outcome of the Resource Leak Checker. This is because the inference occurs within
251-
// the postAnalyze method of the ResourceLeakAnnotatedTypeFactory, once the
252+
// the postAnalyze method of the RLCCalledMethodsAnnotatedTypeFactory, once the
252253
// consistency analyzer has completed its process.
253254
if (node instanceof MethodInvocationNode || node instanceof ObjectCreationNode) {
254255
if (mcca.shouldTrackInvocationResult(obligations, node, true)) {
@@ -393,7 +394,7 @@ private void addOwningToParam(int index) {
393394
* @return true if the field is an owning candidate, false otherwise
394395
*/
395396
private boolean isFieldOwningCandidate(
396-
ResourceLeakAnnotatedTypeFactory resourceLeakAtf, Element field) {
397+
RLCCalledMethodsAnnotatedTypeFactory resourceLeakAtf, Element field) {
397398
AnnotationMirror mustCallAnnotation = resourceLeakAtf.getMustCallAnnotation(field);
398399
if (mustCallAnnotation == null) {
399400
// Indicates @MustCallUnknown. We want to conservatively avoid inferring an @Owning

checker/src/main/java/org/checkerframework/checker/resourceleak/ResourceLeakChecker.java

Lines changed: 28 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -3,28 +3,37 @@
33
import com.google.common.collect.ImmutableSet;
44
import java.io.UnsupportedEncodingException;
55
import java.util.ArrayList;
6+
import java.util.LinkedHashSet;
67
import java.util.List;
8+
import java.util.NavigableSet;
79
import java.util.Set;
810
import java.util.regex.Matcher;
911
import java.util.regex.Pattern;
1012
import javax.lang.model.element.TypeElement;
1113
import javax.lang.model.type.TypeMirror;
1214
import javax.tools.Diagnostic;
13-
import org.checkerframework.checker.calledmethods.CalledMethodsChecker;
1415
import org.checkerframework.checker.compilermsgs.qual.CompilerMessageKey;
1516
import org.checkerframework.checker.mustcall.MustCallChecker;
16-
import org.checkerframework.checker.mustcall.MustCallNoCreatesMustCallForChecker;
1717
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
1818
import org.checkerframework.checker.nullness.qual.Nullable;
19-
import org.checkerframework.common.basetype.BaseTypeVisitor;
20-
import org.checkerframework.framework.qual.StubFiles;
19+
import org.checkerframework.checker.rlccalledmethods.RLCCalledMethodsChecker;
20+
import org.checkerframework.framework.source.AggregateChecker;
2121
import org.checkerframework.framework.source.SourceChecker;
2222
import org.checkerframework.framework.source.SupportedOptions;
2323

2424
/**
25-
* The entry point for the Resource Leak Checker. This checker is a modifed {@link
26-
* CalledMethodsChecker} that checks that the must-call obligations of each expression (as computed
27-
* via the {@link org.checkerframework.checker.mustcall.MustCallChecker} have been fulfilled.
25+
* The entry point for the Resource Leak Checker. This checker only counts the number of {@link
26+
* org.checkerframework.checker.mustcall.qual.MustCall} annotations and defines a set of ignored
27+
* exceptions. This checker calls the {@link RLCCalledMethodsChecker} as a direct subchecker, which
28+
* then in turn calls the {@link MustCallChecker} as a subchecker, and afterwards this checker
29+
* traverses the CFG to check whether all MustCall obligations are fulfilled.
30+
*
31+
* <p>The checker hierarchy is: this "empty" RLC &rarr; RLCCalledMethodsChecker &rarr;
32+
* MustCallChecker
33+
*
34+
* <p>The MustCallChecker is a subchecker of the RLCCm checker (instead of a sibling), since we want
35+
* them to operate on the same CFG (so we can get both a CM and MC store for a given CFG block),
36+
* which only works if one of them is a subchecker of the other.
2837
*/
2938
@SupportedOptions({
3039
"permitStaticOwning",
@@ -37,8 +46,7 @@
3746
ResourceLeakChecker.ENABLE_WPI_FOR_RLC,
3847
ResourceLeakChecker.ENABLE_RETURNS_RECEIVER
3948
})
40-
@StubFiles("IOUtils.astub")
41-
public class ResourceLeakChecker extends CalledMethodsChecker {
49+
public class ResourceLeakChecker extends AggregateChecker {
4250

4351
/** Creates a ResourceLeakChecker. */
4452
public ResourceLeakChecker() {}
@@ -144,23 +152,13 @@ public ResourceLeakChecker() {}
144152
private @MonotonicNonNull SetOfTypes ignoredExceptions = null;
145153

146154
@Override
147-
protected Set<Class<? extends SourceChecker>> getImmediateSubcheckerClasses() {
148-
Set<Class<? extends SourceChecker>> checkers = super.getImmediateSubcheckerClasses();
149-
150-
if (this.processingEnv.getOptions().containsKey(MustCallChecker.NO_CREATES_MUSTCALLFOR)) {
151-
checkers.add(MustCallNoCreatesMustCallForChecker.class);
152-
} else {
153-
checkers.add(MustCallChecker.class);
154-
}
155+
protected Set<Class<? extends SourceChecker>> getSupportedCheckers() {
156+
Set<Class<? extends SourceChecker>> checkers = new LinkedHashSet<>(1);
157+
checkers.add(RLCCalledMethodsChecker.class);
155158

156159
return checkers;
157160
}
158161

159-
@Override
160-
protected BaseTypeVisitor<?> createSourceVisitor() {
161-
return new ResourceLeakVisitor(this);
162-
}
163-
164162
@Override
165163
public void reportError(
166164
@Nullable Object source, @CompilerMessageKey String messageKey, Object... args) {
@@ -188,16 +186,7 @@ public void typeProcessingOver() {
188186
}
189187

190188
/**
191-
* Disable the Returns Receiver Checker unless it has been explicitly enabled with the {@link
192-
* #ENABLE_RETURNS_RECEIVER} option.
193-
*/
194-
@Override
195-
protected boolean isReturnsReceiverDisabled() {
196-
return !hasOption(ENABLE_RETURNS_RECEIVER) || super.isReturnsReceiverDisabled();
197-
}
198-
199-
/**
200-
* Get the set of exceptions that should be ignored. This set comes from the {@link
189+
* Returns the set of exceptions that should be ignored. This set comes from the {@link
201190
* #IGNORED_EXCEPTIONS} option if it was provided, or {@link #DEFAULT_IGNORED_EXCEPTIONS} if not.
202191
*
203192
* @return the set of exceptions to ignore
@@ -306,4 +295,11 @@ protected SetOfTypes parseIgnoredExceptions(String ignoredExceptionsOptionValue)
306295
}
307296
return types.getDeclaredType(elem);
308297
}
298+
299+
@Override
300+
public NavigableSet<String> getSuppressWarningsPrefixes() {
301+
NavigableSet<String> result = super.getSuppressWarningsPrefixes();
302+
result.add("builder");
303+
return result;
304+
}
309305
}
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
package org.checkerframework.checker.resourceleak;
2+
3+
import java.util.ArrayList;
4+
import java.util.Arrays;
5+
import java.util.List;
6+
import org.checkerframework.checker.mustcall.MustCallChecker;
7+
import org.checkerframework.checker.mustcall.MustCallNoCreatesMustCallForChecker;
8+
import org.checkerframework.checker.rlccalledmethods.RLCCalledMethodsChecker;
9+
import org.checkerframework.framework.source.SourceChecker;
10+
import org.checkerframework.framework.type.AnnotatedTypeFactory;
11+
import org.checkerframework.javacutil.TypeSystemError;
12+
13+
/**
14+
* Collection of static utility functions related to the various (sub-) checkers within the
15+
* ResourceLeakChecker.
16+
*/
17+
public class ResourceLeakUtils {
18+
19+
/** Do not instantiate; this class is a collection of static methods. */
20+
private ResourceLeakUtils() {
21+
throw new Error("Do not instantiate");
22+
}
23+
24+
/** List of checker names associated with the Resource Leak Checker. */
25+
public static List<String> rlcCheckers =
26+
new ArrayList<>(
27+
Arrays.asList(
28+
ResourceLeakChecker.class.getCanonicalName(),
29+
RLCCalledMethodsChecker.class.getCanonicalName(),
30+
MustCallChecker.class.getCanonicalName(),
31+
MustCallNoCreatesMustCallForChecker.class.getCanonicalName()));
32+
33+
/**
34+
* Given a type factory that is part of the resource leak checker hierarchy, returns the {@link
35+
* ResourceLeakChecker} in the checker hierarchy.
36+
*
37+
* @param referenceAtf the type factory to retrieve the {@link ResourceLeakChecker} from; must be
38+
* part of the Resource Leak hierarchy
39+
* @return the {@link ResourceLeakChecker} in the checker hierarchy
40+
*/
41+
public static ResourceLeakChecker getResourceLeakChecker(AnnotatedTypeFactory referenceAtf) {
42+
return getResourceLeakChecker(referenceAtf.getChecker());
43+
}
44+
45+
/**
46+
* Given a checker that is part of the resource leak checker hierarchy, returns the {@link
47+
* ResourceLeakChecker} in the checker hierarchy.
48+
*
49+
* @param referenceChecker the checker to retrieve the {@link ResourceLeakChecker} from; must be
50+
* part of the Resource Leak hierarchy
51+
* @return the {@link ResourceLeakChecker} in the checker hierarchy
52+
*/
53+
public static ResourceLeakChecker getResourceLeakChecker(SourceChecker referenceChecker) {
54+
if (referenceChecker instanceof ResourceLeakChecker) {
55+
return (ResourceLeakChecker) referenceChecker;
56+
} else if (referenceChecker instanceof RLCCalledMethodsChecker
57+
|| referenceChecker instanceof MustCallChecker) {
58+
return getResourceLeakChecker(referenceChecker.getParentChecker());
59+
} else {
60+
throw new TypeSystemError(
61+
"Bad argument to ResourceLeakUtils#getResourceLeakChecker(): "
62+
+ (referenceChecker == null ? "null" : referenceChecker.getClass().getSimpleName()));
63+
}
64+
}
65+
66+
/**
67+
* Given a type factory that is part of the resource leak checker hierarchy, returns the {@link
68+
* RLCCalledMethodsChecker} in the checker hierarchy.
69+
*
70+
* @param referenceAtf the type factory to retrieve the {@link RLCCalledMethodsChecker} from; must
71+
* be part of the Resource Leak hierarchy
72+
* @return the {@link RLCCalledMethodsChecker} in the checker hierarchy
73+
*/
74+
public static RLCCalledMethodsChecker getRLCCalledMethodsChecker(
75+
AnnotatedTypeFactory referenceAtf) {
76+
return getRLCCalledMethodsChecker(referenceAtf.getChecker());
77+
}
78+
79+
/**
80+
* Given a checker that is part of the resource leak checker hierarchy, returns the {@link
81+
* RLCCalledMethodsChecker} in the checker hierarchy.
82+
*
83+
* @param referenceChecker the checker to retrieve the {@link RLCCalledMethodsChecker} from; must
84+
* be part of the Resource Leak hierarchy
85+
* @return the {@link RLCCalledMethodsChecker} in the checker hierarchy
86+
*/
87+
public static RLCCalledMethodsChecker getRLCCalledMethodsChecker(SourceChecker referenceChecker) {
88+
if (referenceChecker instanceof RLCCalledMethodsChecker) {
89+
return (RLCCalledMethodsChecker) referenceChecker;
90+
} else if (referenceChecker instanceof ResourceLeakChecker) {
91+
return getRLCCalledMethodsChecker(
92+
referenceChecker.getSubchecker(RLCCalledMethodsChecker.class));
93+
} else if (referenceChecker instanceof MustCallChecker) {
94+
return getRLCCalledMethodsChecker(referenceChecker.getParentChecker());
95+
} else {
96+
throw new TypeSystemError(
97+
"Bad argument to"
98+
+ " ResourceLeakUtils#getRLCCalledMethodsChecker(): "
99+
+ (referenceChecker == null ? "null" : referenceChecker.getClass().getSimpleName()));
100+
}
101+
}
102+
}

checker/src/main/java/org/checkerframework/checker/resourceleak/IOUtils.astub renamed to checker/src/main/java/org/checkerframework/checker/rlccalledmethods/IOUtils.astub

File renamed without changes.

checker/src/main/java/org/checkerframework/checker/resourceleak/ResourceLeakAnalysis.java renamed to checker/src/main/java/org/checkerframework/checker/rlccalledmethods/RLCCalledMethodsAnalysis.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
1-
package org.checkerframework.checker.resourceleak;
1+
package org.checkerframework.checker.rlccalledmethods;
22

33
import javax.lang.model.type.TypeMirror;
44
import org.checkerframework.checker.calledmethods.CalledMethodsAnalysis;
55
import org.checkerframework.checker.calledmethods.CalledMethodsAnnotatedTypeFactory;
6+
import org.checkerframework.checker.resourceleak.SetOfTypes;
67

78
/**
89
* This variant of CFAnalysis extends the set of ignored exception types.
910
*
10-
* @see ResourceLeakChecker#getIgnoredExceptions()
11+
* @see RLCCalledMethodsChecker#getIgnoredExceptions()
1112
*/
12-
public class ResourceLeakAnalysis extends CalledMethodsAnalysis {
13+
public class RLCCalledMethodsAnalysis extends CalledMethodsAnalysis {
1314

1415
/**
1516
* The set of exceptions to ignore, cached from {@link
@@ -23,8 +24,8 @@ public class ResourceLeakAnalysis extends CalledMethodsAnalysis {
2324
* @param checker the checker
2425
* @param factory the factory
2526
*/
26-
protected ResourceLeakAnalysis(
27-
ResourceLeakChecker checker, CalledMethodsAnnotatedTypeFactory factory) {
27+
protected RLCCalledMethodsAnalysis(
28+
RLCCalledMethodsChecker checker, CalledMethodsAnnotatedTypeFactory factory) {
2829
super(checker, factory);
2930
this.ignoredExceptions = checker.getIgnoredExceptions();
3031
}

0 commit comments

Comments
 (0)