DocPretty.java revision 3162:f164d4c2d33e
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 visitIndex(IndexTree node, Void p) {
274        try {
275            print("{");
276            printTagName(node);
277            print(" ");
278            print(node.getSearchTerm());
279            if (!node.getDescription().isEmpty()) {
280                print(" ");
281                print(node.getDescription());
282            }
283            print("}");
284        } catch (IOException e) {
285            throw new UncheckedIOException(e);
286        }
287        return null;
288    }
289
290    @DefinedBy(Api.COMPILER_TREE)
291    public Void visitInheritDoc(InheritDocTree node, Void p) {
292        try {
293            print("{");
294            printTagName(node);
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 visitLink(LinkTree node, Void p) {
304        try {
305            print("{");
306            printTagName(node);
307            print(" ");
308            print(node.getReference());
309            if (!node.getLabel().isEmpty()) {
310                print(" ");
311                print(node.getLabel());
312            }
313            print("}");
314        } catch (IOException e) {
315            throw new UncheckedIOException(e);
316        }
317        return null;
318    }
319
320    @DefinedBy(Api.COMPILER_TREE)
321    public Void visitLiteral(LiteralTree node, Void p) {
322        try {
323            print("{");
324            printTagName(node);
325            String body = node.getBody().getBody();
326            if (!body.isEmpty() && !Character.isWhitespace(body.charAt(0))) {
327                print(" ");
328            }
329            print(node.getBody());
330            print("}");
331        } catch (IOException e) {
332            throw new UncheckedIOException(e);
333        }
334        return null;
335    }
336
337    @DefinedBy(Api.COMPILER_TREE)
338    public Void visitParam(ParamTree node, Void p) {
339        try {
340            printTagName(node);
341            print(" ");
342            if (node.isTypeParameter()) print("<");
343            print(node.getName());
344            if (node.isTypeParameter()) print(">");
345            if (!node.getDescription().isEmpty()) {
346                print(" ");
347                print(node.getDescription());
348            }
349        } catch (IOException e) {
350            throw new UncheckedIOException(e);
351        }
352        return null;
353    }
354
355    @DefinedBy(Api.COMPILER_TREE)
356    public Void visitReference(ReferenceTree node, Void p) {
357        try {
358            print(node.getSignature());
359        } catch (IOException e) {
360            throw new UncheckedIOException(e);
361        }
362        return null;
363    }
364
365    @DefinedBy(Api.COMPILER_TREE)
366    public Void visitReturn(ReturnTree node, Void p) {
367        try {
368            printTagName(node);
369            print(" ");
370            print(node.getDescription());
371        } catch (IOException e) {
372            throw new UncheckedIOException(e);
373        }
374        return null;
375    }
376
377    @DefinedBy(Api.COMPILER_TREE)
378    public Void visitSee(SeeTree node, Void p) {
379        try {
380            printTagName(node);
381            boolean first = true;
382            boolean needSep = true;
383            for (DocTree t: node.getReference()) {
384                if (needSep) print(" ");
385                needSep = (first && (t instanceof ReferenceTree));
386                first = false;
387                print(t);
388            }
389        } catch (IOException e) {
390            throw new UncheckedIOException(e);
391        }
392        return null;
393    }
394
395    @DefinedBy(Api.COMPILER_TREE)
396    public Void visitSerial(SerialTree node, Void p) {
397        try {
398            printTagName(node);
399            if (!node.getDescription().isEmpty()) {
400                print(" ");
401                print(node.getDescription());
402            }
403        } catch (IOException e) {
404            throw new UncheckedIOException(e);
405        }
406        return null;
407    }
408
409    @DefinedBy(Api.COMPILER_TREE)
410    public Void visitSerialData(SerialDataTree node, Void p) {
411        try {
412            printTagName(node);
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 visitSerialField(SerialFieldTree node, Void p) {
425        try {
426            printTagName(node);
427            print(" ");
428            print(node.getName());
429            print(" ");
430            print(node.getType());
431            if (!node.getDescription().isEmpty()) {
432                print(" ");
433                print(node.getDescription());
434            }
435        } catch (IOException e) {
436            throw new UncheckedIOException(e);
437        }
438        return null;
439    }
440
441    @DefinedBy(Api.COMPILER_TREE)
442    public Void visitSince(SinceTree node, Void p) {
443        try {
444            printTagName(node);
445            print(" ");
446            print(node.getBody());
447        } catch (IOException e) {
448            throw new UncheckedIOException(e);
449        }
450        return null;
451    }
452
453    @DefinedBy(Api.COMPILER_TREE)
454    public Void visitStartElement(StartElementTree node, Void p) {
455        try {
456            print("<");
457            print(node.getName());
458            List<? extends DocTree> attrs = node.getAttributes();
459            if (!attrs.isEmpty()) {
460                print(" ");
461                print(attrs);
462                DocTree last = node.getAttributes().get(attrs.size() - 1);
463                if (node.isSelfClosing() && last instanceof AttributeTree
464                        && ((AttributeTree) last).getValueKind() == ValueKind.UNQUOTED)
465                    print(" ");
466            }
467            if (node.isSelfClosing())
468                print("/");
469            print(">");
470        } catch (IOException e) {
471            throw new UncheckedIOException(e);
472        }
473        return null;
474    }
475
476    @DefinedBy(Api.COMPILER_TREE)
477    public Void visitText(TextTree node, Void p) {
478        try {
479            print(node.getBody());
480        } catch (IOException e) {
481            throw new UncheckedIOException(e);
482        }
483        return null;
484    }
485
486    @DefinedBy(Api.COMPILER_TREE)
487    public Void visitThrows(ThrowsTree node, Void p) {
488        try {
489            printTagName(node);
490            print(" ");
491            print(node.getExceptionName());
492            if (!node.getDescription().isEmpty()) {
493                print(" ");
494                print(node.getDescription());
495            }
496        } catch (IOException e) {
497            throw new UncheckedIOException(e);
498        }
499        return null;
500    }
501
502    @DefinedBy(Api.COMPILER_TREE)
503    public Void visitUnknownBlockTag(UnknownBlockTagTree node, Void p) {
504        try {
505            print("@");
506            print(node.getTagName());
507            print(" ");
508            print(node.getContent());
509        } catch (IOException e) {
510            throw new UncheckedIOException(e);
511        }
512        return null;
513    }
514
515    @DefinedBy(Api.COMPILER_TREE)
516    public Void visitUnknownInlineTag(UnknownInlineTagTree node, Void p) {
517        try {
518            print("{");
519            print("@");
520            print(node.getTagName());
521            print(" ");
522            print(node.getContent());
523            print("}");
524        } catch (IOException e) {
525            throw new UncheckedIOException(e);
526        }
527        return null;
528    }
529
530    @DefinedBy(Api.COMPILER_TREE)
531    public Void visitValue(ValueTree node, Void p) {
532        try {
533            print("{");
534            printTagName(node);
535            if (node.getReference() != null) {
536                print(" ");
537                print(node.getReference());
538            }
539            print("}");
540        } catch (IOException e) {
541            throw new UncheckedIOException(e);
542        }
543        return null;
544    }
545
546    @DefinedBy(Api.COMPILER_TREE)
547    public Void visitVersion(VersionTree node, Void p) {
548        try {
549            printTagName(node);
550            print(" ");
551            print(node.getBody());
552        } catch (IOException e) {
553            throw new UncheckedIOException(e);
554        }
555        return null;
556    }
557
558    @DefinedBy(Api.COMPILER_TREE)
559    public Void visitOther(DocTree node, Void p) {
560        try {
561            print("(UNKNOWN: " + node + ")");
562            println();
563        } catch (IOException e) {
564            throw new UncheckedIOException(e);
565        }
566        return null;
567    }
568}
569