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