From 25621a3c3391ddf4bc0bb56535d23e73cd293657 Mon Sep 17 00:00:00 2001 From: Baratali Izmailov Date: Thu, 18 Feb 2016 00:44:28 +0000 Subject: [PATCH] Issue #652: New option to print AST with comment nodes. --- config/suppressions.xml | 5 +- .../checkstyle/AstTreeStringPrinter.java | 26 ++++- .../com/puppycrawl/tools/checkstyle/Main.java | 28 ++++- .../tools/checkstyle/TreeWalker.java | 12 ++ .../checkstyle/AstTreeStringPrinterTest.java | 29 ++++- .../puppycrawl/tools/checkstyle/MainTest.java | 110 ++++++++++++------ .../tools/checkstyle/InputMain.java | 2 +- .../InputAstTreeStringPrinterComments.java | 6 + .../expectedInputAstTreeStringPrinter.txt | 17 +++ ...ectedInputAstTreeStringPrinterComments.txt | 22 ++++ src/xdocs/cmdline.xml.vm | 8 +- 11 files changed, 217 insertions(+), 48 deletions(-) create mode 100644 src/test/resources/com/puppycrawl/tools/checkstyle/astprinter/InputAstTreeStringPrinterComments.java create mode 100644 src/test/resources/com/puppycrawl/tools/checkstyle/astprinter/expectedInputAstTreeStringPrinter.txt create mode 100644 src/test/resources/com/puppycrawl/tools/checkstyle/astprinter/expectedInputAstTreeStringPrinterComments.txt diff --git a/config/suppressions.xml b/config/suppressions.xml index 61ee66063..70ab69be3 100644 --- a/config/suppressions.xml +++ b/config/suppressions.xml @@ -140,7 +140,7 @@ - + @@ -161,5 +161,6 @@ lines="105, 143, 174"/> - + + diff --git a/src/main/java/com/puppycrawl/tools/checkstyle/AstTreeStringPrinter.java b/src/main/java/com/puppycrawl/tools/checkstyle/AstTreeStringPrinter.java index 27c761412..92617bc75 100644 --- a/src/main/java/com/puppycrawl/tools/checkstyle/AstTreeStringPrinter.java +++ b/src/main/java/com/puppycrawl/tools/checkstyle/AstTreeStringPrinter.java @@ -45,6 +45,9 @@ public final class AstTreeStringPrinter { /** Tab pattern. */ private static final Pattern TAB = Pattern.compile("\t"); + /** OS specific line separator. */ + private static final String LINE_SEPARATOR = System.getProperty("line.separator"); + /** Prevent instances. */ private AstTreeStringPrinter() { // no code @@ -53,12 +56,14 @@ public final class AstTreeStringPrinter { /** * Parse a file and print the parse tree. * @param file the file to print. + * @param withComments true to include comments to AST * @return the AST of the file in String form. * @throws IOException if the file could not be read. * @throws CheckstyleException if the file is not a Java source. */ - public static String printFileAst(File file) throws IOException, CheckstyleException { - return printTree(parseFile(file)); + public static String printFileAst(File file, boolean withComments) + throws IOException, CheckstyleException { + return printTree(parseFile(file, withComments)); } /** @@ -73,7 +78,8 @@ public final class AstTreeStringPrinter { messageBuilder.append(getIndentation(node)) .append(TokenUtils.getTokenName(node.getType())).append(" -> ") .append(excapeAllControlChars(node.getText())).append(" [") - .append(node.getLineNo()).append(':').append(node.getColumnNo()).append("]\n") + .append(node.getLineNo()).append(':').append(node.getColumnNo()).append(']') + .append(LINE_SEPARATOR) .append(printTree(node.getFirstChild())); node = node.getNextSibling(); } @@ -127,16 +133,24 @@ public final class AstTreeStringPrinter { /** * Parse a file and return the parse tree. * @param file the file to parse. + * @param withComments true to include comment nodes to the tree * @return the root node of the parse tree. * @throws IOException if the file could not be read. * @throws CheckstyleException if the file is not a Java source. */ - private static DetailAST parseFile(File file) throws IOException, CheckstyleException { + private static DetailAST parseFile(File file, boolean withComments) + throws IOException, CheckstyleException { final FileText text = new FileText(file.getAbsoluteFile(), System.getProperty("file.encoding", "UTF-8")); final FileContents contents = new FileContents(text); + final DetailAST result; try { - return TreeWalker.parse(contents); + if (withComments) { + result = TreeWalker.parseWithComments(contents); + } + else { + result = TreeWalker.parse(contents); + } } catch (RecognitionException | TokenStreamException ex) { final String exceptionMsg = String.format(Locale.ROOT, @@ -144,5 +158,7 @@ public final class AstTreeStringPrinter { ex.getClass().getSimpleName(), file.getPath()); throw new CheckstyleException(exceptionMsg, ex); } + + return result; } } diff --git a/src/main/java/com/puppycrawl/tools/checkstyle/Main.java b/src/main/java/com/puppycrawl/tools/checkstyle/Main.java index bfc7f3eeb..811a19f5b 100644 --- a/src/main/java/com/puppycrawl/tools/checkstyle/Main.java +++ b/src/main/java/com/puppycrawl/tools/checkstyle/Main.java @@ -49,6 +49,9 @@ import com.puppycrawl.tools.checkstyle.utils.CommonUtils; * **/ public final class Main { + /** Width of CLI help option. */ + private static final int HELP_WIDTH = 100; + /** Exit code returned when execution finishes with {@link CheckstyleException}. */ private static final int EXIT_WITH_CHECKSTYLE_EXCEPTION_CODE = -2; @@ -70,6 +73,15 @@ public final class Main { /** Name for the option 't'. */ private static final String OPTION_T_NAME = "t"; + /** Name for the option '--tree'. */ + private static final String OPTION_TREE_NAME = "tree"; + + /** Name for the option '-T'. */ + private static final String OPTION_CAPITAL_T_NAME = "T"; + + /** Name for the option '--treeWithComments'. */ + private static final String OPTION_TREE_COMMENT_NAME = "treeWithComments"; + /** Name for 'xml' format. */ private static final String XML_FORMAT_NAME = "xml"; @@ -120,11 +132,15 @@ public final class Main { else { // create config helper object final CliOptions config = convertCliToPojo(commandLine, filesToProcess); - if (commandLine.hasOption(OPTION_T_NAME)) { // print AST final File file = config.files.get(0); - final String stringAst = AstTreeStringPrinter.printFileAst(file); + final String stringAst = AstTreeStringPrinter.printFileAst(file, false); + System.out.print(stringAst); + } + else if (commandLine.hasOption(OPTION_CAPITAL_T_NAME)) { + final File file = config.files.get(0); + final String stringAst = AstTreeStringPrinter.printFileAst(file, true); System.out.print(stringAst); } else { @@ -188,7 +204,7 @@ public final class Main { result.add("Files to process must be specified, found 0."); } // ensure there is no conflicting options - else if (cmdLine.hasOption(OPTION_T_NAME)) { + else if (cmdLine.hasOption(OPTION_T_NAME) || cmdLine.hasOption(OPTION_CAPITAL_T_NAME)) { if (cmdLine.hasOption(OPTION_C_NAME) || cmdLine.hasOption(OPTION_P_NAME) || cmdLine.hasOption(OPTION_F_NAME) || cmdLine.hasOption(OPTION_O_NAME)) { result.add("Option '-t' cannot be used with other options."); @@ -430,6 +446,7 @@ public final class Main { /** Prints the usage information. **/ private static void printUsage() { final HelpFormatter formatter = new HelpFormatter(); + formatter.setWidth(HELP_WIDTH); formatter.printHelp(String.format("java %s [options] -c file...", Main.class.getName()), buildOptions()); } @@ -447,7 +464,10 @@ public final class Main { "Sets the output format. (%s|%s). Defaults to %s", PLAIN_FORMAT_NAME, XML_FORMAT_NAME, PLAIN_FORMAT_NAME)); options.addOption(OPTION_V_NAME, false, "Print product version and exit"); - options.addOption(OPTION_T_NAME, false, "Print Abstract Syntax Tree(AST) of the file"); + options.addOption(OPTION_T_NAME, OPTION_TREE_NAME, false, + "Print Abstract Syntax Tree(AST) of the file"); + options.addOption(OPTION_CAPITAL_T_NAME, OPTION_TREE_COMMENT_NAME, false, + "Print Abstract Syntax Tree(AST) of the file including comments"); return options; } diff --git a/src/main/java/com/puppycrawl/tools/checkstyle/TreeWalker.java b/src/main/java/com/puppycrawl/tools/checkstyle/TreeWalker.java index 958aeb648..54cc0aeef 100755 --- a/src/main/java/com/puppycrawl/tools/checkstyle/TreeWalker.java +++ b/src/main/java/com/puppycrawl/tools/checkstyle/TreeWalker.java @@ -443,6 +443,18 @@ public final class TreeWalker return (DetailAST) parser.getAST(); } + /** + * Parses Java source file. Result AST contains comment nodes. + * @param contents source file content + * @return DetailAST tree + * @throws RecognitionException if parser failed + * @throws TokenStreamException if lexer failed + */ + public static DetailAST parseWithComments(FileContents contents) + throws RecognitionException, TokenStreamException { + return appendHiddenCommentNodes(parse(contents)); + } + @Override public void destroy() { for (AbstractCheck check : ordinaryChecks) { diff --git a/src/test/java/com/puppycrawl/tools/checkstyle/AstTreeStringPrinterTest.java b/src/test/java/com/puppycrawl/tools/checkstyle/AstTreeStringPrinterTest.java index 9b12cab99..0a20ef2e6 100644 --- a/src/test/java/com/puppycrawl/tools/checkstyle/AstTreeStringPrinterTest.java +++ b/src/test/java/com/puppycrawl/tools/checkstyle/AstTreeStringPrinterTest.java @@ -23,8 +23,11 @@ import static com.puppycrawl.tools.checkstyle.internal.TestUtils.assertUtilsClas import java.io.File; +import org.junit.Assert; import org.junit.Test; +import com.google.common.base.Charsets; +import com.google.common.io.Files; import com.puppycrawl.tools.checkstyle.api.CheckstyleException; public class AstTreeStringPrinterTest { @@ -33,6 +36,10 @@ public class AstTreeStringPrinterTest { return "src/test/resources-noncompilable/com/puppycrawl/tools/checkstyle/" + filename; } + private static String getPath(String filename) { + return "src/test/resources/com/puppycrawl/tools/checkstyle/astprinter/" + filename; + } + @Test public void testIsProperUtilsClass() throws ReflectiveOperationException { assertUtilsClassHasPrivateConstructor(AstTreeStringPrinter.class); @@ -41,6 +48,26 @@ public class AstTreeStringPrinterTest { @Test(expected = CheckstyleException.class) public void testParseFileThrowable() throws Exception { AstTreeStringPrinter.printFileAst( - new File(getNonCompilablePath("InputAstTreeStringPrinter.java"))); + new File(getNonCompilablePath("InputAstTreeStringPrinter.java")), false); + } + + @Test + public void testParseFile() throws Exception { + final String actual = AstTreeStringPrinter.printFileAst( + new File(getPath("InputAstTreeStringPrinterComments.java")), false); + final String expected = Files.toString(new File( + getPath("expectedInputAstTreeStringPrinter.txt")), Charsets.UTF_8); + Assert.assertEquals(expected, actual); + } + + @Test + public void testParseFileWithComments() throws Exception { + final String actual = AstTreeStringPrinter.printFileAst( + new File(getPath("InputAstTreeStringPrinterComments.java")), true) + .replaceAll("\\\\r\\\\n", "\\\\n"); + final String expected = Files.toString(new File( + getPath("expectedInputAstTreeStringPrinterComments.txt")), Charsets.UTF_8) + .replaceAll("\\\\r\\\\n", "\\\\n"); + Assert.assertEquals(expected, actual); } } diff --git a/src/test/java/com/puppycrawl/tools/checkstyle/MainTest.java b/src/test/java/com/puppycrawl/tools/checkstyle/MainTest.java index cbdbeaa50..ffc979ce3 100644 --- a/src/test/java/com/puppycrawl/tools/checkstyle/MainTest.java +++ b/src/test/java/com/puppycrawl/tools/checkstyle/MainTest.java @@ -96,14 +96,17 @@ public class MainTest { @Override public void checkAssertion() { final String usage = String.format(Locale.ROOT, "Unrecognized option: -w%n" - + "usage: java com.puppycrawl.tools.checkstyle.Main [options] -c %n" - + " file...%n" - + " -c Sets the check configuration file to use.%n" - + " -f Sets the output format. (plain|xml). Defaults to plain%n" - + " -o Sets the output file. Defaults to stdout%n" - + " -p Loads the properties file%n" - + " -t Print Abstract Syntax Tree(AST) of the file%n" - + " -v Print product version and exit%n"); + + "usage: java com.puppycrawl.tools.checkstyle.Main [options] -c " + + " file...%n" + + " -c Sets the check configuration file to use.%n" + + " -f Sets the output format. (plain|xml). Defaults to" + + " plain%n" + + " -o Sets the output file. Defaults to stdout%n" + + " -p Loads the properties file%n" + + " -t,--tree Print Abstract Syntax Tree(AST) of the file%n" + + " -T,--treeWithComments Print Abstract Syntax Tree(AST) of the file" + + " including comments%n" + + " -v Print product version and exit%n"); assertEquals(usage, systemOut.getLog()); assertEquals("", systemErr.getLog()); @@ -647,31 +650,31 @@ public class MainTest { @Test public void testPrintTreeOption() throws Exception { - final String expected = "PACKAGE_DEF -> package [1:0]\n" - + "|--ANNOTATIONS -> ANNOTATIONS [1:28]\n" - + "|--DOT -> . [1:28]\n" - + "| |--DOT -> . [1:22]\n" - + "| | |--DOT -> . [1:11]\n" - + "| | | |--IDENT -> com [1:8]\n" - + "| | | `--IDENT -> puppycrawl [1:12]\n" - + "| | `--IDENT -> tools [1:23]\n" - + "| `--IDENT -> checkstyle [1:29]\n" - + "`--SEMI -> ; [1:39]\n" - + "CLASS_DEF -> CLASS_DEF [3:0]\n" - + "|--MODIFIERS -> MODIFIERS [3:0]\n" - + "| `--LITERAL_PUBLIC -> public [3:0]\n" - + "|--LITERAL_CLASS -> class [3:7]\n" - + "|--IDENT -> InputMain [3:13]\n" - + "`--OBJBLOCK -> OBJBLOCK [3:23]\n" - + " |--LCURLY -> { [3:23]\n" - + " `--RCURLY -> } [4:0]\n" - + "CLASS_DEF -> CLASS_DEF [5:0]\n" - + "|--MODIFIERS -> MODIFIERS [5:0]\n" - + "|--LITERAL_CLASS -> class [5:0]\n" - + "|--IDENT -> InputMainInner [5:6]\n" - + "`--OBJBLOCK -> OBJBLOCK [5:21]\n" - + " |--LCURLY -> { [5:21]\n" - + " `--RCURLY -> } [6:0]\n"; + final String expected = String.format(Locale.ROOT, "PACKAGE_DEF -> package [1:0]%n" + + "|--ANNOTATIONS -> ANNOTATIONS [1:28]%n" + + "|--DOT -> . [1:28]%n" + + "| |--DOT -> . [1:22]%n" + + "| | |--DOT -> . [1:11]%n" + + "| | | |--IDENT -> com [1:8]%n" + + "| | | `--IDENT -> puppycrawl [1:12]%n" + + "| | `--IDENT -> tools [1:23]%n" + + "| `--IDENT -> checkstyle [1:29]%n" + + "`--SEMI -> ; [1:39]%n" + + "CLASS_DEF -> CLASS_DEF [3:0]%n" + + "|--MODIFIERS -> MODIFIERS [3:0]%n" + + "| `--LITERAL_PUBLIC -> public [3:0]%n" + + "|--LITERAL_CLASS -> class [3:7]%n" + + "|--IDENT -> InputMain [3:13]%n" + + "`--OBJBLOCK -> OBJBLOCK [3:23]%n" + + " |--LCURLY -> { [3:23]%n" + + " `--RCURLY -> } [4:0]%n" + + "CLASS_DEF -> CLASS_DEF [5:0]%n" + + "|--MODIFIERS -> MODIFIERS [5:0]%n" + + "|--LITERAL_CLASS -> class [5:0]%n" + + "|--IDENT -> InputMainInner [5:6]%n" + + "`--OBJBLOCK -> OBJBLOCK [5:21]%n" + + " |--LCURLY -> { [5:21]%n" + + " `--RCURLY -> } [6:0]%n"); exit.checkAssertionAfterwards(new Assertion() { @Override @@ -683,6 +686,47 @@ public class MainTest { Main.main("-t", getPath("InputMain.java")); } + @Test + public void testPrintTreeCommentsOption() throws Exception { + final String expected = String.format(Locale.ROOT, "PACKAGE_DEF -> package [1:0]%n" + + "|--ANNOTATIONS -> ANNOTATIONS [1:28]%n" + + "|--DOT -> . [1:28]%n" + + "| |--DOT -> . [1:22]%n" + + "| | |--DOT -> . [1:11]%n" + + "| | | |--IDENT -> com [1:8]%n" + + "| | | `--IDENT -> puppycrawl [1:12]%n" + + "| | `--IDENT -> tools [1:23]%n" + + "| `--IDENT -> checkstyle [1:29]%n" + + "`--SEMI -> ; [1:39]%n" + + "CLASS_DEF -> CLASS_DEF [3:0]%n" + + "|--MODIFIERS -> MODIFIERS [3:0]%n" + + "| |--BLOCK_COMMENT_BEGIN -> /* [2:0]%n" + + "| | |--COMMENT_CONTENT -> comment [2:2]%n" + + "| | `--BLOCK_COMMENT_END -> */ [2:8]%n" + + "| `--LITERAL_PUBLIC -> public [3:0]%n" + + "|--LITERAL_CLASS -> class [3:7]%n" + + "|--IDENT -> InputMain [3:13]%n" + + "`--OBJBLOCK -> OBJBLOCK [3:23]%n" + + " |--LCURLY -> { [3:23]%n" + + " `--RCURLY -> } [4:0]%n" + + "CLASS_DEF -> CLASS_DEF [5:0]%n" + + "|--MODIFIERS -> MODIFIERS [5:0]%n" + + "|--LITERAL_CLASS -> class [5:0]%n" + + "|--IDENT -> InputMainInner [5:6]%n" + + "`--OBJBLOCK -> OBJBLOCK [5:21]%n" + + " |--LCURLY -> { [5:21]%n" + + " `--RCURLY -> } [6:0]%n"); + + exit.checkAssertionAfterwards(new Assertion() { + @Override + public void checkAssertion() { + assertEquals(expected, systemOut.getLog()); + assertEquals("", systemErr.getLog()); + } + }); + Main.main("-T", getPath("InputMain.java")); + } + @Test public void testConflictingOptionsTvsC() throws Exception { diff --git a/src/test/resources/com/puppycrawl/tools/checkstyle/InputMain.java b/src/test/resources/com/puppycrawl/tools/checkstyle/InputMain.java index b4ec9758c..1c8a12f42 100644 --- a/src/test/resources/com/puppycrawl/tools/checkstyle/InputMain.java +++ b/src/test/resources/com/puppycrawl/tools/checkstyle/InputMain.java @@ -1,5 +1,5 @@ package com.puppycrawl.tools.checkstyle; - +/*comment*/ public class InputMain { } class InputMainInner { diff --git a/src/test/resources/com/puppycrawl/tools/checkstyle/astprinter/InputAstTreeStringPrinterComments.java b/src/test/resources/com/puppycrawl/tools/checkstyle/astprinter/InputAstTreeStringPrinterComments.java new file mode 100644 index 000000000..76b9675b2 --- /dev/null +++ b/src/test/resources/com/puppycrawl/tools/checkstyle/astprinter/InputAstTreeStringPrinterComments.java @@ -0,0 +1,6 @@ +package com.puppycrawl.tools.checkstyle; + +/**my class*/ +class InputAstTreeStringPrinterComments { + // no code +} \ No newline at end of file diff --git a/src/test/resources/com/puppycrawl/tools/checkstyle/astprinter/expectedInputAstTreeStringPrinter.txt b/src/test/resources/com/puppycrawl/tools/checkstyle/astprinter/expectedInputAstTreeStringPrinter.txt new file mode 100644 index 000000000..97b757a46 --- /dev/null +++ b/src/test/resources/com/puppycrawl/tools/checkstyle/astprinter/expectedInputAstTreeStringPrinter.txt @@ -0,0 +1,17 @@ +PACKAGE_DEF -> package [1:0] +|--ANNOTATIONS -> ANNOTATIONS [1:28] +|--DOT -> . [1:28] +| |--DOT -> . [1:22] +| | |--DOT -> . [1:11] +| | | |--IDENT -> com [1:8] +| | | `--IDENT -> puppycrawl [1:12] +| | `--IDENT -> tools [1:23] +| `--IDENT -> checkstyle [1:29] +`--SEMI -> ; [1:39] +CLASS_DEF -> CLASS_DEF [4:0] +|--MODIFIERS -> MODIFIERS [4:0] +|--LITERAL_CLASS -> class [4:0] +|--IDENT -> InputAstTreeStringPrinterComments [4:6] +`--OBJBLOCK -> OBJBLOCK [4:40] + |--LCURLY -> { [4:40] + `--RCURLY -> } [6:0] diff --git a/src/test/resources/com/puppycrawl/tools/checkstyle/astprinter/expectedInputAstTreeStringPrinterComments.txt b/src/test/resources/com/puppycrawl/tools/checkstyle/astprinter/expectedInputAstTreeStringPrinterComments.txt new file mode 100644 index 000000000..2fd3700c6 --- /dev/null +++ b/src/test/resources/com/puppycrawl/tools/checkstyle/astprinter/expectedInputAstTreeStringPrinterComments.txt @@ -0,0 +1,22 @@ +PACKAGE_DEF -> package [1:0] +|--ANNOTATIONS -> ANNOTATIONS [1:28] +|--DOT -> . [1:28] +| |--DOT -> . [1:22] +| | |--DOT -> . [1:11] +| | | |--IDENT -> com [1:8] +| | | `--IDENT -> puppycrawl [1:12] +| | `--IDENT -> tools [1:23] +| `--IDENT -> checkstyle [1:29] +`--SEMI -> ; [1:39] +CLASS_DEF -> CLASS_DEF [4:0] +|--MODIFIERS -> MODIFIERS [4:0] +|--BLOCK_COMMENT_BEGIN -> /* [3:0] +| |--COMMENT_CONTENT -> *my class [3:2] +| `--BLOCK_COMMENT_END -> */ [3:10] +|--LITERAL_CLASS -> class [4:0] +|--IDENT -> InputAstTreeStringPrinterComments [4:6] +`--OBJBLOCK -> OBJBLOCK [4:40] + |--LCURLY -> { [4:40] + |--SINGLE_LINE_COMMENT -> // [5:1] + | `--COMMENT_CONTENT -> no code\r\n [5:3] + `--RCURLY -> } [6:0] diff --git a/src/xdocs/cmdline.xml.vm b/src/xdocs/cmdline.xml.vm index da9368f63..3c800fe2c 100644 --- a/src/xdocs/cmdline.xml.vm +++ b/src/xdocs/cmdline.xml.vm @@ -38,7 +38,7 @@ java -D<property>=<value> \ com.puppycrawl.tools.checkstyle.Main \ -c <configurationFile> \ [-f <format>] [-p <propertiesFile>] [-o <file>] \ - [-t] [-v] \ + [-t | --tree] [-T | --treeWithComments] [-v] \ file...

@@ -74,7 +74,11 @@ java -D<property>=<value> \ to.
  • - -t - print Abstract Syntax Tree(AST) of the checked file. The option + -t, --tree - print Abstract Syntax Tree(AST) of the checked file. The option + cannot be used other options and requires exactly one file to run on to be specified. +
  • +
  • + -T, --treeWithComments - print Abstract Syntax Tree(AST) with comment nodes of the checked file. The option cannot be used other options and requires exactly one file to run on to be specified.