DocPretty.java revision 3831:209b0eab0e1f
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    @Override @DefinedBy(Api.COMPILER_TREE)
133    public Void visitAttribute(AttributeTree node, Void p) {
134        try {
135            print(node.getName());
136            String quote;
137            switch (node.getValueKind()) {
138                case EMPTY:
139                    quote = null;
140                    break;
141                case UNQUOTED:
142                    quote = "";
143                    break;
144                case SINGLE:
145                    quote = "'";
146                    break;
147                case DOUBLE:
148                    quote = "\"";
149                    break;
150                default:
151                    throw new AssertionError();
152            }
153            if (quote != null) {
154                print("=" + quote);
155                print(node.getValue());
156                print(quote);
157            }
158        } catch (IOException e) {
159            throw new UncheckedIOException(e);
160        }
161        return null;
162    }
163
164    @Override @DefinedBy(Api.COMPILER_TREE)
165    public Void visitAuthor(AuthorTree node, Void p) {
166        try {
167            printTagName(node);
168            print(" ");
169            print(node.getName());
170        } catch (IOException e) {
171            throw new UncheckedIOException(e);
172        }
173        return null;
174    }
175
176    @Override @DefinedBy(Api.COMPILER_TREE)
177    public Void visitComment(CommentTree node, Void p) {
178        try {
179            print(node.getBody());
180        } catch (IOException e) {
181            throw new UncheckedIOException(e);
182        }
183        return null;
184    }
185
186    @Override @DefinedBy(Api.COMPILER_TREE)
187    public Void visitDeprecated(DeprecatedTree node, Void p) {
188        try {
189            printTagName(node);
190            if (!node.getBody().isEmpty()) {
191                print(" ");
192                print(node.getBody());
193            }
194        } catch (IOException e) {
195            throw new UncheckedIOException(e);
196        }
197        return null;
198    }
199
200    @Override @DefinedBy(Api.COMPILER_TREE)
201    public Void visitDocComment(DocCommentTree node, Void p) {
202        try {
203            List<? extends DocTree> b = node.getFullBody();
204            List<? extends DocTree> t = node.getBlockTags();
205            print(b);
206            if (!b.isEmpty() && !t.isEmpty())
207                print("\n");
208            print(t, "\n");
209        } catch (IOException e) {
210            throw new UncheckedIOException(e);
211        }
212        return null;
213    }
214
215    @Override @DefinedBy(Api.COMPILER_TREE)
216    public Void visitDocRoot(DocRootTree node, Void p) {
217        try {
218            print("{");
219            printTagName(node);
220            print("}");
221        } catch (IOException e) {
222            throw new UncheckedIOException(e);
223        }
224        return null;
225    }
226
227    @Override @DefinedBy(Api.COMPILER_TREE)
228    public Void visitEndElement(EndElementTree node, Void p) {
229        try {
230            print("</");
231            print(node.getName());
232            print(">");
233        } catch (IOException e) {
234            throw new UncheckedIOException(e);
235        }
236        return null;
237    }
238
239    @Override @DefinedBy(Api.COMPILER_TREE)
240    public Void visitEntity(EntityTree node, Void p) {
241        try {
242            print("&");
243            print(node.getName());
244            print(";");
245        } catch (IOException e) {
246            throw new UncheckedIOException(e);
247        }
248        return null;
249    }
250
251    @Override @DefinedBy(Api.COMPILER_TREE)
252    public Void visitErroneous(ErroneousTree node, Void p) {
253        try {
254            print(node.getBody());
255        } catch (IOException e) {
256            throw new UncheckedIOException(e);
257        }
258        return null;
259    }
260
261    @Override @DefinedBy(Api.COMPILER_TREE)
262    public Void visitHidden(HiddenTree node, Void p) {
263        try {
264            printTagName(node);
265            if (!node.getBody().isEmpty()) {
266                print(" ");
267                print(node.getBody());
268            }
269        } catch (IOException e) {
270            throw new UncheckedIOException(e);
271        }
272        return null;
273    }
274
275    @Override @DefinedBy(Api.COMPILER_TREE)
276    public Void visitIdentifier(IdentifierTree node, Void p) {
277        try {
278            print(node.getName());
279        } catch (IOException e) {
280            throw new UncheckedIOException(e);
281        }
282        return null;
283    }
284
285    @Override @DefinedBy(Api.COMPILER_TREE)
286    public Void visitIndex(IndexTree node, Void p) {
287        try {
288            print("{");
289            printTagName(node);
290            print(" ");
291            print(node.getSearchTerm());
292            if (!node.getDescription().isEmpty()) {
293                print(" ");
294                print(node.getDescription());
295            }
296            print("}");
297        } catch (IOException e) {
298            throw new UncheckedIOException(e);
299        }
300        return null;
301    }
302
303    @Override @DefinedBy(Api.COMPILER_TREE)
304    public Void visitInheritDoc(InheritDocTree node, Void p) {
305        try {
306            print("{");
307            printTagName(node);
308            print("}");
309        } catch (IOException e) {
310            throw new UncheckedIOException(e);
311        }
312        return null;
313    }
314
315    @Override @DefinedBy(Api.COMPILER_TREE)
316    public Void visitLink(LinkTree node, Void p) {
317        try {
318            print("{");
319            printTagName(node);
320            print(" ");
321            print(node.getReference());
322            if (!node.getLabel().isEmpty()) {
323                print(" ");
324                print(node.getLabel());
325            }
326            print("}");
327        } catch (IOException e) {
328            throw new UncheckedIOException(e);
329        }
330        return null;
331    }
332
333    @Override @DefinedBy(Api.COMPILER_TREE)
334    public Void visitLiteral(LiteralTree node, Void p) {
335        try {
336            print("{");
337            printTagName(node);
338            String body = node.getBody().getBody();
339            if (!body.isEmpty() && !Character.isWhitespace(body.charAt(0))) {
340                print(" ");
341            }
342            print(node.getBody());
343            print("}");
344        } catch (IOException e) {
345            throw new UncheckedIOException(e);
346        }
347        return null;
348    }
349
350    @Override @DefinedBy(Api.COMPILER_TREE)
351    public Void visitParam(ParamTree node, Void p) {
352        try {
353            printTagName(node);
354            print(" ");
355            if (node.isTypeParameter()) print("<");
356            print(node.getName());
357            if (node.isTypeParameter()) print(">");
358            if (!node.getDescription().isEmpty()) {
359                print(" ");
360                print(node.getDescription());
361            }
362        } catch (IOException e) {
363            throw new UncheckedIOException(e);
364        }
365        return null;
366    }
367
368    @Override @DefinedBy(Api.COMPILER_TREE)
369    public Void visitProvides(ProvidesTree node, Void p) {
370        try {
371            printTagName(node);
372            print(" ");
373            print(node.getServiceType());
374            if (!node.getDescription().isEmpty()) {
375                print(" ");
376                print(node.getDescription());
377            }
378        } catch (IOException e) {
379            throw new UncheckedIOException(e);
380        }
381        return null;
382    }
383
384    @Override @DefinedBy(Api.COMPILER_TREE)
385    public Void visitReference(ReferenceTree node, Void p) {
386        try {
387            print(node.getSignature());
388        } catch (IOException e) {
389            throw new UncheckedIOException(e);
390        }
391        return null;
392    }
393
394    @Override @DefinedBy(Api.COMPILER_TREE)
395    public Void visitReturn(ReturnTree node, Void p) {
396        try {
397            printTagName(node);
398            print(" ");
399            print(node.getDescription());
400        } catch (IOException e) {
401            throw new UncheckedIOException(e);
402        }
403        return null;
404    }
405
406    @Override @DefinedBy(Api.COMPILER_TREE)
407    public Void visitSee(SeeTree node, Void p) {
408        try {
409            printTagName(node);
410            boolean first = true;
411            boolean needSep = true;
412            for (DocTree t: node.getReference()) {
413                if (needSep) print(" ");
414                needSep = (first && (t instanceof ReferenceTree));
415                first = false;
416                print(t);
417            }
418        } catch (IOException e) {
419            throw new UncheckedIOException(e);
420        }
421        return null;
422    }
423
424    @Override @DefinedBy(Api.COMPILER_TREE)
425    public Void visitSerial(SerialTree node, Void p) {
426        try {
427            printTagName(node);
428            if (!node.getDescription().isEmpty()) {
429                print(" ");
430                print(node.getDescription());
431            }
432        } catch (IOException e) {
433            throw new UncheckedIOException(e);
434        }
435        return null;
436    }
437
438    @Override @DefinedBy(Api.COMPILER_TREE)
439    public Void visitSerialData(SerialDataTree node, Void p) {
440        try {
441            printTagName(node);
442            if (!node.getDescription().isEmpty()) {
443                print(" ");
444                print(node.getDescription());
445            }
446        } catch (IOException e) {
447            throw new UncheckedIOException(e);
448        }
449        return null;
450    }
451
452    @Override @DefinedBy(Api.COMPILER_TREE)
453    public Void visitSerialField(SerialFieldTree node, Void p) {
454        try {
455            printTagName(node);
456            print(" ");
457            print(node.getName());
458            print(" ");
459            print(node.getType());
460            if (!node.getDescription().isEmpty()) {
461                print(" ");
462                print(node.getDescription());
463            }
464        } catch (IOException e) {
465            throw new UncheckedIOException(e);
466        }
467        return null;
468    }
469
470    @Override @DefinedBy(Api.COMPILER_TREE)
471    public Void visitSince(SinceTree node, Void p) {
472        try {
473            printTagName(node);
474            print(" ");
475            print(node.getBody());
476        } catch (IOException e) {
477            throw new UncheckedIOException(e);
478        }
479        return null;
480    }
481
482    @Override @DefinedBy(Api.COMPILER_TREE)
483    public Void visitStartElement(StartElementTree node, Void p) {
484        try {
485            print("<");
486            print(node.getName());
487            List<? extends DocTree> attrs = node.getAttributes();
488            if (!attrs.isEmpty()) {
489                print(" ");
490                print(attrs);
491                DocTree last = node.getAttributes().get(attrs.size() - 1);
492                if (node.isSelfClosing() && last instanceof AttributeTree
493                        && ((AttributeTree) last).getValueKind() == ValueKind.UNQUOTED)
494                    print(" ");
495            }
496            if (node.isSelfClosing())
497                print("/");
498            print(">");
499        } catch (IOException e) {
500            throw new UncheckedIOException(e);
501        }
502        return null;
503    }
504
505    @Override @DefinedBy(Api.COMPILER_TREE)
506    public Void visitText(TextTree node, Void p) {
507        try {
508            print(node.getBody());
509        } catch (IOException e) {
510            throw new UncheckedIOException(e);
511        }
512        return null;
513    }
514
515    @Override @DefinedBy(Api.COMPILER_TREE)
516    public Void visitThrows(ThrowsTree node, Void p) {
517        try {
518            printTagName(node);
519            print(" ");
520            print(node.getExceptionName());
521            if (!node.getDescription().isEmpty()) {
522                print(" ");
523                print(node.getDescription());
524            }
525        } catch (IOException e) {
526            throw new UncheckedIOException(e);
527        }
528        return null;
529    }
530
531    @Override @DefinedBy(Api.COMPILER_TREE)
532    public Void visitUnknownBlockTag(UnknownBlockTagTree node, Void p) {
533        try {
534            print("@");
535            print(node.getTagName());
536            print(" ");
537            print(node.getContent());
538        } catch (IOException e) {
539            throw new UncheckedIOException(e);
540        }
541        return null;
542    }
543
544    @Override @DefinedBy(Api.COMPILER_TREE)
545    public Void visitUnknownInlineTag(UnknownInlineTagTree node, Void p) {
546        try {
547            print("{");
548            print("@");
549            print(node.getTagName());
550            print(" ");
551            print(node.getContent());
552            print("}");
553        } catch (IOException e) {
554            throw new UncheckedIOException(e);
555        }
556        return null;
557    }
558
559    @Override @DefinedBy(Api.COMPILER_TREE)
560    public Void visitUses(UsesTree node, Void p) {
561        try {
562            printTagName(node);
563            print(" ");
564            print(node.getServiceType());
565            if (!node.getDescription().isEmpty()) {
566                print(" ");
567                print(node.getDescription());
568            }
569        } catch (IOException e) {
570            throw new UncheckedIOException(e);
571        }
572        return null;
573    }
574
575    @Override @DefinedBy(Api.COMPILER_TREE)
576    public Void visitValue(ValueTree node, Void p) {
577        try {
578            print("{");
579            printTagName(node);
580            if (node.getReference() != null) {
581                print(" ");
582                print(node.getReference());
583            }
584            print("}");
585        } catch (IOException e) {
586            throw new UncheckedIOException(e);
587        }
588        return null;
589    }
590
591    @Override @DefinedBy(Api.COMPILER_TREE)
592    public Void visitVersion(VersionTree node, Void p) {
593        try {
594            printTagName(node);
595            print(" ");
596            print(node.getBody());
597        } catch (IOException e) {
598            throw new UncheckedIOException(e);
599        }
600        return null;
601    }
602
603    @Override @DefinedBy(Api.COMPILER_TREE)
604    public Void visitOther(DocTree node, Void p) {
605        try {
606            print("(UNKNOWN: " + node + ")");
607            println();
608        } catch (IOException e) {
609            throw new UncheckedIOException(e);
610        }
611        return null;
612    }
613}
614