-
Notifications
You must be signed in to change notification settings - Fork 347
/
ResourceLeakChecker.java
95 lines (83 loc) · 3.43 KB
/
ResourceLeakChecker.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
package org.checkerframework.checker.resourceleak;
import java.util.LinkedHashSet;
import javax.tools.Diagnostic.Kind;
import org.checkerframework.checker.calledmethods.CalledMethodsChecker;
import org.checkerframework.checker.compilermsgs.qual.CompilerMessageKey;
import org.checkerframework.checker.mustcall.MustCallChecker;
import org.checkerframework.checker.mustcall.MustCallNoCreatesMustCallForChecker;
import org.checkerframework.common.basetype.BaseTypeChecker;
import org.checkerframework.common.basetype.BaseTypeVisitor;
import org.checkerframework.framework.qual.StubFiles;
import org.checkerframework.framework.source.SupportedOptions;
/**
* The entry point for the Resource Leak Checker. This checker is a modifed {@link
* CalledMethodsChecker} that checks that the must-call obligations of each expression (as computed
* via the {@link org.checkerframework.checker.mustcall.MustCallChecker} have been fulfilled.
*/
@SupportedOptions({
"permitStaticOwning",
"permitInitializationLeak",
ResourceLeakChecker.COUNT_MUST_CALL,
MustCallChecker.NO_CREATES_MUSTCALLFOR,
MustCallChecker.NO_LIGHTWEIGHT_OWNERSHIP,
MustCallChecker.NO_RESOURCE_ALIASES
})
@StubFiles("IOUtils.astub")
public class ResourceLeakChecker extends CalledMethodsChecker {
/** Creates a ResourceLeakChecker. */
public ResourceLeakChecker() {}
/**
* Command-line option for counting how many must-call obligations were checked by the Resource
* Leak Checker, and emitting the number after processing all files. Used for generating tables
* for a research paper. Not of interest to most users.
*/
public static final String COUNT_MUST_CALL = "countMustCall";
/**
* The number of expressions with must-call obligations that were checked. Incremented only if the
* {@link #COUNT_MUST_CALL} command-line option was supplied.
*/
int numMustCall = 0;
/**
* The number of must-call-related errors issued. The count of verified must-call expressions is
* the difference between this and {@link #numMustCall}.
*/
int numMustCallFailed = 0;
@Override
protected LinkedHashSet<Class<? extends BaseTypeChecker>> getImmediateSubcheckerClasses() {
LinkedHashSet<Class<? extends BaseTypeChecker>> checkers =
super.getImmediateSubcheckerClasses();
if (this.processingEnv.getOptions().containsKey(MustCallChecker.NO_CREATES_MUSTCALLFOR)) {
checkers.add(MustCallNoCreatesMustCallForChecker.class);
} else {
checkers.add(MustCallChecker.class);
}
return checkers;
}
@Override
protected BaseTypeVisitor<?> createSourceVisitor() {
return new ResourceLeakVisitor(this);
}
@Override
public void reportError(Object source, @CompilerMessageKey String messageKey, Object... args) {
if (messageKey.equals("required.method.not.called")) {
// This is safe because of the message key.
String qualifiedTypeName = (String) args[1];
// Only count classes in the JDK, not user-defined classes.
if (MustCallConsistencyAnalyzer.isJdkClass(qualifiedTypeName)) {
numMustCallFailed++;
}
}
super.reportError(source, messageKey, args);
}
@Override
public void typeProcessingOver() {
if (hasOption(COUNT_MUST_CALL)) {
message(Kind.WARNING, "Found %d must call obligation(s).%n", numMustCall);
message(
Kind.WARNING,
"Successfully verified %d must call obligation(s).%n",
numMustCall - numMustCallFailed);
}
super.typeProcessingOver();
}
}