Skip to content

Commit 5d647de

Browse files
cushonError Prone Team
authored andcommitted
Reconcile BugChecker#isSuppressed with suppression handling in ErrorProneScanner
This makes the full, dizzying complexity of `ErrorProneScanner`'s suppression handling available in `BugChecker#isSuppressed`, including handling of custom suppression annotations and `-XepDisableWarningsInGeneratedCode`. #3094 PiperOrigin-RevId: 441580794
1 parent 47c2b05 commit 5d647de

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+141
-64
lines changed

check_api/src/main/java/com/google/errorprone/VisitorState.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,10 @@ public ErrorProneOptions errorProneOptions() {
262262
return sharedState.errorProneOptions;
263263
}
264264

265+
public Map<String, SeverityLevel> severityMap() {
266+
return sharedState.severityMap;
267+
}
268+
265269
public void reportMatch(Description description) {
266270
checkNotNull(description, "Use Description.NO_MATCH to denote an absent finding.");
267271
if (description == Description.NO_MATCH) {

check_api/src/main/java/com/google/errorprone/bugpatterns/BugChecker.java

Lines changed: 64 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,15 @@
1919
import static com.google.common.collect.ImmutableSet.toImmutableSet;
2020
import static com.google.errorprone.util.ASTHelpers.getModifiers;
2121
import static com.google.errorprone.util.ASTHelpers.getStartPosition;
22+
import static com.google.errorprone.util.ASTHelpers.getSymbol;
2223

2324
import com.google.common.collect.ImmutableRangeSet;
2425
import com.google.common.collect.Iterables;
2526
import com.google.common.collect.Range;
2627
import com.google.errorprone.BugCheckerInfo;
2728
import com.google.errorprone.BugPattern.SeverityLevel;
29+
import com.google.errorprone.ErrorProneOptions;
30+
import com.google.errorprone.SuppressionInfo;
2831
import com.google.errorprone.VisitorState;
2932
import com.google.errorprone.annotations.CheckReturnValue;
3033
import com.google.errorprone.fixes.Fix;
@@ -248,17 +251,17 @@ public boolean suppressedByAnyOf(Set<Name> annotations, VisitorState s) {
248251
}
249252

250253
/**
251-
* Returns true if the given tree is annotated with a {@code @SuppressWarnings} that disables this
252-
* bug checker.
254+
* @deprecated use {@link #isSuppressed(Tree, VisitorState)} instead
253255
*/
256+
@Deprecated
254257
public boolean isSuppressed(Tree tree) {
255258
return isSuppressed(ASTHelpers.getAnnotation(tree, SuppressWarnings.class));
256259
}
257260

258261
/**
259-
* Returns true if the given symbol is annotated with a {@code @SuppressWarnings} that disables
260-
* this bug checker.
262+
* @deprecated use {@link #isSuppressed(Symbol, VisitorState)} instead
261263
*/
264+
@Deprecated
262265
public boolean isSuppressed(Symbol symbol) {
263266
return isSuppressed(ASTHelpers.getAnnotation(symbol, SuppressWarnings.class));
264267
}
@@ -268,13 +271,45 @@ private boolean isSuppressed(SuppressWarnings suppression) {
268271
&& !Collections.disjoint(Arrays.asList(suppression.value()), allNames());
269272
}
270273

274+
/**
275+
* Returns true if the given tree is annotated with a {@code @SuppressWarnings} that disables this
276+
* bug checker.
277+
*/
278+
public boolean isSuppressed(Tree tree, VisitorState state) {
279+
Symbol sym = getSymbol(tree);
280+
return sym != null && isSuppressed(sym, state);
281+
}
282+
283+
/**
284+
* Returns true if the given symbol is annotated with a {@code @SuppressWarnings} or other
285+
* annotation that disables this bug checker.
286+
*/
287+
public boolean isSuppressed(Symbol sym, VisitorState state) {
288+
ErrorProneOptions errorProneOptions = state.errorProneOptions();
289+
boolean suppressedInGeneratedCode =
290+
errorProneOptions.disableWarningsInGeneratedCode()
291+
&& state.severityMap().get(canonicalName()) != SeverityLevel.ERROR;
292+
SuppressionInfo.SuppressedState suppressedState =
293+
SuppressionInfo.EMPTY
294+
.withExtendedSuppressions(sym, state, customSuppressionAnnotationNames.get(state))
295+
.suppressedState(BugChecker.this, suppressedInGeneratedCode, state);
296+
return suppressedState == SuppressionInfo.SuppressedState.SUPPRESSED;
297+
}
298+
299+
private final Supplier<? extends Set<? extends Name>> customSuppressionAnnotationNames =
300+
VisitorState.memoize(
301+
state ->
302+
customSuppressionAnnotations().stream()
303+
.map(a -> state.getName(a.getName()))
304+
.collect(toImmutableSet()));
305+
271306
/** Computes a RangeSet of code regions which are suppressed by this bug checker. */
272307
public ImmutableRangeSet<Integer> suppressedRegions(VisitorState state) {
273308
ImmutableRangeSet.Builder<Integer> suppressedRegions = ImmutableRangeSet.builder();
274309
new TreeScanner<Void, Void>() {
275310
@Override
276311
public Void scan(Tree tree, Void unused) {
277-
if (getModifiers(tree) != null && isSuppressed(tree)) {
312+
if (getModifiers(tree) != null && isSuppressed(tree, state)) {
278313
suppressedRegions.add(Range.closed(getStartPosition(tree), state.getEndPosition(tree)));
279314
} else {
280315
super.scan(tree, null);
@@ -517,11 +552,34 @@ public int hashCode() {
517552

518553
/** A {@link TreePathScanner} which skips trees which are suppressed for this check. */
519554
protected class SuppressibleTreePathScanner<A, B> extends TreePathScanner<A, B> {
555+
556+
// TODO(cushon): make this protected once it is required; currently it would shadow
557+
// other variables named state and break checks that pass the deprecated constructor
558+
private final VisitorState state;
559+
560+
public SuppressibleTreePathScanner(VisitorState state) {
561+
this.state = state;
562+
}
563+
564+
/**
565+
* @deprecated use {@link #SuppressibleTreePathScanner(VisitorState)} instead
566+
*/
567+
@Deprecated
568+
public SuppressibleTreePathScanner() {
569+
this(null);
570+
}
571+
520572
@Override
521573
public A scan(Tree tree, B b) {
522574
boolean isSuppressible =
523575
tree instanceof ClassTree || tree instanceof MethodTree || tree instanceof VariableTree;
524-
return isSuppressible && isSuppressed(tree) ? null : super.scan(tree, b);
576+
if (isSuppressible) {
577+
boolean suppressed = state != null ? isSuppressed(tree, state) : isSuppressed(tree);
578+
if (suppressed) {
579+
return null;
580+
}
581+
}
582+
return super.scan(tree, b);
525583
}
526584
}
527585
}

core/src/main/java/com/google/errorprone/bugpatterns/AlreadyChecked.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ private final class IfScanner extends SuppressibleTreePathScanner<Void, Void> {
8080
private final VisitorState state;
8181

8282
private IfScanner(VisitorState state) {
83+
super(state);
8384
this.state = state;
8485
}
8586

core/src/main/java/com/google/errorprone/bugpatterns/AmbiguousMethodReference.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ public Description matchClass(ClassTree tree, VisitorState state) {
6767
continue;
6868
}
6969
MethodSymbol msym = getSymbol((MethodTree) member);
70-
if (isSuppressed(msym)) {
70+
if (isSuppressed(msym, state)) {
7171
continue;
7272
}
7373
List<MethodSymbol> clash = methods.remove(methodReferenceDescriptor(types, msym));

core/src/main/java/com/google/errorprone/bugpatterns/AutoValueImmutableFields.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ private static Matcher<MethodTree> returning(String type) {
131131
public Description matchClass(ClassTree tree, VisitorState state) {
132132
if (ASTHelpers.hasAnnotation(tree, "com.google.auto.value.AutoValue", state)) {
133133
for (Tree memberTree : tree.getMembers()) {
134-
if (memberTree instanceof MethodTree && !isSuppressed(memberTree)) {
134+
if (memberTree instanceof MethodTree && !isSuppressed(memberTree, state)) {
135135
MethodTree methodTree = (MethodTree) memberTree;
136136
if (ABSTRACT_MATCHER.matches(methodTree, state)) {
137137
for (Map.Entry<String, Matcher<MethodTree>> entry : REPLACEMENT_TO_MATCHERS.entries()) {

core/src/main/java/com/google/errorprone/bugpatterns/AutoValueSubclassLeaked.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ private void scanAndReportAutoValueReferences(
6666
CompilationUnitTree tree,
6767
ImmutableSet<Type> autoValueClassesFromThisFile,
6868
VisitorState state) {
69-
new SuppressibleTreePathScanner<Void, Void>() {
69+
new SuppressibleTreePathScanner<Void, Void>(state) {
7070

7171
@Override
7272
public Void visitClass(ClassTree classTree, Void unused) {

core/src/main/java/com/google/errorprone/bugpatterns/BadImport.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ private Description buildDescription(
171171
CompilationUnitTree compilationUnit = state.getPath().getCompilationUnit();
172172
TreePath path = TreePath.getPath(compilationUnit, compilationUnit);
173173
IdentifierTree firstFound =
174-
new SuppressibleTreePathScanner<IdentifierTree, Void>() {
174+
new SuppressibleTreePathScanner<IdentifierTree, Void>(state) {
175175
@Override
176176
public IdentifierTree reduce(IdentifierTree r1, IdentifierTree r2) {
177177
return (r2 != null) ? r2 : r1;
@@ -180,7 +180,7 @@ public IdentifierTree reduce(IdentifierTree r1, IdentifierTree r2) {
180180
@Override
181181
public IdentifierTree visitIdentifier(IdentifierTree node, Void unused) {
182182
Symbol nodeSymbol = getSymbol(node);
183-
if (symbols.contains(nodeSymbol) && !isSuppressed(node)) {
183+
if (symbols.contains(nodeSymbol) && !isSuppressed(node, state)) {
184184
if (getCurrentPath().getParentPath().getLeaf().getKind() != Kind.CASE) {
185185
builder.prefixWith(node, enclosingReplacement);
186186
moveTypeAnnotations(node);

core/src/main/java/com/google/errorprone/bugpatterns/ClassName.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ public Description matchCompilationUnit(CompilationUnitTree tree, VisitorState s
5252
for (Tree member : tree.getTypeDecls()) {
5353
if (member instanceof ClassTree) {
5454
ClassTree classMember = (ClassTree) member;
55-
if (isSuppressed(classMember)) {
55+
if (isSuppressed(classMember, state)) {
5656
// If any top-level classes have @SuppressWarnings("ClassName"), ignore
5757
// this compilation unit. We can't rely on the normal suppression
5858
// mechanism because the only enclosing element is the package declaration,

core/src/main/java/com/google/errorprone/bugpatterns/DefaultPackage.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ public Description matchCompilationUnit(CompilationUnitTree tree, VisitorState s
3939
if (state.errorProneOptions().isTestOnlyTarget()) {
4040
return Description.NO_MATCH;
4141
}
42-
if (tree.getTypeDecls().stream().anyMatch(s -> isSuppressed(s))) {
42+
if (tree.getTypeDecls().stream().anyMatch(s -> isSuppressed(s, state))) {
4343
return Description.NO_MATCH;
4444
}
4545
if (tree.getTypeDecls().stream()

core/src/main/java/com/google/errorprone/bugpatterns/DoNotCallChecker.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ public Description matchMethod(MethodTree tree, VisitorState state) {
185185
public Description matchCompilationUnit(CompilationUnitTree tree, VisitorState state) {
186186
ImmutableListMultimap<VarSymbol, Type> assignedTypes = getAssignedTypes(state);
187187

188-
new SuppressibleTreePathScanner<Void, Void>() {
188+
new SuppressibleTreePathScanner<Void, Void>(state) {
189189
@Override
190190
public Void visitMethodInvocation(MethodInvocationTree tree, Void unused) {
191191
handleTree(tree, getSymbol(tree));

0 commit comments

Comments
 (0)