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