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.modifier;
21  
22  import static com.google.common.truth.Truth.assertWithMessage;
23  import static com.puppycrawl.tools.checkstyle.checks.modifier.RedundantModifierCheck.MSG_KEY;
24  import static com.puppycrawl.tools.checkstyle.internal.utils.TestUtil.getExpectedThrowable;
25  
26  import org.junit.jupiter.api.Test;
27  
28  import com.puppycrawl.tools.checkstyle.AbstractModuleTestSupport;
29  import com.puppycrawl.tools.checkstyle.DetailAstImpl;
30  import com.puppycrawl.tools.checkstyle.api.TokenTypes;
31  import com.puppycrawl.tools.checkstyle.utils.CommonUtil;
32  
33  public class RedundantModifierCheckTest
34      extends AbstractModuleTestSupport {
35  
36      @Override
37      protected String getPackageLocation() {
38          return "com/puppycrawl/tools/checkstyle/checks/modifier/redundantmodifier";
39      }
40  
41      @Test
42      public void testClassesInsideOfInterfaces() throws Exception {
43          final String[] expected = {
44              "19:5: " + getCheckMessage(MSG_KEY, "static"),
45              "25:5: " + getCheckMessage(MSG_KEY, "public"),
46              "28:5: " + getCheckMessage(MSG_KEY, "public"),
47              "34:5: " + getCheckMessage(MSG_KEY, "static"),
48          };
49          verifyWithInlineConfigParser(
50                  getPath("InputRedundantModifierClassesInsideOfInterfaces.java"),
51              expected);
52      }
53  
54      @Test
55      public void testItOne() throws Exception {
56          final String[] expected = {
57              "57:12: " + getCheckMessage(MSG_KEY, "static"),
58              "60:9: " + getCheckMessage(MSG_KEY, "public"),
59              "66:9: " + getCheckMessage(MSG_KEY, "abstract"),
60              "69:9: " + getCheckMessage(MSG_KEY, "public"),
61              // "72:9: Redundant 'abstract' modifier.",
62              "75:9: " + getCheckMessage(MSG_KEY, "final"),
63              "82:13: " + getCheckMessage(MSG_KEY, "final"),
64              "91:12: " + getCheckMessage(MSG_KEY, "final"),
65              "102:1: " + getCheckMessage(MSG_KEY, "abstract"),
66          };
67          verifyWithInlineConfigParser(
68                  getPath("InputRedundantModifierItOne.java"), expected);
69      }
70  
71      @Test
72      public void testItTwo() throws Exception {
73          final String[] expected = {
74              "22:5: " + getCheckMessage(MSG_KEY, "public"),
75              "23:5: " + getCheckMessage(MSG_KEY, "final"),
76              "24:5: " + getCheckMessage(MSG_KEY, "static"),
77              "26:5: " + getCheckMessage(MSG_KEY, "public"),
78              "27:5: " + getCheckMessage(MSG_KEY, "abstract"),
79          };
80          verifyWithInlineConfigParser(
81                  getPath("InputRedundantModifierItTwo.java"), expected);
82      }
83  
84      @Test
85      public void testStaticMethodInInterface()
86              throws Exception {
87          final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
88          verifyWithInlineConfigParser(
89                  getPath("InputRedundantModifierStaticMethodInInterface.java"),
90              expected);
91      }
92  
93      @Test
94      public void testFinalInInterface()
95              throws Exception {
96          final String[] expected = {
97              "13:9: " + getCheckMessage(MSG_KEY, "final"),
98          };
99          verifyWithInlineConfigParser(
100                 getPath("InputRedundantModifierFinalInInterface.java"), expected);
101     }
102 
103     @Test
104     public void testEnumConstructorIsImplicitlyPrivate() throws Exception {
105         final String[] expected = {
106             "14:5: " + getCheckMessage(MSG_KEY, "private"),
107         };
108         verifyWithInlineConfigParser(
109                 getPath("InputRedundantModifierConstructorModifier.java"), expected);
110     }
111 
112     @Test
113     public void testInnerTypeInInterfaceIsImplicitlyStatic() throws Exception {
114         final String[] expected = {
115             "12:5: " + getCheckMessage(MSG_KEY, "static"),
116             "16:5: " + getCheckMessage(MSG_KEY, "static"),
117         };
118         verifyWithInlineConfigParser(
119                 getPath("InputRedundantModifierStaticInInnerTypeOfInterface.java"),
120             expected);
121     }
122 
123     @Test
124     public void testNotPublicClassConstructorHasNotPublicModifier() throws Exception {
125 
126         final String[] expected = {
127             "22:5: " + getCheckMessage(MSG_KEY, "public"),
128         };
129         verifyWithInlineConfigParser(
130                 getPath("InputRedundantModifierPublicModifierInNotPublicClass.java"),
131             expected);
132     }
133 
134     @Test
135     public void testNestedClassConsInPublicInterfaceHasValidPublicModifier() throws Exception {
136 
137         final String[] expected = {
138             "22:17: " + getCheckMessage(MSG_KEY, "public"),
139             "24:13: " + getCheckMessage(MSG_KEY, "public"),
140             "26:21: " + getCheckMessage(MSG_KEY, "public"),
141             "37:12: " + getCheckMessage(MSG_KEY, "public"),
142             "45:17: " + getCheckMessage(MSG_KEY, "public"),
143         };
144 
145         verifyWithInlineConfigParser(
146             getPath("InputRedundantModifierNestedClassInInt.java"),
147             expected);
148     }
149 
150     @Test
151     public void testGetAcceptableTokens() {
152         final RedundantModifierCheck redundantModifierCheckObj = new RedundantModifierCheck();
153         final int[] actual = redundantModifierCheckObj.getAcceptableTokens();
154         final int[] expected = {
155             TokenTypes.METHOD_DEF,
156             TokenTypes.VARIABLE_DEF,
157             TokenTypes.ANNOTATION_FIELD_DEF,
158             TokenTypes.INTERFACE_DEF,
159             TokenTypes.CTOR_DEF,
160             TokenTypes.CLASS_DEF,
161             TokenTypes.ENUM_DEF,
162             TokenTypes.RESOURCE,
163             TokenTypes.ANNOTATION_DEF,
164             TokenTypes.RECORD_DEF,
165             TokenTypes.PATTERN_VARIABLE_DEF,
166             TokenTypes.LITERAL_CATCH,
167             TokenTypes.LAMBDA,
168         };
169         assertWithMessage("Invalid acceptable tokens")
170             .that(actual)
171             .isEqualTo(expected);
172     }
173 
174     @Test
175     public void testWrongTokenType() {
176         final RedundantModifierCheck obj = new RedundantModifierCheck();
177         final DetailAstImpl ast = new DetailAstImpl();
178         ast.initialize(TokenTypes.LITERAL_NULL, "null");
179 
180         final IllegalStateException exception =
181                 getExpectedThrowable(IllegalStateException.class,
182                         () -> obj.visitToken(ast), "IllegalStateException was expected");
183 
184         assertWithMessage("Expected and actual violation messages do not match")
185                 .that(exception.getMessage())
186                 .isEqualTo("Unexpected token type: " + ast.getType());
187     }
188 
189     @Test
190     public void testGetRequiredTokens() {
191         final RedundantModifierCheck redundantModifierCheckObj = new RedundantModifierCheck();
192         final int[] actual = redundantModifierCheckObj.getRequiredTokens();
193         final int[] expected = CommonUtil.EMPTY_INT_ARRAY;
194         assertWithMessage("Invalid required tokens")
195             .that(actual)
196             .isEqualTo(expected);
197     }
198 
199     @Test
200     public void testNestedStaticEnum() throws Exception {
201         final String[] expected = {
202             "12:5: " + getCheckMessage(MSG_KEY, "static"),
203             "16:9: " + getCheckMessage(MSG_KEY, "static"),
204             "20:9: " + getCheckMessage(MSG_KEY, "static"),
205         };
206         verifyWithInlineConfigParser(
207                 getPath("InputRedundantModifierStaticModifierInNestedEnum.java"),
208             expected);
209     }
210 
211     @Test
212     public void testFinalInAnonymousClass()
213             throws Exception {
214         final String[] expected = {
215             "22:20: " + getCheckMessage(MSG_KEY, "final"),
216         };
217         verifyWithInlineConfigParser(
218                 getPath("InputRedundantModifierFinalInAnonymousClass.java"),
219             expected);
220     }
221 
222     @Test
223     public void testFinalInTryWithResource() throws Exception {
224         final String[] expected = {
225             "38:14: " + getCheckMessage(MSG_KEY, "final"),
226             "43:14: " + getCheckMessage(MSG_KEY, "final"),
227             "44:17: " + getCheckMessage(MSG_KEY, "final"),
228         };
229         verifyWithInlineConfigParser(
230                 getPath("InputRedundantModifierFinalInTryWithResource.java"),
231             expected);
232     }
233 
234     @Test
235     public void testFinalInAbstractMethods() throws Exception {
236         final String[] expected = {
237             "12:33: " + getCheckMessage(MSG_KEY, "final"),
238             "16:49: " + getCheckMessage(MSG_KEY, "final"),
239             "19:17: " + getCheckMessage(MSG_KEY, "final"),
240             "24:24: " + getCheckMessage(MSG_KEY, "final"),
241             "33:33: " + getCheckMessage(MSG_KEY, "final"),
242         };
243         verifyWithInlineConfigParser(
244                 getPath("InputRedundantModifierFinalInAbstractMethods.java"),
245             expected);
246     }
247 
248     @Test
249     public void testEnumMethods() throws Exception {
250         final String[] expected = {
251             "15:16: " + getCheckMessage(MSG_KEY, "final"),
252             "30:16: " + getCheckMessage(MSG_KEY, "final"),
253         };
254         verifyWithInlineConfigParser(
255                 getPath("InputRedundantModifierFinalInEnumMethods.java"), expected);
256     }
257 
258     @Test
259     public void testEnumStaticMethodsInPublicClass() throws Exception {
260         final String[] expected = {
261             "20:23: " + getCheckMessage(MSG_KEY, "final"),
262         };
263         verifyWithInlineConfigParser(
264                 getPath("InputRedundantModifierFinalInEnumStaticMethods.java"), expected);
265     }
266 
267     @Test
268     public void testAnnotationOnEnumConstructor() throws Exception {
269         final String[] expected = {
270             "22:5: " + getCheckMessage(MSG_KEY, "private"),
271         };
272         verifyWithInlineConfigParser(
273                 getPath("InputRedundantModifierAnnotationOnEnumConstructor.java"),
274                 expected);
275     }
276 
277     @Test
278     public void testPrivateMethodInPrivateClass() throws Exception {
279         final String[] expected = {
280             "13:17: " + getCheckMessage(MSG_KEY, "final"),
281         };
282         verifyWithInlineConfigParser(
283                 getPath("InputRedundantModifierPrivateMethodInPrivateClass.java"),
284                 expected);
285     }
286 
287     @Test
288     public void testTryWithResourcesBlock() throws Exception {
289         final String[] expected = {
290             "18:19: " + getCheckMessage(MSG_KEY, "final"),
291         };
292         verifyWithInlineConfigParser(
293                 getPath("InputRedundantModifierTryWithResources.java"),
294                 expected);
295     }
296 
297     @Test
298     public void testNestedDef() throws Exception {
299         final String[] expected = {
300             "10:5: " + getCheckMessage(MSG_KEY, "public"),
301             "11:5: " + getCheckMessage(MSG_KEY, "static"),
302             "12:5: " + getCheckMessage(MSG_KEY, "public"),
303             "12:12: " + getCheckMessage(MSG_KEY, "static"),
304             "13:5: " + getCheckMessage(MSG_KEY, "static"),
305             "13:12: " + getCheckMessage(MSG_KEY, "public"),
306             "16:9: " + getCheckMessage(MSG_KEY, "public"),
307             "19:5: " + getCheckMessage(MSG_KEY, "public"),
308             "19:12: " + getCheckMessage(MSG_KEY, "static"),
309             "22:5: " + getCheckMessage(MSG_KEY, "public"),
310             "22:12: " + getCheckMessage(MSG_KEY, "abstract"),
311             "22:21: " + getCheckMessage(MSG_KEY, "static"),
312             "26:1: " + getCheckMessage(MSG_KEY, "abstract"),
313             "28:5: " + getCheckMessage(MSG_KEY, "public"),
314             "28:12: " + getCheckMessage(MSG_KEY, "static"),
315             "32:9: " + getCheckMessage(MSG_KEY, "public"),
316             "32:16: " + getCheckMessage(MSG_KEY, "static"),
317             "34:13: " + getCheckMessage(MSG_KEY, "public"),
318             "34:20: " + getCheckMessage(MSG_KEY, "static"),
319             "37:13: " + getCheckMessage(MSG_KEY, "public"),
320             "37:20: " + getCheckMessage(MSG_KEY, "static"),
321             "40:13: " + getCheckMessage(MSG_KEY, "public"),
322             "40:20: " + getCheckMessage(MSG_KEY, "static"),
323         };
324         verifyWithInlineConfigParser(getPath(
325                 "InputRedundantModifierNestedDef.java"), expected);
326     }
327 
328     @Test
329     public void testRecords() throws Exception {
330         final String[] expected = {
331             "12:5: " + getCheckMessage(MSG_KEY, "static"),
332             "16:9: " + getCheckMessage(MSG_KEY, "final"),
333             "16:15: " + getCheckMessage(MSG_KEY, "static"),
334             "21:9: " + getCheckMessage(MSG_KEY, "static"),
335             "27:9: " + getCheckMessage(MSG_KEY, "final"),
336             "27:15: " + getCheckMessage(MSG_KEY, "static"),
337             "32:13: " + getCheckMessage(MSG_KEY, "static"),
338             "38:1: " + getCheckMessage(MSG_KEY, "final"),
339             "40:5: " + getCheckMessage(MSG_KEY, "final"),
340             "43:5: " + getCheckMessage(MSG_KEY, "static"),
341             "47:9: " + getCheckMessage(MSG_KEY, "final"),
342             "47:15: " + getCheckMessage(MSG_KEY, "static"),
343         };
344         verifyWithInlineConfigParser(
345                 getNonCompilablePath("InputRedundantModifierRecords.java"), expected);
346     }
347 
348     @Test
349     public void testSealedClasses() throws Exception {
350         final String[] expected = {
351             "11:4: " + getCheckMessage(MSG_KEY, "final"),
352             "11:10: " + getCheckMessage(MSG_KEY, "public"),
353             "11:17: " + getCheckMessage(MSG_KEY, "static"),
354             "16:4: " + getCheckMessage(MSG_KEY, "abstract"),
355             "16:13: " + getCheckMessage(MSG_KEY, "public"),
356             "20:4: " + getCheckMessage(MSG_KEY, "public"),
357             "20:12: " + getCheckMessage(MSG_KEY, "static"),
358             "24:9: " + getCheckMessage(MSG_KEY, "abstract"),
359             "24:18: " + getCheckMessage(MSG_KEY, "public"),
360             "29:4: " + getCheckMessage(MSG_KEY, "public"),
361             "29:11: " + getCheckMessage(MSG_KEY, "static"),
362             "33:4: " + getCheckMessage(MSG_KEY, "public"),
363             "33:11: " + getCheckMessage(MSG_KEY, "static"),
364         };
365         verifyWithInlineConfigParser(
366                 getNonCompilablePath("InputRedundantModifierSealedClasses.java"), expected);
367     }
368 
369     @Test
370     public void testStrictfpWithVersionBeforeJava9() throws Exception {
371         final String[] expected = {
372             "25:5: " + getCheckMessage(MSG_KEY, "abstract"),
373             "27:9: " + getCheckMessage(MSG_KEY, "public"),
374             "27:16: " + getCheckMessage(MSG_KEY, "static"),
375             "34:9: " + getCheckMessage(MSG_KEY, "final"),
376         };
377         verifyWithInlineConfigParser(
378                 getNonCompilablePath("InputRedundantModifierStrictfpWithVersionBeforeJava9.java"),
379                 expected);
380     }
381 
382     @Test
383     public void testStrictfpWithOldVersion() throws Exception {
384         final String[] expected = {
385             "25:5: " + getCheckMessage(MSG_KEY, "abstract"),
386             "27:9: " + getCheckMessage(MSG_KEY, "public"),
387             "27:16: " + getCheckMessage(MSG_KEY, "static"),
388             "34:9: " + getCheckMessage(MSG_KEY, "final"),
389         };
390         verifyWithInlineConfigParser(
391                 getNonCompilablePath("InputRedundantModifierStrictfpWithOldVersion.java"),
392                 expected);
393     }
394 
395     @Test
396     public void testStrictfpWithJava17() throws Exception {
397         final String[] expected = {
398             "15:19: " + getCheckMessage(MSG_KEY, "strictfp"),
399             "18:5: " + getCheckMessage(MSG_KEY, "strictfp"),
400             "21:5: " + getCheckMessage(MSG_KEY, "strictfp"),
401             "24:5: " + getCheckMessage(MSG_KEY, "strictfp"),
402             "27:14: " + getCheckMessage(MSG_KEY, "strictfp"),
403             "30:5: " + getCheckMessage(MSG_KEY, "abstract"),
404             "30:14: " + getCheckMessage(MSG_KEY, "strictfp"),
405             "34:9: " + getCheckMessage(MSG_KEY, "public"),
406             "34:16: " + getCheckMessage(MSG_KEY, "static"),
407             "34:23: " + getCheckMessage(MSG_KEY, "strictfp"),
408             "42:9: " + getCheckMessage(MSG_KEY, "final"),
409             "42:15: " + getCheckMessage(MSG_KEY, "strictfp"),
410         };
411         verifyWithInlineConfigParser(
412                 getNonCompilablePath("InputRedundantModifierStrictfpWithJava17.java"),
413                 expected);
414     }
415 
416     @Test
417     public void testStrictfpWithDefaultVersion() throws Exception {
418         final String[] expected = {
419             "14:19: " + getCheckMessage(MSG_KEY, "strictfp"),
420             "17:5: " + getCheckMessage(MSG_KEY, "strictfp"),
421             "20:5: " + getCheckMessage(MSG_KEY, "strictfp"),
422             "23:5: " + getCheckMessage(MSG_KEY, "strictfp"),
423             "26:14: " + getCheckMessage(MSG_KEY, "strictfp"),
424             "29:5: " + getCheckMessage(MSG_KEY, "abstract"),
425             "29:14: " + getCheckMessage(MSG_KEY, "strictfp"),
426             "33:9: " + getCheckMessage(MSG_KEY, "public"),
427             "33:16: " + getCheckMessage(MSG_KEY, "static"),
428             "33:23: " + getCheckMessage(MSG_KEY, "strictfp"),
429             "41:9: " + getCheckMessage(MSG_KEY, "final"),
430             "41:15: " + getCheckMessage(MSG_KEY, "strictfp"),
431         };
432         verifyWithInlineConfigParser(
433                 getNonCompilablePath("InputRedundantModifierStrictfpWithDefaultVersion.java"),
434                 expected);
435     }
436 
437     @Test
438     public void testFinalUnnamedVariablesWithDefaultVersion() throws Exception {
439         final String[] expected = {
440             "18:26: " + getCheckMessage(MSG_KEY, "final"),
441             "24:9: " + getCheckMessage(MSG_KEY, "final"),
442             "34:18: " + getCheckMessage(MSG_KEY, "final"),
443             "44:14: " + getCheckMessage(MSG_KEY, "final"),
444             "51:14: " + getCheckMessage(MSG_KEY, "final"),
445             "54:18: " + getCheckMessage(MSG_KEY, "final"),
446             "65:53: " + getCheckMessage(MSG_KEY, "final"),
447             "69:53: " + getCheckMessage(MSG_KEY, "final"),
448             "69:70: " + getCheckMessage(MSG_KEY, "final"),
449         };
450         verifyWithInlineConfigParser(
451                 getNonCompilablePath("InputRedundantModifierFinalUnnamedVariables.java"),
452                 expected);
453     }
454 
455     @Test
456     public void testFinalUnnamedVariablesWithOldVersion() throws Exception {
457         final String[] expected = {
458             "40:14: " + getCheckMessage(MSG_KEY, "final"),
459             "47:14: " + getCheckMessage(MSG_KEY, "final"),
460         };
461         verifyWithInlineConfigParser(
462                 getNonCompilablePath(
463                         "InputRedundantModifierFinalUnnamedVariablesWithOldVersion.java"),
464                 expected);
465     }
466 }