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