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