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