View Javadoc
1   ///////////////////////////////////////////////////////////////////////////////////////////////
2   // checkstyle: Checks Java source code and other text files for adherence to a set of rules.
3   // Copyright (C) 2001-2024 the original author or authors.
4   //
5   // This library is free software; you can redistribute it and/or
6   // modify it under the terms of the GNU Lesser General Public
7   // License as published by the Free Software Foundation; either
8   // version 2.1 of the License, or (at your option) any later version.
9   //
10  // This library is distributed in the hope that it will be useful,
11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  // Lesser General Public License for more details.
14  //
15  // You should have received a copy of the GNU Lesser General Public
16  // License along with this library; if not, write to the Free Software
17  // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  ///////////////////////////////////////////////////////////////////////////////////////////////
19  
20  package com.puppycrawl.tools.checkstyle.checks.coding;
21  
22  import static com.google.common.truth.Truth.assertWithMessage;
23  import static com.puppycrawl.tools.checkstyle.checks.coding.UnusedLocalVariableCheck.MSG_UNUSED_LOCAL_VARIABLE;
24  import static com.puppycrawl.tools.checkstyle.checks.coding.UnusedLocalVariableCheck.MSG_UNUSED_NAMED_LOCAL_VARIABLE;
25  
26  import java.io.File;
27  import java.util.Collection;
28  import java.util.Map;
29  import java.util.Objects;
30  import java.util.Optional;
31  import java.util.function.Predicate;
32  
33  import org.junit.jupiter.api.Test;
34  
35  import com.puppycrawl.tools.checkstyle.AbstractModuleTestSupport;
36  import com.puppycrawl.tools.checkstyle.JavaParser;
37  import com.puppycrawl.tools.checkstyle.api.DetailAST;
38  import com.puppycrawl.tools.checkstyle.api.TokenTypes;
39  import com.puppycrawl.tools.checkstyle.internal.utils.TestUtil;
40  import com.puppycrawl.tools.checkstyle.utils.CommonUtil;
41  
42  public class UnusedLocalVariableCheckTest extends AbstractModuleTestSupport {
43  
44      @Override
45      protected String getPackageLocation() {
46          return "com/puppycrawl/tools/checkstyle/checks/coding/unusedlocalvariable";
47      }
48  
49      @Test
50      public void testGetRequiredTokens() {
51          final UnusedLocalVariableCheck checkObj =
52                  new UnusedLocalVariableCheck();
53          final int[] actual = checkObj.getRequiredTokens();
54          final int[] expected = {
55              TokenTypes.DOT,
56              TokenTypes.VARIABLE_DEF,
57              TokenTypes.IDENT,
58              TokenTypes.SLIST,
59              TokenTypes.LITERAL_FOR,
60              TokenTypes.OBJBLOCK,
61              TokenTypes.CLASS_DEF,
62              TokenTypes.INTERFACE_DEF,
63              TokenTypes.ANNOTATION_DEF,
64              TokenTypes.PACKAGE_DEF,
65              TokenTypes.LITERAL_NEW,
66              TokenTypes.METHOD_DEF,
67              TokenTypes.CTOR_DEF,
68              TokenTypes.STATIC_INIT,
69              TokenTypes.INSTANCE_INIT,
70              TokenTypes.COMPILATION_UNIT,
71              TokenTypes.LAMBDA,
72              TokenTypes.ENUM_DEF,
73              TokenTypes.RECORD_DEF,
74              TokenTypes.COMPACT_CTOR_DEF,
75          };
76          assertWithMessage("Required tokens are invalid")
77                  .that(actual)
78                  .isEqualTo(expected);
79      }
80  
81      @Test
82      public void testGetAcceptableTokens() {
83          final UnusedLocalVariableCheck typeParameterNameCheckObj =
84                  new UnusedLocalVariableCheck();
85          final int[] actual = typeParameterNameCheckObj.getAcceptableTokens();
86          final int[] expected = {
87              TokenTypes.DOT,
88              TokenTypes.VARIABLE_DEF,
89              TokenTypes.IDENT,
90              TokenTypes.SLIST,
91              TokenTypes.LITERAL_FOR,
92              TokenTypes.OBJBLOCK,
93              TokenTypes.CLASS_DEF,
94              TokenTypes.INTERFACE_DEF,
95              TokenTypes.ANNOTATION_DEF,
96              TokenTypes.PACKAGE_DEF,
97              TokenTypes.LITERAL_NEW,
98              TokenTypes.METHOD_DEF,
99              TokenTypes.CTOR_DEF,
100             TokenTypes.STATIC_INIT,
101             TokenTypes.INSTANCE_INIT,
102             TokenTypes.COMPILATION_UNIT,
103             TokenTypes.LAMBDA,
104             TokenTypes.ENUM_DEF,
105             TokenTypes.RECORD_DEF,
106             TokenTypes.COMPACT_CTOR_DEF,
107         };
108         assertWithMessage("Acceptable tokens are invalid")
109                 .that(actual)
110                 .isEqualTo(expected);
111     }
112 
113     @Test
114     public void testUnusedLocalVariable() throws Exception {
115         final String[] expected = {
116             "27:9: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "sameName"),
117             "28:9: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "b"),
118             "31:9: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "testInLambdas"),
119             "33:9: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "coding"),
120             "34:9: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE,
121                     "InputUnusedLocalVariable"),
122             "50:13: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "b"),
123             "54:13: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "c"),
124             "65:9: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "b"),
125             "67:9: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "c"),
126             "71:9: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "p"),
127             "81:9: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "f"),
128             "84:9: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "foo"),
129             "91:13: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "a"),
130         };
131         verifyWithInlineConfigParser(
132                 getPath("InputUnusedLocalVariable.java"), expected);
133     }
134 
135     @Test
136     public void testUnusedLocalVar2() throws Exception {
137         final String[] expected = {
138             "17:14: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "i"),
139             "19:14: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "j"),
140             "30:9: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "a"),
141             "31:9: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "b"),
142             "39:13: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "b"),
143             "40:13: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "Test"),
144             "41:13: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "obj"),
145             "61:9: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "a"),
146             "76:17: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "b"),
147         };
148         verifyWithInlineConfigParser(
149                 getPath("InputUnusedLocalVariable2.java"),
150                 expected);
151     }
152 
153     @Test
154     public void testUnusedLocalVar3() throws Exception {
155         final String[] expected = {
156             "21:13: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "a"),
157         };
158         verifyWithInlineConfigParser(
159                 getPath("InputUnusedLocalVariable3.java"),
160                 expected);
161     }
162 
163     @Test
164     public void testUnusedLocalVarInAnonInnerClasses() throws Exception {
165         final String[] expected = {
166             "14:9: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "a"),
167             "15:9: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "b"),
168             "17:9: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "obj"),
169             "22:17: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "obj"),
170             "32:9: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "obj2"),
171             "46:9: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "m"),
172             "47:9: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "l"),
173             "59:9: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "h"),
174             "62:17: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "v"),
175         };
176         verifyWithInlineConfigParser(
177                 getPath("InputUnusedLocalVariableAnonInnerClasses.java"),
178                 expected);
179     }
180 
181     @Test
182     public void testUnusedLocalVarGenericAnonInnerClasses() throws Exception {
183         final String[] expected = {
184             "13:9: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "l"),
185             "14:9: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "obj"),
186             "33:13: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "l"),
187             "34:13: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "obj2"),
188             "47:9: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "s"),
189             "67:9: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "variable"),
190             "69:9: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "anotherVar"),
191             "78:47: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "obj2"),
192         };
193         verifyWithInlineConfigParser(
194                 getPath("InputUnusedLocalVariableGenericAnonInnerClasses.java"),
195                 expected);
196     }
197 
198     @Test
199     public void testUnusedLocalVarDepthOfClasses() throws Exception {
200         final String[] expected = {
201             "28:9: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "r"),
202             "49:21: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "a"),
203             "64:13: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "a"),
204             "94:9: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "variable"),
205         };
206         verifyWithInlineConfigParser(
207                 getPath("InputUnusedLocalVariableDepthOfClasses.java"),
208                 expected);
209     }
210 
211     @Test
212     public void testUnusedLocalVarNestedClasses() throws Exception {
213         final String[] expected = {
214             "21:13: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "V"),
215             "23:13: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "S"),
216             "24:13: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "Q"),
217             "36:9: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "variable"),
218             "44:9: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "anotherVariable"),
219             "67:21: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "s"),
220             "68:21: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "n"),
221         };
222         verifyWithInlineConfigParser(
223                 getPath("InputUnusedLocalVariableNestedClasses.java"),
224                 expected);
225     }
226 
227     @Test
228     public void testUnusedLocalVarNestedClasses2() throws Exception {
229         final String[] expected = {
230             "29:9: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "q"),
231             "30:51: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "obj"),
232             "46:21: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "b"),
233             "57:21: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "b"),
234             "108:33: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "s"),
235         };
236         verifyWithInlineConfigParser(
237                 getPath("InputUnusedLocalVariableNestedClasses2.java"),
238                 expected);
239     }
240 
241     @Test
242     public void testUnusedLocalVarNestedClasses3() throws Exception {
243         final String[] expected = {
244             "36:17: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "p2"),
245             "54:13: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "o"),
246             "93:13: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "b"),
247             "95:13: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "a"),
248         };
249 
250         verifyWithInlineConfigParser(
251                 getPath("InputUnusedLocalVariableNestedClasses3.java"),
252                 expected);
253     }
254 
255     @Test
256     public void testUnusedLocalVarNestedClasses4() throws Exception {
257         final String[] expected = {
258             "12:5: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "a"),
259             "13:5: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "ab"),
260         };
261 
262         verifyWithInlineConfigParser(
263                 getPath("InputUnusedLocalVariableNestedClasses4.java"),
264                 expected);
265     }
266 
267     @Test
268     public void testUnusedLocalVarNestedClasses5() throws Exception {
269         final String[] expected = {
270             "12:5: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "a"),
271             "13:5: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "ab"),
272             "19:11: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "abc"),
273         };
274 
275         verifyWithInlineConfigParser(
276                 getPath("InputUnusedLocalVariableNestedClasses5.java"),
277                 expected);
278     }
279 
280     @Test
281     public void testUnusedLocalVarNestedClasses6() throws Exception {
282         final String[] expected = {
283             "12:5: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "a"),
284             "13:5: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "ab"),
285         };
286 
287         verifyWithInlineConfigParser(
288                 getPath("InputUnusedLocalVariableNestedClasses6.java"),
289                 expected);
290     }
291 
292     @Test
293     public void testUnusedLocalVarNestedClasses7() throws Exception {
294         final String[] expected = {
295             "10:5: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "a"),
296             "11:5: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "ab"),
297             "16:9: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "ab"),
298             "23:9: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "a"),
299             "24:9: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "ab"),
300             "28:13: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "a"),
301         };
302 
303         verifyWithInlineConfigParser(
304                 getPath("InputUnusedLocalVariableNestedClasses7.java"),
305                 expected);
306     }
307 
308     @Test
309     public void testUnusedLocalVarTestWarningSeverity() throws Exception {
310         final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
311 
312         verifyWithInlineConfigParser(
313                 getPath("InputUnusedLocalVariableTestWarningSeverity.java"),
314                 expected);
315     }
316 
317     @Test
318     public void testUnusedLocalVarEnum() throws Exception {
319         final String[] expected = {
320             "22:9: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "a"),
321             "50:9: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "a"),
322             "77:9: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "a"),
323             "80:9: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "j"),
324             "92:9: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "d"),
325         };
326         verifyWithInlineConfigParser(
327                 getPath("InputUnusedLocalVariableEnum.java"),
328                 expected);
329     }
330 
331     @Test
332     public void testUnusedLocalVarLambdas() throws Exception {
333         final String[] expected = {
334             "14:9: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "hoo"),
335             "19:17: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "j"),
336             "29:9: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "hoo2"),
337             "30:9: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "hoo3"),
338             "32:15: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "myComponent"),
339             "34:19: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "myComponent3"),
340             "40:25: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "j"),
341             "52:21: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "j"),
342             "65:17: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "ja"),
343             "73:9: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "k"),
344         };
345         verifyWithInlineConfigParser(
346                 getPath("InputUnusedLocalVariableLambdaExpression.java"),
347                 expected);
348     }
349 
350     @Test
351     public void testUnusedLocalVariableLocalClasses() throws Exception {
352         final String[] expected = {
353             "14:9: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "a"),
354             "15:9: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "ab"),
355         };
356         verifyWithInlineConfigParser(
357                 getPath("InputUnusedLocalVariableLocalClasses.java"),
358                 expected);
359     }
360 
361     @Test
362     public void testUnusedLocalVarRecords() throws Exception {
363         final String[] expected = {
364             "16:9: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "var1"),
365             "25:9: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "var1"),
366             "26:9: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "obj"),
367             "36:9: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "var2"),
368         };
369         verifyWithInlineConfigParser(
370                 getNonCompilablePath("InputUnusedLocalVariableRecords.java"),
371                 expected);
372     }
373 
374     @Test
375     public void testUnusedLocalVarWithoutPackageStatement() throws Exception {
376         final String[] expected = {
377             "12:9: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "a"),
378             "24:9: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "var2"),
379             "45:13: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "var3"),
380         };
381         verifyWithInlineConfigParser(
382                 getNonCompilablePath("InputUnusedLocalVariableWithoutPackageStatement.java"),
383                 expected);
384     }
385 
386     @Test
387     public void testUnusedLocalVariableTernaryAndExpressions() throws Exception {
388         final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
389         verifyWithInlineConfigParser(
390                 getPath("InputUnusedLocalVariableTernaryAndExpressions.java"),
391                 expected);
392     }
393 
394     @Test
395     public void testUnusedLocalVariableSwitchStatement() throws Exception {
396         final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
397         verifyWithInlineConfigParser(
398                 getPath("InputUnusedLocalVariableSwitchStatement.java"),
399                 expected);
400     }
401 
402     @Test
403     public void testUnusedLocalVariableSwitchStatement2() throws Exception {
404         final String[] expected = {
405             "59:9: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "j"),
406         };
407         verifyWithInlineConfigParser(
408                 getPath("InputUnusedLocalVariableSwitchStatement2.java"),
409                 expected);
410     }
411 
412     @Test
413     public void testUnusedLocalVariableSwitchExpression() throws Exception {
414         final String[] expected = {
415             "16:9: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "line2"),
416         };
417         verifyWithInlineConfigParser(
418                 getNonCompilablePath("InputUnusedLocalVariableSwitchExpression.java"),
419                 expected);
420     }
421 
422     @Test
423     public void testUnusedLocalVariableWithAllowUnnamed() throws Exception {
424         final String[] expected = {
425             "20:13: " + getCheckMessage(MSG_UNUSED_NAMED_LOCAL_VARIABLE, "_x"),
426             "21:13: " + getCheckMessage(MSG_UNUSED_NAMED_LOCAL_VARIABLE, "__"),
427             "35:14: " + getCheckMessage(MSG_UNUSED_NAMED_LOCAL_VARIABLE, "__"),
428             "45:14: " + getCheckMessage(MSG_UNUSED_NAMED_LOCAL_VARIABLE, "__"),
429         };
430         verifyWithInlineConfigParser(
431                 getNonCompilablePath("InputUnusedLocalVariableWithAllowUnnamed.java"),
432                 expected);
433     }
434 
435     @Test
436     public void testUnusedLocalVariableWithAllowUnnamedFalse() throws Exception {
437         final String[] expected = {
438             "20:13: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "_x"),
439             "21:13: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "__"),
440             "22:13: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "_"),
441             "32:14: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "_"),
442             "35:14: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "__"),
443             "43:14: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "_"),
444             "46:14: " + getCheckMessage(MSG_UNUSED_LOCAL_VARIABLE, "__"),
445         };
446         verifyWithInlineConfigParser(
447                 getNonCompilablePath("InputUnusedLocalVariableWithAllowUnnamedFalse.java"),
448                 expected);
449     }
450 
451     @Test
452     public void testClearStateVariables() throws Exception {
453         final UnusedLocalVariableCheck check = new UnusedLocalVariableCheck();
454         final Optional<DetailAST> methodDef = TestUtil.findTokenInAstByPredicate(
455                 JavaParser.parseFile(
456                         new File(getPath("InputUnusedLocalVariable.java")),
457                         JavaParser.Options.WITHOUT_COMMENTS),
458                 ast -> ast.getType() == TokenTypes.METHOD_DEF);
459         assertWithMessage("Ast should contain METHOD_DEF")
460                 .that(methodDef.isPresent())
461                 .isTrue();
462         final DetailAST variableDef = methodDef.orElseThrow().getLastChild()
463                 .findFirstToken(TokenTypes.VARIABLE_DEF);
464         assertWithMessage("State is not cleared on beginTree")
465                 .that(TestUtil.isStatefulFieldClearedDuringBeginTree(check, variableDef,
466                         "variables",
467                         variables -> {
468                             return ((Collection<?>) variables).isEmpty();
469                         }))
470                 .isTrue();
471     }
472 
473     @Test
474     public void testClearStateClasses() throws Exception {
475         final UnusedLocalVariableCheck check = new UnusedLocalVariableCheck();
476         final Optional<DetailAST> classDef = TestUtil.findTokenInAstByPredicate(
477                 JavaParser.parseFile(
478                         new File(getPath("InputUnusedLocalVariable.java")),
479                         JavaParser.Options.WITHOUT_COMMENTS),
480                 ast -> ast.getType() == TokenTypes.CLASS_DEF);
481         assertWithMessage("Ast should contain CLASS_DEF")
482                 .that(classDef.isPresent())
483                 .isTrue();
484         final DetailAST classDefToken = classDef.orElseThrow();
485         assertWithMessage("State is not cleared on beginTree")
486                 .that(TestUtil.isStatefulFieldClearedDuringBeginTree(check, classDefToken,
487                         "typeDeclarations",
488                         typeDeclarations -> {
489                             return ((Collection<?>) typeDeclarations).isEmpty();
490                         }))
491                 .isTrue();
492         assertWithMessage("State is not cleared on beginTree")
493                 .that(TestUtil.isStatefulFieldClearedDuringBeginTree(check, classDefToken,
494                         "typeDeclAstToTypeDeclDesc",
495                         typeDeclAstToTypeDeclDesc -> {
496                             return ((Map<?, ?>) typeDeclAstToTypeDeclDesc).isEmpty();
497                         }))
498                 .isTrue();
499         assertWithMessage("State is not cleared on beginTree")
500                 .that(TestUtil.isStatefulFieldClearedDuringBeginTree(check, classDefToken,
501                         "depth",
502                         depth -> {
503                             return (int) depth == 0;
504                         }))
505                 .isTrue();
506     }
507 
508     @Test
509     public void testClearStateAnonInnerClass() throws Exception {
510         final UnusedLocalVariableCheck check = new UnusedLocalVariableCheck();
511         final DetailAST root = JavaParser.parseFile(
512                 new File(getPath("InputUnusedLocalVariableAnonInnerClasses.java")),
513                 JavaParser.Options.WITHOUT_COMMENTS);
514         // Not using TestUtil.isStatefulFieldClearedDuringBeginTree(..) because other
515         // nodes need to be processed first as those collections, maps are dependent on them.
516         final DetailAST classDefAst = root.findFirstToken(TokenTypes.CLASS_DEF);
517         final Optional<DetailAST> literalNew = TestUtil.findTokenInAstByPredicate(root,
518                 ast -> ast.getType() == TokenTypes.LITERAL_NEW);
519         assertWithMessage("Ast should contain LITERAL_NEW")
520                 .that(literalNew.isPresent())
521                 .isTrue();
522         check.beginTree(root);
523         check.visitToken(classDefAst);
524         check.visitToken(literalNew.orElseThrow());
525         check.beginTree(null);
526         final Predicate<Object> isClear = anonInnerAstToTypeDesc -> {
527             return ((Map<?, ?>) anonInnerAstToTypeDesc).isEmpty();
528         };
529         assertWithMessage("State is not cleared on beginTree")
530                 .that(isClear.test(TestUtil.getInternalState(
531                         check, "anonInnerAstToTypeDeclDesc")))
532                 .isTrue();
533         final Predicate<Object> isQueueClear = anonInnerClassHolders -> {
534             return ((Collection<?>) anonInnerClassHolders).isEmpty();
535         };
536         assertWithMessage("State is not cleared on beginTree")
537                 .that(isQueueClear.test(TestUtil.getInternalState(
538                         check, "anonInnerClassHolders")))
539                 .isTrue();
540     }
541 
542     @Test
543     public void testClearStatePackageDef() throws Exception {
544         final UnusedLocalVariableCheck check = new UnusedLocalVariableCheck();
545         final Optional<DetailAST> packageDef = TestUtil.findTokenInAstByPredicate(
546                 JavaParser.parseFile(
547                         new File(getPath("InputUnusedLocalVariable.java")),
548                         JavaParser.Options.WITHOUT_COMMENTS),
549                 ast -> ast.getType() == TokenTypes.PACKAGE_DEF);
550         assertWithMessage("Ast should contain PACKAGE_DEF")
551                 .that(packageDef.isPresent())
552                 .isTrue();
553         final DetailAST packageDefToken = packageDef.orElseThrow();
554         assertWithMessage("State is not cleared on beginTree")
555                 .that(TestUtil.isStatefulFieldClearedDuringBeginTree(check, packageDefToken,
556                         "packageName",
557                         Objects::isNull))
558                 .isTrue();
559     }
560 }