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