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
}
0 commit comments