Don't report NonFinalStaticField findings for fields modified in `@Be… · google/error-prone@d78dd6d (original) (raw)
`@@ -38,15 +38,16 @@
`
38
38
`import com.google.errorprone.bugpatterns.BugChecker.VariableTreeMatcher;
`
39
39
`import com.google.errorprone.fixes.SuggestedFix;
`
40
40
`import com.google.errorprone.matchers.Description;
`
``
41
`+
import com.google.errorprone.util.ASTHelpers;
`
41
42
`import com.sun.source.tree.AssignmentTree;
`
42
43
`import com.sun.source.tree.CompoundAssignmentTree;
`
``
44
`+
import com.sun.source.tree.MethodTree;
`
43
45
`import com.sun.source.tree.Tree.Kind;
`
44
46
`import com.sun.source.tree.UnaryTree;
`
45
47
`import com.sun.source.tree.VariableTree;
`
46
48
`import com.sun.source.util.TreeScanner;
`
47
49
`import com.sun.tools.javac.code.Symbol.VarSymbol;
`
48
50
`import java.util.Objects;
`
49
``
`-
import java.util.concurrent.atomic.AtomicBoolean;
`
50
51
`import javax.lang.model.element.Modifier;
`
51
52
``
52
53
`/** A BugPattern; see the summary. */
`
`@@ -71,7 +72,11 @@ public Description matchVariable(VariableTree tree, VisitorState state) {
`
71
72
` .anyMatch(anno -> hasDirectAnnotationWithSimpleName(tree, anno))) {
`
72
73
`return NO_MATCH;
`
73
74
` }
`
74
``
`-
if (!canBeRemoved(symbol, state) || isEverMutatedInSameCompilationUnit(symbol, state)) {
`
``
75
`+
IsMutated everMutatedInSameCompilationUnit = isEverMutatedInSameCompilationUnit(symbol, state);
`
``
76
`+
if (everMutatedInSameCompilationUnit == IsMutated.IN_BEFORE_METHOD) {
`
``
77
`+
return NO_MATCH;
`
``
78
`+
}
`
``
79
`+
if (!canBeRemoved(symbol, state) || everMutatedInSameCompilationUnit == IsMutated.TRUE) {
`
75
80
`return describeMatch(tree);
`
76
81
` }
`
77
82
`return describeMatch(
`
`@@ -117,45 +122,77 @@ private static String getDefaultInitializer(VariableTree tree, VisitorState stat
`
117
122
`return "null";
`
118
123
` }
`
119
124
``
120
``
`-
private static boolean isEverMutatedInSameCompilationUnit(VarSymbol symbol, VisitorState state) {
`
121
``
`-
AtomicBoolean seen = new AtomicBoolean(false);
`
122
``
`-
new TreeScanner<Void, Void>() {
`
123
``
`-
@Override
`
124
``
`-
public Void visitAssignment(AssignmentTree tree, Void unused) {
`
125
``
`-
if (Objects.equals(getSymbol(tree.getVariable()), symbol)) {
`
126
``
`-
seen.set(true);
`
127
``
`-
}
`
128
``
`-
return super.visitAssignment(tree, null);
`
129
``
`-
}
`
130
``
-
131
``
`-
@Override
`
132
``
`-
public Void visitCompoundAssignment(CompoundAssignmentTree tree, Void unused) {
`
133
``
`-
if (Objects.equals(getSymbol(tree.getVariable()), symbol)) {
`
134
``
`-
seen.set(true);
`
135
``
`-
}
`
136
``
`-
return super.visitCompoundAssignment(tree, null);
`
137
``
`-
}
`
138
``
-
139
``
`-
@Override
`
140
``
`-
public Void visitUnary(UnaryTree tree, Void unused) {
`
141
``
`-
if (Objects.equals(getSymbol(tree.getExpression()), symbol) && isMutating(tree.getKind())) {
`
142
``
`-
seen.set(true);
`
143
``
`-
}
`
144
``
`-
return super.visitUnary(tree, null);
`
145
``
`-
}
`
146
``
-
147
``
`-
private boolean isMutating(Kind kind) {
`
148
``
`-
switch (kind) {
`
149
``
`-
case POSTFIX_DECREMENT:
`
150
``
`-
case POSTFIX_INCREMENT:
`
151
``
`-
case PREFIX_DECREMENT:
`
152
``
`-
case PREFIX_INCREMENT:
`
153
``
`-
return true;
`
154
``
`-
default:
`
155
``
`-
return false;
`
156
``
`-
}
`
157
``
`-
}
`
158
``
`-
}.scan(state.getPath().getCompilationUnit(), null);
`
159
``
`-
return seen.get();
`
``
125
`+
enum IsMutated {
`
``
126
`+
TRUE,
`
``
127
`+
FALSE,
`
``
128
`+
IN_BEFORE_METHOD
`
``
129
`+
}
`
``
130
+
``
131
`+
private static IsMutated isEverMutatedInSameCompilationUnit(
`
``
132
`+
VarSymbol symbol, VisitorState state) {
`
``
133
`+
var scanner =
`
``
134
`+
new TreeScanner<Void, Void>() {
`
``
135
`+
IsMutated isMutated = IsMutated.FALSE;
`
``
136
+
``
137
`+
boolean inBeforeMethod = false;
`
``
138
+
``
139
`+
@Override
`
``
140
`+
public Void visitAssignment(AssignmentTree tree, Void unused) {
`
``
141
`+
if (Objects.equals(getSymbol(tree.getVariable()), symbol)) {
`
``
142
`+
isMutated();
`
``
143
`+
}
`
``
144
`+
return super.visitAssignment(tree, null);
`
``
145
`+
}
`
``
146
+
``
147
`+
@Override
`
``
148
`+
public Void visitCompoundAssignment(CompoundAssignmentTree tree, Void unused) {
`
``
149
`+
if (Objects.equals(getSymbol(tree.getVariable()), symbol)) {
`
``
150
`+
isMutated();
`
``
151
`+
}
`
``
152
`+
return super.visitCompoundAssignment(tree, null);
`
``
153
`+
}
`
``
154
+
``
155
`+
@Override
`
``
156
`+
public Void visitUnary(UnaryTree tree, Void unused) {
`
``
157
`+
if (Objects.equals(getSymbol(tree.getExpression()), symbol)
`
``
158
`+
&& isMutating(tree.getKind())) {
`
``
159
`+
isMutated();
`
``
160
`+
}
`
``
161
`+
return super.visitUnary(tree, null);
`
``
162
`+
}
`
``
163
+
``
164
`+
private void isMutated() {
`
``
165
`+
if (inBeforeMethod) {
`
``
166
`+
isMutated = IsMutated.IN_BEFORE_METHOD;
`
``
167
`+
} else if (isMutated.equals(IsMutated.FALSE)) {
`
``
168
`+
isMutated = IsMutated.TRUE;
`
``
169
`+
}
`
``
170
`+
}
`
``
171
+
``
172
`+
private boolean isMutating(Kind kind) {
`
``
173
`+
switch (kind) {
`
``
174
`+
case POSTFIX_DECREMENT:
`
``
175
`+
case POSTFIX_INCREMENT:
`
``
176
`+
case PREFIX_DECREMENT:
`
``
177
`+
case PREFIX_INCREMENT:
`
``
178
`+
return true;
`
``
179
`+
default:
`
``
180
`+
return false;
`
``
181
`+
}
`
``
182
`+
}
`
``
183
+
``
184
`+
@Override
`
``
185
`+
public Void visitMethod(MethodTree tree, Void unused) {
`
``
186
`+
boolean prev = inBeforeMethod;
`
``
187
`+
try {
`
``
188
`+
inBeforeMethod |= ASTHelpers.hasAnnotation(tree, "org.junit.BeforeClass", state);
`
``
189
`+
return super.visitMethod(tree, null);
`
``
190
`+
} finally {
`
``
191
`+
inBeforeMethod = prev;
`
``
192
`+
}
`
``
193
`+
}
`
``
194
`+
};
`
``
195
`+
scanner.scan(state.getPath().getCompilationUnit(), null);
`
``
196
`+
return scanner.isMutated;
`
160
197
` }
`
161
198
`}
`