1 /*
2  * Copyright (c) 1999, 2019, 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 
26 package com.sun.tools.javac.tree;
27 
28 import java.io.*;
29 
30 import com.sun.source.tree.CaseTree.CaseKind;
31 import com.sun.source.tree.MemberReferenceTree.ReferenceMode;
32 import com.sun.source.tree.ModuleTree.ModuleKind;
33 import com.sun.tools.javac.code.*;
34 import com.sun.tools.javac.tree.JCTree.*;
35 import com.sun.tools.javac.util.*;
36 import com.sun.tools.javac.util.List;
37 import static com.sun.tools.javac.code.Flags.*;
38 import static com.sun.tools.javac.code.Flags.ANNOTATION;
39 import static com.sun.tools.javac.tree.JCTree.Tag.*;
40 
41 /** Prints out a tree as an indented Java source program.
42  *
43  *  <p><b>This is NOT part of any supported API.
44  *  If you write code that depends on this, you do so at your own risk.
45  *  This code and its internal interfaces are subject to change or
46  *  deletion without notice.</b>
47  */
48 public class Pretty extends JCTree.Visitor {
49 
Pretty(Writer out, boolean sourceOutput)50     public Pretty(Writer out, boolean sourceOutput) {
51         this.out = out;
52         this.sourceOutput = sourceOutput;
53     }
54 
55     /** Set when we are producing source output.  If we're not
56      *  producing source output, we can sometimes give more detail in
57      *  the output even though that detail would not be valid java
58      *  source.
59      */
60     private final boolean sourceOutput;
61 
62     /** The output stream on which trees are printed.
63      */
64     Writer out;
65 
66     /** Indentation width (can be reassigned from outside).
67      */
68     public int width = 4;
69 
70     /** The current left margin.
71      */
72     int lmargin = 0;
73 
74     /** The enclosing class name.
75      */
76     Name enclClassName;
77 
78     /** A table mapping trees to their documentation comments
79      *  (can be null)
80      */
81     DocCommentTable docComments = null;
82 
83     /**
84      * A string sequence to be used when Pretty output should be constrained
85      * to fit into a given size
86      */
87     private final static String trimSequence = "[...]";
88 
89     /**
90      * Max number of chars to be generated when output should fit into a single line
91      */
92     private final static int PREFERRED_LENGTH = 20;
93 
94     /** Align code to be indented to left margin.
95      */
align()96     void align() throws IOException {
97         for (int i = 0; i < lmargin; i++) out.write(" ");
98     }
99 
100     /** Increase left margin by indentation width.
101      */
indent()102     void indent() {
103         lmargin = lmargin + width;
104     }
105 
106     /** Decrease left margin by indentation width.
107      */
undent()108     void undent() {
109         lmargin = lmargin - width;
110     }
111 
112     /** Enter a new precedence level. Emit a `(' if new precedence level
113      *  is less than precedence level so far.
114      *  @param contextPrec    The precedence level in force so far.
115      *  @param ownPrec        The new precedence level.
116      */
open(int contextPrec, int ownPrec)117     void open(int contextPrec, int ownPrec) throws IOException {
118         if (ownPrec < contextPrec) out.write("(");
119     }
120 
121     /** Leave precedence level. Emit a `(' if inner precedence level
122      *  is less than precedence level we revert to.
123      *  @param contextPrec    The precedence level we revert to.
124      *  @param ownPrec        The inner precedence level.
125      */
close(int contextPrec, int ownPrec)126     void close(int contextPrec, int ownPrec) throws IOException {
127         if (ownPrec < contextPrec) out.write(")");
128     }
129 
130     /** Print string, replacing all non-ascii character with unicode escapes.
131      */
print(Object s)132     public void print(Object s) throws IOException {
133         out.write(Convert.escapeUnicode(s.toString()));
134     }
135 
136     /** Print new line.
137      */
println()138     public void println() throws IOException {
139         out.write(lineSep);
140     }
141 
toSimpleString(JCTree tree)142     public static String toSimpleString(JCTree tree) {
143         return toSimpleString(tree, PREFERRED_LENGTH);
144     }
145 
toSimpleString(JCTree tree, int maxLength)146     public static String toSimpleString(JCTree tree, int maxLength) {
147         StringWriter s = new StringWriter();
148         try {
149             new Pretty(s, false).printExpr(tree);
150         }
151         catch (IOException e) {
152             // should never happen, because StringWriter is defined
153             // never to throw any IOExceptions
154             throw new AssertionError(e);
155         }
156         //we need to (i) replace all line terminators with a space and (ii) remove
157         //occurrences of 'missing' in the Pretty output (generated when types are missing)
158         String res = s.toString().trim().replaceAll("\\s+", " ").replaceAll("/\\*missing\\*/", "");
159         if (res.length() < maxLength) {
160             return res;
161         } else {
162             int head = (maxLength - trimSequence.length()) * 2 / 3;
163             int tail = maxLength - trimSequence.length() - head;
164             return res.substring(0, head) + trimSequence + res.substring(res.length() - tail);
165         }
166     }
167 
168     String lineSep = System.getProperty("line.separator");
169 
170     /**************************************************************************
171      * Traversal methods
172      *************************************************************************/
173 
174     /** Exception to propogate IOException through visitXXX methods */
175     private static class UncheckedIOException extends Error {
176         static final long serialVersionUID = -4032692679158424751L;
UncheckedIOException(IOException e)177         UncheckedIOException(IOException e) {
178             super(e.getMessage(), e);
179         }
180     }
181 
182     /** Visitor argument: the current precedence level.
183      */
184     int prec;
185 
186     /** Visitor method: print expression tree.
187      *  @param prec  The current precedence level.
188      */
printExpr(JCTree tree, int prec)189     public void printExpr(JCTree tree, int prec) throws IOException {
190         int prevPrec = this.prec;
191         try {
192             this.prec = prec;
193             if (tree == null) print("/*missing*/");
194             else {
195                 tree.accept(this);
196             }
197         } catch (UncheckedIOException ex) {
198             IOException e = new IOException(ex.getMessage());
199             e.initCause(ex);
200             throw e;
201         } finally {
202             this.prec = prevPrec;
203         }
204     }
205 
206     /** Derived visitor method: print expression tree at minimum precedence level
207      *  for expression.
208      */
printExpr(JCTree tree)209     public void printExpr(JCTree tree) throws IOException {
210         printExpr(tree, TreeInfo.noPrec);
211     }
212 
213     /** Derived visitor method: print statement tree.
214      */
printStat(JCTree tree)215     public void printStat(JCTree tree) throws IOException {
216         printExpr(tree, TreeInfo.notExpression);
217     }
218 
219     /** Derived visitor method: print list of expression trees, separated by given string.
220      *  @param sep the separator string
221      */
printExprs(List<T> trees, String sep)222     public <T extends JCTree> void printExprs(List<T> trees, String sep) throws IOException {
223         if (trees.nonEmpty()) {
224             printExpr(trees.head);
225             for (List<T> l = trees.tail; l.nonEmpty(); l = l.tail) {
226                 print(sep);
227                 printExpr(l.head);
228             }
229         }
230     }
231 
232     /** Derived visitor method: print list of expression trees, separated by commas.
233      */
printExprs(List<T> trees)234     public <T extends JCTree> void printExprs(List<T> trees) throws IOException {
235         printExprs(trees, ", ");
236     }
237 
238     /** Derived visitor method: print list of statements, each on a separate line.
239      */
printStats(List<? extends JCTree> trees)240     public void printStats(List<? extends JCTree> trees) throws IOException {
241         for (List<? extends JCTree> l = trees; l.nonEmpty(); l = l.tail) {
242             align();
243             printStat(l.head);
244             println();
245         }
246     }
247 
248     /** Print a set of modifiers.
249      */
printFlags(long flags)250     public void printFlags(long flags) throws IOException {
251         if ((flags & SYNTHETIC) != 0) print("/*synthetic*/ ");
252         print(TreeInfo.flagNames(flags));
253         if ((flags & ExtendedStandardFlags) != 0) print(" ");
254         if ((flags & ANNOTATION) != 0) print("@");
255     }
256 
printAnnotations(List<JCAnnotation> trees)257     public void printAnnotations(List<JCAnnotation> trees) throws IOException {
258         for (List<JCAnnotation> l = trees; l.nonEmpty(); l = l.tail) {
259             printStat(l.head);
260             println();
261             align();
262         }
263     }
264 
printTypeAnnotations(List<JCAnnotation> trees)265     public void printTypeAnnotations(List<JCAnnotation> trees) throws IOException {
266         for (List<JCAnnotation> l = trees; l.nonEmpty(); l = l.tail) {
267             printExpr(l.head);
268             print(" ");
269         }
270     }
271 
272     /** Print documentation comment, if it exists
273      *  @param tree    The tree for which a documentation comment should be printed.
274      */
printDocComment(JCTree tree)275     public void printDocComment(JCTree tree) throws IOException {
276         if (docComments != null) {
277             String dc = docComments.getCommentText(tree);
278             if (dc != null) {
279                 print("/**"); println();
280                 int pos = 0;
281                 int endpos = lineEndPos(dc, pos);
282                 while (pos < dc.length()) {
283                     align();
284                     print(" *");
285                     if (pos < dc.length() && dc.charAt(pos) > ' ') print(" ");
286                     print(dc.substring(pos, endpos)); println();
287                     pos = endpos + 1;
288                     endpos = lineEndPos(dc, pos);
289                 }
290                 align(); print(" */"); println();
291                 align();
292             }
293         }
294     }
295 //where
lineEndPos(String s, int start)296     static int lineEndPos(String s, int start) {
297         int pos = s.indexOf('\n', start);
298         if (pos < 0) pos = s.length();
299         return pos;
300     }
301 
302     /** If type parameter list is non-empty, print it enclosed in
303      *  {@literal "<...>"} brackets.
304      */
printTypeParameters(List<JCTypeParameter> trees)305     public void printTypeParameters(List<JCTypeParameter> trees) throws IOException {
306         if (trees.nonEmpty()) {
307             print("<");
308             printExprs(trees);
309             print(">");
310         }
311     }
312 
313     /** Print a block.
314      */
printBlock(List<? extends JCTree> stats)315     public void printBlock(List<? extends JCTree> stats) throws IOException {
316         print("{");
317         println();
318         indent();
319         printStats(stats);
320         undent();
321         align();
322         print("}");
323     }
324 
325     /** Print a block.
326      */
printEnumBody(List<JCTree> stats)327     public void printEnumBody(List<JCTree> stats) throws IOException {
328         print("{");
329         println();
330         indent();
331         boolean first = true;
332         for (List<JCTree> l = stats; l.nonEmpty(); l = l.tail) {
333             if (isEnumerator(l.head)) {
334                 if (!first) {
335                     print(",");
336                     println();
337                 }
338                 align();
339                 printStat(l.head);
340                 first = false;
341             }
342         }
343         print(";");
344         println();
345         for (List<JCTree> l = stats; l.nonEmpty(); l = l.tail) {
346             if (!isEnumerator(l.head)) {
347                 align();
348                 printStat(l.head);
349                 println();
350             }
351         }
352         undent();
353         align();
354         print("}");
355     }
356 
357     /** Is the given tree an enumerator definition? */
isEnumerator(JCTree t)358     boolean isEnumerator(JCTree t) {
359         return t.hasTag(VARDEF) && (((JCVariableDecl) t).mods.flags & ENUM) != 0;
360     }
361 
362     /** Print unit consisting of package clause and import statements in toplevel,
363      *  followed by class definition. if class definition == null,
364      *  print all definitions in toplevel.
365      *  @param tree     The toplevel tree
366      *  @param cdef     The class definition, which is assumed to be part of the
367      *                  toplevel tree.
368      */
printUnit(JCCompilationUnit tree, JCClassDecl cdef)369     public void printUnit(JCCompilationUnit tree, JCClassDecl cdef) throws IOException {
370         docComments = tree.docComments;
371         printDocComment(tree);
372 
373         boolean firstImport = true;
374         for (List<JCTree> l = tree.defs;
375              l.nonEmpty() &&
376                  (cdef == null ||
377                   l.head.hasTag(IMPORT) || l.head.hasTag(PACKAGEDEF));
378              l = l.tail) {
379             if (l.head.hasTag(IMPORT)) {
380                 JCImport imp = (JCImport)l.head;
381                 Name name = TreeInfo.name(imp.qualid);
382                 if (name == name.table.names.asterisk ||
383                         cdef == null ||
384                         isUsed(TreeInfo.symbol(imp.qualid), cdef)) {
385                     if (firstImport) {
386                         firstImport = false;
387                         println();
388                     }
389                     printStat(imp);
390                 }
391             } else {
392                 printStat(l.head);
393             }
394         }
395         if (cdef != null) {
396             printStat(cdef);
397             println();
398         }
399     }
400     // where
isUsed(final Symbol t, JCTree cdef)401     boolean isUsed(final Symbol t, JCTree cdef) {
402         class UsedVisitor extends TreeScanner {
403             public void scan(JCTree tree) {
404                 if (tree!=null && !result) tree.accept(this);
405             }
406             boolean result = false;
407             public void visitIdent(JCIdent tree) {
408                 if (tree.sym == t) result = true;
409             }
410         }
411         UsedVisitor v = new UsedVisitor();
412         v.scan(cdef);
413         return v.result;
414     }
415 
416     /**************************************************************************
417      * Visitor methods
418      *************************************************************************/
419 
visitTopLevel(JCCompilationUnit tree)420     public void visitTopLevel(JCCompilationUnit tree) {
421         try {
422             printUnit(tree, null);
423         } catch (IOException e) {
424             throw new UncheckedIOException(e);
425         }
426     }
427 
visitPackageDef(JCPackageDecl tree)428     public void visitPackageDef(JCPackageDecl tree) {
429         try {
430             printDocComment(tree);
431             printAnnotations(tree.annotations);
432             if (tree.pid != null) {
433                 print("package ");
434                 printExpr(tree.pid);
435                 print(";");
436                 println();
437             }
438         } catch (IOException e) {
439             throw new UncheckedIOException(e);
440         }
441     }
442 
443     @Override
visitModuleDef(JCModuleDecl tree)444     public void visitModuleDef(JCModuleDecl tree) {
445         try {
446             printDocComment(tree);
447             printAnnotations(tree.mods.annotations);
448             if (tree.getModuleType() == ModuleKind.OPEN) {
449                 print("open ");
450             }
451             print("module ");
452             printExpr(tree.qualId);
453             if (tree.directives == null) {
454                 print(";");
455             } else {
456                 printBlock(tree.directives);
457             }
458             println();
459         } catch (IOException e) {
460             throw new UncheckedIOException(e);
461         }
462     }
463 
464     @Override
visitExports(JCExports tree)465     public void visitExports(JCExports tree) {
466         try {
467             print("exports ");
468             printExpr(tree.qualid);
469             if (tree.moduleNames != null) {
470                 print(" to ");
471                 printExprs(tree.moduleNames);
472             }
473             print(";");
474         } catch (IOException e) {
475             throw new UncheckedIOException(e);
476         }
477     }
478 
479     @Override
visitOpens(JCOpens tree)480     public void visitOpens(JCOpens tree) {
481         try {
482             print("opens ");
483             printExpr(tree.qualid);
484             if (tree.moduleNames != null) {
485                 print(" to ");
486                 printExprs(tree.moduleNames);
487             }
488             print(";");
489         } catch (IOException e) {
490             throw new UncheckedIOException(e);
491         }
492     }
493 
494     @Override
visitProvides(JCProvides tree)495     public void visitProvides(JCProvides tree) {
496         try {
497             print("provides ");
498             printExpr(tree.serviceName);
499             print(" with ");
500             printExprs(tree.implNames);
501             print(";");
502         } catch (IOException e) {
503             throw new UncheckedIOException(e);
504         }
505     }
506 
507     @Override
visitRequires(JCRequires tree)508     public void visitRequires(JCRequires tree) {
509         try {
510             print("requires ");
511             if (tree.isStaticPhase)
512                 print("static ");
513             if (tree.isTransitive)
514                 print("transitive ");
515             printExpr(tree.moduleName);
516             print(";");
517         } catch (IOException e) {
518             throw new UncheckedIOException(e);
519         }
520     }
521 
522     @Override
visitUses(JCUses tree)523     public void visitUses(JCUses tree) {
524         try {
525             print("uses ");
526             printExpr(tree.qualid);
527             print(";");
528         } catch (IOException e) {
529             throw new UncheckedIOException(e);
530         }
531     }
532 
visitImport(JCImport tree)533     public void visitImport(JCImport tree) {
534         try {
535             print("import ");
536             if (tree.staticImport) print("static ");
537             printExpr(tree.qualid);
538             print(";");
539             println();
540         } catch (IOException e) {
541             throw new UncheckedIOException(e);
542         }
543     }
544 
visitClassDef(JCClassDecl tree)545     public void visitClassDef(JCClassDecl tree) {
546         try {
547             println(); align();
548             printDocComment(tree);
549             printAnnotations(tree.mods.annotations);
550             printFlags(tree.mods.flags & ~INTERFACE);
551             Name enclClassNamePrev = enclClassName;
552             enclClassName = tree.name;
553             if ((tree.mods.flags & INTERFACE) != 0) {
554                 print("interface " + tree.name);
555                 printTypeParameters(tree.typarams);
556                 if (tree.implementing.nonEmpty()) {
557                     print(" extends ");
558                     printExprs(tree.implementing);
559                 }
560             } else {
561                 if ((tree.mods.flags & ENUM) != 0)
562                     print("enum " + tree.name);
563                 else
564                     print("class " + tree.name);
565                 printTypeParameters(tree.typarams);
566                 if (tree.extending != null) {
567                     print(" extends ");
568                     printExpr(tree.extending);
569                 }
570                 if (tree.implementing.nonEmpty()) {
571                     print(" implements ");
572                     printExprs(tree.implementing);
573                 }
574             }
575             print(" ");
576             if ((tree.mods.flags & ENUM) != 0) {
577                 printEnumBody(tree.defs);
578             } else {
579                 printBlock(tree.defs);
580             }
581             enclClassName = enclClassNamePrev;
582         } catch (IOException e) {
583             throw new UncheckedIOException(e);
584         }
585     }
586 
visitMethodDef(JCMethodDecl tree)587     public void visitMethodDef(JCMethodDecl tree) {
588         try {
589             // when producing source output, omit anonymous constructors
590             if (tree.name == tree.name.table.names.init &&
591                     enclClassName == null &&
592                     sourceOutput) return;
593             println(); align();
594             printDocComment(tree);
595             printExpr(tree.mods);
596             printTypeParameters(tree.typarams);
597             if (tree.name == tree.name.table.names.init) {
598                 print(enclClassName != null ? enclClassName : tree.name);
599             } else {
600                 printExpr(tree.restype);
601                 print(" " + tree.name);
602             }
603             print("(");
604             if (tree.recvparam!=null) {
605                 printExpr(tree.recvparam);
606                 if (tree.params.size() > 0) {
607                     print(", ");
608                 }
609             }
610             printExprs(tree.params);
611             print(")");
612             if (tree.thrown.nonEmpty()) {
613                 print(" throws ");
614                 printExprs(tree.thrown);
615             }
616             if (tree.defaultValue != null) {
617                 print(" default ");
618                 printExpr(tree.defaultValue);
619             }
620             if (tree.body != null) {
621                 print(" ");
622                 printStat(tree.body);
623             } else {
624                 print(";");
625             }
626         } catch (IOException e) {
627             throw new UncheckedIOException(e);
628         }
629     }
630 
visitVarDef(JCVariableDecl tree)631     public void visitVarDef(JCVariableDecl tree) {
632         try {
633             if (docComments != null && docComments.hasComment(tree)) {
634                 println(); align();
635             }
636             printDocComment(tree);
637             if ((tree.mods.flags & ENUM) != 0) {
638                 print("/*public static final*/ ");
639                 print(tree.name);
640                 if (tree.init != null) {
641                     if (tree.init.hasTag(NEWCLASS)) {
642                         JCNewClass init = (JCNewClass) tree.init;
643                         if (sourceOutput) {
644                             print(" /*enum*/ ");
645                             if (init.args != null && init.args.nonEmpty()) {
646                                 print("(");
647                                 print(init.args);
648                                 print(")");
649                             }
650                             if (init.def != null && init.def.defs != null) {
651                                 print(" ");
652                                 printBlock(init.def.defs);
653                             }
654                             return;
655                         }else {
656                             print(" /* = ");
657                             print("new ");
658                             if (init.def != null && init.def.mods.annotations.nonEmpty()) {
659                                 printTypeAnnotations(init.def.mods.annotations);
660                             }
661                             printExpr(init.clazz);
662                             print("(");
663                             printExprs(init.args);
664                             print(")");
665                             print(" */");
666                             print(" /*enum*/ ");
667                             if (init.args != null && init.args.nonEmpty()) {
668                                 print("(");
669                                 printExprs(init.args);
670                                 print(")");
671                             }
672                             if (init.def != null && init.def.defs != null) {
673                                 print(" ");
674                                 printBlock(init.def.defs);
675                             }
676                             return;
677                         }
678                     }
679                     print(" /* = ");
680                     printExpr(tree.init);
681                     print(" */");
682                 }
683             } else {
684                 printExpr(tree.mods);
685                 if ((tree.mods.flags & VARARGS) != 0) {
686                     JCTree vartype = tree.vartype;
687                     List<JCAnnotation> tas = null;
688                     if (vartype instanceof JCAnnotatedType) {
689                         tas = ((JCAnnotatedType)vartype).annotations;
690                         vartype = ((JCAnnotatedType)vartype).underlyingType;
691                     }
692                     printExpr(((JCArrayTypeTree) vartype).elemtype);
693                     if (tas != null) {
694                         print(' ');
695                         printTypeAnnotations(tas);
696                     }
697                     print("... " + tree.name);
698                 } else {
699                     printExpr(tree.vartype);
700                     print(" " + tree.name);
701                 }
702                 if (tree.init != null) {
703                     print(" = ");
704                     printExpr(tree.init);
705                 }
706                 if (prec == TreeInfo.notExpression) print(";");
707             }
708         } catch (IOException e) {
709             throw new UncheckedIOException(e);
710         }
711     }
712 
visitSkip(JCSkip tree)713     public void visitSkip(JCSkip tree) {
714         try {
715             print(";");
716         } catch (IOException e) {
717             throw new UncheckedIOException(e);
718         }
719     }
720 
visitBlock(JCBlock tree)721     public void visitBlock(JCBlock tree) {
722         try {
723             printFlags(tree.flags);
724             printBlock(tree.stats);
725         } catch (IOException e) {
726             throw new UncheckedIOException(e);
727         }
728     }
729 
visitDoLoop(JCDoWhileLoop tree)730     public void visitDoLoop(JCDoWhileLoop tree) {
731         try {
732             print("do ");
733             printStat(tree.body);
734             align();
735             print(" while ");
736             if (tree.cond.hasTag(PARENS)) {
737                 printExpr(tree.cond);
738             } else {
739                 print("(");
740                 printExpr(tree.cond);
741                 print(")");
742             }
743             print(";");
744         } catch (IOException e) {
745             throw new UncheckedIOException(e);
746         }
747     }
748 
visitWhileLoop(JCWhileLoop tree)749     public void visitWhileLoop(JCWhileLoop tree) {
750         try {
751             print("while ");
752             if (tree.cond.hasTag(PARENS)) {
753                 printExpr(tree.cond);
754             } else {
755                 print("(");
756                 printExpr(tree.cond);
757                 print(")");
758             }
759             print(" ");
760             printStat(tree.body);
761         } catch (IOException e) {
762             throw new UncheckedIOException(e);
763         }
764     }
765 
visitForLoop(JCForLoop tree)766     public void visitForLoop(JCForLoop tree) {
767         try {
768             print("for (");
769             if (tree.init.nonEmpty()) {
770                 if (tree.init.head.hasTag(VARDEF)) {
771                     printExpr(tree.init.head);
772                     for (List<JCStatement> l = tree.init.tail; l.nonEmpty(); l = l.tail) {
773                         JCVariableDecl vdef = (JCVariableDecl)l.head;
774                         print(", " + vdef.name);
775                         if (vdef.init != null) {
776                             print(" = ");
777                             printExpr(vdef.init);
778                         }
779                     }
780                 } else {
781                     printExprs(tree.init);
782                 }
783             }
784             print("; ");
785             if (tree.cond != null) printExpr(tree.cond);
786             print("; ");
787             printExprs(tree.step);
788             print(") ");
789             printStat(tree.body);
790         } catch (IOException e) {
791             throw new UncheckedIOException(e);
792         }
793     }
794 
visitForeachLoop(JCEnhancedForLoop tree)795     public void visitForeachLoop(JCEnhancedForLoop tree) {
796         try {
797             print("for (");
798             printExpr(tree.var);
799             print(" : ");
800             printExpr(tree.expr);
801             print(") ");
802             printStat(tree.body);
803         } catch (IOException e) {
804             throw new UncheckedIOException(e);
805         }
806     }
807 
visitLabelled(JCLabeledStatement tree)808     public void visitLabelled(JCLabeledStatement tree) {
809         try {
810             print(tree.label + ": ");
811             printStat(tree.body);
812         } catch (IOException e) {
813             throw new UncheckedIOException(e);
814         }
815     }
816 
visitSwitch(JCSwitch tree)817     public void visitSwitch(JCSwitch tree) {
818         try {
819             print("switch ");
820             if (tree.selector.hasTag(PARENS)) {
821                 printExpr(tree.selector);
822             } else {
823                 print("(");
824                 printExpr(tree.selector);
825                 print(")");
826             }
827             print(" {");
828             println();
829             printStats(tree.cases);
830             align();
831             print("}");
832         } catch (IOException e) {
833             throw new UncheckedIOException(e);
834         }
835     }
836 
visitCase(JCCase tree)837     public void visitCase(JCCase tree) {
838         try {
839             if (tree.pats.isEmpty()) {
840                 print("default");
841             } else {
842                 print("case ");
843                 printExprs(tree.pats);
844             }
845             if (tree.caseKind == JCCase.STATEMENT) {
846                 print(":");
847                 println();
848                 indent();
849                 printStats(tree.stats);
850                 undent();
851                 align();
852             } else {
853                 print(" -> ");
854                 printStat(tree.stats.head);
855             }
856         } catch (IOException e) {
857             throw new UncheckedIOException(e);
858         }
859     }
860 
visitSwitchExpression(JCSwitchExpression tree)861     public void visitSwitchExpression(JCSwitchExpression tree) {
862         try {
863             print("switch ");
864             if (tree.selector.hasTag(PARENS)) {
865                 printExpr(tree.selector);
866             } else {
867                 print("(");
868                 printExpr(tree.selector);
869                 print(")");
870             }
871             print(" {");
872             println();
873             printStats(tree.cases);
874             align();
875             print("}");
876         } catch (IOException e) {
877             throw new UncheckedIOException(e);
878         }
879     }
880 
visitSynchronized(JCSynchronized tree)881     public void visitSynchronized(JCSynchronized tree) {
882         try {
883             print("synchronized ");
884             if (tree.lock.hasTag(PARENS)) {
885                 printExpr(tree.lock);
886             } else {
887                 print("(");
888                 printExpr(tree.lock);
889                 print(")");
890             }
891             print(" ");
892             printStat(tree.body);
893         } catch (IOException e) {
894             throw new UncheckedIOException(e);
895         }
896     }
897 
visitTry(JCTry tree)898     public void visitTry(JCTry tree) {
899         try {
900             print("try ");
901             if (tree.resources.nonEmpty()) {
902                 print("(");
903                 boolean first = true;
904                 for (JCTree var : tree.resources) {
905                     if (!first) {
906                         println();
907                         indent();
908                     }
909                     printStat(var);
910                     first = false;
911                 }
912                 print(") ");
913             }
914             printStat(tree.body);
915             for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
916                 printStat(l.head);
917             }
918             if (tree.finalizer != null) {
919                 print(" finally ");
920                 printStat(tree.finalizer);
921             }
922         } catch (IOException e) {
923             throw new UncheckedIOException(e);
924         }
925     }
926 
visitCatch(JCCatch tree)927     public void visitCatch(JCCatch tree) {
928         try {
929             print(" catch (");
930             printExpr(tree.param);
931             print(") ");
932             printStat(tree.body);
933         } catch (IOException e) {
934             throw new UncheckedIOException(e);
935         }
936     }
937 
visitConditional(JCConditional tree)938     public void visitConditional(JCConditional tree) {
939         try {
940             open(prec, TreeInfo.condPrec);
941             printExpr(tree.cond, TreeInfo.condPrec + 1);
942             print(" ? ");
943             printExpr(tree.truepart);
944             print(" : ");
945             printExpr(tree.falsepart, TreeInfo.condPrec);
946             close(prec, TreeInfo.condPrec);
947         } catch (IOException e) {
948             throw new UncheckedIOException(e);
949         }
950     }
951 
visitIf(JCIf tree)952     public void visitIf(JCIf tree) {
953         try {
954             print("if ");
955             if (tree.cond.hasTag(PARENS)) {
956                 printExpr(tree.cond);
957             } else {
958                 print("(");
959                 printExpr(tree.cond);
960                 print(")");
961             }
962             print(" ");
963             printStat(tree.thenpart);
964             if (tree.elsepart != null) {
965                 print(" else ");
966                 printStat(tree.elsepart);
967             }
968         } catch (IOException e) {
969             throw new UncheckedIOException(e);
970         }
971     }
972 
visitExec(JCExpressionStatement tree)973     public void visitExec(JCExpressionStatement tree) {
974         try {
975             printExpr(tree.expr);
976             if (prec == TreeInfo.notExpression) print(";");
977         } catch (IOException e) {
978             throw new UncheckedIOException(e);
979         }
980     }
981 
visitBreak(JCBreak tree)982     public void visitBreak(JCBreak tree) {
983         try {
984             print("break");
985             if (tree.label != null) print(" " + tree.label);
986             print(";");
987         } catch (IOException e) {
988             throw new UncheckedIOException(e);
989         }
990     }
991 
visitYield(JCYield tree)992     public void visitYield(JCYield tree) {
993         try {
994             print("yield");
995             print(" ");
996             printExpr(tree.value);
997             print(";");
998         } catch (IOException e) {
999             throw new UncheckedIOException(e);
1000         }
1001     }
1002 
visitContinue(JCContinue tree)1003     public void visitContinue(JCContinue tree) {
1004         try {
1005             print("continue");
1006             if (tree.label != null) print(" " + tree.label);
1007             print(";");
1008         } catch (IOException e) {
1009             throw new UncheckedIOException(e);
1010         }
1011     }
1012 
visitReturn(JCReturn tree)1013     public void visitReturn(JCReturn tree) {
1014         try {
1015             print("return");
1016             if (tree.expr != null) {
1017                 print(" ");
1018                 printExpr(tree.expr);
1019             }
1020             print(";");
1021         } catch (IOException e) {
1022             throw new UncheckedIOException(e);
1023         }
1024     }
1025 
visitThrow(JCThrow tree)1026     public void visitThrow(JCThrow tree) {
1027         try {
1028             print("throw ");
1029             printExpr(tree.expr);
1030             print(";");
1031         } catch (IOException e) {
1032             throw new UncheckedIOException(e);
1033         }
1034     }
1035 
visitAssert(JCAssert tree)1036     public void visitAssert(JCAssert tree) {
1037         try {
1038             print("assert ");
1039             printExpr(tree.cond);
1040             if (tree.detail != null) {
1041                 print(" : ");
1042                 printExpr(tree.detail);
1043             }
1044             print(";");
1045         } catch (IOException e) {
1046             throw new UncheckedIOException(e);
1047         }
1048     }
1049 
visitApply(JCMethodInvocation tree)1050     public void visitApply(JCMethodInvocation tree) {
1051         try {
1052             if (!tree.typeargs.isEmpty()) {
1053                 if (tree.meth.hasTag(SELECT)) {
1054                     JCFieldAccess left = (JCFieldAccess)tree.meth;
1055                     printExpr(left.selected);
1056                     print(".<");
1057                     printExprs(tree.typeargs);
1058                     print(">" + left.name);
1059                 } else {
1060                     print("<");
1061                     printExprs(tree.typeargs);
1062                     print(">");
1063                     printExpr(tree.meth);
1064                 }
1065             } else {
1066                 printExpr(tree.meth);
1067             }
1068             print("(");
1069             printExprs(tree.args);
1070             print(")");
1071         } catch (IOException e) {
1072             throw new UncheckedIOException(e);
1073         }
1074     }
1075 
visitNewClass(JCNewClass tree)1076     public void visitNewClass(JCNewClass tree) {
1077         try {
1078             if (tree.encl != null) {
1079                 printExpr(tree.encl);
1080                 print(".");
1081             }
1082             print("new ");
1083             if (!tree.typeargs.isEmpty()) {
1084                 print("<");
1085                 printExprs(tree.typeargs);
1086                 print(">");
1087             }
1088             if (tree.def != null && tree.def.mods.annotations.nonEmpty()) {
1089                 printTypeAnnotations(tree.def.mods.annotations);
1090             }
1091             printExpr(tree.clazz);
1092             print("(");
1093             printExprs(tree.args);
1094             print(")");
1095             if (tree.def != null) {
1096                 Name enclClassNamePrev = enclClassName;
1097                 enclClassName =
1098                         tree.def.name != null ? tree.def.name :
1099                             tree.type != null && tree.type.tsym.name != tree.type.tsym.name.table.names.empty
1100                                 ? tree.type.tsym.name : null;
1101                 if ((tree.def.mods.flags & Flags.ENUM) != 0) print("/*enum*/");
1102                 printBlock(tree.def.defs);
1103                 enclClassName = enclClassNamePrev;
1104             }
1105         } catch (IOException e) {
1106             throw new UncheckedIOException(e);
1107         }
1108     }
1109 
visitNewArray(JCNewArray tree)1110     public void visitNewArray(JCNewArray tree) {
1111         try {
1112             if (tree.elemtype != null) {
1113                 print("new ");
1114                 JCTree elem = tree.elemtype;
1115                 printBaseElementType(elem);
1116 
1117                 if (!tree.annotations.isEmpty()) {
1118                     print(' ');
1119                     printTypeAnnotations(tree.annotations);
1120                 }
1121                 if (tree.elems != null) {
1122                     print("[]");
1123                 }
1124 
1125                 int i = 0;
1126                 List<List<JCAnnotation>> da = tree.dimAnnotations;
1127                 for (List<JCExpression> l = tree.dims; l.nonEmpty(); l = l.tail) {
1128                     if (da.size() > i && !da.get(i).isEmpty()) {
1129                         print(' ');
1130                         printTypeAnnotations(da.get(i));
1131                     }
1132                     print("[");
1133                     i++;
1134                     printExpr(l.head);
1135                     print("]");
1136                 }
1137                 printBrackets(elem);
1138             }
1139             if (tree.elems != null) {
1140                 print("{");
1141                 printExprs(tree.elems);
1142                 print("}");
1143             }
1144         } catch (IOException e) {
1145             throw new UncheckedIOException(e);
1146         }
1147     }
1148 
visitLambda(JCLambda tree)1149     public void visitLambda(JCLambda tree) {
1150         try {
1151             print("(");
1152             if (tree.paramKind == JCLambda.ParameterKind.EXPLICIT) {
1153                 printExprs(tree.params);
1154             } else {
1155                 String sep = "";
1156                 for (JCVariableDecl param : tree.params) {
1157                     print(sep);
1158                     print(param.name);
1159                     sep = ",";
1160                 }
1161             }
1162             print(")->");
1163             printExpr(tree.body);
1164         } catch (IOException e) {
1165             throw new UncheckedIOException(e);
1166         }
1167     }
1168 
visitParens(JCParens tree)1169     public void visitParens(JCParens tree) {
1170         try {
1171             print("(");
1172             printExpr(tree.expr);
1173             print(")");
1174         } catch (IOException e) {
1175             throw new UncheckedIOException(e);
1176         }
1177     }
1178 
visitAssign(JCAssign tree)1179     public void visitAssign(JCAssign tree) {
1180         try {
1181             open(prec, TreeInfo.assignPrec);
1182             printExpr(tree.lhs, TreeInfo.assignPrec + 1);
1183             print(" = ");
1184             printExpr(tree.rhs, TreeInfo.assignPrec);
1185             close(prec, TreeInfo.assignPrec);
1186         } catch (IOException e) {
1187             throw new UncheckedIOException(e);
1188         }
1189     }
1190 
operatorName(JCTree.Tag tag)1191     public String operatorName(JCTree.Tag tag) {
1192         switch(tag) {
1193             case POS:     return "+";
1194             case NEG:     return "-";
1195             case NOT:     return "!";
1196             case COMPL:   return "~";
1197             case PREINC:  return "++";
1198             case PREDEC:  return "--";
1199             case POSTINC: return "++";
1200             case POSTDEC: return "--";
1201             case NULLCHK: return "<*nullchk*>";
1202             case OR:      return "||";
1203             case AND:     return "&&";
1204             case EQ:      return "==";
1205             case NE:      return "!=";
1206             case LT:      return "<";
1207             case GT:      return ">";
1208             case LE:      return "<=";
1209             case GE:      return ">=";
1210             case BITOR:   return "|";
1211             case BITXOR:  return "^";
1212             case BITAND:  return "&";
1213             case SL:      return "<<";
1214             case SR:      return ">>";
1215             case USR:     return ">>>";
1216             case PLUS:    return "+";
1217             case MINUS:   return "-";
1218             case MUL:     return "*";
1219             case DIV:     return "/";
1220             case MOD:     return "%";
1221             default: throw new Error();
1222         }
1223     }
1224 
visitAssignop(JCAssignOp tree)1225     public void visitAssignop(JCAssignOp tree) {
1226         try {
1227             open(prec, TreeInfo.assignopPrec);
1228             printExpr(tree.lhs, TreeInfo.assignopPrec + 1);
1229             print(" " + operatorName(tree.getTag().noAssignOp()) + "= ");
1230             printExpr(tree.rhs, TreeInfo.assignopPrec);
1231             close(prec, TreeInfo.assignopPrec);
1232         } catch (IOException e) {
1233             throw new UncheckedIOException(e);
1234         }
1235     }
1236 
visitUnary(JCUnary tree)1237     public void visitUnary(JCUnary tree) {
1238         try {
1239             int ownprec = TreeInfo.opPrec(tree.getTag());
1240             String opname = operatorName(tree.getTag());
1241             open(prec, ownprec);
1242             if (!tree.getTag().isPostUnaryOp()) {
1243                 print(opname);
1244                 printExpr(tree.arg, ownprec);
1245             } else {
1246                 printExpr(tree.arg, ownprec);
1247                 print(opname);
1248             }
1249             close(prec, ownprec);
1250         } catch (IOException e) {
1251             throw new UncheckedIOException(e);
1252         }
1253     }
1254 
visitBinary(JCBinary tree)1255     public void visitBinary(JCBinary tree) {
1256         try {
1257             int ownprec = TreeInfo.opPrec(tree.getTag());
1258             String opname = operatorName(tree.getTag());
1259             open(prec, ownprec);
1260             printExpr(tree.lhs, ownprec);
1261             print(" " + opname + " ");
1262             printExpr(tree.rhs, ownprec + 1);
1263             close(prec, ownprec);
1264         } catch (IOException e) {
1265             throw new UncheckedIOException(e);
1266         }
1267     }
1268 
visitTypeCast(JCTypeCast tree)1269     public void visitTypeCast(JCTypeCast tree) {
1270         try {
1271             open(prec, TreeInfo.prefixPrec);
1272             print("(");
1273             printExpr(tree.clazz);
1274             print(")");
1275             printExpr(tree.expr, TreeInfo.prefixPrec);
1276             close(prec, TreeInfo.prefixPrec);
1277         } catch (IOException e) {
1278             throw new UncheckedIOException(e);
1279         }
1280     }
1281 
visitTypeTest(JCInstanceOf tree)1282     public void visitTypeTest(JCInstanceOf tree) {
1283         try {
1284             open(prec, TreeInfo.ordPrec);
1285             printExpr(tree.expr, TreeInfo.ordPrec);
1286             print(" instanceof ");
1287             printExpr(tree.clazz, TreeInfo.ordPrec + 1);
1288             close(prec, TreeInfo.ordPrec);
1289         } catch (IOException e) {
1290             throw new UncheckedIOException(e);
1291         }
1292     }
1293 
visitIndexed(JCArrayAccess tree)1294     public void visitIndexed(JCArrayAccess tree) {
1295         try {
1296             printExpr(tree.indexed, TreeInfo.postfixPrec);
1297             print("[");
1298             printExpr(tree.index);
1299             print("]");
1300         } catch (IOException e) {
1301             throw new UncheckedIOException(e);
1302         }
1303     }
1304 
visitSelect(JCFieldAccess tree)1305     public void visitSelect(JCFieldAccess tree) {
1306         try {
1307             printExpr(tree.selected, TreeInfo.postfixPrec);
1308             print("." + tree.name);
1309         } catch (IOException e) {
1310             throw new UncheckedIOException(e);
1311         }
1312     }
1313 
visitReference(JCMemberReference tree)1314     public void visitReference(JCMemberReference tree) {
1315         try {
1316             printExpr(tree.expr);
1317             print("::");
1318             if (tree.typeargs != null) {
1319                 print("<");
1320                 printExprs(tree.typeargs);
1321                 print(">");
1322             }
1323             print(tree.getMode() == ReferenceMode.INVOKE ? tree.name : "new");
1324         } catch (IOException e) {
1325             throw new UncheckedIOException(e);
1326         }
1327     }
1328 
visitIdent(JCIdent tree)1329     public void visitIdent(JCIdent tree) {
1330         try {
1331             print(tree.name);
1332         } catch (IOException e) {
1333             throw new UncheckedIOException(e);
1334         }
1335     }
1336 
visitLiteral(JCLiteral tree)1337     public void visitLiteral(JCLiteral tree) {
1338         try {
1339             switch (tree.typetag) {
1340                 case INT:
1341                     print(tree.value.toString());
1342                     break;
1343                 case LONG:
1344                     print(tree.value + "L");
1345                     break;
1346                 case FLOAT:
1347                     print(tree.value + "F");
1348                     break;
1349                 case DOUBLE:
1350                     print(tree.value.toString());
1351                     break;
1352                 case CHAR:
1353                     print("\'" +
1354                             Convert.quote(
1355                             String.valueOf((char)((Number)tree.value).intValue())) +
1356                             "\'");
1357                     break;
1358                 case BOOLEAN:
1359                     print(((Number)tree.value).intValue() == 1 ? "true" : "false");
1360                     break;
1361                 case BOT:
1362                     print("null");
1363                     break;
1364                 default:
1365                     print("\"" + Convert.quote(tree.value.toString()) + "\"");
1366                     break;
1367             }
1368         } catch (IOException e) {
1369             throw new UncheckedIOException(e);
1370         }
1371     }
1372 
visitTypeIdent(JCPrimitiveTypeTree tree)1373     public void visitTypeIdent(JCPrimitiveTypeTree tree) {
1374         try {
1375             switch(tree.typetag) {
1376                 case BYTE:
1377                     print("byte");
1378                     break;
1379                 case CHAR:
1380                     print("char");
1381                     break;
1382                 case SHORT:
1383                     print("short");
1384                     break;
1385                 case INT:
1386                     print("int");
1387                     break;
1388                 case LONG:
1389                     print("long");
1390                     break;
1391                 case FLOAT:
1392                     print("float");
1393                     break;
1394                 case DOUBLE:
1395                     print("double");
1396                     break;
1397                 case BOOLEAN:
1398                     print("boolean");
1399                     break;
1400                 case VOID:
1401                     print("void");
1402                     break;
1403                 default:
1404                     print("error");
1405                     break;
1406             }
1407         } catch (IOException e) {
1408             throw new UncheckedIOException(e);
1409         }
1410     }
1411 
visitTypeArray(JCArrayTypeTree tree)1412     public void visitTypeArray(JCArrayTypeTree tree) {
1413         try {
1414             printBaseElementType(tree);
1415             printBrackets(tree);
1416         } catch (IOException e) {
1417             throw new UncheckedIOException(e);
1418         }
1419     }
1420 
1421     // Prints the inner element type of a nested array
printBaseElementType(JCTree tree)1422     private void printBaseElementType(JCTree tree) throws IOException {
1423         printExpr(TreeInfo.innermostType(tree, false));
1424     }
1425 
1426     // prints the brackets of a nested array in reverse order
1427     // tree is either JCArrayTypeTree or JCAnnotatedTypeTree
printBrackets(JCTree tree)1428     private void printBrackets(JCTree tree) throws IOException {
1429         JCTree elem = tree;
1430         while (true) {
1431             if (elem.hasTag(ANNOTATED_TYPE)) {
1432                 JCAnnotatedType atype = (JCAnnotatedType) elem;
1433                 elem = atype.underlyingType;
1434                 if (elem.hasTag(TYPEARRAY)) {
1435                     print(' ');
1436                     printTypeAnnotations(atype.annotations);
1437                 }
1438             }
1439             if (elem.hasTag(TYPEARRAY)) {
1440                 print("[]");
1441                 elem = ((JCArrayTypeTree)elem).elemtype;
1442             } else {
1443                 break;
1444             }
1445         }
1446     }
1447 
visitTypeApply(JCTypeApply tree)1448     public void visitTypeApply(JCTypeApply tree) {
1449         try {
1450             printExpr(tree.clazz);
1451             print("<");
1452             printExprs(tree.arguments);
1453             print(">");
1454         } catch (IOException e) {
1455             throw new UncheckedIOException(e);
1456         }
1457     }
1458 
visitTypeUnion(JCTypeUnion tree)1459     public void visitTypeUnion(JCTypeUnion tree) {
1460         try {
1461             printExprs(tree.alternatives, " | ");
1462         } catch (IOException e) {
1463             throw new UncheckedIOException(e);
1464         }
1465     }
1466 
visitTypeIntersection(JCTypeIntersection tree)1467     public void visitTypeIntersection(JCTypeIntersection tree) {
1468         try {
1469             printExprs(tree.bounds, " & ");
1470         } catch (IOException e) {
1471             throw new UncheckedIOException(e);
1472         }
1473     }
1474 
visitTypeParameter(JCTypeParameter tree)1475     public void visitTypeParameter(JCTypeParameter tree) {
1476         try {
1477             if (tree.annotations.nonEmpty()) {
1478                 this.printTypeAnnotations(tree.annotations);
1479             }
1480             print(tree.name);
1481             if (tree.bounds.nonEmpty()) {
1482                 print(" extends ");
1483                 printExprs(tree.bounds, " & ");
1484             }
1485         } catch (IOException e) {
1486             throw new UncheckedIOException(e);
1487         }
1488     }
1489 
1490     @Override
visitWildcard(JCWildcard tree)1491     public void visitWildcard(JCWildcard tree) {
1492         try {
1493             print(tree.kind);
1494             if (tree.kind.kind != BoundKind.UNBOUND)
1495                 printExpr(tree.inner);
1496         } catch (IOException e) {
1497             throw new UncheckedIOException(e);
1498         }
1499     }
1500 
1501     @Override
visitTypeBoundKind(TypeBoundKind tree)1502     public void visitTypeBoundKind(TypeBoundKind tree) {
1503         try {
1504             print(String.valueOf(tree.kind));
1505         } catch (IOException e) {
1506             throw new UncheckedIOException(e);
1507         }
1508     }
1509 
visitErroneous(JCErroneous tree)1510     public void visitErroneous(JCErroneous tree) {
1511         try {
1512             print("(ERROR)");
1513         } catch (IOException e) {
1514             throw new UncheckedIOException(e);
1515         }
1516     }
1517 
visitLetExpr(LetExpr tree)1518     public void visitLetExpr(LetExpr tree) {
1519         try {
1520             print("(let " + tree.defs + " in " + tree.expr + ")");
1521         } catch (IOException e) {
1522             throw new UncheckedIOException(e);
1523         }
1524     }
1525 
visitModifiers(JCModifiers mods)1526     public void visitModifiers(JCModifiers mods) {
1527         try {
1528             printAnnotations(mods.annotations);
1529             printFlags(mods.flags);
1530         } catch (IOException e) {
1531             throw new UncheckedIOException(e);
1532         }
1533     }
1534 
visitAnnotation(JCAnnotation tree)1535     public void visitAnnotation(JCAnnotation tree) {
1536         try {
1537             print("@");
1538             printExpr(tree.annotationType);
1539             if (!tree.args.isEmpty()) {
1540                 print("(");
1541                 printExprs(tree.args);
1542                 print(")");
1543             }
1544         } catch (IOException e) {
1545             throw new UncheckedIOException(e);
1546         }
1547     }
1548 
visitAnnotatedType(JCAnnotatedType tree)1549     public void visitAnnotatedType(JCAnnotatedType tree) {
1550         try {
1551             if (tree.underlyingType.hasTag(SELECT)) {
1552                 JCFieldAccess access = (JCFieldAccess) tree.underlyingType;
1553                 printExpr(access.selected, TreeInfo.postfixPrec);
1554                 print(".");
1555                 printTypeAnnotations(tree.annotations);
1556                 print(access.name);
1557             } else if (tree.underlyingType.hasTag(TYPEARRAY)) {
1558                 printBaseElementType(tree);
1559                 printBrackets(tree);
1560             } else {
1561                 printTypeAnnotations(tree.annotations);
1562                 printExpr(tree.underlyingType);
1563             }
1564         } catch (IOException e) {
1565             throw new UncheckedIOException(e);
1566         }
1567     }
1568 
visitTree(JCTree tree)1569     public void visitTree(JCTree tree) {
1570         try {
1571             print("(UNKNOWN: " + tree.getTag() + ")");
1572             println();
1573         } catch (IOException e) {
1574             throw new UncheckedIOException(e);
1575         }
1576     }
1577 
1578 }
1579