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