Skip to content

Commit d78dd6d

Browse files
cushonError Prone Team
authored and
Error Prone Team
committed
Don't report NonFinalStaticField findings for fields modified in @BeforeClass methods
PiperOrigin-RevId: 590890283
1 parent aadfdc3 commit d78dd6d

File tree

2 files changed

+95
-42
lines changed

2 files changed

+95
-42
lines changed

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

+79-42
Original file line numberDiff line numberDiff line change
@@ -38,15 +38,16 @@
3838
import com.google.errorprone.bugpatterns.BugChecker.VariableTreeMatcher;
3939
import com.google.errorprone.fixes.SuggestedFix;
4040
import com.google.errorprone.matchers.Description;
41+
import com.google.errorprone.util.ASTHelpers;
4142
import com.sun.source.tree.AssignmentTree;
4243
import com.sun.source.tree.CompoundAssignmentTree;
44+
import com.sun.source.tree.MethodTree;
4345
import com.sun.source.tree.Tree.Kind;
4446
import com.sun.source.tree.UnaryTree;
4547
import com.sun.source.tree.VariableTree;
4648
import com.sun.source.util.TreeScanner;
4749
import com.sun.tools.javac.code.Symbol.VarSymbol;
4850
import java.util.Objects;
49-
import java.util.concurrent.atomic.AtomicBoolean;
5051
import javax.lang.model.element.Modifier;
5152

5253
/** A BugPattern; see the summary. */
@@ -71,7 +72,11 @@ public Description matchVariable(VariableTree tree, VisitorState state) {
7172
.anyMatch(anno -> hasDirectAnnotationWithSimpleName(tree, anno))) {
7273
return NO_MATCH;
7374
}
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) {
7580
return describeMatch(tree);
7681
}
7782
return describeMatch(
@@ -117,45 +122,77 @@ private static String getDefaultInitializer(VariableTree tree, VisitorState stat
117122
return "null";
118123
}
119124

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;
160197
}
161198
}

core/src/test/java/com/google/errorprone/bugpatterns/NonFinalStaticFieldTest.java

+16
Original file line numberDiff line numberDiff line change
@@ -211,4 +211,20 @@ public void volatileRemoved() {
211211
"}")
212212
.doTest();
213213
}
214+
215+
@Test
216+
public void beforeClass() {
217+
compilationTestHelper
218+
.addSourceLines(
219+
"Test.java", //
220+
"import org.junit.BeforeClass;",
221+
"public class Test {",
222+
" private static String foo;",
223+
" @BeforeClass",
224+
" public static void setup() {",
225+
" foo = \"\";",
226+
" }",
227+
"}")
228+
.doTest();
229+
}
214230
}

0 commit comments

Comments
 (0)