| //////////////////////////////////////////////////////////////////////////////// |
| // checkstyle: Checks Java source code for adherence to a set of rules. |
| // Copyright (C) 2001-2017 the original author or authors. |
| // |
| // This library is free software; you can redistribute it and/or |
| // modify it under the terms of the GNU Lesser General Public |
| // License as published by the Free Software Foundation; either |
| // version 2.1 of the License, or (at your option) any later version. |
| // |
| // This library is distributed in the hope that it will be useful, |
| // but WITHOUT ANY WARRANTY; without even the implied warranty of |
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| // Lesser General Public License for more details. |
| // |
| // You should have received a copy of the GNU Lesser General Public |
| // License along with this library; if not, write to the Free Software |
| // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| package com.puppycrawl.tools.checkstyle; |
| |
| import java.io.File; |
| import java.io.IOException; |
| import java.nio.charset.StandardCharsets; |
| |
| import com.puppycrawl.tools.checkstyle.JavadocDetailNodeParser.ParseErrorMessage; |
| import com.puppycrawl.tools.checkstyle.JavadocDetailNodeParser.ParseStatus; |
| import com.puppycrawl.tools.checkstyle.api.DetailAST; |
| import com.puppycrawl.tools.checkstyle.api.DetailNode; |
| import com.puppycrawl.tools.checkstyle.api.FileText; |
| import com.puppycrawl.tools.checkstyle.api.JavadocTokenTypes; |
| import com.puppycrawl.tools.checkstyle.api.LocalizedMessage; |
| import com.puppycrawl.tools.checkstyle.utils.CommonUtils; |
| import com.puppycrawl.tools.checkstyle.utils.JavadocUtils; |
| |
| /** |
| * Parses file as javadoc DetailNode tree and prints to system output stream. |
| * @author bizmailov |
| */ |
| public final class DetailNodeTreeStringPrinter { |
| |
| /** OS specific line separator. */ |
| private static final String LINE_SEPARATOR = System.getProperty("line.separator"); |
| |
| /** Prevent instances. */ |
| private DetailNodeTreeStringPrinter() { |
| // no code |
| } |
| |
| /** |
| * Parse a file and print the parse tree. |
| * @param file the file to print. |
| * @return parse tree as a string |
| * @throws IOException if the file could not be read. |
| */ |
| public static String printFileAst(File file) throws IOException { |
| return printTree(parseFile(file), "", ""); |
| } |
| |
| /** |
| * Parse block comment DetailAST as Javadoc DetailNode tree. |
| * @param blockComment DetailAST |
| * @return DetailNode tree |
| */ |
| public static DetailNode parseJavadocAsDetailNode(DetailAST blockComment) { |
| final JavadocDetailNodeParser parser = new JavadocDetailNodeParser(); |
| final ParseStatus status = parser.parseJavadocAsDetailNode(blockComment); |
| if (status.getParseErrorMessage() != null) { |
| throw new IllegalArgumentException(getParseErrorMessage(status.getParseErrorMessage())); |
| } |
| return status.getTree(); |
| } |
| |
| /** |
| * Parse javadoc comment to DetailNode tree. |
| * @param javadocComment javadoc comment content |
| * @return tree |
| */ |
| private static DetailNode parseJavadocAsDetailNode(String javadocComment) { |
| final DetailAST blockComment = CommonUtils.createBlockCommentNode(javadocComment); |
| return parseJavadocAsDetailNode(blockComment); |
| } |
| |
| /** |
| * Builds error message base on ParseErrorMessage's message key, its arguments, etc. |
| * @param parseErrorMessage ParseErrorMessage |
| * @return error message |
| */ |
| private static String getParseErrorMessage(ParseErrorMessage parseErrorMessage) { |
| final LocalizedMessage lmessage = new LocalizedMessage( |
| parseErrorMessage.getLineNumber(), |
| "com.puppycrawl.tools.checkstyle.checks.javadoc.messages", |
| parseErrorMessage.getMessageKey(), |
| parseErrorMessage.getMessageArguments(), |
| "", |
| DetailNodeTreeStringPrinter.class, |
| null); |
| return "[ERROR:" + parseErrorMessage.getLineNumber() + "] " + lmessage.getMessage(); |
| } |
| |
| /** |
| * Print AST. |
| * @param ast the root AST node. |
| * @param rootPrefix prefix for the root node |
| * @param prefix prefix for other nodes |
| * @return string AST. |
| */ |
| public static String printTree(DetailNode ast, String rootPrefix, String prefix) { |
| final StringBuilder messageBuilder = new StringBuilder(1024); |
| DetailNode node = ast; |
| while (node != null) { |
| if (node.getType() == JavadocTokenTypes.JAVADOC) { |
| messageBuilder.append(rootPrefix); |
| } |
| else { |
| messageBuilder.append(prefix); |
| } |
| messageBuilder.append(getIndentation(node)) |
| .append(JavadocUtils.getTokenName(node.getType())).append(" -> ") |
| .append(JavadocUtils.escapeAllControlChars(node.getText())).append(" [") |
| .append(node.getLineNumber()).append(':').append(node.getColumnNumber()) |
| .append(']').append(LINE_SEPARATOR) |
| .append(printTree(JavadocUtils.getFirstChild(node), rootPrefix, prefix)); |
| node = JavadocUtils.getNextSibling(node); |
| } |
| return messageBuilder.toString(); |
| } |
| |
| /** |
| * Get indentation for a node. |
| * @param node the DetailNode to get the indentation for. |
| * @return the indentation in String format. |
| */ |
| private static String getIndentation(DetailNode node) { |
| final boolean isLastChild = JavadocUtils.getNextSibling(node) == null; |
| DetailNode currentNode = node; |
| final StringBuilder indentation = new StringBuilder(1024); |
| while (currentNode.getParent() != null) { |
| currentNode = currentNode.getParent(); |
| if (currentNode.getParent() == null) { |
| if (isLastChild) { |
| // only ASCII symbols must be used due to |
| // problems with running tests on Windows |
| indentation.append("`--"); |
| } |
| else { |
| indentation.append("|--"); |
| } |
| } |
| else { |
| if (JavadocUtils.getNextSibling(currentNode) == null) { |
| indentation.insert(0, " "); |
| } |
| else { |
| indentation.insert(0, "| "); |
| } |
| } |
| } |
| return indentation.toString(); |
| } |
| |
| /** |
| * Parse a file and return the parse tree. |
| * @param file the file to parse. |
| * @return the root node of the parse tree. |
| * @throws IOException if the file could not be read. |
| */ |
| private static DetailNode parseFile(File file) throws IOException { |
| final FileText text = new FileText(file.getAbsoluteFile(), |
| System.getProperty("file.encoding", StandardCharsets.UTF_8.name())); |
| return parseJavadocAsDetailNode(text.getFullText().toString()); |
| } |
| |
| } |