Tue, 09 Oct 2012 19:10:00 -0700
8000663: clean up langtools imports
Reviewed-by: darcy
1 /*
2 * Copyright (c) 1999, 2012, 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 */
26 package com.sun.tools.javac.tree;
28 import java.io.*;
30 import com.sun.source.tree.MemberReferenceTree.ReferenceMode;
31 import com.sun.tools.javac.code.*;
32 import com.sun.tools.javac.code.Symbol.*;
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.*;
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 {
49 public Pretty(Writer out, boolean sourceOutput) {
50 this.out = out;
51 this.sourceOutput = sourceOutput;
52 }
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;
61 /** The output stream on which trees are printed.
62 */
63 Writer out;
65 /** Indentation width (can be reassigned from outside).
66 */
67 public int width = 4;
69 /** The current left margin.
70 */
71 int lmargin = 0;
73 /** The enclosing class name.
74 */
75 Name enclClassName;
77 /** A table mapping trees to their documentation comments
78 * (can be null)
79 */
80 DocCommentTable docComments = null;
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 = "[...]";
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;
93 /** Align code to be indented to left margin.
94 */
95 void align() throws IOException {
96 for (int i = 0; i < lmargin; i++) out.write(" ");
97 }
99 /** Increase left margin by indentation width.
100 */
101 void indent() {
102 lmargin = lmargin + width;
103 }
105 /** Decrease left margin by indentation width.
106 */
107 void undent() {
108 lmargin = lmargin - width;
109 }
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 */
116 void open(int contextPrec, int ownPrec) throws IOException {
117 if (ownPrec < contextPrec) out.write("(");
118 }
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 */
125 void close(int contextPrec, int ownPrec) throws IOException {
126 if (ownPrec < contextPrec) out.write(")");
127 }
129 /** Print string, replacing all non-ascii character with unicode escapes.
130 */
131 public void print(Object s) throws IOException {
132 out.write(Convert.escapeUnicode(s.toString()));
133 }
135 /** Print new line.
136 */
137 public void println() throws IOException {
138 out.write(lineSep);
139 }
141 public static String toSimpleString(JCTree tree) {
142 return toSimpleString(tree, PREFERRED_LENGTH);
143 }
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().replaceAll("\\s+", " ").replaceAll("/\\*missing\\*/", "");
158 if (res.length() < maxLength) {
159 return res;
160 } else {
161 int split = (maxLength - trimSequence.length()) * 2 / 3;
162 return res.substring(0, split) + trimSequence + res.substring(split);
163 }
164 }
166 String lineSep = System.getProperty("line.separator");
168 /**************************************************************************
169 * Traversal methods
170 *************************************************************************/
172 /** Exception to propogate IOException through visitXXX methods */
173 private static class UncheckedIOException extends Error {
174 static final long serialVersionUID = -4032692679158424751L;
175 UncheckedIOException(IOException e) {
176 super(e.getMessage(), e);
177 }
178 }
180 /** Visitor argument: the current precedence level.
181 */
182 int prec;
184 /** Visitor method: print expression tree.
185 * @param prec The current precedence level.
186 */
187 public void printExpr(JCTree tree, int prec) throws IOException {
188 int prevPrec = this.prec;
189 try {
190 this.prec = prec;
191 if (tree == null) print("/*missing*/");
192 else {
193 tree.accept(this);
194 }
195 } catch (UncheckedIOException ex) {
196 IOException e = new IOException(ex.getMessage());
197 e.initCause(ex);
198 throw e;
199 } finally {
200 this.prec = prevPrec;
201 }
202 }
204 /** Derived visitor method: print expression tree at minimum precedence level
205 * for expression.
206 */
207 public void printExpr(JCTree tree) throws IOException {
208 printExpr(tree, TreeInfo.noPrec);
209 }
211 /** Derived visitor method: print statement tree.
212 */
213 public void printStat(JCTree tree) throws IOException {
214 printExpr(tree, TreeInfo.notExpression);
215 }
217 /** Derived visitor method: print list of expression trees, separated by given string.
218 * @param sep the separator string
219 */
220 public <T extends JCTree> void printExprs(List<T> trees, String sep) throws IOException {
221 if (trees.nonEmpty()) {
222 printExpr(trees.head);
223 for (List<T> l = trees.tail; l.nonEmpty(); l = l.tail) {
224 print(sep);
225 printExpr(l.head);
226 }
227 }
228 }
230 /** Derived visitor method: print list of expression trees, separated by commas.
231 */
232 public <T extends JCTree> void printExprs(List<T> trees) throws IOException {
233 printExprs(trees, ", ");
234 }
236 /** Derived visitor method: print list of statements, each on a separate line.
237 */
238 public void printStats(List<? extends JCTree> trees) throws IOException {
239 for (List<? extends JCTree> l = trees; l.nonEmpty(); l = l.tail) {
240 align();
241 printStat(l.head);
242 println();
243 }
244 }
246 /** Print a set of modifiers.
247 */
248 public void printFlags(long flags) throws IOException {
249 if ((flags & SYNTHETIC) != 0) print("/*synthetic*/ ");
250 print(TreeInfo.flagNames(flags));
251 if ((flags & StandardFlags) != 0) print(" ");
252 if ((flags & ANNOTATION) != 0) print("@");
253 }
255 public void printAnnotations(List<JCAnnotation> trees) throws IOException {
256 for (List<JCAnnotation> l = trees; l.nonEmpty(); l = l.tail) {
257 printStat(l.head);
258 println();
259 align();
260 }
261 }
263 /** Print documentation comment, if it exists
264 * @param tree The tree for which a documentation comment should be printed.
265 */
266 public void printDocComment(JCTree tree) throws IOException {
267 if (docComments != null) {
268 String dc = docComments.getCommentText(tree);
269 if (dc != null) {
270 print("/**"); println();
271 int pos = 0;
272 int endpos = lineEndPos(dc, pos);
273 while (pos < dc.length()) {
274 align();
275 print(" *");
276 if (pos < dc.length() && dc.charAt(pos) > ' ') print(" ");
277 print(dc.substring(pos, endpos)); println();
278 pos = endpos + 1;
279 endpos = lineEndPos(dc, pos);
280 }
281 align(); print(" */"); println();
282 align();
283 }
284 }
285 }
286 //where
287 static int lineEndPos(String s, int start) {
288 int pos = s.indexOf('\n', start);
289 if (pos < 0) pos = s.length();
290 return pos;
291 }
293 /** If type parameter list is non-empty, print it enclosed in
294 * {@literal "<...>"} brackets.
295 */
296 public void printTypeParameters(List<JCTypeParameter> trees) throws IOException {
297 if (trees.nonEmpty()) {
298 print("<");
299 printExprs(trees);
300 print(">");
301 }
302 }
304 /** Print a block.
305 */
306 public void printBlock(List<? extends JCTree> stats) throws IOException {
307 print("{");
308 println();
309 indent();
310 printStats(stats);
311 undent();
312 align();
313 print("}");
314 }
316 /** Print a block.
317 */
318 public void printEnumBody(List<JCTree> stats) throws IOException {
319 print("{");
320 println();
321 indent();
322 boolean first = true;
323 for (List<JCTree> l = stats; l.nonEmpty(); l = l.tail) {
324 if (isEnumerator(l.head)) {
325 if (!first) {
326 print(",");
327 println();
328 }
329 align();
330 printStat(l.head);
331 first = false;
332 }
333 }
334 print(";");
335 println();
336 for (List<JCTree> l = stats; l.nonEmpty(); l = l.tail) {
337 if (!isEnumerator(l.head)) {
338 align();
339 printStat(l.head);
340 println();
341 }
342 }
343 undent();
344 align();
345 print("}");
346 }
348 /** Is the given tree an enumerator definition? */
349 boolean isEnumerator(JCTree t) {
350 return t.hasTag(VARDEF) && (((JCVariableDecl) t).mods.flags & ENUM) != 0;
351 }
353 /** Print unit consisting of package clause and import statements in toplevel,
354 * followed by class definition. if class definition == null,
355 * print all definitions in toplevel.
356 * @param tree The toplevel tree
357 * @param cdef The class definition, which is assumed to be part of the
358 * toplevel tree.
359 */
360 public void printUnit(JCCompilationUnit tree, JCClassDecl cdef) throws IOException {
361 docComments = tree.docComments;
362 printDocComment(tree);
363 if (tree.pid != null) {
364 print("package ");
365 printExpr(tree.pid);
366 print(";");
367 println();
368 }
369 boolean firstImport = true;
370 for (List<JCTree> l = tree.defs;
371 l.nonEmpty() && (cdef == null || l.head.hasTag(IMPORT));
372 l = l.tail) {
373 if (l.head.hasTag(IMPORT)) {
374 JCImport imp = (JCImport)l.head;
375 Name name = TreeInfo.name(imp.qualid);
376 if (name == name.table.names.asterisk ||
377 cdef == null ||
378 isUsed(TreeInfo.symbol(imp.qualid), cdef)) {
379 if (firstImport) {
380 firstImport = false;
381 println();
382 }
383 printStat(imp);
384 }
385 } else {
386 printStat(l.head);
387 }
388 }
389 if (cdef != null) {
390 printStat(cdef);
391 println();
392 }
393 }
394 // where
395 boolean isUsed(final Symbol t, JCTree cdef) {
396 class UsedVisitor extends TreeScanner {
397 public void scan(JCTree tree) {
398 if (tree!=null && !result) tree.accept(this);
399 }
400 boolean result = false;
401 public void visitIdent(JCIdent tree) {
402 if (tree.sym == t) result = true;
403 }
404 }
405 UsedVisitor v = new UsedVisitor();
406 v.scan(cdef);
407 return v.result;
408 }
410 /**************************************************************************
411 * Visitor methods
412 *************************************************************************/
414 public void visitTopLevel(JCCompilationUnit tree) {
415 try {
416 printUnit(tree, null);
417 } catch (IOException e) {
418 throw new UncheckedIOException(e);
419 }
420 }
422 public void visitImport(JCImport tree) {
423 try {
424 print("import ");
425 if (tree.staticImport) print("static ");
426 printExpr(tree.qualid);
427 print(";");
428 println();
429 } catch (IOException e) {
430 throw new UncheckedIOException(e);
431 }
432 }
434 public void visitClassDef(JCClassDecl tree) {
435 try {
436 println(); align();
437 printDocComment(tree);
438 printAnnotations(tree.mods.annotations);
439 printFlags(tree.mods.flags & ~INTERFACE);
440 Name enclClassNamePrev = enclClassName;
441 enclClassName = tree.name;
442 if ((tree.mods.flags & INTERFACE) != 0) {
443 print("interface " + tree.name);
444 printTypeParameters(tree.typarams);
445 if (tree.implementing.nonEmpty()) {
446 print(" extends ");
447 printExprs(tree.implementing);
448 }
449 } else {
450 if ((tree.mods.flags & ENUM) != 0)
451 print("enum " + tree.name);
452 else
453 print("class " + tree.name);
454 printTypeParameters(tree.typarams);
455 if (tree.extending != null) {
456 print(" extends ");
457 printExpr(tree.extending);
458 }
459 if (tree.implementing.nonEmpty()) {
460 print(" implements ");
461 printExprs(tree.implementing);
462 }
463 }
464 print(" ");
465 if ((tree.mods.flags & ENUM) != 0) {
466 printEnumBody(tree.defs);
467 } else {
468 printBlock(tree.defs);
469 }
470 enclClassName = enclClassNamePrev;
471 } catch (IOException e) {
472 throw new UncheckedIOException(e);
473 }
474 }
476 public void visitMethodDef(JCMethodDecl tree) {
477 try {
478 // when producing source output, omit anonymous constructors
479 if (tree.name == tree.name.table.names.init &&
480 enclClassName == null &&
481 sourceOutput) return;
482 println(); align();
483 printDocComment(tree);
484 printExpr(tree.mods);
485 printTypeParameters(tree.typarams);
486 if (tree.name == tree.name.table.names.init) {
487 print(enclClassName != null ? enclClassName : tree.name);
488 } else {
489 printExpr(tree.restype);
490 print(" " + tree.name);
491 }
492 print("(");
493 printExprs(tree.params);
494 print(")");
495 if (tree.thrown.nonEmpty()) {
496 print(" throws ");
497 printExprs(tree.thrown);
498 }
499 if (tree.defaultValue != null) {
500 print(" default ");
501 printExpr(tree.defaultValue);
502 }
503 if (tree.body != null) {
504 print(" ");
505 printStat(tree.body);
506 } else {
507 print(";");
508 }
509 } catch (IOException e) {
510 throw new UncheckedIOException(e);
511 }
512 }
514 public void visitVarDef(JCVariableDecl tree) {
515 try {
516 if (docComments != null && docComments.hasComment(tree)) {
517 println(); align();
518 }
519 printDocComment(tree);
520 if ((tree.mods.flags & ENUM) != 0) {
521 print("/*public static final*/ ");
522 print(tree.name);
523 if (tree.init != null) {
524 if (sourceOutput && tree.init.hasTag(NEWCLASS)) {
525 print(" /*enum*/ ");
526 JCNewClass init = (JCNewClass) tree.init;
527 if (init.args != null && init.args.nonEmpty()) {
528 print("(");
529 print(init.args);
530 print(")");
531 }
532 if (init.def != null && init.def.defs != null) {
533 print(" ");
534 printBlock(init.def.defs);
535 }
536 return;
537 }
538 print(" /* = ");
539 printExpr(tree.init);
540 print(" */");
541 }
542 } else {
543 printExpr(tree.mods);
544 if ((tree.mods.flags & VARARGS) != 0) {
545 printExpr(((JCArrayTypeTree) tree.vartype).elemtype);
546 print("... " + tree.name);
547 } else {
548 printExpr(tree.vartype);
549 print(" " + tree.name);
550 }
551 if (tree.init != null) {
552 print(" = ");
553 printExpr(tree.init);
554 }
555 if (prec == TreeInfo.notExpression) print(";");
556 }
557 } catch (IOException e) {
558 throw new UncheckedIOException(e);
559 }
560 }
562 public void visitSkip(JCSkip tree) {
563 try {
564 print(";");
565 } catch (IOException e) {
566 throw new UncheckedIOException(e);
567 }
568 }
570 public void visitBlock(JCBlock tree) {
571 try {
572 printFlags(tree.flags);
573 printBlock(tree.stats);
574 } catch (IOException e) {
575 throw new UncheckedIOException(e);
576 }
577 }
579 public void visitDoLoop(JCDoWhileLoop tree) {
580 try {
581 print("do ");
582 printStat(tree.body);
583 align();
584 print(" while ");
585 if (tree.cond.hasTag(PARENS)) {
586 printExpr(tree.cond);
587 } else {
588 print("(");
589 printExpr(tree.cond);
590 print(")");
591 }
592 print(";");
593 } catch (IOException e) {
594 throw new UncheckedIOException(e);
595 }
596 }
598 public void visitWhileLoop(JCWhileLoop tree) {
599 try {
600 print("while ");
601 if (tree.cond.hasTag(PARENS)) {
602 printExpr(tree.cond);
603 } else {
604 print("(");
605 printExpr(tree.cond);
606 print(")");
607 }
608 print(" ");
609 printStat(tree.body);
610 } catch (IOException e) {
611 throw new UncheckedIOException(e);
612 }
613 }
615 public void visitForLoop(JCForLoop tree) {
616 try {
617 print("for (");
618 if (tree.init.nonEmpty()) {
619 if (tree.init.head.hasTag(VARDEF)) {
620 printExpr(tree.init.head);
621 for (List<JCStatement> l = tree.init.tail; l.nonEmpty(); l = l.tail) {
622 JCVariableDecl vdef = (JCVariableDecl)l.head;
623 print(", " + vdef.name + " = ");
624 printExpr(vdef.init);
625 }
626 } else {
627 printExprs(tree.init);
628 }
629 }
630 print("; ");
631 if (tree.cond != null) printExpr(tree.cond);
632 print("; ");
633 printExprs(tree.step);
634 print(") ");
635 printStat(tree.body);
636 } catch (IOException e) {
637 throw new UncheckedIOException(e);
638 }
639 }
641 public void visitForeachLoop(JCEnhancedForLoop tree) {
642 try {
643 print("for (");
644 printExpr(tree.var);
645 print(" : ");
646 printExpr(tree.expr);
647 print(") ");
648 printStat(tree.body);
649 } catch (IOException e) {
650 throw new UncheckedIOException(e);
651 }
652 }
654 public void visitLabelled(JCLabeledStatement tree) {
655 try {
656 print(tree.label + ": ");
657 printStat(tree.body);
658 } catch (IOException e) {
659 throw new UncheckedIOException(e);
660 }
661 }
663 public void visitSwitch(JCSwitch tree) {
664 try {
665 print("switch ");
666 if (tree.selector.hasTag(PARENS)) {
667 printExpr(tree.selector);
668 } else {
669 print("(");
670 printExpr(tree.selector);
671 print(")");
672 }
673 print(" {");
674 println();
675 printStats(tree.cases);
676 align();
677 print("}");
678 } catch (IOException e) {
679 throw new UncheckedIOException(e);
680 }
681 }
683 public void visitCase(JCCase tree) {
684 try {
685 if (tree.pat == null) {
686 print("default");
687 } else {
688 print("case ");
689 printExpr(tree.pat);
690 }
691 print(": ");
692 println();
693 indent();
694 printStats(tree.stats);
695 undent();
696 align();
697 } catch (IOException e) {
698 throw new UncheckedIOException(e);
699 }
700 }
702 public void visitSynchronized(JCSynchronized tree) {
703 try {
704 print("synchronized ");
705 if (tree.lock.hasTag(PARENS)) {
706 printExpr(tree.lock);
707 } else {
708 print("(");
709 printExpr(tree.lock);
710 print(")");
711 }
712 print(" ");
713 printStat(tree.body);
714 } catch (IOException e) {
715 throw new UncheckedIOException(e);
716 }
717 }
719 public void visitTry(JCTry tree) {
720 try {
721 print("try ");
722 if (tree.resources.nonEmpty()) {
723 print("(");
724 boolean first = true;
725 for (JCTree var : tree.resources) {
726 if (!first) {
727 println();
728 indent();
729 }
730 printStat(var);
731 first = false;
732 }
733 print(") ");
734 }
735 printStat(tree.body);
736 for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
737 printStat(l.head);
738 }
739 if (tree.finalizer != null) {
740 print(" finally ");
741 printStat(tree.finalizer);
742 }
743 } catch (IOException e) {
744 throw new UncheckedIOException(e);
745 }
746 }
748 public void visitCatch(JCCatch tree) {
749 try {
750 print(" catch (");
751 printExpr(tree.param);
752 print(") ");
753 printStat(tree.body);
754 } catch (IOException e) {
755 throw new UncheckedIOException(e);
756 }
757 }
759 public void visitConditional(JCConditional tree) {
760 try {
761 open(prec, TreeInfo.condPrec);
762 printExpr(tree.cond, TreeInfo.condPrec);
763 print(" ? ");
764 printExpr(tree.truepart, TreeInfo.condPrec);
765 print(" : ");
766 printExpr(tree.falsepart, TreeInfo.condPrec);
767 close(prec, TreeInfo.condPrec);
768 } catch (IOException e) {
769 throw new UncheckedIOException(e);
770 }
771 }
773 public void visitIf(JCIf tree) {
774 try {
775 print("if ");
776 if (tree.cond.hasTag(PARENS)) {
777 printExpr(tree.cond);
778 } else {
779 print("(");
780 printExpr(tree.cond);
781 print(")");
782 }
783 print(" ");
784 printStat(tree.thenpart);
785 if (tree.elsepart != null) {
786 print(" else ");
787 printStat(tree.elsepart);
788 }
789 } catch (IOException e) {
790 throw new UncheckedIOException(e);
791 }
792 }
794 public void visitExec(JCExpressionStatement tree) {
795 try {
796 printExpr(tree.expr);
797 if (prec == TreeInfo.notExpression) print(";");
798 } catch (IOException e) {
799 throw new UncheckedIOException(e);
800 }
801 }
803 public void visitBreak(JCBreak tree) {
804 try {
805 print("break");
806 if (tree.label != null) print(" " + tree.label);
807 print(";");
808 } catch (IOException e) {
809 throw new UncheckedIOException(e);
810 }
811 }
813 public void visitContinue(JCContinue tree) {
814 try {
815 print("continue");
816 if (tree.label != null) print(" " + tree.label);
817 print(";");
818 } catch (IOException e) {
819 throw new UncheckedIOException(e);
820 }
821 }
823 public void visitReturn(JCReturn tree) {
824 try {
825 print("return");
826 if (tree.expr != null) {
827 print(" ");
828 printExpr(tree.expr);
829 }
830 print(";");
831 } catch (IOException e) {
832 throw new UncheckedIOException(e);
833 }
834 }
836 public void visitThrow(JCThrow tree) {
837 try {
838 print("throw ");
839 printExpr(tree.expr);
840 print(";");
841 } catch (IOException e) {
842 throw new UncheckedIOException(e);
843 }
844 }
846 public void visitAssert(JCAssert tree) {
847 try {
848 print("assert ");
849 printExpr(tree.cond);
850 if (tree.detail != null) {
851 print(" : ");
852 printExpr(tree.detail);
853 }
854 print(";");
855 } catch (IOException e) {
856 throw new UncheckedIOException(e);
857 }
858 }
860 public void visitApply(JCMethodInvocation tree) {
861 try {
862 if (!tree.typeargs.isEmpty()) {
863 if (tree.meth.hasTag(SELECT)) {
864 JCFieldAccess left = (JCFieldAccess)tree.meth;
865 printExpr(left.selected);
866 print(".<");
867 printExprs(tree.typeargs);
868 print(">" + left.name);
869 } else {
870 print("<");
871 printExprs(tree.typeargs);
872 print(">");
873 printExpr(tree.meth);
874 }
875 } else {
876 printExpr(tree.meth);
877 }
878 print("(");
879 printExprs(tree.args);
880 print(")");
881 } catch (IOException e) {
882 throw new UncheckedIOException(e);
883 }
884 }
886 public void visitNewClass(JCNewClass tree) {
887 try {
888 if (tree.encl != null) {
889 printExpr(tree.encl);
890 print(".");
891 }
892 print("new ");
893 if (!tree.typeargs.isEmpty()) {
894 print("<");
895 printExprs(tree.typeargs);
896 print(">");
897 }
898 printExpr(tree.clazz);
899 print("(");
900 printExprs(tree.args);
901 print(")");
902 if (tree.def != null) {
903 Name enclClassNamePrev = enclClassName;
904 enclClassName =
905 tree.def.name != null ? tree.def.name :
906 tree.type != null && tree.type.tsym.name != tree.type.tsym.name.table.names.empty
907 ? tree.type.tsym.name : null;
908 if ((tree.def.mods.flags & Flags.ENUM) != 0) print("/*enum*/");
909 printBlock(tree.def.defs);
910 enclClassName = enclClassNamePrev;
911 }
912 } catch (IOException e) {
913 throw new UncheckedIOException(e);
914 }
915 }
917 public void visitNewArray(JCNewArray tree) {
918 try {
919 if (tree.elemtype != null) {
920 print("new ");
921 JCTree elem = tree.elemtype;
922 if (elem.hasTag(TYPEARRAY))
923 printBaseElementType((JCArrayTypeTree) elem);
924 else
925 printExpr(elem);
926 for (List<JCExpression> l = tree.dims; l.nonEmpty(); l = l.tail) {
927 print("[");
928 printExpr(l.head);
929 print("]");
930 }
931 if (elem instanceof JCArrayTypeTree)
932 printBrackets((JCArrayTypeTree) elem);
933 }
934 if (tree.elems != null) {
935 if (tree.elemtype != null) print("[]");
936 print("{");
937 printExprs(tree.elems);
938 print("}");
939 }
940 } catch (IOException e) {
941 throw new UncheckedIOException(e);
942 }
943 }
945 public void visitLambda(JCLambda tree) {
946 try {
947 print("(");
948 if (TreeInfo.isExplicitLambda(tree)) {
949 printExprs(tree.params);
950 } else {
951 String sep = "";
952 for (JCVariableDecl param : tree.params) {
953 print(sep);
954 print(param.name);
955 sep = ",";
956 }
957 }
958 print(")->");
959 printExpr(tree.body);
960 } catch (IOException e) {
961 throw new UncheckedIOException(e);
962 }
963 }
965 public void visitParens(JCParens tree) {
966 try {
967 print("(");
968 printExpr(tree.expr);
969 print(")");
970 } catch (IOException e) {
971 throw new UncheckedIOException(e);
972 }
973 }
975 public void visitAssign(JCAssign tree) {
976 try {
977 open(prec, TreeInfo.assignPrec);
978 printExpr(tree.lhs, TreeInfo.assignPrec + 1);
979 print(" = ");
980 printExpr(tree.rhs, TreeInfo.assignPrec);
981 close(prec, TreeInfo.assignPrec);
982 } catch (IOException e) {
983 throw new UncheckedIOException(e);
984 }
985 }
987 public String operatorName(JCTree.Tag tag) {
988 switch(tag) {
989 case POS: return "+";
990 case NEG: return "-";
991 case NOT: return "!";
992 case COMPL: return "~";
993 case PREINC: return "++";
994 case PREDEC: return "--";
995 case POSTINC: return "++";
996 case POSTDEC: return "--";
997 case NULLCHK: return "<*nullchk*>";
998 case OR: return "||";
999 case AND: return "&&";
1000 case EQ: return "==";
1001 case NE: return "!=";
1002 case LT: return "<";
1003 case GT: return ">";
1004 case LE: return "<=";
1005 case GE: return ">=";
1006 case BITOR: return "|";
1007 case BITXOR: return "^";
1008 case BITAND: return "&";
1009 case SL: return "<<";
1010 case SR: return ">>";
1011 case USR: return ">>>";
1012 case PLUS: return "+";
1013 case MINUS: return "-";
1014 case MUL: return "*";
1015 case DIV: return "/";
1016 case MOD: return "%";
1017 default: throw new Error();
1018 }
1019 }
1021 public void visitAssignop(JCAssignOp tree) {
1022 try {
1023 open(prec, TreeInfo.assignopPrec);
1024 printExpr(tree.lhs, TreeInfo.assignopPrec + 1);
1025 print(" " + operatorName(tree.getTag().noAssignOp()) + "= ");
1026 printExpr(tree.rhs, TreeInfo.assignopPrec);
1027 close(prec, TreeInfo.assignopPrec);
1028 } catch (IOException e) {
1029 throw new UncheckedIOException(e);
1030 }
1031 }
1033 public void visitUnary(JCUnary tree) {
1034 try {
1035 int ownprec = TreeInfo.opPrec(tree.getTag());
1036 String opname = operatorName(tree.getTag());
1037 open(prec, ownprec);
1038 if (!tree.getTag().isPostUnaryOp()) {
1039 print(opname);
1040 printExpr(tree.arg, ownprec);
1041 } else {
1042 printExpr(tree.arg, ownprec);
1043 print(opname);
1044 }
1045 close(prec, ownprec);
1046 } catch (IOException e) {
1047 throw new UncheckedIOException(e);
1048 }
1049 }
1051 public void visitBinary(JCBinary tree) {
1052 try {
1053 int ownprec = TreeInfo.opPrec(tree.getTag());
1054 String opname = operatorName(tree.getTag());
1055 open(prec, ownprec);
1056 printExpr(tree.lhs, ownprec);
1057 print(" " + opname + " ");
1058 printExpr(tree.rhs, ownprec + 1);
1059 close(prec, ownprec);
1060 } catch (IOException e) {
1061 throw new UncheckedIOException(e);
1062 }
1063 }
1065 public void visitTypeCast(JCTypeCast tree) {
1066 try {
1067 open(prec, TreeInfo.prefixPrec);
1068 print("(");
1069 printExpr(tree.clazz);
1070 print(")");
1071 printExpr(tree.expr, TreeInfo.prefixPrec);
1072 close(prec, TreeInfo.prefixPrec);
1073 } catch (IOException e) {
1074 throw new UncheckedIOException(e);
1075 }
1076 }
1078 public void visitTypeTest(JCInstanceOf tree) {
1079 try {
1080 open(prec, TreeInfo.ordPrec);
1081 printExpr(tree.expr, TreeInfo.ordPrec);
1082 print(" instanceof ");
1083 printExpr(tree.clazz, TreeInfo.ordPrec + 1);
1084 close(prec, TreeInfo.ordPrec);
1085 } catch (IOException e) {
1086 throw new UncheckedIOException(e);
1087 }
1088 }
1090 public void visitIndexed(JCArrayAccess tree) {
1091 try {
1092 printExpr(tree.indexed, TreeInfo.postfixPrec);
1093 print("[");
1094 printExpr(tree.index);
1095 print("]");
1096 } catch (IOException e) {
1097 throw new UncheckedIOException(e);
1098 }
1099 }
1101 public void visitSelect(JCFieldAccess tree) {
1102 try {
1103 printExpr(tree.selected, TreeInfo.postfixPrec);
1104 print("." + tree.name);
1105 } catch (IOException e) {
1106 throw new UncheckedIOException(e);
1107 }
1108 }
1110 public void visitReference(JCMemberReference tree) {
1111 try {
1112 printExpr(tree.expr);
1113 print("#");
1114 if (tree.typeargs != null) {
1115 print("<");
1116 printExprs(tree.typeargs);
1117 print(">");
1118 }
1119 print(tree.getMode() == ReferenceMode.INVOKE ? tree.name : "new");
1120 } catch (IOException e) {
1121 throw new UncheckedIOException(e);
1122 }
1123 }
1125 public void visitIdent(JCIdent tree) {
1126 try {
1127 print(tree.name);
1128 } catch (IOException e) {
1129 throw new UncheckedIOException(e);
1130 }
1131 }
1133 public void visitLiteral(JCLiteral tree) {
1134 try {
1135 switch (tree.typetag) {
1136 case TypeTags.INT:
1137 print(tree.value.toString());
1138 break;
1139 case TypeTags.LONG:
1140 print(tree.value + "L");
1141 break;
1142 case TypeTags.FLOAT:
1143 print(tree.value + "F");
1144 break;
1145 case TypeTags.DOUBLE:
1146 print(tree.value.toString());
1147 break;
1148 case TypeTags.CHAR:
1149 print("\'" +
1150 Convert.quote(
1151 String.valueOf((char)((Number)tree.value).intValue())) +
1152 "\'");
1153 break;
1154 case TypeTags.BOOLEAN:
1155 print(((Number)tree.value).intValue() == 1 ? "true" : "false");
1156 break;
1157 case TypeTags.BOT:
1158 print("null");
1159 break;
1160 default:
1161 print("\"" + Convert.quote(tree.value.toString()) + "\"");
1162 break;
1163 }
1164 } catch (IOException e) {
1165 throw new UncheckedIOException(e);
1166 }
1167 }
1169 public void visitTypeIdent(JCPrimitiveTypeTree tree) {
1170 try {
1171 switch(tree.typetag) {
1172 case TypeTags.BYTE:
1173 print("byte");
1174 break;
1175 case TypeTags.CHAR:
1176 print("char");
1177 break;
1178 case TypeTags.SHORT:
1179 print("short");
1180 break;
1181 case TypeTags.INT:
1182 print("int");
1183 break;
1184 case TypeTags.LONG:
1185 print("long");
1186 break;
1187 case TypeTags.FLOAT:
1188 print("float");
1189 break;
1190 case TypeTags.DOUBLE:
1191 print("double");
1192 break;
1193 case TypeTags.BOOLEAN:
1194 print("boolean");
1195 break;
1196 case TypeTags.VOID:
1197 print("void");
1198 break;
1199 default:
1200 print("error");
1201 break;
1202 }
1203 } catch (IOException e) {
1204 throw new UncheckedIOException(e);
1205 }
1206 }
1208 public void visitTypeArray(JCArrayTypeTree tree) {
1209 try {
1210 printBaseElementType(tree);
1211 printBrackets(tree);
1212 } catch (IOException e) {
1213 throw new UncheckedIOException(e);
1214 }
1215 }
1217 // Prints the inner element type of a nested array
1218 private void printBaseElementType(JCTree tree) throws IOException {
1219 printExpr(TreeInfo.innermostType(tree));
1220 }
1222 // prints the brackets of a nested array in reverse order
1223 private void printBrackets(JCArrayTypeTree tree) throws IOException {
1224 JCTree elem;
1225 while (true) {
1226 elem = tree.elemtype;
1227 print("[]");
1228 if (!elem.hasTag(TYPEARRAY)) break;
1229 tree = (JCArrayTypeTree) elem;
1230 }
1231 }
1233 public void visitTypeApply(JCTypeApply tree) {
1234 try {
1235 printExpr(tree.clazz);
1236 print("<");
1237 printExprs(tree.arguments);
1238 print(">");
1239 } catch (IOException e) {
1240 throw new UncheckedIOException(e);
1241 }
1242 }
1244 public void visitTypeUnion(JCTypeUnion tree) {
1245 try {
1246 printExprs(tree.alternatives, " | ");
1247 } catch (IOException e) {
1248 throw new UncheckedIOException(e);
1249 }
1250 }
1252 public void visitTypeParameter(JCTypeParameter tree) {
1253 try {
1254 print(tree.name);
1255 if (tree.bounds.nonEmpty()) {
1256 print(" extends ");
1257 printExprs(tree.bounds, " & ");
1258 }
1259 } catch (IOException e) {
1260 throw new UncheckedIOException(e);
1261 }
1262 }
1264 @Override
1265 public void visitWildcard(JCWildcard tree) {
1266 try {
1267 print(tree.kind);
1268 if (tree.kind.kind != BoundKind.UNBOUND)
1269 printExpr(tree.inner);
1270 } catch (IOException e) {
1271 throw new UncheckedIOException(e);
1272 }
1273 }
1275 @Override
1276 public void visitTypeBoundKind(TypeBoundKind tree) {
1277 try {
1278 print(String.valueOf(tree.kind));
1279 } catch (IOException e) {
1280 throw new UncheckedIOException(e);
1281 }
1282 }
1284 public void visitErroneous(JCErroneous tree) {
1285 try {
1286 print("(ERROR)");
1287 } catch (IOException e) {
1288 throw new UncheckedIOException(e);
1289 }
1290 }
1292 public void visitLetExpr(LetExpr tree) {
1293 try {
1294 print("(let " + tree.defs + " in " + tree.expr + ")");
1295 } catch (IOException e) {
1296 throw new UncheckedIOException(e);
1297 }
1298 }
1300 public void visitModifiers(JCModifiers mods) {
1301 try {
1302 printAnnotations(mods.annotations);
1303 printFlags(mods.flags);
1304 } catch (IOException e) {
1305 throw new UncheckedIOException(e);
1306 }
1307 }
1309 public void visitAnnotation(JCAnnotation tree) {
1310 try {
1311 print("@");
1312 printExpr(tree.annotationType);
1313 print("(");
1314 printExprs(tree.args);
1315 print(")");
1316 } catch (IOException e) {
1317 throw new UncheckedIOException(e);
1318 }
1319 }
1321 public void visitTree(JCTree tree) {
1322 try {
1323 print("(UNKNOWN: " + tree + ")");
1324 println();
1325 } catch (IOException e) {
1326 throw new UncheckedIOException(e);
1327 }
1328 }
1330 }