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;
21  
22  import static com.google.common.truth.Truth.assertWithMessage;
23  import static com.puppycrawl.tools.checkstyle.checks.javadoc.JavadocContentLocationCheck.MSG_JAVADOC_CONTENT_SECOND_LINE;
24  
25  import java.io.File;
26  import java.util.ArrayList;
27  import java.util.Arrays;
28  import java.util.List;
29  import java.util.Optional;
30  
31  import org.junit.jupiter.api.Test;
32  
33  import com.puppycrawl.tools.checkstyle.api.CheckstyleException;
34  import com.puppycrawl.tools.checkstyle.api.DetailAST;
35  import com.puppycrawl.tools.checkstyle.api.TokenTypes;
36  import com.puppycrawl.tools.checkstyle.checks.javadoc.JavadocContentLocationCheck;
37  import com.puppycrawl.tools.checkstyle.internal.utils.TestUtil;
38  
39  public class JavaParserTest extends AbstractModuleTestSupport {
40  
41      @Override
42      protected String getPackageLocation() {
43          return "com/puppycrawl/tools/checkstyle/javaparser";
44      }
45  
46      @Test
47      public void testIsProperUtilsClass() throws ReflectiveOperationException {
48          assertWithMessage("Constructor is not private")
49                  .that(TestUtil.isUtilsClassHasPrivateConstructor(JavaParser.class))
50                  .isTrue();
51      }
52  
53      @Test
54      public void testNullRootWithComments() {
55          assertWithMessage("Invalid return root")
56              .that(JavaParser.appendHiddenCommentNodes(null))
57              .isNull();
58      }
59  
60      @Test
61      public void testAppendHiddenBlockCommentNodes() throws Exception {
62          final DetailAST root =
63              JavaParser.parseFile(new File(getPath("InputJavaParserHiddenComments.java")),
64                  JavaParser.Options.WITH_COMMENTS);
65  
66          final Optional<DetailAST> blockComment = TestUtil.findTokenInAstByPredicate(root,
67              ast -> ast.getType() == TokenTypes.BLOCK_COMMENT_BEGIN);
68  
69          assertWithMessage("Block comment should be present")
70                  .that(blockComment.isPresent())
71                  .isTrue();
72  
73          final DetailAST comment = blockComment.orElseThrow();
74  
75          assertWithMessage("Unexpected line number")
76              .that(comment.getLineNo())
77              .isEqualTo(3);
78          assertWithMessage("Unexpected column number")
79              .that(comment.getColumnNo())
80              .isEqualTo(0);
81          assertWithMessage("Unexpected comment content")
82              .that(comment.getText())
83              .isEqualTo("/*");
84  
85          final DetailAST commentContent = comment.getFirstChild();
86          final DetailAST commentEnd = comment.getLastChild();
87  
88          assertWithMessage("Unexpected line number")
89              .that(commentContent.getLineNo())
90              .isEqualTo(3);
91          assertWithMessage("Unexpected column number")
92              .that(commentContent.getColumnNo())
93              .isEqualTo(2);
94          assertWithMessage("Unexpected line number")
95              .that(commentEnd.getLineNo())
96              .isEqualTo(9);
97          assertWithMessage("Unexpected column number")
98              .that(commentEnd.getColumnNo())
99              .isEqualTo(1);
100     }
101 
102     @Test
103     public void testAppendHiddenSingleLineCommentNodes() throws Exception {
104         final DetailAST root =
105             JavaParser.parseFile(new File(getPath("InputJavaParserHiddenComments.java")),
106                 JavaParser.Options.WITH_COMMENTS);
107 
108         final Optional<DetailAST> singleLineComment = TestUtil.findTokenInAstByPredicate(root,
109             ast -> ast.getType() == TokenTypes.SINGLE_LINE_COMMENT);
110         assertWithMessage("Single line comment should be present")
111             .that(singleLineComment.isPresent())
112             .isTrue();
113 
114         final DetailAST comment = singleLineComment.orElseThrow();
115 
116         assertWithMessage("Unexpected line number")
117             .that(comment.getLineNo())
118             .isEqualTo(13);
119         assertWithMessage("Unexpected column number")
120             .that(comment.getColumnNo())
121             .isEqualTo(0);
122         assertWithMessage("Unexpected comment content")
123             .that(comment.getText())
124             .isEqualTo("//");
125 
126         final DetailAST commentContent = comment.getFirstChild();
127 
128         assertWithMessage("Unexpected token type")
129             .that(commentContent.getType())
130             .isEqualTo(TokenTypes.COMMENT_CONTENT);
131         assertWithMessage("Unexpected line number")
132             .that(commentContent.getLineNo())
133             .isEqualTo(13);
134         assertWithMessage("Unexpected column number")
135             .that(commentContent.getColumnNo())
136             .isEqualTo(2);
137         assertWithMessage("Unexpected comment content")
138                 .that(commentContent.getText())
139                 .startsWith(" inline comment");
140     }
141 
142     @Test
143     public void testAppendHiddenSingleLineCommentNodes2() throws Exception {
144         final DetailAST root =
145             JavaParser.parseFile(new File(getPath("InputJavaParserHiddenComments2.java")),
146                 JavaParser.Options.WITH_COMMENTS);
147 
148         final Optional<DetailAST> singleLineComment = TestUtil.findTokenInAstByPredicate(root,
149             ast -> ast.getType() == TokenTypes.SINGLE_LINE_COMMENT);
150         assertWithMessage("Single line comment should be present")
151                 .that(singleLineComment.isPresent())
152                 .isTrue();
153 
154         final DetailAST comment = singleLineComment.orElseThrow();
155 
156         assertWithMessage("Unexpected line number")
157             .that(comment.getLineNo())
158             .isEqualTo(1);
159         assertWithMessage("Unexpected column number")
160             .that(comment.getColumnNo())
161             .isEqualTo(4);
162         assertWithMessage("Unexpected comment content")
163             .that(comment.getText())
164             .isEqualTo("//");
165 
166         final DetailAST commentContent = comment.getFirstChild();
167 
168         assertWithMessage("Unexpected token type")
169             .that(commentContent.getType())
170             .isEqualTo(TokenTypes.COMMENT_CONTENT);
171         assertWithMessage("Unexpected line number")
172             .that(commentContent.getLineNo())
173             .isEqualTo(1);
174         assertWithMessage("Unexpected column number")
175             .that(commentContent.getColumnNo())
176             .isEqualTo(6);
177         assertWithMessage("Unexpected comment content")
178                 .that(commentContent.getText())
179                 .startsWith(" indented comment");
180     }
181 
182     @Test
183     public void testDontAppendCommentNodes() throws Exception {
184         final DetailAST root =
185             JavaParser.parseFile(new File(getPath("InputJavaParserHiddenComments.java")),
186                 JavaParser.Options.WITHOUT_COMMENTS);
187 
188         final Optional<DetailAST> singleLineComment = TestUtil.findTokenInAstByPredicate(root,
189             ast -> ast.getType() == TokenTypes.SINGLE_LINE_COMMENT);
190         assertWithMessage("Single line comment should be present")
191                 .that(singleLineComment.isPresent())
192                 .isFalse();
193     }
194 
195     @Test
196     public void testParseException() throws Exception {
197         final File input = new File(getNonCompilablePath("InputJavaParser.java"));
198         try {
199             JavaParser.parseFile(input, JavaParser.Options.WITH_COMMENTS);
200             assertWithMessage("exception expected").fail();
201         }
202         catch (CheckstyleException ex) {
203             assertWithMessage("Invalid exception message")
204                 .that(ex.toString())
205                 .isEqualTo(CheckstyleException.class.getName()
206                             + ": IllegalStateException occurred while parsing file "
207                             + input.getAbsolutePath() + ".");
208             assertWithMessage("Invalid class")
209                 .that(ex.getCause())
210                 .isInstanceOf(IllegalStateException.class);
211             assertWithMessage("Invalid exception message")
212                 .that(ex.getCause().toString())
213                 .isEqualTo(IllegalStateException.class.getName()
214                             + ": 2:0: no viable alternative at input 'classD'");
215         }
216     }
217 
218     @Test
219     public void testComments() throws Exception {
220         final DetailAST root =
221             JavaParser.parseFile(new File(getPath("InputJavaParserHiddenComments3.java")),
222                 JavaParser.Options.WITH_COMMENTS);
223         final CountComments counter = new CountComments(root);
224 
225         assertWithMessage("Invalid line comments")
226             .that(counter.lineComments)
227             .isEqualTo(Arrays.asList("1,4", "6,4", "9,0"));
228         assertWithMessage("Invalid block comments")
229             .that(counter.blockComments)
230             .isEqualTo(Arrays.asList("5,4", "8,0"));
231     }
232 
233     @Test
234     public void testJava14TextBlocks() throws Exception {
235         final DetailAST root =
236             JavaParser.parseFile(new File(
237                     getNonCompilablePath("InputJavaParserTextBlocks.java")),
238                 JavaParser.Options.WITHOUT_COMMENTS);
239 
240         final Optional<DetailAST> textBlockContent = TestUtil.findTokenInAstByPredicate(root,
241             ast -> ast.getType() == TokenTypes.TEXT_BLOCK_CONTENT);
242 
243         assertWithMessage("Text block content should be present")
244                 .that(textBlockContent.isPresent())
245                 .isTrue();
246 
247         final DetailAST content = textBlockContent.orElseThrow();
248         final String expectedContents = "\n                 string";
249 
250         assertWithMessage("Unexpected line number")
251             .that(content.getLineNo())
252             .isEqualTo(5);
253         assertWithMessage("Unexpected column number")
254             .that(content.getColumnNo())
255             .isEqualTo(32);
256         assertWithMessage("Unexpected text block content")
257             .that(content.getText())
258             .isEqualTo(expectedContents);
259     }
260 
261     @Test
262     public void testNoFreezeOnDeeplyNestedLambdas() throws Exception {
263         final File file =
264                 new File(getNonCompilablePath("InputJavaParserNoFreezeOnDeeplyNestedLambdas.java"));
265         assertWithMessage("File parsing should complete successfully.")
266                 .that(JavaParser.parseFile(file, JavaParser.Options.WITH_COMMENTS))
267                 .isNotNull();
268     }
269 
270     @Test
271     public void testFullJavaIdentifierSupport1() throws Exception {
272         final File file =
273                 new File(getNonCompilablePath("InputJavaParserFullJavaIdentifierSupport1.java"));
274         assertWithMessage("File parsing should complete successfully.")
275                 .that(JavaParser.parseFile(file, JavaParser.Options.WITH_COMMENTS))
276                 .isNotNull();
277     }
278 
279     @Test
280     public void testFullJavaIdentifierSupport2() throws Exception {
281         final File file =
282                 new File(getNonCompilablePath("InputJavaParserFullJavaIdentifierSupport2.java"));
283         assertWithMessage("File parsing should complete successfully.")
284                 .that(JavaParser.parseFile(file, JavaParser.Options.WITH_COMMENTS))
285                 .isNotNull();
286     }
287 
288     @Test
289     public void testFullJavaIdentifierSupport3() throws Exception {
290         final File file =
291                 new File(getNonCompilablePath("InputJavaParserFullJavaIdentifierSupport3.java"));
292         assertWithMessage("File parsing should complete successfully.")
293                 .that(JavaParser.parseFile(file, JavaParser.Options.WITH_COMMENTS))
294                 .isNotNull();
295     }
296 
297     @Test
298     public void testFullJavaIdentifierSupport4() throws Exception {
299         final File file =
300                 new File(getNonCompilablePath("InputJavaParserFullJavaIdentifierSupport4.java"));
301         assertWithMessage("File parsing should complete successfully.")
302                 .that(JavaParser.parseFile(file, JavaParser.Options.WITH_COMMENTS))
303                 .isNotNull();
304     }
305 
306     @Test
307     public void testFullJavaIdentifierSupport5() throws Exception {
308         final File file =
309                 new File(getNonCompilablePath("InputJavaParserFullJavaIdentifierSupport5.java"));
310         assertWithMessage("File parsing should complete successfully.")
311                 .that(JavaParser.parseFile(file, JavaParser.Options.WITH_COMMENTS))
312                 .isNotNull();
313     }
314 
315     @Test
316     public void testFullJavaIdentifierSupport6() throws Exception {
317         final File file =
318                 new File(getNonCompilablePath("InputJavaParserFullJavaIdentifierSupport6.java"));
319         assertWithMessage("File parsing should complete successfully.")
320                 .that(JavaParser.parseFile(file, JavaParser.Options.WITH_COMMENTS))
321                 .isNotNull();
322     }
323 
324     @Test
325     public void testFullJavaIdentifierSupport7() throws Exception {
326         final File file =
327                 new File(getNonCompilablePath("InputJavaParserFullJavaIdentifierSupport7.java"));
328         assertWithMessage("File parsing should complete successfully.")
329                 .that(JavaParser.parseFile(file, JavaParser.Options.WITH_COMMENTS))
330                 .isNotNull();
331     }
332 
333     @Test
334     public void testFullJavaIdentifierSupport8() throws Exception {
335         final File file =
336                 new File(getNonCompilablePath("InputJavaParserFullJavaIdentifierSupport8.java"));
337         assertWithMessage("File parsing should complete successfully.")
338                 .that(JavaParser.parseFile(file, JavaParser.Options.WITH_COMMENTS))
339                 .isNotNull();
340     }
341 
342     @Test
343     public void testFullJavaIdentifierSupport9() throws Exception {
344         final File file =
345                 new File(getNonCompilablePath("InputJavaParserFullJavaIdentifierSupport9.java"));
346         assertWithMessage("File parsing should complete successfully.")
347                 .that(JavaParser.parseFile(file, JavaParser.Options.WITH_COMMENTS))
348                 .isNotNull();
349     }
350 
351     @Test
352     public void testFullJavaIdentifierSupport10() throws Exception {
353         final File file =
354                 new File(getNonCompilablePath("InputJavaParserFullJavaIdentifierSupport10.java"));
355         assertWithMessage("File parsing should complete successfully.")
356                 .that(JavaParser.parseFile(file, JavaParser.Options.WITH_COMMENTS))
357                 .isNotNull();
358     }
359 
360     @Test
361     public void testFullJavaIdentifierSupport11() throws Exception {
362         final File file =
363                 new File(getNonCompilablePath("InputJavaParserFullJavaIdentifierSupport11.java"));
364         assertWithMessage("File parsing should complete successfully.")
365                 .that(JavaParser.parseFile(file, JavaParser.Options.WITH_COMMENTS))
366                 .isNotNull();
367     }
368 
369     @Test
370     public void testFullJavaIdentifierSupport12() throws Exception {
371         final File file =
372                 new File(getNonCompilablePath("InputJavaParserFullJavaIdentifierSupport12.java"));
373         assertWithMessage("File parsing should complete successfully.")
374                 .that(JavaParser.parseFile(file, JavaParser.Options.WITH_COMMENTS))
375                 .isNotNull();
376     }
377 
378     @Test
379     public void testFullJavaIdentifierSupport13() throws Exception {
380         final File file =
381                 new File(getNonCompilablePath("InputJavaParserFullJavaIdentifierSupport13.java"));
382         assertWithMessage("File parsing should complete successfully.")
383                 .that(JavaParser.parseFile(file, JavaParser.Options.WITH_COMMENTS))
384                 .isNotNull();
385     }
386 
387     @Test
388     public void testFullJavaIdentifierSupport14() throws Exception {
389         final File file =
390                 new File(getNonCompilablePath("InputJavaParserFullJavaIdentifierSupport14.java"));
391         assertWithMessage("File parsing should complete successfully.")
392                 .that(JavaParser.parseFile(file, JavaParser.Options.WITH_COMMENTS))
393                 .isNotNull();
394     }
395 
396     @Test
397     public void testFullJavaIdentifierSupport15() throws Exception {
398         final File file =
399                 new File(getNonCompilablePath("InputJavaParserFullJavaIdentifierSupport15.java"));
400         assertWithMessage("File parsing should complete successfully.")
401                 .that(JavaParser.parseFile(file, JavaParser.Options.WITH_COMMENTS))
402                 .isNotNull();
403     }
404 
405     @Test
406     public void testFullJavaIdentifierSupport16() throws Exception {
407         final File file =
408                 new File(getNonCompilablePath("InputJavaParserFullJavaIdentifierSupport16.java"));
409         assertWithMessage("File parsing should complete successfully.")
410                 .that(JavaParser.parseFile(file, JavaParser.Options.WITH_COMMENTS))
411                 .isNotNull();
412     }
413 
414     @Test
415     public void testReturnValueOfAppendHiddenCommentNodes()
416             throws Exception {
417         final String[] expected = {
418             "9:1: " + getCheckMessage(JavadocContentLocationCheck.class,
419                     MSG_JAVADOC_CONTENT_SECOND_LINE),
420         };
421         verifyWithInlineConfigParser(
422                 getPath("InputJavaParserHiddenComments4.java"), expected);
423     }
424 
425     private static final class CountComments {
426         private final List<String> lineComments = new ArrayList<>();
427         private final List<String> blockComments = new ArrayList<>();
428 
429         private CountComments(DetailAST root) {
430             forEachChild(root);
431         }
432 
433         private void forEachChild(DetailAST root) {
434             for (DetailAST ast = root; ast != null; ast = ast.getNextSibling()) {
435                 if (ast.getType() == TokenTypes.SINGLE_LINE_COMMENT) {
436                     lineComments.add(ast.getLineNo() + "," + ast.getColumnNo());
437                 }
438                 else if (ast.getType() == TokenTypes.BLOCK_COMMENT_BEGIN) {
439                     blockComments.add(ast.getLineNo() + "," + ast.getColumnNo());
440                 }
441 
442                 forEachChild(ast.getFirstChild());
443             }
444         }
445     }
446 }