Coverage Report - com.puppycrawl.tools.checkstyle.AstTreeStringPrinter
 
Classes in this File Line Coverage Branch Coverage Complexity
AstTreeStringPrinter
100%
60/60
100%
18/18
1.8
 
 1  
 ////////////////////////////////////////////////////////////////////////////////
 2  
 // checkstyle: Checks Java source code for adherence to a set of rules.
 3  
 // Copyright (C) 2001-2018 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 java.io.File;
 23  
 import java.io.IOException;
 24  
 import java.util.regex.Pattern;
 25  
 
 26  
 import com.puppycrawl.tools.checkstyle.api.CheckstyleException;
 27  
 import com.puppycrawl.tools.checkstyle.api.DetailAST;
 28  
 import com.puppycrawl.tools.checkstyle.api.DetailNode;
 29  
 import com.puppycrawl.tools.checkstyle.api.FileText;
 30  
 import com.puppycrawl.tools.checkstyle.api.TokenTypes;
 31  
 import com.puppycrawl.tools.checkstyle.utils.JavadocUtils;
 32  
 import com.puppycrawl.tools.checkstyle.utils.TokenUtils;
 33  
 
 34  
 /**
 35  
  * Class for printing AST to String.
 36  
  * @author Vladislav Lisetskii
 37  
  */
 38  
 public final class AstTreeStringPrinter {
 39  
 
 40  
     /** Newline pattern. */
 41  2
     private static final Pattern NEWLINE = Pattern.compile("\n");
 42  
     /** Return pattern. */
 43  2
     private static final Pattern RETURN = Pattern.compile("\r");
 44  
     /** Tab pattern. */
 45  2
     private static final Pattern TAB = Pattern.compile("\t");
 46  
 
 47  
     /** OS specific line separator. */
 48  2
     private static final String LINE_SEPARATOR = System.getProperty("line.separator");
 49  
 
 50  
     /** Prevent instances. */
 51  1
     private AstTreeStringPrinter() {
 52  
         // no code
 53  1
     }
 54  
 
 55  
     /**
 56  
      * Parse a file and print the parse tree.
 57  
      * @param file the file to print.
 58  
      * @param options {@link JavaParser.Options} to control the inclusion of comment nodes.
 59  
      * @return the AST of the file in String form.
 60  
      * @throws IOException if the file could not be read.
 61  
      * @throws CheckstyleException if the file is not a Java source.
 62  
      */
 63  
     public static String printFileAst(File file, JavaParser.Options options)
 64  
             throws IOException, CheckstyleException {
 65  20
         return printTree(JavaParser.parseFile(file, options));
 66  
     }
 67  
 
 68  
     /**
 69  
      * Prints full AST (java + comments + javadoc) of the java file.
 70  
      * @param file java file
 71  
      * @return Full tree
 72  
      * @throws IOException Failed to open a file
 73  
      * @throws CheckstyleException error while parsing the file
 74  
      */
 75  
     public static String printJavaAndJavadocTree(File file)
 76  
             throws IOException, CheckstyleException {
 77  5
         final DetailAST tree = JavaParser.parseFile(file, JavaParser.Options.WITH_COMMENTS);
 78  5
         return printJavaAndJavadocTree(tree);
 79  
     }
 80  
 
 81  
     /**
 82  
      * Prints full tree (java + comments + javadoc) of the DetailAST.
 83  
      * @param ast root DetailAST
 84  
      * @return Full tree
 85  
      */
 86  
     private static String printJavaAndJavadocTree(DetailAST ast) {
 87  132
         final StringBuilder messageBuilder = new StringBuilder(1024);
 88  132
         DetailAST node = ast;
 89  265
         while (node != null) {
 90  133
             messageBuilder.append(getIndentation(node))
 91  133
                 .append(getNodeInfo(node))
 92  133
                 .append(LINE_SEPARATOR);
 93  133
             if (node.getType() == TokenTypes.COMMENT_CONTENT
 94  9
                     && JavadocUtils.isJavadocComment(node.getParent())) {
 95  6
                 final String javadocTree = parseAndPrintJavadocTree(node);
 96  6
                 messageBuilder.append(javadocTree);
 97  6
             }
 98  
             else {
 99  127
                 messageBuilder.append(printJavaAndJavadocTree(node.getFirstChild()));
 100  
             }
 101  133
             node = node.getNextSibling();
 102  
         }
 103  132
         return messageBuilder.toString();
 104  
     }
 105  
 
 106  
     /**
 107  
      * Parses block comment as javadoc and prints its tree.
 108  
      * @param node block comment begin
 109  
      * @return string javadoc tree
 110  
      */
 111  
     private static String parseAndPrintJavadocTree(DetailAST node) {
 112  6
         final DetailAST javadocBlock = node.getParent();
 113  6
         final DetailNode tree = DetailNodeTreeStringPrinter.parseJavadocAsDetailNode(javadocBlock);
 114  
 
 115  6
         String baseIndentation = getIndentation(node);
 116  6
         baseIndentation = baseIndentation.substring(0, baseIndentation.length() - 2);
 117  6
         final String rootPrefix = baseIndentation + "   `--";
 118  6
         final String prefix = baseIndentation + "       ";
 119  6
         return DetailNodeTreeStringPrinter.printTree(tree, rootPrefix, prefix);
 120  
     }
 121  
 
 122  
     /**
 123  
      * Parse a file and print the parse tree.
 124  
      * @param text the text to parse.
 125  
      * @param options {@link JavaParser.Options} to control the inclusion of comment nodes.
 126  
      * @return the AST of the file in String form.
 127  
      * @throws CheckstyleException if the file is not a Java source.
 128  
      */
 129  
     public static String printAst(FileText text, JavaParser.Options options)
 130  
             throws CheckstyleException {
 131  13
         final DetailAST ast = JavaParser.parseFileText(text, options);
 132  13
         return printTree(ast);
 133  
     }
 134  
 
 135  
     /**
 136  
      * Print AST.
 137  
      * @param ast the root AST node.
 138  
      * @return string AST.
 139  
      */
 140  
     private static String printTree(DetailAST ast) {
 141  4854
         final StringBuilder messageBuilder = new StringBuilder(1024);
 142  4854
         DetailAST node = ast;
 143  9676
         while (node != null) {
 144  4822
             messageBuilder.append(getIndentation(node))
 145  4822
                     .append(getNodeInfo(node))
 146  4822
                     .append(LINE_SEPARATOR)
 147  4822
                     .append(printTree(node.getFirstChild()));
 148  4822
             node = node.getNextSibling();
 149  
         }
 150  4854
         return messageBuilder.toString();
 151  
     }
 152  
 
 153  
     /**
 154  
      * Get string representation of the node as token name,
 155  
      * node text, line number and column number.
 156  
      * @param node DetailAST
 157  
      * @return node info
 158  
      */
 159  
     private static String getNodeInfo(DetailAST node) {
 160  9910
         return TokenUtils.getTokenName(node.getType())
 161  4955
                 + " -> " + escapeAllControlChars(node.getText())
 162  4955
                 + " [" + node.getLineNo() + ':' + node.getColumnNo() + ']';
 163  
     }
 164  
 
 165  
     /**
 166  
      * Get indentation for an AST node.
 167  
      * @param ast the AST to get the indentation for.
 168  
      * @return the indentation in String format.
 169  
      */
 170  
     private static String getIndentation(DetailAST ast) {
 171  4961
         final boolean isLastChild = ast.getNextSibling() == null;
 172  4961
         DetailAST node = ast;
 173  4961
         final StringBuilder indentation = new StringBuilder(1024);
 174  28634
         while (node.getParent() != null) {
 175  23673
             node = node.getParent();
 176  23673
             if (node.getParent() == null) {
 177  4864
                 if (isLastChild) {
 178  
                     // only ASCII symbols must be used due to
 179  
                     // problems with running tests on Windows
 180  1960
                     indentation.append("`--");
 181  
                 }
 182  
                 else {
 183  2904
                     indentation.append("|--");
 184  
                 }
 185  
             }
 186  
             else {
 187  18809
                 if (node.getNextSibling() == null) {
 188  9247
                     indentation.insert(0, "    ");
 189  
                 }
 190  
                 else {
 191  9562
                     indentation.insert(0, "|   ");
 192  
                 }
 193  
             }
 194  
         }
 195  4961
         return indentation.toString();
 196  
     }
 197  
 
 198  
     /**
 199  
      * Replace all control chars with escaped symbols.
 200  
      * @param text the String to process.
 201  
      * @return the processed String with all control chars escaped.
 202  
      */
 203  
     private static String escapeAllControlChars(String text) {
 204  4955
         final String textWithoutNewlines = NEWLINE.matcher(text).replaceAll("\\\\n");
 205  4955
         final String textWithoutReturns = RETURN.matcher(textWithoutNewlines).replaceAll("\\\\r");
 206  4955
         return TAB.matcher(textWithoutReturns).replaceAll("\\\\t");
 207  
     }
 208  
 
 209  
 }