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.RequireThisCheck.MSG_METHOD;
24  import static com.puppycrawl.tools.checkstyle.checks.coding.RequireThisCheck.MSG_VARIABLE;
25  
26  import java.io.File;
27  import java.lang.reflect.Constructor;
28  import java.util.Collection;
29  import java.util.Optional;
30  import java.util.SortedSet;
31  
32  import org.antlr.v4.runtime.CommonToken;
33  import org.junit.jupiter.api.Test;
34  
35  import com.puppycrawl.tools.checkstyle.AbstractModuleTestSupport;
36  import com.puppycrawl.tools.checkstyle.DetailAstImpl;
37  import com.puppycrawl.tools.checkstyle.JavaParser;
38  import com.puppycrawl.tools.checkstyle.api.DetailAST;
39  import com.puppycrawl.tools.checkstyle.api.TokenTypes;
40  import com.puppycrawl.tools.checkstyle.api.Violation;
41  import com.puppycrawl.tools.checkstyle.internal.utils.TestUtil;
42  import com.puppycrawl.tools.checkstyle.utils.CommonUtil;
43  
44  public class RequireThisCheckTest extends AbstractModuleTestSupport {
45  
46      @Override
47      protected String getPackageLocation() {
48          return "com/puppycrawl/tools/checkstyle/checks/coding/requirethis";
49      }
50  
51      @Test
52      public void testIt() throws Exception {
53          final String[] expected = {
54              "20:9: " + getCheckMessage(MSG_VARIABLE, "i", ""),
55              "26:9: " + getCheckMessage(MSG_METHOD, "method1", ""),
56              "40:9: " + getCheckMessage(MSG_VARIABLE, "i", ""),
57              "58:13: " + getCheckMessage(MSG_VARIABLE, "z", ""),
58              "65:9: " + getCheckMessage(MSG_VARIABLE, "z", ""),
59              "122:9: " + getCheckMessage(MSG_VARIABLE, "i", ""),
60              "123:9: " + getCheckMessage(MSG_VARIABLE, "i", ""),
61              "124:9: " + getCheckMessage(MSG_METHOD, "instanceMethod", ""),
62              "130:13: " + getCheckMessage(MSG_METHOD, "instanceMethod", "Issue2240."),
63              "131:13: " + getCheckMessage(MSG_VARIABLE, "i", "Issue2240."),
64              "143:9: " + getCheckMessage(MSG_METHOD, "foo", ""),
65              "151:9: " + getCheckMessage(MSG_VARIABLE, "s", ""),
66              "177:16: " + getCheckMessage(MSG_VARIABLE, "a", ""),
67              "177:20: " + getCheckMessage(MSG_VARIABLE, "a", ""),
68              "177:24: " + getCheckMessage(MSG_VARIABLE, "a", ""),
69              "183:16: " + getCheckMessage(MSG_VARIABLE, "b", ""),
70              "183:20: " + getCheckMessage(MSG_VARIABLE, "b", ""),
71              "183:24: " + getCheckMessage(MSG_VARIABLE, "b", ""),
72              "211:25: " + getCheckMessage(MSG_VARIABLE, "field", ""),
73          };
74          verifyWithInlineConfigParser(
75                  getPath("InputRequireThisEnumInnerClassesAndBugs.java"),
76                 expected);
77      }
78  
79      @Test
80      public void testMethodsOnly() throws Exception {
81          final String[] expected = {
82              "25:9: " + getCheckMessage(MSG_METHOD, "method1", ""),
83              "124:9: " + getCheckMessage(MSG_METHOD, "instanceMethod", ""),
84              "130:13: " + getCheckMessage(MSG_METHOD, "instanceMethod", "Issue22402."),
85              "143:9: " + getCheckMessage(MSG_METHOD, "foo", ""),
86          };
87          verifyWithInlineConfigParser(
88                  getPath("InputRequireThisEnumInnerClassesAndBugs2.java"),
89                 expected);
90      }
91  
92      @Test
93      public void testFieldsOnly() throws Exception {
94          final String[] expected = {
95              "19:9: " + getCheckMessage(MSG_VARIABLE, "i", ""),
96              "39:9: " + getCheckMessage(MSG_VARIABLE, "i", ""),
97              "58:13: " + getCheckMessage(MSG_VARIABLE, "z", ""),
98              "65:9: " + getCheckMessage(MSG_VARIABLE, "z", ""),
99              "122:9: " + getCheckMessage(MSG_VARIABLE, "i", ""),
100             "123:9: " + getCheckMessage(MSG_VARIABLE, "i", ""),
101             "131:13: " + getCheckMessage(MSG_VARIABLE, "i", "Issue22403."),
102             "152:9: " + getCheckMessage(MSG_VARIABLE, "s", ""),
103             "179:16: " + getCheckMessage(MSG_VARIABLE, "a", ""),
104             "179:20: " + getCheckMessage(MSG_VARIABLE, "a", ""),
105             "179:24: " + getCheckMessage(MSG_VARIABLE, "a", ""),
106             "185:16: " + getCheckMessage(MSG_VARIABLE, "b", ""),
107             "185:20: " + getCheckMessage(MSG_VARIABLE, "b", ""),
108             "185:24: " + getCheckMessage(MSG_VARIABLE, "b", ""),
109         };
110         verifyWithInlineConfigParser(
111                 getPath("InputRequireThisEnumInnerClassesAndBugs3.java"),
112                expected);
113     }
114 
115     @Test
116     public void testFieldsInExpressions() throws Exception {
117         final String[] expected = {
118             "18:28: " + getCheckMessage(MSG_VARIABLE, "id", ""),
119             "19:28: " + getCheckMessage(MSG_VARIABLE, "length", ""),
120             "20:28: " + getCheckMessage(MSG_VARIABLE, "length", ""),
121             "21:26: " + getCheckMessage(MSG_VARIABLE, "length", ""),
122             "22:26: " + getCheckMessage(MSG_VARIABLE, "length", ""),
123             "23:25: " + getCheckMessage(MSG_VARIABLE, "length", ""),
124             "24:25: " + getCheckMessage(MSG_VARIABLE, "length", ""),
125             "25:26: " + getCheckMessage(MSG_VARIABLE, "length", ""),
126             "26:26: " + getCheckMessage(MSG_VARIABLE, "length", ""),
127             "27:33: " + getCheckMessage(MSG_VARIABLE, "b", ""),
128             "28:36: " + getCheckMessage(MSG_VARIABLE, "b", ""),
129             "29:26: " + getCheckMessage(MSG_VARIABLE, "length", ""),
130             "30:26: " + getCheckMessage(MSG_VARIABLE, "length", ""),
131             "31:28: " + getCheckMessage(MSG_VARIABLE, "length", ""),
132             "32:26: " + getCheckMessage(MSG_VARIABLE, "length", ""),
133             "33:26: " + getCheckMessage(MSG_VARIABLE, "length", ""),
134             "34:26: " + getCheckMessage(MSG_VARIABLE, "length", ""),
135             "35:31: " + getCheckMessage(MSG_VARIABLE, "b", ""),
136             "36:32: " + getCheckMessage(MSG_VARIABLE, "b", ""),
137         };
138         verifyWithInlineConfigParser(
139                 getPath("InputRequireThisExpressions.java"),
140                expected);
141     }
142 
143     @Test
144     public void testGenerics() throws Exception {
145         final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
146         verifyWithInlineConfigParser(
147                 getPath("InputRequireThis15Extensions.java"), expected);
148     }
149 
150     @Test
151     public void testGithubIssue41() throws Exception {
152         final String[] expected = {
153             "16:19: " + getCheckMessage(MSG_VARIABLE, "number", ""),
154             "17:16: " + getCheckMessage(MSG_METHOD, "other", ""),
155         };
156         verifyWithInlineConfigParser(
157                 getPath("InputRequireThisSimple.java"),
158                 expected);
159     }
160 
161     @Test
162     public void testTokensNotNull() {
163         final RequireThisCheck check = new RequireThisCheck();
164         assertWithMessage("Acceptable tokens should not be null")
165             .that(check.getAcceptableTokens())
166             .isNotNull();
167         assertWithMessage("Default tokens should not be null")
168             .that(check.getDefaultTokens())
169             .isNotNull();
170         assertWithMessage("Required tokens should not be null")
171             .that(check.getRequiredTokens())
172             .isNotNull();
173     }
174 
175     @Test
176     public void testWithAnonymousClass() throws Exception {
177         final String[] expected = {
178             "29:25: " + getCheckMessage(MSG_METHOD, "doSideEffect", ""),
179             "33:24: " + getCheckMessage(MSG_VARIABLE, "bar", "InputRequireThisAnonymousEmpty."),
180             "56:17: " + getCheckMessage(MSG_VARIABLE, "foobar", ""),
181         };
182         verifyWithInlineConfigParser(
183                 getPath("InputRequireThisAnonymousEmpty.java"),
184                 expected);
185     }
186 
187     @Test
188     public void testDefaultSwitch() {
189         final RequireThisCheck check = new RequireThisCheck();
190 
191         final DetailAstImpl ast = new DetailAstImpl();
192         ast.initialize(new CommonToken(TokenTypes.ENUM, "ENUM"));
193 
194         check.visitToken(ast);
195         final SortedSet<Violation> violations = check.getViolations();
196 
197         assertWithMessage("No exception violations expected")
198             .that(violations)
199             .isEmpty();
200     }
201 
202     @Test
203     public void testValidateOnlyOverlappingFalse() throws Exception {
204         final String[] expected = {
205             "29:9: " + getCheckMessage(MSG_VARIABLE, "field1", ""),
206             "30:9: " + getCheckMessage(MSG_VARIABLE, "fieldFinal1", ""),
207             "31:9: " + getCheckMessage(MSG_VARIABLE, "fieldFinal2", ""),
208             "32:9: " + getCheckMessage(MSG_VARIABLE, "fieldFinal3", ""),
209             "36:9: " + getCheckMessage(MSG_VARIABLE, "fieldFinal1", ""),
210             "37:9: " + getCheckMessage(MSG_VARIABLE, "fieldFinal2", ""),
211             "38:9: " + getCheckMessage(MSG_VARIABLE, "fieldFinal3", ""),
212             "42:9: " + getCheckMessage(MSG_VARIABLE, "fieldFinal1", ""),
213             "46:9: " + getCheckMessage(MSG_VARIABLE, "fieldFinal3", ""),
214             "50:9: " + getCheckMessage(MSG_VARIABLE, "fieldFinal1", ""),
215             "52:9: " + getCheckMessage(MSG_VARIABLE, "field1", ""),
216             "54:9: " + getCheckMessage(MSG_VARIABLE, "fieldFinal3", ""),
217             "58:9: " + getCheckMessage(MSG_VARIABLE, "fieldFinal2", ""),
218             "59:9: " + getCheckMessage(MSG_VARIABLE, "fieldFinal3", ""),
219             "69:9: " + getCheckMessage(MSG_VARIABLE, "fieldFinal1", ""),
220             "70:9: " + getCheckMessage(MSG_VARIABLE, "fieldFinal2", ""),
221             "89:9: " + getCheckMessage(MSG_VARIABLE, "field1", ""),
222             "128:9: " + getCheckMessage(MSG_VARIABLE, "field1", ""),
223             "137:9: " + getCheckMessage(MSG_VARIABLE, "field1", ""),
224             "141:9: " + getCheckMessage(MSG_METHOD, "method1", ""),
225             "177:9: " + getCheckMessage(MSG_VARIABLE, "fieldFinal1", ""),
226             "178:9: " + getCheckMessage(MSG_VARIABLE, "fieldFinal2", ""),
227             "179:9: " + getCheckMessage(MSG_VARIABLE, "fieldFinal3", ""),
228             "181:9: " + getCheckMessage(MSG_VARIABLE, "field1", ""),
229             "185:9: " + getCheckMessage(MSG_VARIABLE, "fieldFinal1", ""),
230             "186:9: " + getCheckMessage(MSG_VARIABLE, "fieldFinal2", ""),
231             "187:9: " + getCheckMessage(MSG_VARIABLE, "fieldFinal3", ""),
232             "189:9: " + getCheckMessage(MSG_VARIABLE, "field1", ""),
233             "194:9: " + getCheckMessage(MSG_VARIABLE, "field1", ""),
234             "198:9: " + getCheckMessage(MSG_VARIABLE, "field1", ""),
235             "219:9: " + getCheckMessage(MSG_VARIABLE, "field1", ""),
236             "226:29: " + getCheckMessage(MSG_VARIABLE, "booleanField", ""),
237             "237:21: " + getCheckMessage(MSG_VARIABLE, "field1", ""),
238             "247:9: " + getCheckMessage(MSG_VARIABLE, "field1", ""),
239             "262:9: " + getCheckMessage(MSG_VARIABLE, "booleanField", ""),
240             "271:9: " + getCheckMessage(MSG_VARIABLE, "field1", ""),
241             "279:18: " + getCheckMessage(MSG_METHOD, "addSuf2F", ""),
242             "284:9: " + getCheckMessage(MSG_VARIABLE, "field1", ""),
243             "284:18: " + getCheckMessage(MSG_METHOD, "addSuf2F", ""),
244             "310:9: " + getCheckMessage(MSG_VARIABLE, "field1", ""),
245             "349:9: " + getCheckMessage(MSG_VARIABLE, "field1", ""),
246             "383:25: " + getCheckMessage(MSG_METHOD, "getAction", ""),
247             "385:20: " + getCheckMessage(MSG_METHOD, "processAction", ""),
248             "393:16: " + getCheckMessage(MSG_METHOD, "processAction", ""),
249             "499:22: " + getCheckMessage(MSG_VARIABLE, "add", ""),
250         };
251         verifyWithInlineConfigParser(
252                 getPath("InputRequireThisValidateOnlyOverlappingFalse.java"), expected);
253     }
254 
255     @Test
256     public void testValidateOnlyOverlappingFalseLeaves() throws Exception {
257         final String[] expected = {
258             "26:31: " + getCheckMessage(MSG_METHOD, "id", ""),
259             "36:16: " + getCheckMessage(MSG_VARIABLE, "_a", ""),
260         };
261         verifyWithInlineConfigParser(
262                 getNonCompilablePath("InputRequireThisValidateOnlyOverlappingFalseLeaves.java"),
263                 expected);
264     }
265 
266     @Test
267     public void testValidateOnlyOverlappingTrue() throws Exception {
268         final String[] expected = {
269             "29:9: " + getCheckMessage(MSG_VARIABLE, "field1", ""),
270             "52:9: " + getCheckMessage(MSG_VARIABLE, "field1", ""),
271             "89:9: " + getCheckMessage(MSG_VARIABLE, "field1", ""),
272             "128:9: " + getCheckMessage(MSG_VARIABLE, "field1", ""),
273             "181:9: " + getCheckMessage(MSG_VARIABLE, "field1", ""),
274             "189:9: " + getCheckMessage(MSG_VARIABLE, "field1", ""),
275             "247:9: " + getCheckMessage(MSG_VARIABLE, "field1", ""),
276             "262:9: " + getCheckMessage(MSG_VARIABLE, "booleanField", ""),
277             "271:9: " + getCheckMessage(MSG_VARIABLE, "field1", ""),
278             "284:9: " + getCheckMessage(MSG_VARIABLE, "field1", ""),
279             "310:9: " + getCheckMessage(MSG_VARIABLE, "field1", ""),
280             "348:9: " + getCheckMessage(MSG_VARIABLE, "field1", ""),
281         };
282         verifyWithInlineConfigParser(
283                 getPath("InputRequireThisValidateOnlyOverlappingTrue.java"), expected);
284     }
285 
286     @Test
287     public void testValidateOnlyOverlappingTrue2() throws Exception {
288         final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
289         verifyWithInlineConfigParser(
290                 getPath("InputRequireThisValidateOnlyOverlappingTrue2.java"), expected);
291     }
292 
293     @Test
294     public void testReceiverParameter() throws Exception {
295         final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
296         verifyWithInlineConfigParser(
297                 getPath("InputRequireThisReceiver.java"), expected);
298     }
299 
300     @Test
301     public void testBraceAlone() throws Exception {
302         final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
303         verifyWithInlineConfigParser(
304                 getPath("InputRequireThisBraceAlone.java"), expected);
305     }
306 
307     @Test
308     public void testStatic() throws Exception {
309         final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
310         verifyWithInlineConfigParser(
311                 getPath("InputRequireThisStatic.java"), expected);
312     }
313 
314     @Test
315     public void testMethodReferences() throws Exception {
316         final String[] expected = {
317             "24:9: " + getCheckMessage(MSG_VARIABLE, "tags", ""),
318         };
319         verifyWithInlineConfigParser(
320                 getPath("InputRequireThisMethodReferences.java"), expected);
321     }
322 
323     @Test
324     public void testAllowLocalVars() throws Exception {
325         final String[] expected = {
326             "18:9: " + getCheckMessage(MSG_VARIABLE, "s1", ""),
327             "26:9: " + getCheckMessage(MSG_VARIABLE, "s1", ""),
328             "39:9: " + getCheckMessage(MSG_VARIABLE, "s2", ""),
329             "44:9: " + getCheckMessage(MSG_VARIABLE, "s2", ""),
330             "50:9: " + getCheckMessage(MSG_VARIABLE, "s2", ""),
331             "51:16: " + getCheckMessage(MSG_VARIABLE, "s1", ""),
332         };
333         verifyWithInlineConfigParser(
334                 getPath("InputRequireThisAllowLocalVars.java"), expected);
335     }
336 
337     @Test
338     public void testAllowLambdaParameters() throws Exception {
339         final String[] expected = {
340             "24:9: " + getCheckMessage(MSG_VARIABLE, "s1", ""),
341             "46:21: " + getCheckMessage(MSG_VARIABLE, "z", ""),
342             "71:29: " + getCheckMessage(MSG_VARIABLE, "a", ""),
343             "71:34: " + getCheckMessage(MSG_VARIABLE, "b", ""),
344             "81:17: " + getCheckMessage(MSG_VARIABLE, "thread", ""),
345         };
346         verifyWithInlineConfigParser(
347                 getPath("InputRequireThisAllowLambdaParameters.java"), expected);
348     }
349 
350     @Test
351     public void testTryWithResources() throws Exception {
352         final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
353         verifyWithInlineConfigParser(
354                 getPath("InputRequireThisTryWithResources.java"), expected);
355     }
356 
357     @Test
358     public void testTryWithResourcesOnlyOverlappingFalse() throws Exception {
359         final String[] expected = {
360             "44:23: " + getCheckMessage(MSG_VARIABLE, "fldCharset", ""),
361             "57:13: " + getCheckMessage(MSG_VARIABLE, "fldCharset", ""),
362             "69:45: " + getCheckMessage(MSG_METHOD, "methodToInvoke", ""),
363             "77:24: " + getCheckMessage(MSG_METHOD, "methodToInvoke", ""),
364             "103:51: " + getCheckMessage(MSG_VARIABLE, "fldBufferedReader", ""),
365             "107:23: " + getCheckMessage(MSG_VARIABLE, "fldBufferedReader", ""),
366             "107:54: " + getCheckMessage(MSG_VARIABLE, "fldScanner", ""),
367             "110:24: " + getCheckMessage(MSG_VARIABLE, "fldStreamReader", ""),
368             "111:23: " + getCheckMessage(MSG_VARIABLE, "fldBufferedReader", ""),
369             "111:54: " + getCheckMessage(MSG_VARIABLE, "fldScanner", ""),
370         };
371         verifyWithInlineConfigParser(
372                 getPath("InputRequireThisTryWithResourcesOnlyOverlappingFalse.java"), expected);
373     }
374 
375     @Test
376     public void testCatchVariables() throws Exception {
377         final String[] expected = {
378             "38:21: " + getCheckMessage(MSG_VARIABLE, "ex", ""),
379         };
380         verifyWithInlineConfigParser(
381                 getPath("InputRequireThisCatchVariables.java"), expected);
382     }
383 
384     @Test
385     public void testEnumConstant() throws Exception {
386         final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
387         verifyWithInlineConfigParser(
388                 getPath("InputRequireThisEnumConstant.java"), expected);
389     }
390 
391     @Test
392     public void testAnnotationInterface() throws Exception {
393         final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
394         verifyWithInlineConfigParser(
395                 getPath("InputRequireThisAnnotationInterface.java"), expected);
396     }
397 
398     @Test
399     public void testFor() throws Exception {
400         final String[] expected = {
401             "22:13: " + getCheckMessage(MSG_VARIABLE, "bottom", ""),
402             "30:34: " + getCheckMessage(MSG_VARIABLE, "name", ""),
403         };
404         verifyWithInlineConfigParser(
405                 getPath("InputRequireThisFor.java"), expected);
406     }
407 
408     @Test
409     public void testFinalInstanceVariable() throws Exception {
410         final String[] expected = {
411             "18:9: " + getCheckMessage(MSG_VARIABLE, "y", ""),
412             "19:9: " + getCheckMessage(MSG_VARIABLE, "z", ""),
413         };
414         verifyWithInlineConfigParser(
415                 getPath("InputRequireThisFinalInstanceVariable.java"), expected);
416     }
417 
418     @Test
419     public void test() throws Exception {
420         final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
421         verifyWithInlineConfigParser(
422                 getPath("InputRequireThisCaseGroup.java"), expected);
423     }
424 
425     @Test
426     public void testExtendedMethod() throws Exception {
427         final String[] expected = {
428             "31:9: " + getCheckMessage(MSG_VARIABLE, "EXPR", ""),
429         };
430         verifyWithInlineConfigParser(
431                 getPath("InputRequireThisExtendedMethod.java"), expected);
432     }
433 
434     @Test
435     public void testRecordsAndCompactCtors() throws Exception {
436         final String[] expected = {
437             "18:13: " + getCheckMessage(MSG_METHOD, "method1", ""),
438             "19:13: " + getCheckMessage(MSG_METHOD, "method2", ""),
439             "20:13: " + getCheckMessage(MSG_METHOD, "method3", ""),
440             "30:13: " + getCheckMessage(MSG_METHOD, "method1", ""),
441             "56:13: " + getCheckMessage(MSG_METHOD, "method1", ""),
442             "57:13: " + getCheckMessage(MSG_METHOD, "method2", ""),
443             "58:13: " + getCheckMessage(MSG_METHOD, "method3", ""),
444             "68:13: " + getCheckMessage(MSG_METHOD, "method1", ""),
445         };
446         verifyWithInlineConfigParser(
447                 getNonCompilablePath("InputRequireThisRecordsAndCompactCtors.java"),
448                 expected);
449     }
450 
451     @Test
452     public void testRecordCompactCtors() throws Exception {
453         final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
454         verifyWithInlineConfigParser(
455                 getNonCompilablePath("InputRequireThisRecordCompactCtors.java"),
456                 expected);
457     }
458 
459     @Test
460     public void testRecordsAsTopLevel() throws Exception {
461         final String[] expected = {
462             "17:9: " + getCheckMessage(MSG_METHOD, "method1", ""),
463             "18:9: " + getCheckMessage(MSG_METHOD, "method2", ""),
464             "19:9: " + getCheckMessage(MSG_METHOD, "method3", ""),
465             "26:9: " + getCheckMessage(MSG_METHOD, "method1", ""),
466             "30:21: " + getCheckMessage(MSG_VARIABLE, "x", ""),
467             "38:17: " + getCheckMessage(MSG_VARIABLE, "y", ""),
468             "45:9: " + getCheckMessage(MSG_METHOD, "method1", ""),
469         };
470         verifyWithInlineConfigParser(
471                 getNonCompilablePath("InputRequireThisRecordAsTopLevel.java"),
472                 expected);
473     }
474 
475     @Test
476     public void testRecordsDefault() throws Exception {
477         final String[] expected = {
478             "26:9: " + getCheckMessage(MSG_VARIABLE, "x", ""),
479         };
480         verifyWithInlineConfigParser(
481                 getNonCompilablePath("InputRequireThisRecordDefault.java"),
482                 expected);
483     }
484 
485     @Test
486     public void testRecordsWithCheckFields() throws Exception {
487         final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
488         verifyWithInlineConfigParser(
489                 getNonCompilablePath("InputRequireThisRecordsWithCheckFields.java"),
490                 expected);
491     }
492 
493     @Test
494     public void testRecordsWithCheckFieldsOverlap() throws Exception {
495         final String[] expected = {
496             "20:20: " + getCheckMessage(MSG_VARIABLE, "a", ""),
497             "39:20: " + getCheckMessage(MSG_VARIABLE, "a", ""),
498             "46:16: " + getCheckMessage(MSG_VARIABLE, "a", ""),
499         };
500         verifyWithInlineConfigParser(
501                 getNonCompilablePath("InputRequireThisRecordsWithCheckFieldsOverlap.java"),
502                 expected);
503     }
504 
505     @Test
506     public void testLocalClassesInsideLambdas() throws Exception {
507         final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
508         verifyWithInlineConfigParser(
509             getPath("InputRequireThisLocalClassesInsideLambdas.java"),
510             expected);
511     }
512 
513     /**
514      * We cannot confirm the type of the private class unless using reflection.
515      * Until <a href="https://github.com/checkstyle/checkstyle/issues/12666">#12666</a>.
516      *
517      * @throws Exception when code tested throws an exception.
518      */
519     @Test
520     public void testUnusedMethodCatch() throws Exception {
521         final DetailAstImpl ident = new DetailAstImpl();
522         ident.setText("testName");
523 
524         final Class<?> cls = Class.forName(RequireThisCheck.class.getName() + "$CatchFrame");
525         final Constructor<?> constructor = cls.getDeclaredConstructors()[0];
526         constructor.setAccessible(true);
527         final Object o = constructor.newInstance(null, ident);
528 
529         final DetailAstImpl actual = TestUtil.invokeMethod(o, "getFrameNameIdent");
530         assertWithMessage("expected ident token")
531             .that(actual)
532             .isSameInstanceAs(ident);
533         assertWithMessage("expected catch frame type")
534             .that(TestUtil.invokeMethod(o, "getType").toString())
535             .isEqualTo("CATCH_FRAME");
536     }
537 
538     /**
539      * We cannot confirm the type of the private class unless using reflection.
540      * Until <a href="https://github.com/checkstyle/checkstyle/issues/12666">#12666</a>.
541      *
542      * @throws Exception when code tested throws an exception.
543      */
544     @Test
545     public void testUnusedMethodFor() throws Exception {
546         final DetailAstImpl ident = new DetailAstImpl();
547         ident.setText("testName");
548 
549         final Class<?> cls = Class.forName(RequireThisCheck.class.getName() + "$ForFrame");
550         final Constructor<?> constructor = cls.getDeclaredConstructors()[0];
551         constructor.setAccessible(true);
552         final Object o = constructor.newInstance(null, ident);
553 
554         assertWithMessage("expected for frame type")
555             .that(TestUtil.invokeMethod(o, "getType").toString())
556             .isEqualTo("FOR_FRAME");
557     }
558 
559     /**
560      * We cannot reproduce situation when visitToken is called and leaveToken is not.
561      * So, we have to use reflection to be sure that even in such situation
562      * state of the field will be cleared.
563      *
564      * @throws Exception when code tested throws exception
565      */
566     @Test
567     public void testClearState() throws Exception {
568         final RequireThisCheck check = new RequireThisCheck();
569         final DetailAST root = JavaParser.parseFile(
570                 new File(getPath("InputRequireThisSimple.java")),
571                 JavaParser.Options.WITHOUT_COMMENTS);
572         final Optional<DetailAST> classDef = TestUtil.findTokenInAstByPredicate(root,
573             ast -> ast.getType() == TokenTypes.CLASS_DEF);
574 
575         assertWithMessage("Ast should contain CLASS_DEF")
576                 .that(classDef.isPresent())
577                 .isTrue();
578         assertWithMessage("State is not cleared on beginTree")
579                 .that(TestUtil.isStatefulFieldClearedDuringBeginTree(check, classDef.get(),
580                         "current", current -> ((Collection<?>) current).isEmpty()))
581                 .isTrue();
582     }
583 
584 }