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