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