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