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 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 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 fs = node.getFirstSentence(); jjg@1409: List b = node.getBody(); jjg@1409: List 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: } 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 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: }