jjg@1409: /*
jjg@1409: * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
jjg@1409: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
jjg@1409: *
jjg@1409: * This code is free software; you can redistribute it and/or modify it
jjg@1409: * under the terms of the GNU General Public License version 2 only, as
jjg@1409: * published by the Free Software Foundation. Oracle designates this
jjg@1409: * particular file as subject to the "Classpath" exception as provided
jjg@1409: * by Oracle in the LICENSE file that accompanied this code.
jjg@1409: *
jjg@1409: * This code is distributed in the hope that it will be useful, but WITHOUT
jjg@1409: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
jjg@1409: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
jjg@1409: * version 2 for more details (a copy is included in the LICENSE file that
jjg@1409: * accompanied this code).
jjg@1409: *
jjg@1409: * You should have received a copy of the GNU General Public License version
jjg@1409: * 2 along with this work; if not, write to the Free Software Foundation,
jjg@1409: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
jjg@1409: *
jjg@1409: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
jjg@1409: * or visit www.oracle.com if you need additional information or have any
jjg@1409: * questions.
jjg@1409: */
jjg@1409:
jjg@1409: package com.sun.tools.javac.tree;
jjg@1409:
jjg@1409: import java.io.Writer;
jjg@1409:
jjg@1409: import com.sun.source.doctree.*;
jjg@1409: import com.sun.source.doctree.AttributeTree.ValueKind;
jjg@1409: import com.sun.tools.javac.util.Convert;
jjg@1409: import java.io.IOException;
jjg@1409: import java.util.List;
jjg@1409:
jjg@1409: /**
jjg@1409: * Prints out a doc comment tree.
jjg@1409: *
jjg@1409: *
This is NOT part of any supported API.
jjg@1409: * If you write code that depends on this, you do so at your own risk.
jjg@1409: * This code and its internal interfaces are subject to change or
jjg@1409: * deletion without notice.
jjg@1409: */
jjg@1409: public class DocPretty implements DocTreeVisitor {
jjg@1409:
jjg@1409: /**
jjg@1409: * The output stream on which trees are printed.
jjg@1409: */
jjg@1409: final Writer out;
jjg@1409:
jjg@1409: /**
jjg@1409: * The left margin.
jjg@1409: */
jjg@1409: int lmargin = 0;
jjg@1409:
jjg@1409: public DocPretty(Writer out) {
jjg@1409: this.out = out;
jjg@1409: }
jjg@1409:
jjg@1409: /** Visitor method: print expression tree.
jjg@1409: */
jjg@1409: public void print(DocTree tree) throws IOException {
jjg@1409: try {
jjg@1409: if (tree == null)
jjg@1409: print("/*missing*/");
jjg@1409: else {
jjg@1409: tree.accept(this, null);
jjg@1409: }
jjg@1409: } catch (UncheckedIOException ex) {
jjg@1409: throw new IOException(ex.getMessage(), ex);
jjg@1409: }
jjg@1409: }
jjg@1409:
jjg@1409: /**
jjg@1409: * Print string, replacing all non-ascii character with unicode escapes.
jjg@1409: */
jjg@1409: protected void print(Object s) throws IOException {
jjg@1409: out.write(Convert.escapeUnicode(s.toString()));
jjg@1409: }
jjg@1409:
jjg@1409: /**
jjg@1409: * Print list.
jjg@1409: */
jjg@1455: public void print(List extends DocTree> list) throws IOException {
jjg@1409: for (DocTree t: list) {
jjg@1409: print(t);
jjg@1409: }
jjg@1409: }
jjg@1409:
jjg@1409: /**
jjg@1409: * Print list., with separators
jjg@1409: */
jjg@1409: protected void print(List extends DocTree> list, String sep) throws IOException {
jjg@1409: if (list.isEmpty())
jjg@1409: return;
jjg@1409: boolean first = true;
jjg@1409: for (DocTree t: list) {
jjg@1409: if (!first)
jjg@1409: print(sep);
jjg@1409: print(t);
jjg@1409: first = false;
jjg@1409: }
jjg@1409: }
jjg@1409:
jjg@1409: /** Print new line.
jjg@1409: */
jjg@1409: protected void println() throws IOException {
jjg@1409: out.write(lineSep);
jjg@1409: }
jjg@1409:
jjg@1409: protected void printTagName(DocTree node) throws IOException {
jjg@1409: out.write("@");
jjg@1409: out.write(node.getKind().tagName);
jjg@1409: }
jjg@1409:
jjg@1409: final String lineSep = System.getProperty("line.separator");
jjg@1409:
jjg@1409: /**************************************************************************
jjg@1409: * Traversal methods
jjg@1409: *************************************************************************/
jjg@1409:
jjg@1409: /** Exception to propagate IOException through visitXXX methods */
jjg@1409: private static class UncheckedIOException extends Error {
jjg@1409: static final long serialVersionUID = -4032692679158424751L;
jjg@1409: UncheckedIOException(IOException e) {
jjg@1409: super(e.getMessage(), e);
jjg@1409: }
jjg@1409: }
jjg@1409:
jjg@1409:
jjg@1409: public Void visitAttribute(AttributeTree node, Void p) {
jjg@1409: try {
jjg@1409: print(node.getName());
jjg@1409: String quote;
jjg@1409: switch (node.getValueKind()) {
jjg@1409: case EMPTY:
jjg@1409: quote = null;
jjg@1409: break;
jjg@1409: case UNQUOTED:
jjg@1409: quote = "";
jjg@1409: break;
jjg@1409: case SINGLE:
jjg@1409: quote = "'";
jjg@1409: break;
jjg@1409: case DOUBLE:
jjg@1409: quote = "\"";
jjg@1409: break;
jjg@1409: default:
jjg@1409: throw new AssertionError();
jjg@1409: }
jjg@1409: if (quote != null) {
jjg@1409: print("=" + quote);
jjg@1409: print(node.getValue());
jjg@1409: print(quote);
jjg@1409: }
jjg@1409: } catch (IOException e) {
jjg@1409: throw new UncheckedIOException(e);
jjg@1409: }
jjg@1409: return null;
jjg@1409: }
jjg@1409:
jjg@1409: public Void visitAuthor(AuthorTree node, Void p) {
jjg@1409: try {
jjg@1409: printTagName(node);
jjg@1409: print(" ");
jjg@1409: print(node.getName());
jjg@1409: } catch (IOException e) {
jjg@1409: throw new UncheckedIOException(e);
jjg@1409: }
jjg@1409: return null;
jjg@1409: }
jjg@1409:
jjg@1409: public Void visitComment(CommentTree node, Void p) {
jjg@1409: try {
jjg@1409: print(node.getBody());
jjg@1409: } catch (IOException e) {
jjg@1409: throw new UncheckedIOException(e);
jjg@1409: }
jjg@1409: return null;
jjg@1409: }
jjg@1409:
jjg@1409: public Void visitDeprecated(DeprecatedTree node, Void p) {
jjg@1409: try {
jjg@1409: printTagName(node);
jjg@1409: if (!node.getBody().isEmpty()) {
jjg@1409: print(" ");
jjg@1409: print(node.getBody());
jjg@1409: }
jjg@1409: } catch (IOException e) {
jjg@1409: throw new UncheckedIOException(e);
jjg@1409: }
jjg@1409: return null;
jjg@1409: }
jjg@1409:
jjg@1409: public Void visitDocComment(DocCommentTree node, Void p) {
jjg@1409: try {
jjg@1409: List extends DocTree> fs = node.getFirstSentence();
jjg@1409: List extends DocTree> b = node.getBody();
jjg@1409: List extends DocTree> t = node.getBlockTags();
jjg@1409: print(fs);
jjg@1409: if (!fs.isEmpty() && !b.isEmpty())
jjg@1409: print(" ");
jjg@1409: print(b);
jjg@1409: if ((!fs.isEmpty() || !b.isEmpty()) && !t.isEmpty())
jjg@1409: print("\n");
jjg@1409: print(t, "\n");
jjg@1409: } catch (IOException e) {
jjg@1409: throw new UncheckedIOException(e);
jjg@1409: }
jjg@1409: return null;
jjg@1409: }
jjg@1409:
jjg@1409: public Void visitDocRoot(DocRootTree node, Void p) {
jjg@1409: try {
jjg@1409: print("{");
jjg@1409: printTagName(node);
jjg@1409: print("}");
jjg@1409: } catch (IOException e) {
jjg@1409: throw new UncheckedIOException(e);
jjg@1409: }
jjg@1409: return null;
jjg@1409: }
jjg@1409:
jjg@1409: public Void visitEndElement(EndElementTree node, Void p) {
jjg@1409: try {
jjg@1409: print("");
jjg@1409: print(node.getName());
jjg@1409: print(">");
jjg@1409: } catch (IOException e) {
jjg@1409: throw new UncheckedIOException(e);
jjg@1409: }
jjg@1409: return null;
jjg@1409: }
jjg@1409:
jjg@1409: public Void visitEntity(EntityTree node, Void p) {
jjg@1409: try {
jjg@1409: print("&");
jjg@1409: print(node.getName());
jjg@1409: print(";");
jjg@1409: } catch (IOException e) {
jjg@1409: throw new UncheckedIOException(e);
jjg@1409: }
jjg@1409: return null;
jjg@1409: }
jjg@1409:
jjg@1409: public Void visitErroneous(ErroneousTree node, Void p) {
jjg@1409: try {
jjg@1409: print(node.getBody());
jjg@1409: } catch (IOException e) {
jjg@1409: throw new UncheckedIOException(e);
jjg@1409: }
jjg@1409: return null;
jjg@1409: }
jjg@1409:
jjg@1409: public Void visitIdentifier(IdentifierTree node, Void p) {
jjg@1409: try {
jjg@1409: print(node.getName());
jjg@1409: } catch (IOException e) {
jjg@1409: throw new UncheckedIOException(e);
jjg@1409: }
jjg@1409: return null;
jjg@1409: }
jjg@1409:
jjg@1409: public Void visitInheritDoc(InheritDocTree node, Void p) {
jjg@1409: try {
jjg@1409: print("{");
jjg@1409: printTagName(node);
jjg@1409: print("}");
jjg@1409: } catch (IOException e) {
jjg@1409: throw new UncheckedIOException(e);
jjg@1409: }
jjg@1409: return null;
jjg@1409: }
jjg@1409:
jjg@1409: public Void visitLink(LinkTree node, Void p) {
jjg@1409: try {
jjg@1409: print("{");
jjg@1409: printTagName(node);
jjg@1409: print(" ");
jjg@1409: print(node.getReference());
jjg@1409: if (!node.getLabel().isEmpty()) {
jjg@1409: print(" ");
jjg@1409: print(node.getLabel());
jjg@1409: }
jjg@1409: print("}");
jjg@1409: } catch (IOException e) {
jjg@1409: throw new UncheckedIOException(e);
jjg@1409: }
jjg@1409: return null;
jjg@1409: }
jjg@1409:
jjg@1409: public Void visitLiteral(LiteralTree node, Void p) {
jjg@1409: try {
jjg@1409: print("{");
jjg@1409: printTagName(node);
jjg@1409: print(" ");
jjg@1409: print(node.getBody());
jjg@1409: print("}");
jjg@1409: } catch (IOException e) {
jjg@1409: throw new UncheckedIOException(e);
jjg@1409: }
jjg@1409: return null;
jjg@1409: }
jjg@1409:
jjg@1409: public Void visitParam(ParamTree node, Void p) {
jjg@1409: try {
jjg@1409: printTagName(node);
jjg@1409: print(" ");
jjg@1409: if (node.isTypeParameter()) print("<");
jjg@1409: print(node.getName());
jjg@1409: if (node.isTypeParameter()) print(">");
jjg@1409: if (!node.getDescription().isEmpty()) {
jjg@1409: print(" ");
jjg@1409: print(node.getDescription());
jjg@1409: }
jjg@1409: } catch (IOException e) {
jjg@1409: throw new UncheckedIOException(e);
jjg@1409: }
jjg@1409: return null;
jjg@1409: }
jjg@1409:
jjg@1409: public Void visitReference(ReferenceTree node, Void p) {
jjg@1409: try {
jjg@1409: print(node.getSignature());
jjg@1409: } catch (IOException e) {
jjg@1409: throw new UncheckedIOException(e);
jjg@1409: }
jjg@1409: return null;
jjg@1409: }
jjg@1409:
jjg@1409: public Void visitReturn(ReturnTree node, Void p) {
jjg@1409: try {
jjg@1409: printTagName(node);
jjg@1409: print(" ");
jjg@1409: print(node.getDescription());
jjg@1409: } catch (IOException e) {
jjg@1409: throw new UncheckedIOException(e);
jjg@1409: }
jjg@1409: return null;
jjg@1409: }
jjg@1409:
jjg@1409: public Void visitSee(SeeTree node, Void p) {
jjg@1409: try {
jjg@1409: printTagName(node);
jjg@1409: boolean first = true;
jjg@1409: boolean needSep = true;
jjg@1409: for (DocTree t: node.getReference()) {
jjg@1409: if (needSep) print(" ");
jjg@1409: needSep = (first && (t instanceof ReferenceTree));
jjg@1409: first = false;
jjg@1409: print(t);
jjg@1409: }
jjg@1409: } catch (IOException e) {
jjg@1409: throw new UncheckedIOException(e);
jjg@1409: }
jjg@1409: return null;
jjg@1409: }
jjg@1409:
jjg@1409: public Void visitSerial(SerialTree node, Void p) {
jjg@1409: try {
jjg@1409: printTagName(node);
jjg@1409: if (!node.getDescription().isEmpty()) {
jjg@1409: print(" ");
jjg@1409: print(node.getDescription());
jjg@1409: }
jjg@1409: } catch (IOException e) {
jjg@1409: throw new UncheckedIOException(e);
jjg@1409: }
jjg@1409: return null;
jjg@1409: }
jjg@1409:
jjg@1409: public Void visitSerialData(SerialDataTree node, Void p) {
jjg@1409: try {
jjg@1409: printTagName(node);
jjg@1409: if (!node.getDescription().isEmpty()) {
jjg@1409: print(" ");
jjg@1409: print(node.getDescription());
jjg@1409: }
jjg@1409: } catch (IOException e) {
jjg@1409: throw new UncheckedIOException(e);
jjg@1409: }
jjg@1409: return null;
jjg@1409: }
jjg@1409:
jjg@1409: public Void visitSerialField(SerialFieldTree node, Void p) {
jjg@1409: try {
jjg@1409: printTagName(node);
jjg@1409: print(" ");
jjg@1409: print(node.getName());
jjg@1409: print(" ");
jjg@1409: print(node.getType());
jjg@1409: if (!node.getDescription().isEmpty()) {
jjg@1409: print(" ");
jjg@1409: print(node.getDescription());
jjg@1409: }
jjg@1409: } catch (IOException e) {
jjg@1409: throw new UncheckedIOException(e);
jjg@1409: }
jjg@1409: return null;
jjg@1409: }
jjg@1409:
jjg@1409: public Void visitSince(SinceTree node, Void p) {
jjg@1409: try {
jjg@1409: printTagName(node);
jjg@1409: print(" ");
jjg@1409: print(node.getBody());
jjg@1409: } catch (IOException e) {
jjg@1409: throw new UncheckedIOException(e);
jjg@1409: }
jjg@1409: return null;
jjg@1409: }
jjg@1409:
jjg@1409: public Void visitStartElement(StartElementTree node, Void p) {
jjg@1409: try {
jjg@1409: print("<");
jjg@1409: print(node.getName());
jjg@1409: List extends DocTree> attrs = node.getAttributes();
jjg@1409: if (!attrs.isEmpty()) {
jjg@1409: print(" ");
jjg@1409: print(attrs);
jjg@1409: DocTree last = node.getAttributes().get(attrs.size() - 1);
jjg@1409: if (node.isSelfClosing() && last instanceof AttributeTree
jjg@1409: && ((AttributeTree) last).getValueKind() == ValueKind.UNQUOTED)
jjg@1409: print(" ");
jjg@1409: }
jjg@1409: if (node.isSelfClosing())
jjg@1409: print("/");
jjg@1409: print(">");
jjg@1409: } catch (IOException e) {
jjg@1409: throw new UncheckedIOException(e);
jjg@1409: }
jjg@1409: return null;
jjg@1409: }
jjg@1409:
jjg@1409: public Void visitText(TextTree node, Void p) {
jjg@1409: try {
jjg@1409: print(node.getBody());
jjg@1409: } catch (IOException e) {
jjg@1409: throw new UncheckedIOException(e);
jjg@1409: }
jjg@1409: return null;
jjg@1409: }
jjg@1409:
jjg@1409: public Void visitThrows(ThrowsTree node, Void p) {
jjg@1409: try {
jjg@1409: printTagName(node);
jjg@1409: print(" ");
jjg@1409: print(node.getExceptionName());
jjg@1409: if (!node.getDescription().isEmpty()) {
jjg@1409: print(" ");
jjg@1409: print(node.getDescription());
jjg@1409: }
jjg@1409: } catch (IOException e) {
jjg@1409: throw new UncheckedIOException(e);
jjg@1409: }
jjg@1409: return null;
jjg@1409: }
jjg@1409:
jjg@1409: public Void visitUnknownBlockTag(UnknownBlockTagTree node, Void p) {
jjg@1409: try {
jjg@1409: print("@");
jjg@1409: print(node.getTagName());
jjg@1409: print(" ");
jjg@1409: print(node.getContent());
jjg@1409: } catch (IOException e) {
jjg@1409: throw new UncheckedIOException(e);
jjg@1409: }
jjg@1409: return null;
jjg@1409: }
jjg@1409:
jjg@1409: public Void visitUnknownInlineTag(UnknownInlineTagTree node, Void p) {
jjg@1409: try {
jjg@1409: print("{");
jjg@1409: print("@");
jjg@1409: print(node.getTagName());
jjg@1409: print(" ");
jjg@1409: print(node.getContent());
jjg@1409: print("}");
jjg@1409: } catch (IOException e) {
jjg@1409: throw new UncheckedIOException(e);
jjg@1409: }
jjg@1409: return null;
jjg@1409: }
jjg@1409:
jjg@1409: public Void visitValue(ValueTree node, Void p) {
jjg@1409: try {
jjg@1409: print("{");
jjg@1409: printTagName(node);
jjg@1409: if (node.getReference() != null) {
jjg@1409: print(" ");
jjg@1409: print(node.getReference());
jjg@1409: }
jjg@1409: print("}");
jjg@1409: } catch (IOException e) {
jjg@1409: throw new UncheckedIOException(e);
jjg@1409: }
jjg@1409: return null;
jjg@1409: }
jjg@1409:
jjg@1409: public Void visitVersion(VersionTree node, Void p) {
jjg@1409: try {
jjg@1409: printTagName(node);
jjg@1409: print(" ");
jjg@1409: print(node.getBody());
jjg@1409: } catch (IOException e) {
jjg@1409: throw new UncheckedIOException(e);
jjg@1409: }
jjg@1409: return null;
jjg@1409: }
jjg@1409:
jjg@1409: public Void visitOther(DocTree node, Void p) {
jjg@1409: try {
jjg@1409: print("(UNKNOWN: " + node + ")");
jjg@1409: println();
jjg@1409: } catch (IOException e) {
jjg@1409: throw new UncheckedIOException(e);
jjg@1409: }
jjg@1409: return null;
jjg@1409: }
jjg@1409: }