View Javadoc
1   ///////////////////////////////////////////////////////////////////////////////////////////////
2   // checkstyle: Checks Java source code and other text files for adherence to a set of rules.
3   // Copyright (C) 2001-2026 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.utils;
21  
22  import static com.google.common.truth.Truth.assertWithMessage;
23  import static com.puppycrawl.tools.checkstyle.internal.utils.TestUtil.isUtilsClassHasPrivateConstructor;
24  
25  import java.util.Optional;
26  
27  import org.junit.jupiter.api.Test;
28  
29  import com.puppycrawl.tools.checkstyle.AbstractModuleTestSupport;
30  import com.puppycrawl.tools.checkstyle.DetailAstImpl;
31  import com.puppycrawl.tools.checkstyle.api.DetailAST;
32  import com.puppycrawl.tools.checkstyle.api.Scope;
33  import com.puppycrawl.tools.checkstyle.api.TokenTypes;
34  
35  public class ScopeUtilTest
36      extends AbstractModuleTestSupport {
37  
38      @Override
39      public String getPackageLocation() {
40          return "com/puppycrawl/tools/checkstyle/utils/scopeutil";
41      }
42  
43      @Test
44      public void testIsProperUtilsClass() throws ReflectiveOperationException {
45          assertWithMessage("Constructor is not private")
46                  .that(isUtilsClassHasPrivateConstructor(ScopeUtil.class))
47                  .isTrue();
48      }
49  
50      @Test
51      public void testInClassBlock() {
52          assertWithMessage("Should return false when passed is not class")
53                  .that(ScopeUtil.isInClassBlock(new DetailAstImpl()))
54                  .isFalse();
55          assertWithMessage("Should return false when passed is not class")
56                  .that(ScopeUtil
57                          .isInClassBlock(getNode(TokenTypes.LITERAL_NEW, TokenTypes.MODIFIERS)))
58                  .isFalse();
59          assertWithMessage("Should return true when passed is class")
60                  .that(ScopeUtil.isInClassBlock(
61                          getNode(TokenTypes.OBJBLOCK, TokenTypes.CLASS_DEF, TokenTypes.MODIFIERS)))
62                  .isTrue();
63          assertWithMessage("Should return false when passed is not class")
64                  .that(ScopeUtil.isInClassBlock(getNode(TokenTypes.CLASS_DEF,
65                          TokenTypes.INTERFACE_DEF, TokenTypes.MODIFIERS)))
66                  .isFalse();
67          assertWithMessage("Should return false when passed is not class")
68                  .that(ScopeUtil.isInClassBlock(getNode(TokenTypes.CLASS_DEF,
69                          TokenTypes.ANNOTATION_DEF, TokenTypes.MODIFIERS)))
70                  .isFalse();
71          assertWithMessage("Should return false when passed is not class")
72                  .that(ScopeUtil.isInClassBlock(
73                          getNode(TokenTypes.CLASS_DEF, TokenTypes.ENUM_DEF, TokenTypes.MODIFIERS)))
74                  .isFalse();
75          assertWithMessage("Should return false when passed is not class")
76                  .that(ScopeUtil.isInClassBlock(
77                          getNode(TokenTypes.CLASS_DEF, TokenTypes.LITERAL_NEW, TokenTypes.IDENT)))
78                  .isFalse();
79          assertWithMessage("Should return false when passed is not expected")
80                  .that(ScopeUtil.isInClassBlock(getNode(TokenTypes.PACKAGE_DEF, TokenTypes.DOT)))
81                  .isFalse();
82      }
83  
84      @Test
85      public void testInEnumBlock() {
86          assertWithMessage("Should return false when passed is not enum")
87                  .that(ScopeUtil.isInEnumBlock(new DetailAstImpl()))
88                  .isFalse();
89          assertWithMessage("Should return false when passed is not enum")
90                  .that(ScopeUtil
91                          .isInEnumBlock(getNode(TokenTypes.LITERAL_NEW, TokenTypes.MODIFIERS)))
92                  .isFalse();
93          assertWithMessage("Should return true when passed is enum")
94                  .that(ScopeUtil.isInEnumBlock(
95                          getNode(TokenTypes.OBJBLOCK, TokenTypes.ENUM_DEF, TokenTypes.MODIFIERS)))
96                  .isTrue();
97          assertWithMessage("Should return false when passed is not enum")
98                  .that(ScopeUtil.isInEnumBlock(getNode(TokenTypes.ENUM_DEF, TokenTypes.INTERFACE_DEF,
99                          TokenTypes.MODIFIERS)))
100                 .isFalse();
101         assertWithMessage("Should return false when passed is not enum")
102                 .that(ScopeUtil.isInEnumBlock(getNode(TokenTypes.ENUM_DEF,
103                         TokenTypes.ANNOTATION_DEF, TokenTypes.MODIFIERS)))
104                 .isFalse();
105         assertWithMessage("Should return false when passed is not enum")
106                 .that(ScopeUtil.isInEnumBlock(
107                         getNode(TokenTypes.ENUM_DEF, TokenTypes.CLASS_DEF, TokenTypes.MODIFIERS)))
108                 .isFalse();
109         assertWithMessage("Should return false when passed is not enum")
110                 .that(ScopeUtil.isInEnumBlock(
111                         getNode(TokenTypes.ENUM_DEF, TokenTypes.LITERAL_NEW, TokenTypes.IDENT)))
112                 .isFalse();
113         assertWithMessage("Should return false when passed is not expected")
114                 .that(ScopeUtil.isInEnumBlock(getNode(TokenTypes.PACKAGE_DEF, TokenTypes.DOT)))
115                 .isFalse();
116     }
117 
118     @Test
119     public void testIsInCodeBlock() {
120         assertWithMessage("invalid result")
121                 .that(ScopeUtil.isInCodeBlock(getNode(TokenTypes.CLASS_DEF)))
122                 .isFalse();
123         assertWithMessage("invalid result")
124                 .that(ScopeUtil.isInCodeBlock(getNode(TokenTypes.METHOD_DEF)))
125                 .isFalse();
126         assertWithMessage("invalid result")
127                 .that(ScopeUtil.isInCodeBlock(getNode(TokenTypes.ASSIGN, TokenTypes.VARIABLE_DEF)))
128                 .isFalse();
129         assertWithMessage("invalid result")
130                 .that(ScopeUtil.isInCodeBlock(getNode(TokenTypes.METHOD_DEF, TokenTypes.OBJBLOCK)))
131                 .isTrue();
132         assertWithMessage("invalid result")
133                 .that(ScopeUtil.isInCodeBlock(getNode(TokenTypes.CTOR_DEF, TokenTypes.OBJBLOCK)))
134                 .isTrue();
135         assertWithMessage("invalid result")
136                 .that(ScopeUtil
137                         .isInCodeBlock(getNode(TokenTypes.INSTANCE_INIT, TokenTypes.OBJBLOCK)))
138                 .isTrue();
139         assertWithMessage("invalid result")
140                 .that(ScopeUtil.isInCodeBlock(getNode(TokenTypes.STATIC_INIT, TokenTypes.OBJBLOCK)))
141                 .isTrue();
142         assertWithMessage("invalid result")
143                 .that(ScopeUtil.isInCodeBlock(getNode(TokenTypes.LAMBDA, TokenTypes.ASSIGN)))
144                 .isTrue();
145     }
146 
147     @Test
148     public void testIsInCodeBlockWithCompactCtor() throws Exception {
149         final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
150         verifyWithInlineConfigParser(
151                 getPath("InputScopeUtilJavadocVariableCompactCtor.java"), expected);
152     }
153 
154     @Test
155     public void testInRecordBlock() {
156         assertWithMessage("Should return false when passed is not record")
157                 .that(ScopeUtil.isInRecordBlock(new DetailAstImpl()))
158                 .isFalse();
159         assertWithMessage("Should return false when passed is not record")
160                 .that(ScopeUtil
161                         .isInRecordBlock(getNode(TokenTypes.LITERAL_NEW, TokenTypes.MODIFIERS)))
162                 .isFalse();
163         assertWithMessage("Should return true when passed is record")
164                 .that(ScopeUtil.isInRecordBlock(
165                         getNode(TokenTypes.OBJBLOCK, TokenTypes.RECORD_DEF, TokenTypes.MODIFIERS)))
166                 .isTrue();
167         assertWithMessage("Should return false when passed is not record")
168                 .that(ScopeUtil.isInRecordBlock(getNode(TokenTypes.RECORD_DEF,
169                         TokenTypes.INTERFACE_DEF, TokenTypes.MODIFIERS)))
170                 .isFalse();
171         assertWithMessage("Should return false when passed is not record")
172                 .that(ScopeUtil.isInRecordBlock(getNode(TokenTypes.RECORD_DEF,
173                         TokenTypes.ANNOTATION_DEF, TokenTypes.MODIFIERS)))
174                 .isFalse();
175         assertWithMessage("Should return false when passed is not record")
176                 .that(ScopeUtil.isInRecordBlock(
177                         getNode(TokenTypes.RECORD_DEF, TokenTypes.ENUM_DEF, TokenTypes.MODIFIERS)))
178                 .isFalse();
179         assertWithMessage("Should return false when passed is not record")
180                 .that(ScopeUtil.isInRecordBlock(
181                         getNode(TokenTypes.RECORD_DEF, TokenTypes.LITERAL_NEW, TokenTypes.IDENT)))
182                 .isFalse();
183         assertWithMessage("Should return false when passed is not expected")
184                 .that(ScopeUtil.isInRecordBlock(getNode(TokenTypes.PACKAGE_DEF, TokenTypes.DOT)))
185                 .isFalse();
186     }
187 
188     @Test
189     public void testIsOuterMostTypeInterface() {
190         assertWithMessage("Should return false when passed is not outer most type")
191                 .that(ScopeUtil
192                         .isOuterMostType(getNode(TokenTypes.INTERFACE_DEF, TokenTypes.MODIFIERS)))
193                 .isFalse();
194     }
195 
196     @Test
197     public void testIsOuterMostTypeAnnotation() {
198         assertWithMessage("Should return false when passed is not outer most type")
199                 .that(ScopeUtil
200                         .isOuterMostType(getNode(TokenTypes.ANNOTATION_DEF, TokenTypes.MODIFIERS)))
201                 .isFalse();
202     }
203 
204     @Test
205     public void testIsOuterMostTypeEnum() {
206         assertWithMessage("Should return false when passed is not outer most type")
207                 .that(ScopeUtil.isOuterMostType(getNode(TokenTypes.ENUM_DEF, TokenTypes.MODIFIERS)))
208                 .isFalse();
209     }
210 
211     @Test
212     public void testIsOuterMostTypeClass() {
213         assertWithMessage("Should return false when passed is not outer most type")
214                 .that(ScopeUtil
215                         .isOuterMostType(getNode(TokenTypes.CLASS_DEF, TokenTypes.MODIFIERS)))
216                 .isFalse();
217     }
218 
219     @Test
220     public void testIsOuterMostTypePackageDef() {
221         assertWithMessage("Should return false when passed is not outer most type")
222                 .that(ScopeUtil.isOuterMostType(getNode(TokenTypes.PACKAGE_DEF, TokenTypes.DOT)))
223                 .isTrue();
224     }
225 
226     @Test
227     public void testIsLocalVariableDefCatch() {
228         assertWithMessage("Should return true when passed is variable def")
229             .that(ScopeUtil
230                 .isLocalVariableDef(getNode(TokenTypes.LITERAL_CATCH, TokenTypes.PARAMETER_DEF)))
231                 .isTrue();
232     }
233 
234     @Test
235     public void testIsLocalVariableDefUnexpected() {
236         assertWithMessage("Should return false when passed is not variable def")
237                 .that(ScopeUtil.isLocalVariableDef(getNode(TokenTypes.LITERAL_CATCH)))
238                 .isFalse();
239         assertWithMessage("Should return false when passed is not variable def")
240                 .that(ScopeUtil
241                         .isLocalVariableDef(getNode(TokenTypes.COMMA, TokenTypes.PARAMETER_DEF)))
242                 .isFalse();
243     }
244 
245     @Test
246     public void testIsLocalVariableDefResource() {
247         final DetailAstImpl node = getNode(TokenTypes.RESOURCE);
248         final DetailAstImpl modifiers = new DetailAstImpl();
249         modifiers.setType(TokenTypes.MODIFIERS);
250         node.addChild(modifiers);
251         final DetailAstImpl ident = new DetailAstImpl();
252         ident.setType(TokenTypes.IDENT);
253         node.addChild(ident);
254         assertWithMessage("invalid result")
255                 .that(ScopeUtil.isLocalVariableDef(node))
256                 .isTrue();
257         final DetailAstImpl resourceWithIdent = getNode(TokenTypes.RESOURCE);
258         resourceWithIdent.addChild(ident);
259         assertWithMessage("invalid result")
260                 .that(ScopeUtil.isLocalVariableDef(resourceWithIdent))
261                 .isFalse();
262         assertWithMessage("invalid result")
263                 .that(ScopeUtil.isLocalVariableDef(getNode(TokenTypes.RESOURCE)))
264                 .isFalse();
265     }
266 
267     @Test
268     public void testIsLocalVariableDefVariable() {
269         assertWithMessage("invalid result")
270                 .that(ScopeUtil
271                         .isLocalVariableDef(getNode(TokenTypes.SLIST, TokenTypes.VARIABLE_DEF)))
272                 .isTrue();
273         assertWithMessage("invalid result")
274                 .that(ScopeUtil
275                         .isLocalVariableDef(getNode(TokenTypes.FOR_INIT, TokenTypes.VARIABLE_DEF)))
276                 .isTrue();
277         assertWithMessage("invalid result")
278             .that(ScopeUtil
279                 .isLocalVariableDef(getNode(TokenTypes.FOR_EACH_CLAUSE, TokenTypes.VARIABLE_DEF)))
280                 .isTrue();
281         assertWithMessage("invalid result")
282                 .that(ScopeUtil
283                         .isLocalVariableDef(getNode(TokenTypes.CLASS_DEF, TokenTypes.VARIABLE_DEF)))
284                 .isFalse();
285     }
286 
287     @Test
288     public void testIsClassFieldDef() {
289         assertWithMessage("Should return true when passed is class field def")
290                 .that(ScopeUtil.isClassFieldDef(getNode(TokenTypes.CLASS_DEF, TokenTypes.OBJBLOCK,
291                         TokenTypes.VARIABLE_DEF)))
292                 .isTrue();
293         assertWithMessage("Should return false when passed is unexpected")
294                 .that(ScopeUtil.isClassFieldDef(getNode(TokenTypes.CLASS_DEF)))
295                 .isFalse();
296         assertWithMessage("Should return false when passed is method variable def")
297                 .that(ScopeUtil.isClassFieldDef(
298                         getNode(TokenTypes.METHOD_DEF, TokenTypes.SLIST, TokenTypes.VARIABLE_DEF)))
299                 .isFalse();
300     }
301 
302     @Test
303     public void testSurroundingScope() {
304         final Optional<Scope> publicScope = ScopeUtil.getSurroundingScope(getNodeWithParentScope(
305                 TokenTypes.LITERAL_PUBLIC, "public", TokenTypes.ANNOTATION_DEF));
306         assertWithMessage("Invalid surrounding scope")
307             .that(publicScope)
308             .isEqualTo(Optional.of(Scope.PUBLIC));
309         final Optional<Scope> protectedScope = ScopeUtil.getSurroundingScope(getNodeWithParentScope(
310                 TokenTypes.LITERAL_PROTECTED, "protected", TokenTypes.INTERFACE_DEF));
311         assertWithMessage("Invalid surrounding scope")
312             .that(protectedScope)
313             .isEqualTo(Optional.of(Scope.PROTECTED));
314         final Optional<Scope> privateScope = ScopeUtil.getSurroundingScope(getNodeWithParentScope(
315                 TokenTypes.LITERAL_PRIVATE, "private", TokenTypes.ENUM_DEF));
316         assertWithMessage("Invalid surrounding scope")
317             .that(privateScope)
318             .isEqualTo(Optional.of(Scope.PRIVATE));
319         final Optional<Scope> staticScope = ScopeUtil.getSurroundingScope(getNodeWithParentScope(
320                 TokenTypes.LITERAL_STATIC, "static", TokenTypes.CLASS_DEF));
321         assertWithMessage("Invalid surrounding scope")
322             .that(staticScope)
323             .isEqualTo(Optional.of(Scope.PACKAGE));
324     }
325 
326     @Test
327     public void testIsInScope() {
328         assertWithMessage("Should return true when node is in valid scope")
329                 .that(ScopeUtil.isInScope(getNodeWithParentScope(TokenTypes.LITERAL_PUBLIC,
330                         "public", TokenTypes.ANNOTATION_DEF), Scope.PUBLIC))
331                 .isTrue();
332         assertWithMessage("Should return false when node is in invalid scope")
333                 .that(ScopeUtil.isInScope(getNodeWithParentScope(TokenTypes.LITERAL_PROTECTED,
334                         "protected", TokenTypes.INTERFACE_DEF), Scope.PRIVATE))
335                 .isFalse();
336     }
337 
338     @Test
339     public void testSurroundingScopeOfNodeChildOfLiteralNewIsAnoninner() {
340         final Optional<Scope> scope =
341                 ScopeUtil.getSurroundingScope(getNode(TokenTypes.LITERAL_NEW, TokenTypes.IDENT));
342         assertWithMessage("Invalid surrounding scope")
343             .that(scope)
344             .isEqualTo(Optional.of(Scope.ANONINNER));
345     }
346 
347     @Test
348     public void testGetScopeOfEnumConstantIsPublic() {
349         final Scope scope = ScopeUtil.getScope(
350                 getNode(TokenTypes.ENUM_DEF, TokenTypes.OBJBLOCK, TokenTypes.ENUM_CONSTANT_DEF));
351 
352         assertWithMessage("Invalid enum constant scope")
353                 .that(scope)
354                 .isEqualTo(Scope.PUBLIC);
355     }
356 
357     @Test
358     public void testIsInInterfaceBlock() {
359         final DetailAST ast = getNode(TokenTypes.INTERFACE_DEF, TokenTypes.OBJBLOCK,
360                 TokenTypes.CLASS_DEF, TokenTypes.MODIFIERS);
361 
362         assertWithMessage("Should return true when node is interface block")
363                 .that(ScopeUtil.isInInterfaceBlock(ast.getParent()))
364                 .isTrue();
365         assertWithMessage("Should return false when node is not interface block")
366                 .that(ScopeUtil.isInInterfaceBlock(ast))
367                 .isFalse();
368     }
369 
370     @Test
371     public void testIsInAnnotationBlock() {
372         final DetailAST ast = getNode(TokenTypes.ANNOTATION_DEF, TokenTypes.OBJBLOCK,
373                 TokenTypes.INTERFACE_DEF, TokenTypes.MODIFIERS);
374 
375         assertWithMessage("Should return true when node is annotation block")
376                 .that(ScopeUtil.isInAnnotationBlock(ast.getParent()))
377                 .isTrue();
378         assertWithMessage("Should return false when node is not annotation block")
379                 .that(ScopeUtil.isInAnnotationBlock(ast))
380                 .isFalse();
381     }
382 
383     @Test
384     public void testisInInterfaceOrAnnotationBlock() {
385         assertWithMessage("Should return true when node is in interface or annotation block")
386                 .that(ScopeUtil.isInInterfaceOrAnnotationBlock(
387                         getNode(TokenTypes.ANNOTATION_DEF, TokenTypes.OBJBLOCK)))
388                 .isTrue();
389         assertWithMessage("Should return true when node is in interface or annotation block")
390                 .that(ScopeUtil.isInInterfaceOrAnnotationBlock(
391                         getNode(TokenTypes.INTERFACE_DEF, TokenTypes.OBJBLOCK)))
392                 .isTrue();
393         assertWithMessage("Should return false when node is not in interface or annotation block")
394                 .that(ScopeUtil.isInInterfaceOrAnnotationBlock(
395                         getNode(TokenTypes.CLASS_DEF, TokenTypes.OBJBLOCK)))
396                 .isFalse();
397         assertWithMessage("Should return false when node is not in interface or annotation block")
398                 .that(ScopeUtil.isInInterfaceOrAnnotationBlock(
399                         getNode(TokenTypes.LITERAL_NEW, TokenTypes.IDENT)))
400                 .isFalse();
401         assertWithMessage("Should return false when node is not in interface or annotation block")
402                 .that(ScopeUtil.isInInterfaceOrAnnotationBlock(
403                         getNode(TokenTypes.ENUM_DEF, TokenTypes.OBJBLOCK)))
404                 .isFalse();
405     }
406 
407     private static DetailAstImpl getNode(int... nodeTypes) {
408         DetailAstImpl ast = new DetailAstImpl();
409         ast.setType(nodeTypes[0]);
410         for (int i = 1; i < nodeTypes.length; i++) {
411             final DetailAstImpl astChild = new DetailAstImpl();
412             astChild.setType(nodeTypes[i]);
413             ast.addChild(astChild);
414             ast = astChild;
415         }
416         return ast;
417     }
418 
419     private static DetailAST getNodeWithParentScope(int literal, String scope,
420                                                     int parentTokenType) {
421         final DetailAstImpl ast = getNode(parentTokenType, TokenTypes.MODIFIERS, literal);
422         ast.setText(scope);
423         final DetailAstImpl ast2 = getNode(TokenTypes.OBJBLOCK);
424         ((DetailAstImpl) ast.getParent().getParent()).addChild(ast2);
425         return ast;
426     }
427 
428 }