DocPretty.java revision 3060:23f76aadbb36
1/*
2 * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package com.sun.tools.javac.tree;
27
28import java.io.IOException;
29import java.io.Writer;
30import java.util.List;
31
32import com.sun.source.doctree.*;
33import com.sun.source.doctree.AttributeTree.ValueKind;
34import com.sun.tools.javac.util.Convert;
35import com.sun.tools.javac.util.DefinedBy;
36import com.sun.tools.javac.util.DefinedBy.Api;
37
38/**
39 * Prints out a doc comment tree.
40 *
41 *  <p><b>This is NOT part of any supported API.
42 *  If you write code that depends on this, you do so at your own risk.
43 *  This code and its internal interfaces are subject to change or
44 *  deletion without notice.</b>
45 */
46public class DocPretty implements DocTreeVisitor<Void,Void> {
47
48    /**
49     * The output stream on which trees are printed.
50     */
51    final Writer out;
52
53    /**
54     * The left margin.
55     */
56    int lmargin = 0;
57
58    public DocPretty(Writer out) {
59        this.out = out;
60    }
61
62    /** Visitor method: print expression tree.
63     */
64    public void print(DocTree tree) throws IOException {
65        try {
66            if (tree == null)
67                print("/*missing*/");
68            else {
69                tree.accept(this, null);
70            }
71        } catch (UncheckedIOException ex) {
72            throw new IOException(ex.getMessage(), ex);
73        }
74    }
75
76    /**
77     * Print string, replacing all non-ascii character with unicode escapes.
78     */
79    protected void print(Object s) throws IOException {
80        out.write(Convert.escapeUnicode(s.toString()));
81    }
82
83    /**
84     * Print list.
85     */
86    public void print(List<? extends DocTree> list) throws IOException {
87        for (DocTree t: list) {
88            print(t);
89        }
90    }
91
92    /**
93     * Print list., with separators
94     */
95    protected void print(List<? extends DocTree> list, String sep) throws IOException {
96        if (list.isEmpty())
97            return;
98        boolean first = true;
99        for (DocTree t: list) {
100            if (!first)
101                print(sep);
102            print(t);
103            first = false;
104        }
105    }
106
107    /** Print new line.
108     */
109    protected void println() throws IOException {
110        out.write(lineSep);
111    }
112
113    protected void printTagName(DocTree node) throws IOException {
114        out.write("@");
115        out.write(node.getKind().tagName);
116    }
117
118    final String lineSep = System.getProperty("line.separator");
119
120    /**************************************************************************
121     * Traversal methods
122     *************************************************************************/
123
124    /** Exception to propagate IOException through visitXXX methods */
125    private static class UncheckedIOException extends Error {
126        static final long serialVersionUID = -4032692679158424751L;
127        UncheckedIOException(IOException e) {
128            super(e.getMessage(), e);
129        }
130    }
131
132
133    @DefinedBy(Api.COMPILER_TREE)
134    public Void visitAttribute(AttributeTree node, Void p) {
135        try {
136            print(node.getName());
137            String quote;
138            switch (node.getValueKind()) {
139                case EMPTY:
140                    quote = null;
141                    break;
142                case UNQUOTED:
143                    quote = "";
144                    break;
145                case SINGLE:
146                    quote = "'";
147                    break;
148                case DOUBLE:
149                    quote = "\"";
150                    break;
151                default:
152                    throw new AssertionError();
153            }
154            if (quote != null) {
155                print("=" + quote);
156                print(node.getValue());
157                print(quote);
158            }
159        } catch (IOException e) {
160            throw new UncheckedIOException(e);
161        }
162        return null;
163    }
164
165    @DefinedBy(Api.COMPILER_TREE)
166    public Void visitAuthor(AuthorTree node, Void p) {
167        try {
168            printTagName(node);
169            print(" ");
170            print(node.getName());
171        } catch (IOException e) {
172            throw new UncheckedIOException(e);
173        }
174        return null;
175    }
176
177    @DefinedBy(Api.COMPILER_TREE)
178    public Void visitComment(CommentTree node, Void p) {
179        try {
180            print(node.getBody());
181        } catch (IOException e) {
182            throw new UncheckedIOException(e);
183        }
184        return null;
185    }
186
187    @DefinedBy(Api.COMPILER_TREE)
188    public Void visitDeprecated(DeprecatedTree node, Void p) {
189        try {
190            printTagName(node);
191            if (!node.getBody().isEmpty()) {
192                print(" ");
193                print(node.getBody());
194            }
195        } catch (IOException e) {
196            throw new UncheckedIOException(e);
197        }
198        return null;
199    }
200
201    @DefinedBy(Api.COMPILER_TREE)
202    public Void visitDocComment(DocCommentTree node, Void p) {
203        try {
204            List<? extends DocTree> b = node.getFullBody();
205            List<? extends DocTree> t = node.getBlockTags();
206            print(b);
207            if (!b.isEmpty() && !t.isEmpty())
208                print("\n");
209            print(t, "\n");
210        } catch (IOException e) {
211            throw new UncheckedIOException(e);
212        }
213        return null;
214    }
215
216    @DefinedBy(Api.COMPILER_TREE)
217    public Void visitDocRoot(DocRootTree node, Void p) {
218        try {
219            print("{");
220            printTagName(node);
221            print("}");
222        } catch (IOException e) {
223            throw new UncheckedIOException(e);
224        }
225        return null;
226    }
227
228    @DefinedBy(Api.COMPILER_TREE)
229    public Void visitEndElement(EndElementTree node, Void p) {
230        try {
231            print("</");
232            print(node.getName());
233            print(">");
234        } catch (IOException e) {
235            throw new UncheckedIOException(e);
236        }
237        return null;
238    }
239
240    @DefinedBy(Api.COMPILER_TREE)
241    public Void visitEntity(EntityTree node, Void p) {
242        try {
243            print("&");
244            print(node.getName());
245            print(";");
246        } catch (IOException e) {
247            throw new UncheckedIOException(e);
248        }
249        return null;
250    }
251
252    @DefinedBy(Api.COMPILER_TREE)
253    public Void visitErroneous(ErroneousTree node, Void p) {
254        try {
255            print(node.getBody());
256        } catch (IOException e) {
257            throw new UncheckedIOException(e);
258        }
259        return null;
260    }
261
262    @DefinedBy(Api.COMPILER_TREE)
263    public Void visitIdentifier(IdentifierTree node, Void p) {
264        try {
265            print(node.getName());
266        } catch (IOException e) {
267            throw new UncheckedIOException(e);
268        }
269        return null;
270    }
271
272    @DefinedBy(Api.COMPILER_TREE)
273    public Void visitInheritDoc(InheritDocTree node, Void p) {
274        try {
275            print("{");
276            printTagName(node);
277            print("}");
278        } catch (IOException e) {
279            throw new UncheckedIOException(e);
280        }
281        return null;
282    }
283
284    @DefinedBy(Api.COMPILER_TREE)
285    public Void visitLink(LinkTree node, Void p) {
286        try {
287            print("{");
288            printTagName(node);
289            print(" ");
290            print(node.getReference());
291            if (!node.getLabel().isEmpty()) {
292                print(" ");
293                print(node.getLabel());
294            }
295            print("}");
296        } catch (IOException e) {
297            throw new UncheckedIOException(e);
298        }
299        return null;
300    }
301
302    @DefinedBy(Api.COMPILER_TREE)
303    public Void visitLiteral(LiteralTree node, Void p) {
304        try {
305            print("{");
306            printTagName(node);
307            String body = node.getBody().getBody();
308            if (!body.isEmpty() && !Character.isWhitespace(body.charAt(0))) {
309                print(" ");
310            }
311            print(node.getBody());
312            print("}");
313        } catch (IOException e) {
314            throw new UncheckedIOException(e);
315        }
316        return null;
317    }
318
319    @DefinedBy(Api.COMPILER_TREE)
320    public Void visitParam(ParamTree node, Void p) {
321        try {
322            printTagName(node);
323            print(" ");
324            if (node.isTypeParameter()) print("<");
325            print(node.getName());
326            if (node.isTypeParameter()) print(">");
327            if (!node.getDescription().isEmpty()) {
328                print(" ");
329                print(node.getDescription());
330            }
331        } catch (IOException e) {
332            throw new UncheckedIOException(e);
333        }
334        return null;
335    }
336
337    @DefinedBy(Api.COMPILER_TREE)
338    public Void visitReference(ReferenceTree node, Void p) {
339        try {
340            print(node.getSignature());
341        } catch (IOException e) {
342            throw new UncheckedIOException(e);
343        }
344        return null;
345    }
346
347    @DefinedBy(Api.COMPILER_TREE)
348    public Void visitReturn(ReturnTree node, Void p) {
349        try {
350            printTagName(node);
351            print(" ");
352            print(node.getDescription());
353        } catch (IOException e) {
354            throw new UncheckedIOException(e);
355        }
356        return null;
357    }
358
359    @DefinedBy(Api.COMPILER_TREE)
360    public Void visitSee(SeeTree node, Void p) {
361        try {
362            printTagName(node);
363            boolean first = true;
364            boolean needSep = true;
365            for (DocTree t: node.getReference()) {
366                if (needSep) print(" ");
367                needSep = (first && (t instanceof ReferenceTree));
368                first = false;
369                print(t);
370            }
371        } catch (IOException e) {
372            throw new UncheckedIOException(e);
373        }
374        return null;
375    }
376
377    @DefinedBy(Api.COMPILER_TREE)
378    public Void visitSerial(SerialTree node, Void p) {
379        try {
380            printTagName(node);
381            if (!node.getDescription().isEmpty()) {
382                print(" ");
383                print(node.getDescription());
384            }
385        } catch (IOException e) {
386            throw new UncheckedIOException(e);
387        }
388        return null;
389    }
390
391    @DefinedBy(Api.COMPILER_TREE)
392    public Void visitSerialData(SerialDataTree node, Void p) {
393        try {
394            printTagName(node);
395            if (!node.getDescription().isEmpty()) {
396                print(" ");
397                print(node.getDescription());
398            }
399        } catch (IOException e) {
400            throw new UncheckedIOException(e);
401        }
402        return null;
403    }
404
405    @DefinedBy(Api.COMPILER_TREE)
406    public Void visitSerialField(SerialFieldTree node, Void p) {
407        try {
408            printTagName(node);
409            print(" ");
410            print(node.getName());
411            print(" ");
412            print(node.getType());
413            if (!node.getDescription().isEmpty()) {
414                print(" ");
415                print(node.getDescription());
416            }
417        } catch (IOException e) {
418            throw new UncheckedIOException(e);
419        }
420        return null;
421    }
422
423    @DefinedBy(Api.COMPILER_TREE)
424    public Void visitSince(SinceTree node, Void p) {
425        try {
426            printTagName(node);
427            print(" ");
428            print(node.getBody());
429        } catch (IOException e) {
430            throw new UncheckedIOException(e);
431        }
432        return null;
433    }
434
435    @DefinedBy(Api.COMPILER_TREE)
436    public Void visitStartElement(StartElementTree node, Void p) {
437        try {
438            print("<");
439            print(node.getName());
440            List<? extends DocTree> attrs = node.getAttributes();
441            if (!attrs.isEmpty()) {
442                print(" ");
443                print(attrs);
444                DocTree last = node.getAttributes().get(attrs.size() - 1);
445                if (node.isSelfClosing() && last instanceof AttributeTree
446                        && ((AttributeTree) last).getValueKind() == ValueKind.UNQUOTED)
447                    print(" ");
448            }
449            if (node.isSelfClosing())
450                print("/");
451            print(">");
452        } catch (IOException e) {
453            throw new UncheckedIOException(e);
454        }
455        return null;
456    }
457
458    @DefinedBy(Api.COMPILER_TREE)
459    public Void visitText(TextTree node, Void p) {
460        try {
461            print(node.getBody());
462        } catch (IOException e) {
463            throw new UncheckedIOException(e);
464        }
465        return null;
466    }
467
468    @DefinedBy(Api.COMPILER_TREE)
469    public Void visitThrows(ThrowsTree node, Void p) {
470        try {
471            printTagName(node);
472            print(" ");
473            print(node.getExceptionName());
474            if (!node.getDescription().isEmpty()) {
475                print(" ");
476                print(node.getDescription());
477            }
478        } catch (IOException e) {
479            throw new UncheckedIOException(e);
480        }
481        return null;
482    }
483
484    @DefinedBy(Api.COMPILER_TREE)
485    public Void visitUnknownBlockTag(UnknownBlockTagTree node, Void p) {
486        try {
487            print("@");
488            print(node.getTagName());
489            print(" ");
490            print(node.getContent());
491        } catch (IOException e) {
492            throw new UncheckedIOException(e);
493        }
494        return null;
495    }
496
497    @DefinedBy(Api.COMPILER_TREE)
498    public Void visitUnknownInlineTag(UnknownInlineTagTree node, Void p) {
499        try {
500            print("{");
501            print("@");
502            print(node.getTagName());
503            print(" ");
504            print(node.getContent());
505            print("}");
506        } catch (IOException e) {
507            throw new UncheckedIOException(e);
508        }
509        return null;
510    }
511
512    @DefinedBy(Api.COMPILER_TREE)
513    public Void visitValue(ValueTree node, Void p) {
514        try {
515            print("{");
516            printTagName(node);
517            if (node.getReference() != null) {
518                print(" ");
519                print(node.getReference());
520            }
521            print("}");
522        } catch (IOException e) {
523            throw new UncheckedIOException(e);
524        }
525        return null;
526    }
527
528    @DefinedBy(Api.COMPILER_TREE)
529    public Void visitVersion(VersionTree node, Void p) {
530        try {
531            printTagName(node);
532            print(" ");
533            print(node.getBody());
534        } catch (IOException e) {
535            throw new UncheckedIOException(e);
536        }
537        return null;
538    }
539
540    @DefinedBy(Api.COMPILER_TREE)
541    public Void visitOther(DocTree node, Void p) {
542        try {
543            print("(UNKNOWN: " + node + ")");
544            println();
545        } catch (IOException e) {
546            throw new UncheckedIOException(e);
547        }
548        return null;
549    }
550}
551