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