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.HiddenFieldCheck.MSG_KEY;
24  
25  import java.io.File;
26  import java.util.Optional;
27  import java.util.function.Predicate;
28  
29  import org.junit.jupiter.api.Test;
30  
31  import com.puppycrawl.tools.checkstyle.AbstractModuleTestSupport;
32  import com.puppycrawl.tools.checkstyle.DefaultConfiguration;
33  import com.puppycrawl.tools.checkstyle.JavaParser;
34  import com.puppycrawl.tools.checkstyle.api.DetailAST;
35  import com.puppycrawl.tools.checkstyle.api.TokenTypes;
36  import com.puppycrawl.tools.checkstyle.internal.utils.TestUtil;
37  import com.puppycrawl.tools.checkstyle.utils.CommonUtil;
38  
39  public class HiddenFieldCheckTest
40      extends AbstractModuleTestSupport {
41  
42      @Override
43      protected String getPackageLocation() {
44          return "com/puppycrawl/tools/checkstyle/checks/coding/hiddenfield";
45      }
46  
47      @Test
48      public void testStaticVisibilityFromLambdas() throws Exception {
49          final String[] expected = {
50              "31:34: " + getCheckMessage(MSG_KEY, "value"),
51              "63:31: " + getCheckMessage(MSG_KEY, "languageCode"),
52              "72:35: " + getCheckMessage(MSG_KEY, "number"),
53              "85:35: " + getCheckMessage(MSG_KEY, "id"),
54              "113:33: " + getCheckMessage(MSG_KEY, "note"),
55              "138:48: " + getCheckMessage(MSG_KEY, "stringValue"),
56              "138:69: " + getCheckMessage(MSG_KEY, "intValue"),
57              "149:69: " + getCheckMessage(MSG_KEY, "doubleValue"),
58              "161:51: " + getCheckMessage(MSG_KEY, "firstString"),
59              "161:64: " + getCheckMessage(MSG_KEY, "secondString"),
60              "177:49: " + getCheckMessage(MSG_KEY, "first"),
61              "203:62: " + getCheckMessage(MSG_KEY, "mPi"),
62              "219:27: " + getCheckMessage(MSG_KEY, "justSomeList"),
63              "219:61: " + getCheckMessage(MSG_KEY, "justSomeMap"),
64              "231:55: " + getCheckMessage(MSG_KEY, "someObject"),
65              "239:52: " + getCheckMessage(MSG_KEY, "someObject"),
66          };
67          verifyWithInlineConfigParser(
68                  getPath("InputHiddenFieldLambdas.java"), expected);
69      }
70  
71      @Test
72      public void testStaticVisibilityFromAnonymousClasses() throws Exception {
73          final String[] expected = {
74              "22:45: " + getCheckMessage(MSG_KEY, "other"),
75              "28:42: " + getCheckMessage(MSG_KEY, "other"),
76              "36:49: " + getCheckMessage(MSG_KEY, "other"),
77              "46:53: " + getCheckMessage(MSG_KEY, "other"),
78              "58:26: " + getCheckMessage(MSG_KEY, "someField"),
79          };
80          verifyWithInlineConfigParser(
81                  getPath("InputHiddenFieldStaticVisibility.java"), expected);
82      }
83  
84      @Test
85      public void testNoParameters()
86              throws Exception {
87          final String[] expected = {
88              "30:13: " + getCheckMessage(MSG_KEY, "hidden"),
89              "39:13: " + getCheckMessage(MSG_KEY, "hidden"),
90              "44:18: " + getCheckMessage(MSG_KEY, "hidden"),
91              "58:17: " + getCheckMessage(MSG_KEY, "innerHidden"),
92              "67:17: " + getCheckMessage(MSG_KEY, "innerHidden"),
93              "68:17: " + getCheckMessage(MSG_KEY, "hidden"),
94              "73:22: " + getCheckMessage(MSG_KEY, "innerHidden"),
95              "76:22: " + getCheckMessage(MSG_KEY, "hidden"),
96              "88:17: " + getCheckMessage(MSG_KEY, "innerHidden"),
97              "89:17: " + getCheckMessage(MSG_KEY, "hidden"),
98              "94:13: " + getCheckMessage(MSG_KEY, "hidden"),
99              "150:13: " + getCheckMessage(MSG_KEY, "hidden"),
100             "155:13: " + getCheckMessage(MSG_KEY, "hidden"),
101             "160:13: " + getCheckMessage(MSG_KEY, "hidden"),
102             "164:13: " + getCheckMessage(MSG_KEY, "hidden"),
103             "212:17: " + getCheckMessage(MSG_KEY, "hidden"),
104             "229:13: " + getCheckMessage(MSG_KEY, "hidden"),
105             "235:13: " + getCheckMessage(MSG_KEY, "hiddenStatic"),
106         };
107         verifyWithInlineConfigParser(
108                 getPath("InputHiddenField1.java"), expected);
109     }
110 
111     @Test
112     public void testDefault()
113             throws Exception {
114         final String[] expected = {
115             "30:13: " + getCheckMessage(MSG_KEY, "hidden"),
116             "33:34: " + getCheckMessage(MSG_KEY, "hidden"),
117             "39:13: " + getCheckMessage(MSG_KEY, "hidden"),
118             "44:18: " + getCheckMessage(MSG_KEY, "hidden"),
119             "48:33: " + getCheckMessage(MSG_KEY, "hidden"),
120             "58:17: " + getCheckMessage(MSG_KEY, "innerHidden"),
121             "61:26: " + getCheckMessage(MSG_KEY, "innerHidden"),
122             "67:17: " + getCheckMessage(MSG_KEY, "innerHidden"),
123             "68:17: " + getCheckMessage(MSG_KEY, "hidden"),
124             "73:22: " + getCheckMessage(MSG_KEY, "innerHidden"),
125             "76:22: " + getCheckMessage(MSG_KEY, "hidden"),
126             "81:17: " + getCheckMessage(MSG_KEY, "innerHidden"),
127             "82:17: " + getCheckMessage(MSG_KEY, "hidden"),
128             "88:17: " + getCheckMessage(MSG_KEY, "innerHidden"),
129             "89:17: " + getCheckMessage(MSG_KEY, "hidden"),
130             "94:13: " + getCheckMessage(MSG_KEY, "hidden"),
131             "112:29: " + getCheckMessage(MSG_KEY, "prop"),
132             "118:29: " + getCheckMessage(MSG_KEY, "prop"),
133             "124:29: " + getCheckMessage(MSG_KEY, "prop"),
134             "136:28: " + getCheckMessage(MSG_KEY, "prop"),
135             "150:13: " + getCheckMessage(MSG_KEY, "hidden"),
136             "155:13: " + getCheckMessage(MSG_KEY, "hidden"),
137             "160:13: " + getCheckMessage(MSG_KEY, "hidden"),
138             "164:13: " + getCheckMessage(MSG_KEY, "hidden"),
139             "191:23: " + getCheckMessage(MSG_KEY, "y"),
140             "212:17: " + getCheckMessage(MSG_KEY, "hidden"),
141             "222:22: " + getCheckMessage(MSG_KEY, "hidden"),
142             "229:13: " + getCheckMessage(MSG_KEY, "hidden"),
143             "235:13: " + getCheckMessage(MSG_KEY, "hiddenStatic"),
144             "242:41: " + getCheckMessage(MSG_KEY, "x"),
145             "248:30: " + getCheckMessage(MSG_KEY, "xAxis"),
146             "265:41: " + getCheckMessage(MSG_KEY, "prop"),
147             "279:29: " + getCheckMessage(MSG_KEY, "prop"),
148             "290:42: " + getCheckMessage(MSG_KEY, "prop2"),
149             "302:19: " + getCheckMessage(MSG_KEY, "i"),
150         };
151         verifyWithInlineConfigParser(
152                 getPath("InputHiddenField2.java"), expected);
153     }
154 
155     /** Tests ignoreFormat property. */
156     @Test
157     public void testIgnoreFormat()
158             throws Exception {
159         final DefaultConfiguration checkConfig =
160             createModuleConfig(HiddenFieldCheck.class);
161         checkConfig.addProperty("ignoreFormat", "^i.*$");
162         assertWithMessage("Ignore format should not be null")
163             .that(checkConfig.getProperty("ignoreFormat"))
164             .isNotNull();
165         final String[] expected = {
166             "30:13: " + getCheckMessage(MSG_KEY, "hidden"),
167             "33:34: " + getCheckMessage(MSG_KEY, "hidden"),
168             "39:13: " + getCheckMessage(MSG_KEY, "hidden"),
169             "44:18: " + getCheckMessage(MSG_KEY, "hidden"),
170             "48:33: " + getCheckMessage(MSG_KEY, "hidden"),
171             "68:17: " + getCheckMessage(MSG_KEY, "hidden"),
172             "76:22: " + getCheckMessage(MSG_KEY, "hidden"),
173             "82:17: " + getCheckMessage(MSG_KEY, "hidden"),
174             "89:17: " + getCheckMessage(MSG_KEY, "hidden"),
175             "94:13: " + getCheckMessage(MSG_KEY, "hidden"),
176             "112:29: " + getCheckMessage(MSG_KEY, "prop"),
177             "118:29: " + getCheckMessage(MSG_KEY, "prop"),
178             "124:29: " + getCheckMessage(MSG_KEY, "prop"),
179             "136:28: " + getCheckMessage(MSG_KEY, "prop"),
180             "150:13: " + getCheckMessage(MSG_KEY, "hidden"),
181             "155:13: " + getCheckMessage(MSG_KEY, "hidden"),
182             "160:13: " + getCheckMessage(MSG_KEY, "hidden"),
183             "164:13: " + getCheckMessage(MSG_KEY, "hidden"),
184             "191:23: " + getCheckMessage(MSG_KEY, "y"),
185             "212:17: " + getCheckMessage(MSG_KEY, "hidden"),
186             "222:22: " + getCheckMessage(MSG_KEY, "hidden"),
187             "229:13: " + getCheckMessage(MSG_KEY, "hidden"),
188             "235:13: " + getCheckMessage(MSG_KEY, "hiddenStatic"),
189             "242:41: " + getCheckMessage(MSG_KEY, "x"),
190             "248:30: " + getCheckMessage(MSG_KEY, "xAxis"),
191             "265:41: " + getCheckMessage(MSG_KEY, "prop"),
192             "279:29: " + getCheckMessage(MSG_KEY, "prop"),
193             "290:42: " + getCheckMessage(MSG_KEY, "prop2"),
194         };
195         verifyWithInlineConfigParser(
196                 getPath("InputHiddenField3.java"), expected);
197     }
198 
199     /** Tests ignoreSetter property. */
200     @Test
201     public void testIgnoreSetter()
202             throws Exception {
203         final String[] expected = {
204             "30:13: " + getCheckMessage(MSG_KEY, "hidden"),
205             "33:34: " + getCheckMessage(MSG_KEY, "hidden"),
206             "39:13: " + getCheckMessage(MSG_KEY, "hidden"),
207             "44:18: " + getCheckMessage(MSG_KEY, "hidden"),
208             "48:33: " + getCheckMessage(MSG_KEY, "hidden"),
209             "58:17: " + getCheckMessage(MSG_KEY, "innerHidden"),
210             "61:26: " + getCheckMessage(MSG_KEY, "innerHidden"),
211             "67:17: " + getCheckMessage(MSG_KEY, "innerHidden"),
212             "68:17: " + getCheckMessage(MSG_KEY, "hidden"),
213             "73:22: " + getCheckMessage(MSG_KEY, "innerHidden"),
214             "76:22: " + getCheckMessage(MSG_KEY, "hidden"),
215             "81:17: " + getCheckMessage(MSG_KEY, "innerHidden"),
216             "82:17: " + getCheckMessage(MSG_KEY, "hidden"),
217             "88:17: " + getCheckMessage(MSG_KEY, "innerHidden"),
218             "89:17: " + getCheckMessage(MSG_KEY, "hidden"),
219             "94:13: " + getCheckMessage(MSG_KEY, "hidden"),
220             "118:29: " + getCheckMessage(MSG_KEY, "prop"),
221             "124:29: " + getCheckMessage(MSG_KEY, "prop"),
222             "136:28: " + getCheckMessage(MSG_KEY, "prop"),
223             "150:13: " + getCheckMessage(MSG_KEY, "hidden"),
224             "155:13: " + getCheckMessage(MSG_KEY, "hidden"),
225             "160:13: " + getCheckMessage(MSG_KEY, "hidden"),
226             "164:13: " + getCheckMessage(MSG_KEY, "hidden"),
227             "191:23: " + getCheckMessage(MSG_KEY, "y"),
228             "212:17: " + getCheckMessage(MSG_KEY, "hidden"),
229             "222:22: " + getCheckMessage(MSG_KEY, "hidden"),
230             "229:13: " + getCheckMessage(MSG_KEY, "hidden"),
231             "235:13: " + getCheckMessage(MSG_KEY, "hiddenStatic"),
232             "242:41: " + getCheckMessage(MSG_KEY, "x"),
233             "265:41: " + getCheckMessage(MSG_KEY, "prop"),
234             "290:42: " + getCheckMessage(MSG_KEY, "prop2"),
235         };
236         verifyWithInlineConfigParser(
237                 getPath("InputHiddenField4.java"), expected);
238     }
239 
240     /** Tests ignoreSetter and setterCanReturnItsClass properties. */
241     @Test
242     public void testIgnoreChainSetter()
243             throws Exception {
244         final String[] expected = {
245             "30:13: " + getCheckMessage(MSG_KEY, "hidden"),
246             "33:34: " + getCheckMessage(MSG_KEY, "hidden"),
247             "39:13: " + getCheckMessage(MSG_KEY, "hidden"),
248             "44:18: " + getCheckMessage(MSG_KEY, "hidden"),
249             "48:33: " + getCheckMessage(MSG_KEY, "hidden"),
250             "58:17: " + getCheckMessage(MSG_KEY, "innerHidden"),
251             "61:26: " + getCheckMessage(MSG_KEY, "innerHidden"),
252             "67:17: " + getCheckMessage(MSG_KEY, "innerHidden"),
253             "68:17: " + getCheckMessage(MSG_KEY, "hidden"),
254             "73:22: " + getCheckMessage(MSG_KEY, "innerHidden"),
255             "76:22: " + getCheckMessage(MSG_KEY, "hidden"),
256             "81:17: " + getCheckMessage(MSG_KEY, "innerHidden"),
257             "82:17: " + getCheckMessage(MSG_KEY, "hidden"),
258             "88:17: " + getCheckMessage(MSG_KEY, "innerHidden"),
259             "89:17: " + getCheckMessage(MSG_KEY, "hidden"),
260             "94:13: " + getCheckMessage(MSG_KEY, "hidden"),
261             "118:29: " + getCheckMessage(MSG_KEY, "prop"),
262             "124:29: " + getCheckMessage(MSG_KEY, "prop"),
263             "136:28: " + getCheckMessage(MSG_KEY, "prop"),
264             "150:13: " + getCheckMessage(MSG_KEY, "hidden"),
265             "155:13: " + getCheckMessage(MSG_KEY, "hidden"),
266             "160:13: " + getCheckMessage(MSG_KEY, "hidden"),
267             "164:13: " + getCheckMessage(MSG_KEY, "hidden"),
268             "191:23: " + getCheckMessage(MSG_KEY, "y"),
269             "212:17: " + getCheckMessage(MSG_KEY, "hidden"),
270             "222:22: " + getCheckMessage(MSG_KEY, "hidden"),
271             "229:13: " + getCheckMessage(MSG_KEY, "hidden"),
272             "235:13: " + getCheckMessage(MSG_KEY, "hiddenStatic"),
273             "242:41: " + getCheckMessage(MSG_KEY, "x"),
274         };
275         verifyWithInlineConfigParser(
276                 getPath("InputHiddenField5.java"), expected);
277     }
278 
279     /** Tests ignoreConstructorParameter property. */
280     @Test
281     public void testIgnoreConstructorParameter()
282             throws Exception {
283         final String[] expected = {
284             "29:13: " + getCheckMessage(MSG_KEY, "hidden"),
285             "38:13: " + getCheckMessage(MSG_KEY, "hidden"),
286             "43:18: " + getCheckMessage(MSG_KEY, "hidden"),
287             "47:33: " + getCheckMessage(MSG_KEY, "hidden"),
288             "57:17: " + getCheckMessage(MSG_KEY, "innerHidden"),
289             "66:17: " + getCheckMessage(MSG_KEY, "innerHidden"),
290             "67:17: " + getCheckMessage(MSG_KEY, "hidden"),
291             "72:22: " + getCheckMessage(MSG_KEY, "innerHidden"),
292             "75:22: " + getCheckMessage(MSG_KEY, "hidden"),
293             "80:17: " + getCheckMessage(MSG_KEY, "innerHidden"),
294             "81:17: " + getCheckMessage(MSG_KEY, "hidden"),
295             "87:17: " + getCheckMessage(MSG_KEY, "innerHidden"),
296             "88:17: " + getCheckMessage(MSG_KEY, "hidden"),
297             "93:13: " + getCheckMessage(MSG_KEY, "hidden"),
298             "111:29: " + getCheckMessage(MSG_KEY, "prop"),
299             "117:29: " + getCheckMessage(MSG_KEY, "prop"),
300             "123:29: " + getCheckMessage(MSG_KEY, "prop"),
301             "135:28: " + getCheckMessage(MSG_KEY, "prop"),
302             "149:13: " + getCheckMessage(MSG_KEY, "hidden"),
303             "154:13: " + getCheckMessage(MSG_KEY, "hidden"),
304             "159:13: " + getCheckMessage(MSG_KEY, "hidden"),
305             "163:13: " + getCheckMessage(MSG_KEY, "hidden"),
306             "190:23: " + getCheckMessage(MSG_KEY, "y"),
307             "211:17: " + getCheckMessage(MSG_KEY, "hidden"),
308             "228:13: " + getCheckMessage(MSG_KEY, "hidden"),
309             "234:13: " + getCheckMessage(MSG_KEY, "hiddenStatic"),
310             "241:41: " + getCheckMessage(MSG_KEY, "x"),
311             "247:30: " + getCheckMessage(MSG_KEY, "xAxis"),
312             "264:41: " + getCheckMessage(MSG_KEY, "prop"),
313             "278:29: " + getCheckMessage(MSG_KEY, "prop"),
314             "289:42: " + getCheckMessage(MSG_KEY, "prop2"),
315             "301:19: " + getCheckMessage(MSG_KEY, "i"),
316         };
317         verifyWithInlineConfigParser(
318                 getPath("InputHiddenField6.java"), expected);
319     }
320 
321     /** Test against a class with field declarations in different order. */
322     @Test
323     public void testReordered()
324             throws Exception {
325         final String[] expected = {
326             "30:13: " + getCheckMessage(MSG_KEY, "hidden"),
327             "33:40: " + getCheckMessage(MSG_KEY, "hidden"),
328             "39:13: " + getCheckMessage(MSG_KEY, "hidden"),
329             "44:18: " + getCheckMessage(MSG_KEY, "hidden"),
330             "48:33: " + getCheckMessage(MSG_KEY, "hidden"),
331             "58:17: " + getCheckMessage(MSG_KEY, "innerHidden"),
332             "61:26: " + getCheckMessage(MSG_KEY, "innerHidden"),
333             "67:17: " + getCheckMessage(MSG_KEY, "innerHidden"),
334             "68:17: " + getCheckMessage(MSG_KEY, "hidden"),
335             "73:22: " + getCheckMessage(MSG_KEY, "innerHidden"),
336             "76:22: " + getCheckMessage(MSG_KEY, "hidden"),
337             "81:17: " + getCheckMessage(MSG_KEY, "innerHidden"),
338             "82:17: " + getCheckMessage(MSG_KEY, "hidden"),
339             "88:17: " + getCheckMessage(MSG_KEY, "innerHidden"),
340             "89:17: " + getCheckMessage(MSG_KEY, "hidden"),
341             "95:13: " + getCheckMessage(MSG_KEY, "hidden"),
342             "117:17: " + getCheckMessage(MSG_KEY, "hidden"),
343             "130:21: " + getCheckMessage(MSG_KEY, "hidden"),
344             "137:13: " + getCheckMessage(MSG_KEY, "hidden"),
345             "143:13: " + getCheckMessage(MSG_KEY, "hiddenStatic"),
346         };
347         verifyWithInlineConfigParser(
348                 getPath("InputHiddenFieldReorder.java"), expected);
349     }
350 
351     @Test
352     public void testIgnoreAbstractMethods() throws Exception {
353 
354         final String[] expected = {
355             "30:13: " + getCheckMessage(MSG_KEY, "hidden"),
356             "33:34: " + getCheckMessage(MSG_KEY, "hidden"),
357             "39:13: " + getCheckMessage(MSG_KEY, "hidden"),
358             "44:18: " + getCheckMessage(MSG_KEY, "hidden"),
359             "48:33: " + getCheckMessage(MSG_KEY, "hidden"),
360             "58:17: " + getCheckMessage(MSG_KEY, "innerHidden"),
361             "61:26: " + getCheckMessage(MSG_KEY, "innerHidden"),
362             "67:17: " + getCheckMessage(MSG_KEY, "innerHidden"),
363             "68:17: " + getCheckMessage(MSG_KEY, "hidden"),
364             "73:22: " + getCheckMessage(MSG_KEY, "innerHidden"),
365             "76:22: " + getCheckMessage(MSG_KEY, "hidden"),
366             "81:17: " + getCheckMessage(MSG_KEY, "innerHidden"),
367             "82:17: " + getCheckMessage(MSG_KEY, "hidden"),
368             "88:17: " + getCheckMessage(MSG_KEY, "innerHidden"),
369             "89:17: " + getCheckMessage(MSG_KEY, "hidden"),
370             "94:13: " + getCheckMessage(MSG_KEY, "hidden"),
371             "112:29: " + getCheckMessage(MSG_KEY, "prop"),
372             "118:29: " + getCheckMessage(MSG_KEY, "prop"),
373             "124:29: " + getCheckMessage(MSG_KEY, "prop"),
374             "136:28: " + getCheckMessage(MSG_KEY, "prop"),
375             "150:13: " + getCheckMessage(MSG_KEY, "hidden"),
376             "155:13: " + getCheckMessage(MSG_KEY, "hidden"),
377             "160:13: " + getCheckMessage(MSG_KEY, "hidden"),
378             "164:13: " + getCheckMessage(MSG_KEY, "hidden"),
379             "191:23: " + getCheckMessage(MSG_KEY, "y"),
380             "212:17: " + getCheckMessage(MSG_KEY, "hidden"),
381             "222:22: " + getCheckMessage(MSG_KEY, "hidden"),
382             "229:13: " + getCheckMessage(MSG_KEY, "hidden"),
383             "235:13: " + getCheckMessage(MSG_KEY, "hiddenStatic"),
384             "248:30: " + getCheckMessage(MSG_KEY, "xAxis"),
385             "265:41: " + getCheckMessage(MSG_KEY, "prop"),
386             "279:29: " + getCheckMessage(MSG_KEY, "prop"),
387             "290:42: " + getCheckMessage(MSG_KEY, "prop2"),
388             "302:19: " + getCheckMessage(MSG_KEY, "i"),
389         };
390         verifyWithInlineConfigParser(
391                 getPath("InputHiddenField7.java"), expected);
392     }
393 
394     @Test
395     public void testReceiverParameter() throws Exception {
396         final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
397         verifyWithInlineConfigParser(
398                 getPath("InputHiddenFieldReceiver.java"), expected);
399     }
400 
401     @Test
402     public void testHiddenFieldEnhancedInstanceof() throws Exception {
403 
404         final String[] expected = {
405             "26:39: " + getCheckMessage(MSG_KEY, "price"),
406             "37:35: " + getCheckMessage(MSG_KEY, "hiddenStaticField"),
407         };
408         verifyWithInlineConfigParser(
409                 getNonCompilablePath("InputHiddenFieldEnhancedInstanceof.java"), expected);
410     }
411 
412     @Test
413     public void testHiddenFieldSwitchExpression() throws Exception {
414 
415         final String[] expected = {
416             "28:13: " + getCheckMessage(MSG_KEY, "x"),
417             "32:30: " + getCheckMessage(MSG_KEY, "word"),
418             "33:35: " + getCheckMessage(MSG_KEY, "otherWord"),
419             "34:21: " + getCheckMessage(MSG_KEY, "y"),
420             "38:21: " + getCheckMessage(MSG_KEY, "z"),
421             "42:21: " + getCheckMessage(MSG_KEY, "a"),
422             "46:21: " + getCheckMessage(MSG_KEY, "b"),
423             "53:13: " + getCheckMessage(MSG_KEY, "x"),
424             "57:30: " + getCheckMessage(MSG_KEY, "word"),
425             "58:35: " + getCheckMessage(MSG_KEY, "otherWord"),
426             "59:21: " + getCheckMessage(MSG_KEY, "y"),
427             "63:21: " + getCheckMessage(MSG_KEY, "z"),
428             "67:21: " + getCheckMessage(MSG_KEY, "a"),
429             "71:21: " + getCheckMessage(MSG_KEY, "b"),
430         };
431         verifyWithInlineConfigParser(
432                 getNonCompilablePath("InputHiddenFieldSwitchExpression.java"), expected);
433     }
434 
435     @Test
436     public void testHiddenFieldRecords() throws Exception {
437 
438         final String[] expected = {
439             "23:17: " + getCheckMessage(MSG_KEY, "myHiddenInt"),
440             "28:17: " + getCheckMessage(MSG_KEY, "myHiddenInt"),
441             "36:17: " + getCheckMessage(MSG_KEY, "hiddenField"),
442             "44:39: " + getCheckMessage(MSG_KEY, "hiddenStaticField"),
443             "58:39: " + getCheckMessage(MSG_KEY, "price"),
444             "67:21: " + getCheckMessage(MSG_KEY, "x"),
445             "71:20: " + getCheckMessage(MSG_KEY, "string"),
446             "81:21: " + getCheckMessage(MSG_KEY, "x"),
447             "85:20: " + getCheckMessage(MSG_KEY, "string"),
448         };
449         verifyWithInlineConfigParser(
450                 getNonCompilablePath("InputHiddenFieldRecords.java"), expected);
451     }
452 
453     @Test
454     public void testHiddenFieldLambdasInNestedScope() throws Exception {
455         final String[] expected = {
456             "21:34: " + getCheckMessage(MSG_KEY, "value"),
457         };
458         verifyWithInlineConfigParser(
459             getPath("InputHiddenFieldLambdas2.java"), expected);
460     }
461 
462     @Test
463     public void testClassNestedInRecord() throws Exception {
464 
465         final String[] expected = {
466             "23:26: " + getCheckMessage(MSG_KEY, "a"),
467         };
468         verifyWithInlineConfigParser(
469             getNonCompilablePath("InputHiddenFieldClassNestedInRecord.java"),
470             expected);
471     }
472 
473     @Test
474     public void testHiddenFieldInnerRecordsImplicitlyStatic() throws Exception {
475 
476         final String[] expected = {
477             "35:30: " + getCheckMessage(MSG_KEY, "pointer"),
478         };
479 
480         verifyWithInlineConfigParser(
481                 getNonCompilablePath("InputHiddenFieldInnerRecordsImplicitlyStatic.java"),
482                 expected);
483     }
484 
485     @Test
486     public void testHiddenFieldRecordsImplicitlyStaticClassComparison() throws Exception {
487 
488         final String[] expected = {
489             "49:27: " + getCheckMessage(MSG_KEY, "x"),
490         };
491 
492         verifyWithInlineConfigParser(
493                 getNonCompilablePath("InputHiddenFieldRecordsImplicitlyStaticClassComparison.java"),
494                 expected);
495     }
496 
497     /**
498      * We cannot reproduce situation when visitToken is called and leaveToken is not.
499      * So, we have to use reflection to be sure that even in such situation
500      * state of the field will be cleared.
501      *
502      * @throws Exception when code tested throws exception
503      */
504     @Test
505     public void testClearState() throws Exception {
506         final HiddenFieldCheck check = new HiddenFieldCheck();
507         final DetailAST root = JavaParser.parseFile(new File(getPath("InputHiddenField8.java")),
508                 JavaParser.Options.WITHOUT_COMMENTS);
509         final Optional<DetailAST> classDef = TestUtil.findTokenInAstByPredicate(root,
510             ast -> ast.getType() == TokenTypes.CLASS_DEF);
511 
512         assertWithMessage("Ast should contain CLASS_DEF")
513                 .that(classDef.isPresent())
514                 .isTrue();
515         assertWithMessage("State is not cleared on beginTree")
516                 .that(
517                     TestUtil.isStatefulFieldClearedDuringBeginTree(check, classDef.get(), "frame",
518                         new CheckIfStatefulFieldCleared()))
519                 .isTrue();
520     }
521 
522     private static final class CheckIfStatefulFieldCleared implements Predicate<Object> {
523 
524         @Override
525         public boolean test(Object frame) {
526             boolean result = frame != null;
527 
528             // verify object is cleared
529             if (result
530                     && (TestUtil.getInternalState(frame, "parent") != null
531                         || !TestUtil.<Boolean>getInternalState(frame, "staticType")
532                         || TestUtil.getInternalState(frame, "frameName") != null)) {
533                 result = false;
534             }
535 
536             return result;
537         }
538 
539     }
540 
541 }