1 /* 2 * Copyright (c) 1999, 2019, 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 */ 25 26 package com.sun.tools.javac.tree; 27 28 import java.io.*; 29 30 import com.sun.source.tree.MemberReferenceTree.ReferenceMode; 31 import com.sun.source.tree.ModuleTree.ModuleKind; 32 import com.sun.tools.javac.code.*; 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.*; 39 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 { 48 49 public Pretty(Writer out, boolean sourceOutput) { 50 this.out = out; 51 this.sourceOutput = sourceOutput; 52 } 53 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; 60 61 /** The output stream on which trees are printed. 62 */ 63 Writer out; 64 65 /** Indentation width (can be reassigned from outside). 66 */ 67 public int width = 4; 68 69 /** The current left margin. 70 */ 71 int lmargin = 0; 72 73 /** The enclosing class name. 74 */ 75 Name enclClassName; 76 77 /** A table mapping trees to their documentation comments 78 * (can be null) 79 */ 80 DocCommentTable docComments = null; 81 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 = "[...]"; 87 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; 92 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 } 98 99 /** Increase left margin by indentation width. 100 */ 101 void indent() { 102 lmargin = lmargin + width; 103 } 104 105 /** Decrease left margin by indentation width. 106 */ 107 void undent() { 108 lmargin = lmargin - width; 109 } 110 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 } 119 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 } 128 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 } 134 135 /** Print new line. 136 */ 137 public void println() throws IOException { 138 out.write(lineSep); 139 } 140 141 public static String toSimpleString(JCTree tree) { 142 return toSimpleString(tree, PREFERRED_LENGTH); 143 } 144 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 } 166 167 String lineSep = System.getProperty("line.separator"); 168 169 /************************************************************************** 170 * Traversal methods 171 *************************************************************************/ 172 173 /** Exception to propagate 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 } 180 181 /** Visitor argument: the current precedence level. 182 */ 183 int prec; 184 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 } 204 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 } 211 212 /** Derived visitor method: print statement tree. 213 */ 214 public void printStat(JCTree tree) throws IOException { 215 printExpr(tree, TreeInfo.notExpression); 216 } 217 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 } 230 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 } 236 237 238 /** Derived visitor method: print pattern. 239 */ 240 241 public void printPattern(JCTree tree) throws IOException { 242 printExpr(tree); 243 } 244 245 /** Derived visitor method: print list of statements, each on a separate line. 246 */ 247 public void printStats(List<? extends JCTree> trees) throws IOException { 248 for (List<? extends JCTree> l = trees; l.nonEmpty(); l = l.tail) { 249 align(); 250 printStat(l.head); 251 println(); 252 } 253 } 254 255 /** Print a set of modifiers. 256 */ 257 public void printFlags(long flags) throws IOException { 258 if ((flags & SYNTHETIC) != 0) print("/*synthetic*/ "); 259 print(TreeInfo.flagNames(flags)); 260 if ((flags & ExtendedStandardFlags) != 0) print(" "); 261 if ((flags & ANNOTATION) != 0) print("@"); 262 } 263 264 public void printAnnotations(List<JCAnnotation> trees) throws IOException { 265 for (List<JCAnnotation> l = trees; l.nonEmpty(); l = l.tail) { 266 printStat(l.head); 267 println(); 268 align(); 269 } 270 } 271 272 public void printTypeAnnotations(List<JCAnnotation> trees) throws IOException { 273 for (List<JCAnnotation> l = trees; l.nonEmpty(); l = l.tail) { 274 printExpr(l.head); 275 print(" "); 276 } 277 } 278 279 /** Print documentation comment, if it exists 280 * @param tree The tree for which a documentation comment should be printed. 281 */ 282 public void printDocComment(JCTree tree) throws IOException { 283 if (docComments != null) { 284 String dc = docComments.getCommentText(tree); 285 if (dc != null) { 286 print("/**"); println(); 287 int pos = 0; 288 int endpos = lineEndPos(dc, pos); 289 while (pos < dc.length()) { 290 align(); 291 print(" *"); 292 if (pos < dc.length() && dc.charAt(pos) > ' ') print(" "); 293 print(dc.substring(pos, endpos)); println(); 294 pos = endpos + 1; 295 endpos = lineEndPos(dc, pos); 296 } 297 align(); print(" */"); println(); 298 align(); 299 } 300 } 301 } 302 //where 303 static int lineEndPos(String s, int start) { 304 int pos = s.indexOf('\n', start); 305 if (pos < 0) pos = s.length(); 306 return pos; 307 } 308 309 /** If type parameter list is non-empty, print it enclosed in 310 * {@literal "<...>"} brackets. 311 */ 312 public void printTypeParameters(List<JCTypeParameter> trees) throws IOException { 313 if (trees.nonEmpty()) { 314 print("<"); 315 printExprs(trees); 316 print(">"); 317 } 318 } 319 320 /** Print a block. 321 */ 322 public void printBlock(List<? extends JCTree> stats) throws IOException { 323 print("{"); 324 println(); 325 indent(); 326 printStats(stats); 327 undent(); 328 align(); 329 print("}"); 330 } 331 332 /** Print a block. 333 */ 334 public void printEnumBody(List<JCTree> stats) throws IOException { 335 print("{"); 336 println(); 337 indent(); 338 boolean first = true; 339 for (List<JCTree> l = stats; l.nonEmpty(); l = l.tail) { 340 if (isEnumerator(l.head)) { 341 if (!first) { 342 print(","); 343 println(); 344 } 345 align(); 346 printStat(l.head); 347 first = false; 348 } 349 } 350 print(";"); 351 println(); 352 for (List<JCTree> l = stats; l.nonEmpty(); l = l.tail) { 353 if (!isEnumerator(l.head)) { 354 align(); 355 printStat(l.head); 356 println(); 357 } 358 } 359 undent(); 360 align(); 361 print("}"); 362 } 363 364 /** Is the given tree an enumerator definition? */ 365 boolean isEnumerator(JCTree t) { 366 return t.hasTag(VARDEF) && (((JCVariableDecl) t).mods.flags & ENUM) != 0; 367 } 368 369 /** Print unit consisting of package clause and import statements in toplevel, 370 * followed by class definition. if class definition == null, 371 * print all definitions in toplevel. 372 * @param tree The toplevel tree 373 * @param cdef The class definition, which is assumed to be part of the 374 * toplevel tree. 375 */ 376 public void printUnit(JCCompilationUnit tree, JCClassDecl cdef) throws IOException { 377 docComments = tree.docComments; 378 printDocComment(tree); 379 380 boolean firstImport = true; 381 for (List<JCTree> l = tree.defs; 382 l.nonEmpty() && 383 (cdef == null || 384 l.head.hasTag(IMPORT) || l.head.hasTag(PACKAGEDEF)); 385 l = l.tail) { 386 if (l.head.hasTag(IMPORT)) { 387 JCImport imp = (JCImport)l.head; 388 Name name = TreeInfo.name(imp.qualid); 389 if (name == name.table.names.asterisk || 390 cdef == null || 391 isUsed(TreeInfo.symbol(imp.qualid), cdef)) { 392 if (firstImport) { 393 firstImport = false; 394 println(); 395 } 396 printStat(imp); 397 } 398 } else { 399 printStat(l.head); 400 } 401 } 402 if (cdef != null) { 403 printStat(cdef); 404 println(); 405 } 406 } 407 // where 408 boolean isUsed(final Symbol t, JCTree cdef) { 409 class UsedVisitor extends TreeScanner { 410 public void scan(JCTree tree) { 411 if (tree!=null && !result) tree.accept(this); 412 } 413 boolean result = false; 414 public void visitIdent(JCIdent tree) { 415 if (tree.sym == t) result = true; 416 } 417 } 418 UsedVisitor v = new UsedVisitor(); 419 v.scan(cdef); 420 return v.result; 421 } 422 423 /************************************************************************** 424 * Visitor methods 425 *************************************************************************/ 426 427 public void visitTopLevel(JCCompilationUnit tree) { 428 try { 429 printUnit(tree, null); 430 } catch (IOException e) { 431 throw new UncheckedIOException(e); 432 } 433 } 434 435 public void visitPackageDef(JCPackageDecl tree) { 436 try { 437 printDocComment(tree); 438 printAnnotations(tree.annotations); 439 if (tree.pid != null) { 440 print("package "); 441 printExpr(tree.pid); 442 print(";"); 443 println(); 444 } 445 } catch (IOException e) { 446 throw new UncheckedIOException(e); 447 } 448 } 449 450 @Override 451 public void visitModuleDef(JCModuleDecl tree) { 452 try { 453 printDocComment(tree); 454 printAnnotations(tree.mods.annotations); 455 if (tree.getModuleType() == ModuleKind.OPEN) { 456 print("open "); 457 } 458 print("module "); 459 printExpr(tree.qualId); 460 if (tree.directives == null) { 461 print(";"); 462 } else { 463 printBlock(tree.directives); 464 } 465 println(); 466 } catch (IOException e) { 467 throw new UncheckedIOException(e); 468 } 469 } 470 471 @Override 472 public void visitExports(JCExports tree) { 473 try { 474 print("exports "); 475 printExpr(tree.qualid); 476 if (tree.moduleNames != null) { 477 print(" to "); 478 printExprs(tree.moduleNames); 479 } 480 print(";"); 481 } catch (IOException e) { 482 throw new UncheckedIOException(e); 483 } 484 } 485 486 @Override 487 public void visitOpens(JCOpens tree) { 488 try { 489 print("opens "); 490 printExpr(tree.qualid); 491 if (tree.moduleNames != null) { 492 print(" to "); 493 printExprs(tree.moduleNames); 494 } 495 print(";"); 496 } catch (IOException e) { 497 throw new UncheckedIOException(e); 498 } 499 } 500 501 @Override 502 public void visitProvides(JCProvides tree) { 503 try { 504 print("provides "); 505 printExpr(tree.serviceName); 506 print(" with "); 507 printExprs(tree.implNames); 508 print(";"); 509 } catch (IOException e) { 510 throw new UncheckedIOException(e); 511 } 512 } 513 514 @Override 515 public void visitRequires(JCRequires tree) { 516 try { 517 print("requires "); 518 if (tree.isStaticPhase) 519 print("static "); 520 if (tree.isTransitive) 521 print("transitive "); 522 printExpr(tree.moduleName); 523 print(";"); 524 } catch (IOException e) { 525 throw new UncheckedIOException(e); 526 } 527 } 528 529 @Override 530 public void visitUses(JCUses tree) { 531 try { 532 print("uses "); 533 printExpr(tree.qualid); 534 print(";"); 535 } catch (IOException e) { 536 throw new UncheckedIOException(e); 537 } 538 } 539 540 public void visitImport(JCImport tree) { 541 try { 542 print("import "); 543 if (tree.staticImport) print("static "); 544 printExpr(tree.qualid); 545 print(";"); 546 println(); 547 } catch (IOException e) { 548 throw new UncheckedIOException(e); 549 } 550 } 551 552 public void visitClassDef(JCClassDecl tree) { 553 try { 554 println(); align(); 555 printDocComment(tree); 556 printAnnotations(tree.mods.annotations); 557 printFlags(tree.mods.flags & ~INTERFACE); 558 Name enclClassNamePrev = enclClassName; 559 enclClassName = tree.name; 560 if ((tree.mods.flags & INTERFACE) != 0) { 561 print("interface " + tree.name); 562 printTypeParameters(tree.typarams); 563 if (tree.implementing.nonEmpty()) { 564 print(" extends "); 565 printExprs(tree.implementing); 566 } 567 } else { 568 if ((tree.mods.flags & ENUM) != 0) 569 print("enum " + tree.name); 570 else 571 print("class " + tree.name); 572 printTypeParameters(tree.typarams); 573 if (tree.extending != null) { 574 print(" extends "); 575 printExpr(tree.extending); 576 } 577 if (tree.implementing.nonEmpty()) { 578 print(" implements "); 579 printExprs(tree.implementing); 580 } 581 } 582 print(" "); 583 if ((tree.mods.flags & ENUM) != 0) { 584 printEnumBody(tree.defs); 585 } else { 586 printBlock(tree.defs); 587 } 588 enclClassName = enclClassNamePrev; 589 } catch (IOException e) { 590 throw new UncheckedIOException(e); 591 } 592 } 593 594 public void visitMethodDef(JCMethodDecl tree) { 595 try { 596 // when producing source output, omit anonymous constructors 597 if (tree.name == tree.name.table.names.init && 598 enclClassName == null && 599 sourceOutput) return; 600 println(); align(); 601 printDocComment(tree); 602 printExpr(tree.mods); 603 printTypeParameters(tree.typarams); 604 if (tree.name == tree.name.table.names.init) { 605 print(enclClassName != null ? enclClassName : tree.name); 606 } else { 607 printExpr(tree.restype); 608 print(" " + tree.name); 609 } 610 print("("); 611 if (tree.recvparam!=null) { 612 printExpr(tree.recvparam); 613 if (tree.params.size() > 0) { 614 print(", "); 615 } 616 } 617 printExprs(tree.params); 618 print(")"); 619 if (tree.thrown.nonEmpty()) { 620 print(" throws "); 621 printExprs(tree.thrown); 622 } 623 if (tree.defaultValue != null) { 624 print(" default "); 625 printExpr(tree.defaultValue); 626 } 627 if (tree.body != null) { 628 print(" "); 629 printStat(tree.body); 630 } else { 631 print(";"); 632 } 633 } catch (IOException e) { 634 throw new UncheckedIOException(e); 635 } 636 } 637 638 public void visitVarDef(JCVariableDecl tree) { 639 try { 640 if (docComments != null && docComments.hasComment(tree)) { 641 println(); align(); 642 } 643 printDocComment(tree); 644 if ((tree.mods.flags & ENUM) != 0) { 645 print("/*public static final*/ "); 646 print(tree.name); 647 if (tree.init != null) { 648 if (tree.init.hasTag(NEWCLASS)) { 649 JCNewClass init = (JCNewClass) tree.init; 650 if (sourceOutput) { 651 print(" /*enum*/ "); 652 if (init.args != null && init.args.nonEmpty()) { 653 print("("); 654 print(init.args); 655 print(")"); 656 } 657 if (init.def != null && init.def.defs != null) { 658 print(" "); 659 printBlock(init.def.defs); 660 } 661 return; 662 }else { 663 print(" /* = "); 664 print("new "); 665 if (init.def != null && init.def.mods.annotations.nonEmpty()) { 666 printTypeAnnotations(init.def.mods.annotations); 667 } 668 printExpr(init.clazz); 669 print("("); 670 printExprs(init.args); 671 print(")"); 672 print(" */"); 673 print(" /*enum*/ "); 674 if (init.args != null && init.args.nonEmpty()) { 675 print("("); 676 printExprs(init.args); 677 print(")"); 678 } 679 if (init.def != null && init.def.defs != null) { 680 print(" "); 681 printBlock(init.def.defs); 682 } 683 return; 684 } 685 } 686 print(" /* = "); 687 printExpr(tree.init); 688 print(" */"); 689 } 690 } else { 691 printExpr(tree.mods); 692 if ((tree.mods.flags & VARARGS) != 0) { 693 JCTree vartype = tree.vartype; 694 List<JCAnnotation> tas = null; 695 if (vartype instanceof JCAnnotatedType) { 696 tas = ((JCAnnotatedType)vartype).annotations; 697 vartype = ((JCAnnotatedType)vartype).underlyingType; 698 } 699 printExpr(((JCArrayTypeTree) vartype).elemtype); 700 if (tas != null) { 701 print(' '); 702 printTypeAnnotations(tas); 703 } 704 print("... " + tree.name); 705 } else { 706 printExpr(tree.vartype); 707 print(" " + tree.name); 708 } 709 if (tree.init != null) { 710 print(" = "); 711 printExpr(tree.init); 712 } 713 if (prec == TreeInfo.notExpression) print(";"); 714 } 715 } catch (IOException e) { 716 throw new UncheckedIOException(e); 717 } 718 } 719 720 public void visitSkip(JCSkip tree) { 721 try { 722 print(";"); 723 } catch (IOException e) { 724 throw new UncheckedIOException(e); 725 } 726 } 727 728 public void visitBlock(JCBlock tree) { 729 try { 730 printFlags(tree.flags); 731 printBlock(tree.stats); 732 } catch (IOException e) { 733 throw new UncheckedIOException(e); 734 } 735 } 736 737 public void visitDoLoop(JCDoWhileLoop tree) { 738 try { 739 print("do "); 740 printStat(tree.body); 741 align(); 742 print(" while "); 743 if (tree.cond.hasTag(PARENS)) { 744 printExpr(tree.cond); 745 } else { 746 print("("); 747 printExpr(tree.cond); 748 print(")"); 749 } 750 print(";"); 751 } catch (IOException e) { 752 throw new UncheckedIOException(e); 753 } 754 } 755 756 public void visitWhileLoop(JCWhileLoop tree) { 757 try { 758 print("while "); 759 if (tree.cond.hasTag(PARENS)) { 760 printExpr(tree.cond); 761 } else { 762 print("("); 763 printExpr(tree.cond); 764 print(")"); 765 } 766 print(" "); 767 printStat(tree.body); 768 } catch (IOException e) { 769 throw new UncheckedIOException(e); 770 } 771 } 772 773 public void visitForLoop(JCForLoop tree) { 774 try { 775 print("for ("); 776 if (tree.init.nonEmpty()) { 777 if (tree.init.head.hasTag(VARDEF)) { 778 printExpr(tree.init.head); 779 for (List<JCStatement> l = tree.init.tail; l.nonEmpty(); l = l.tail) { 780 JCVariableDecl vdef = (JCVariableDecl)l.head; 781 print(", " + vdef.name); 782 if (vdef.init != null) { 783 print(" = "); 784 printExpr(vdef.init); 785 } 786 } 787 } else { 788 printExprs(tree.init); 789 } 790 } 791 print("; "); 792 if (tree.cond != null) printExpr(tree.cond); 793 print("; "); 794 printExprs(tree.step); 795 print(") "); 796 printStat(tree.body); 797 } catch (IOException e) { 798 throw new UncheckedIOException(e); 799 } 800 } 801 802 public void visitForeachLoop(JCEnhancedForLoop tree) { 803 try { 804 print("for ("); 805 printExpr(tree.var); 806 print(" : "); 807 printExpr(tree.expr); 808 print(") "); 809 printStat(tree.body); 810 } catch (IOException e) { 811 throw new UncheckedIOException(e); 812 } 813 } 814 815 public void visitLabelled(JCLabeledStatement tree) { 816 try { 817 print(tree.label + ": "); 818 printStat(tree.body); 819 } catch (IOException e) { 820 throw new UncheckedIOException(e); 821 } 822 } 823 824 public void visitSwitch(JCSwitch tree) { 825 try { 826 print("switch "); 827 if (tree.selector.hasTag(PARENS)) { 828 printExpr(tree.selector); 829 } else { 830 print("("); 831 printExpr(tree.selector); 832 print(")"); 833 } 834 print(" {"); 835 println(); 836 printStats(tree.cases); 837 align(); 838 print("}"); 839 } catch (IOException e) { 840 throw new UncheckedIOException(e); 841 } 842 } 843 844 public void visitCase(JCCase tree) { 845 try { 846 if (tree.pats.isEmpty()) { 847 print("default"); 848 } else { 849 print("case "); 850 printExprs(tree.pats); 851 } 852 if (tree.caseKind == JCCase.STATEMENT) { 853 print(":"); 854 println(); 855 indent(); 856 printStats(tree.stats); 857 undent(); 858 align(); 859 } else { 860 print(" -> "); 861 printStat(tree.stats.head); 862 } 863 } catch (IOException e) { 864 throw new UncheckedIOException(e); 865 } 866 } 867 868 public void visitSwitchExpression(JCSwitchExpression tree) { 869 try { 870 print("switch "); 871 if (tree.selector.hasTag(PARENS)) { 872 printExpr(tree.selector); 873 } else { 874 print("("); 875 printExpr(tree.selector); 876 print(")"); 877 } 878 print(" {"); 879 println(); 880 printStats(tree.cases); 881 align(); 882 print("}"); 883 } catch (IOException e) { 884 throw new UncheckedIOException(e); 885 } 886 } 887 888 public void visitBindingPattern(JCBindingPattern patt) { 889 try { 890 printExpr(patt.vartype); 891 print(" "); 892 print(patt.name); 893 } catch (IOException e) { 894 throw new UncheckedIOException(e); 895 } 896 } 897 898 public void visitSynchronized(JCSynchronized tree) { 899 try { 900 print("synchronized "); 901 if (tree.lock.hasTag(PARENS)) { 902 printExpr(tree.lock); 903 } else { 904 print("("); 905 printExpr(tree.lock); 906 print(")"); 907 } 908 print(" "); 909 printStat(tree.body); 910 } catch (IOException e) { 911 throw new UncheckedIOException(e); 912 } 913 } 914 915 public void visitTry(JCTry tree) { 916 try { 917 print("try "); 918 if (tree.resources.nonEmpty()) { 919 print("("); 920 boolean first = true; 921 for (JCTree var : tree.resources) { 922 if (!first) { 923 println(); 924 indent(); 925 } 926 printStat(var); 927 first = false; 928 } 929 print(") "); 930 } 931 printStat(tree.body); 932 for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) { 933 printStat(l.head); 934 } 935 if (tree.finalizer != null) { 936 print(" finally "); 937 printStat(tree.finalizer); 938 } 939 } catch (IOException e) { 940 throw new UncheckedIOException(e); 941 } 942 } 943 944 public void visitCatch(JCCatch tree) { 945 try { 946 print(" catch ("); 947 printExpr(tree.param); 948 print(") "); 949 printStat(tree.body); 950 } catch (IOException e) { 951 throw new UncheckedIOException(e); 952 } 953 } 954 955 public void visitConditional(JCConditional tree) { 956 try { 957 open(prec, TreeInfo.condPrec); 958 printExpr(tree.cond, TreeInfo.condPrec + 1); 959 print(" ? "); 960 printExpr(tree.truepart); 961 print(" : "); 962 printExpr(tree.falsepart, TreeInfo.condPrec); 963 close(prec, TreeInfo.condPrec); 964 } catch (IOException e) { 965 throw new UncheckedIOException(e); 966 } 967 } 968 969 public void visitIf(JCIf tree) { 970 try { 971 print("if "); 972 if (tree.cond.hasTag(PARENS)) { 973 printExpr(tree.cond); 974 } else { 975 print("("); 976 printExpr(tree.cond); 977 print(")"); 978 } 979 print(" "); 980 printStat(tree.thenpart); 981 if (tree.elsepart != null) { 982 print(" else "); 983 printStat(tree.elsepart); 984 } 985 } catch (IOException e) { 986 throw new UncheckedIOException(e); 987 } 988 } 989 990 public void visitExec(JCExpressionStatement tree) { 991 try { 992 printExpr(tree.expr); 993 if (prec == TreeInfo.notExpression) print(";"); 994 } catch (IOException e) { 995 throw new UncheckedIOException(e); 996 } 997 } 998 999 public void visitBreak(JCBreak tree) { 1000 try { 1001 print("break"); 1002 if (tree.label != null) print(" " + tree.label); 1003 print(";"); 1004 } catch (IOException e) { 1005 throw new UncheckedIOException(e); 1006 } 1007 } 1008 1009 public void visitYield(JCYield tree) { 1010 try { 1011 print("yield"); 1012 print(" "); 1013 printExpr(tree.value); 1014 print(";"); 1015 } catch (IOException e) { 1016 throw new UncheckedIOException(e); 1017 } 1018 } 1019 1020 public void visitContinue(JCContinue tree) { 1021 try { 1022 print("continue"); 1023 if (tree.label != null) print(" " + tree.label); 1024 print(";"); 1025 } catch (IOException e) { 1026 throw new UncheckedIOException(e); 1027 } 1028 } 1029 1030 public void visitReturn(JCReturn tree) { 1031 try { 1032 print("return"); 1033 if (tree.expr != null) { 1034 print(" "); 1035 printExpr(tree.expr); 1036 } 1037 print(";"); 1038 } catch (IOException e) { 1039 throw new UncheckedIOException(e); 1040 } 1041 } 1042 1043 public void visitThrow(JCThrow tree) { 1044 try { 1045 print("throw "); 1046 printExpr(tree.expr); 1047 print(";"); 1048 } catch (IOException e) { 1049 throw new UncheckedIOException(e); 1050 } 1051 } 1052 1053 public void visitAssert(JCAssert tree) { 1054 try { 1055 print("assert "); 1056 printExpr(tree.cond); 1057 if (tree.detail != null) { 1058 print(" : "); 1059 printExpr(tree.detail); 1060 } 1061 print(";"); 1062 } catch (IOException e) { 1063 throw new UncheckedIOException(e); 1064 } 1065 } 1066 1067 public void visitApply(JCMethodInvocation tree) { 1068 try { 1069 if (!tree.typeargs.isEmpty()) { 1070 if (tree.meth.hasTag(SELECT)) { 1071 JCFieldAccess left = (JCFieldAccess)tree.meth; 1072 printExpr(left.selected); 1073 print(".<"); 1074 printExprs(tree.typeargs); 1075 print(">" + left.name); 1076 } else { 1077 print("<"); 1078 printExprs(tree.typeargs); 1079 print(">"); 1080 printExpr(tree.meth); 1081 } 1082 } else { 1083 printExpr(tree.meth); 1084 } 1085 print("("); 1086 printExprs(tree.args); 1087 print(")"); 1088 } catch (IOException e) { 1089 throw new UncheckedIOException(e); 1090 } 1091 } 1092 1093 public void visitNewClass(JCNewClass tree) { 1094 try { 1095 if (tree.encl != null) { 1096 printExpr(tree.encl); 1097 print("."); 1098 } 1099 print("new "); 1100 if (!tree.typeargs.isEmpty()) { 1101 print("<"); 1102 printExprs(tree.typeargs); 1103 print(">"); 1104 } 1105 if (tree.def != null && tree.def.mods.annotations.nonEmpty()) { 1106 printTypeAnnotations(tree.def.mods.annotations); 1107 } 1108 printExpr(tree.clazz); 1109 print("("); 1110 printExprs(tree.args); 1111 print(")"); 1112 if (tree.def != null) { 1113 Name enclClassNamePrev = enclClassName; 1114 enclClassName = 1115 tree.def.name != null ? tree.def.name : 1116 tree.type != null && tree.type.tsym.name != tree.type.tsym.name.table.names.empty 1117 ? tree.type.tsym.name : null; 1118 if ((tree.def.mods.flags & Flags.ENUM) != 0) print("/*enum*/"); 1119 printBlock(tree.def.defs); 1120 enclClassName = enclClassNamePrev; 1121 } 1122 } catch (IOException e) { 1123 throw new UncheckedIOException(e); 1124 } 1125 } 1126 1127 public void visitNewArray(JCNewArray tree) { 1128 try { 1129 if (tree.elemtype != null) { 1130 print("new "); 1131 JCTree elem = tree.elemtype; 1132 printBaseElementType(elem); 1133 1134 if (!tree.annotations.isEmpty()) { 1135 print(' '); 1136 printTypeAnnotations(tree.annotations); 1137 } 1138 if (tree.elems != null) { 1139 print("[]"); 1140 } 1141 1142 int i = 0; 1143 List<List<JCAnnotation>> da = tree.dimAnnotations; 1144 for (List<JCExpression> l = tree.dims; l.nonEmpty(); l = l.tail) { 1145 if (da.size() > i && !da.get(i).isEmpty()) { 1146 print(' '); 1147 printTypeAnnotations(da.get(i)); 1148 } 1149 print("["); 1150 i++; 1151 printExpr(l.head); 1152 print("]"); 1153 } 1154 printBrackets(elem); 1155 } 1156 if (tree.elems != null) { 1157 print("{"); 1158 printExprs(tree.elems); 1159 print("}"); 1160 } 1161 } catch (IOException e) { 1162 throw new UncheckedIOException(e); 1163 } 1164 } 1165 1166 public void visitLambda(JCLambda tree) { 1167 try { 1168 print("("); 1169 if (tree.paramKind == JCLambda.ParameterKind.EXPLICIT) { 1170 printExprs(tree.params); 1171 } else { 1172 String sep = ""; 1173 for (JCVariableDecl param : tree.params) { 1174 print(sep); 1175 print(param.name); 1176 sep = ","; 1177 } 1178 } 1179 print(")->"); 1180 printExpr(tree.body); 1181 } catch (IOException e) { 1182 throw new UncheckedIOException(e); 1183 } 1184 } 1185 1186 public void visitParens(JCParens tree) { 1187 try { 1188 print("("); 1189 printExpr(tree.expr); 1190 print(")"); 1191 } catch (IOException e) { 1192 throw new UncheckedIOException(e); 1193 } 1194 } 1195 1196 public void visitAssign(JCAssign tree) { 1197 try { 1198 open(prec, TreeInfo.assignPrec); 1199 printExpr(tree.lhs, TreeInfo.assignPrec + 1); 1200 print(" = "); 1201 printExpr(tree.rhs, TreeInfo.assignPrec); 1202 close(prec, TreeInfo.assignPrec); 1203 } catch (IOException e) { 1204 throw new UncheckedIOException(e); 1205 } 1206 } 1207 1208 public String operatorName(JCTree.Tag tag) { 1209 switch(tag) { 1210 case POS: return "+"; 1211 case NEG: return "-"; 1212 case NOT: return "!"; 1213 case COMPL: return "~"; 1214 case PREINC: return "++"; 1215 case PREDEC: return "--"; 1216 case POSTINC: return "++"; 1217 case POSTDEC: return "--"; 1218 case NULLCHK: return "<*nullchk*>"; 1219 case OR: return "||"; 1220 case AND: return "&&"; 1221 case EQ: return "=="; 1222 case NE: return "!="; 1223 case LT: return "<"; 1224 case GT: return ">"; 1225 case LE: return "<="; 1226 case GE: return ">="; 1227 case BITOR: return "|"; 1228 case BITXOR: return "^"; 1229 case BITAND: return "&"; 1230 case SL: return "<<"; 1231 case SR: return ">>"; 1232 case USR: return ">>>"; 1233 case PLUS: return "+"; 1234 case MINUS: return "-"; 1235 case MUL: return "*"; 1236 case DIV: return "/"; 1237 case MOD: return "%"; 1238 default: throw new Error(); 1239 } 1240 } 1241 1242 public void visitAssignop(JCAssignOp tree) { 1243 try { 1244 open(prec, TreeInfo.assignopPrec); 1245 printExpr(tree.lhs, TreeInfo.assignopPrec + 1); 1246 print(" " + operatorName(tree.getTag().noAssignOp()) + "= "); 1247 printExpr(tree.rhs, TreeInfo.assignopPrec); 1248 close(prec, TreeInfo.assignopPrec); 1249 } catch (IOException e) { 1250 throw new UncheckedIOException(e); 1251 } 1252 } 1253 1254 public void visitUnary(JCUnary tree) { 1255 try { 1256 int ownprec = TreeInfo.opPrec(tree.getTag()); 1257 String opname = operatorName(tree.getTag()); 1258 open(prec, ownprec); 1259 if (!tree.getTag().isPostUnaryOp()) { 1260 print(opname); 1261 printExpr(tree.arg, ownprec); 1262 } else { 1263 printExpr(tree.arg, ownprec); 1264 print(opname); 1265 } 1266 close(prec, ownprec); 1267 } catch (IOException e) { 1268 throw new UncheckedIOException(e); 1269 } 1270 } 1271 1272 public void visitBinary(JCBinary tree) { 1273 try { 1274 int ownprec = TreeInfo.opPrec(tree.getTag()); 1275 String opname = operatorName(tree.getTag()); 1276 open(prec, ownprec); 1277 printExpr(tree.lhs, ownprec); 1278 print(" " + opname + " "); 1279 printExpr(tree.rhs, ownprec + 1); 1280 close(prec, ownprec); 1281 } catch (IOException e) { 1282 throw new UncheckedIOException(e); 1283 } 1284 } 1285 1286 public void visitTypeCast(JCTypeCast tree) { 1287 try { 1288 open(prec, TreeInfo.prefixPrec); 1289 print("("); 1290 printExpr(tree.clazz); 1291 print(")"); 1292 printExpr(tree.expr, TreeInfo.prefixPrec); 1293 close(prec, TreeInfo.prefixPrec); 1294 } catch (IOException e) { 1295 throw new UncheckedIOException(e); 1296 } 1297 } 1298 1299 public void visitTypeTest(JCInstanceOf tree) { 1300 try { 1301 open(prec, TreeInfo.ordPrec); 1302 printExpr(tree.expr, TreeInfo.ordPrec); 1303 print(" instanceof "); 1304 if (tree.pattern instanceof JCPattern) { 1305 printPattern(tree.pattern); 1306 } else { 1307 printExpr(tree.getType(), TreeInfo.ordPrec + 1); 1308 } 1309 close(prec, TreeInfo.ordPrec); 1310 } catch (IOException e) { 1311 throw new UncheckedIOException(e); 1312 } 1313 } 1314 1315 public void visitIndexed(JCArrayAccess tree) { 1316 try { 1317 printExpr(tree.indexed, TreeInfo.postfixPrec); 1318 print("["); 1319 printExpr(tree.index); 1320 print("]"); 1321 } catch (IOException e) { 1322 throw new UncheckedIOException(e); 1323 } 1324 } 1325 1326 public void visitSelect(JCFieldAccess tree) { 1327 try { 1328 printExpr(tree.selected, TreeInfo.postfixPrec); 1329 print("." + tree.name); 1330 } catch (IOException e) { 1331 throw new UncheckedIOException(e); 1332 } 1333 } 1334 1335 public void visitReference(JCMemberReference tree) { 1336 try { 1337 printExpr(tree.expr); 1338 print("::"); 1339 if (tree.typeargs != null) { 1340 print("<"); 1341 printExprs(tree.typeargs); 1342 print(">"); 1343 } 1344 print(tree.getMode() == ReferenceMode.INVOKE ? tree.name : "new"); 1345 } catch (IOException e) { 1346 throw new UncheckedIOException(e); 1347 } 1348 } 1349 1350 public void visitIdent(JCIdent tree) { 1351 try { 1352 print(tree.name); 1353 } catch (IOException e) { 1354 throw new UncheckedIOException(e); 1355 } 1356 } 1357 1358 public void visitLiteral(JCLiteral tree) { 1359 try { 1360 switch (tree.typetag) { 1361 case INT: 1362 print(tree.value.toString()); 1363 break; 1364 case LONG: 1365 print(tree.value + "L"); 1366 break; 1367 case FLOAT: 1368 print(tree.value + "F"); 1369 break; 1370 case DOUBLE: 1371 print(tree.value.toString()); 1372 break; 1373 case CHAR: 1374 print("\'" + 1375 Convert.quote( 1376 String.valueOf((char)((Number)tree.value).intValue())) + 1377 "\'"); 1378 break; 1379 case BOOLEAN: 1380 print(((Number)tree.value).intValue() == 1 ? "true" : "false"); 1381 break; 1382 case BOT: 1383 print("null"); 1384 break; 1385 default: 1386 print("\"" + Convert.quote(tree.value.toString()) + "\""); 1387 break; 1388 } 1389 } catch (IOException e) { 1390 throw new UncheckedIOException(e); 1391 } 1392 } 1393 1394 public void visitTypeIdent(JCPrimitiveTypeTree tree) { 1395 try { 1396 switch(tree.typetag) { 1397 case BYTE: 1398 print("byte"); 1399 break; 1400 case CHAR: 1401 print("char"); 1402 break; 1403 case SHORT: 1404 print("short"); 1405 break; 1406 case INT: 1407 print("int"); 1408 break; 1409 case LONG: 1410 print("long"); 1411 break; 1412 case FLOAT: 1413 print("float"); 1414 break; 1415 case DOUBLE: 1416 print("double"); 1417 break; 1418 case BOOLEAN: 1419 print("boolean"); 1420 break; 1421 case VOID: 1422 print("void"); 1423 break; 1424 default: 1425 print("error"); 1426 break; 1427 } 1428 } catch (IOException e) { 1429 throw new UncheckedIOException(e); 1430 } 1431 } 1432 1433 public void visitTypeArray(JCArrayTypeTree tree) { 1434 try { 1435 printBaseElementType(tree); 1436 printBrackets(tree); 1437 } catch (IOException e) { 1438 throw new UncheckedIOException(e); 1439 } 1440 } 1441 1442 // Prints the inner element type of a nested array 1443 private void printBaseElementType(JCTree tree) throws IOException { 1444 printExpr(TreeInfo.innermostType(tree, false)); 1445 } 1446 1447 // prints the brackets of a nested array in reverse order 1448 // tree is either JCArrayTypeTree or JCAnnotatedTypeTree 1449 private void printBrackets(JCTree tree) throws IOException { 1450 JCTree elem = tree; 1451 while (true) { 1452 if (elem.hasTag(ANNOTATED_TYPE)) { 1453 JCAnnotatedType atype = (JCAnnotatedType) elem; 1454 elem = atype.underlyingType; 1455 if (elem.hasTag(TYPEARRAY)) { 1456 print(' '); 1457 printTypeAnnotations(atype.annotations); 1458 } 1459 } 1460 if (elem.hasTag(TYPEARRAY)) { 1461 print("[]"); 1462 elem = ((JCArrayTypeTree)elem).elemtype; 1463 } else { 1464 break; 1465 } 1466 } 1467 } 1468 1469 public void visitTypeApply(JCTypeApply tree) { 1470 try { 1471 printExpr(tree.clazz); 1472 print("<"); 1473 printExprs(tree.arguments); 1474 print(">"); 1475 } catch (IOException e) { 1476 throw new UncheckedIOException(e); 1477 } 1478 } 1479 1480 public void visitTypeUnion(JCTypeUnion tree) { 1481 try { 1482 printExprs(tree.alternatives, " | "); 1483 } catch (IOException e) { 1484 throw new UncheckedIOException(e); 1485 } 1486 } 1487 1488 public void visitTypeIntersection(JCTypeIntersection tree) { 1489 try { 1490 printExprs(tree.bounds, " & "); 1491 } catch (IOException e) { 1492 throw new UncheckedIOException(e); 1493 } 1494 } 1495 1496 public void visitTypeParameter(JCTypeParameter tree) { 1497 try { 1498 if (tree.annotations.nonEmpty()) { 1499 this.printTypeAnnotations(tree.annotations); 1500 } 1501 print(tree.name); 1502 if (tree.bounds.nonEmpty()) { 1503 print(" extends "); 1504 printExprs(tree.bounds, " & "); 1505 } 1506 } catch (IOException e) { 1507 throw new UncheckedIOException(e); 1508 } 1509 } 1510 1511 @Override 1512 public void visitWildcard(JCWildcard tree) { 1513 try { 1514 print(tree.kind); 1515 if (tree.kind.kind != BoundKind.UNBOUND) 1516 printExpr(tree.inner); 1517 } catch (IOException e) { 1518 throw new UncheckedIOException(e); 1519 } 1520 } 1521 1522 @Override 1523 public void visitTypeBoundKind(TypeBoundKind tree) { 1524 try { 1525 print(String.valueOf(tree.kind)); 1526 } catch (IOException e) { 1527 throw new UncheckedIOException(e); 1528 } 1529 } 1530 1531 public void visitErroneous(JCErroneous tree) { 1532 try { 1533 print("(ERROR)"); 1534 } catch (IOException e) { 1535 throw new UncheckedIOException(e); 1536 } 1537 } 1538 1539 public void visitLetExpr(LetExpr tree) { 1540 try { 1541 print("(let " + tree.defs + " in " + tree.expr + ")"); 1542 } catch (IOException e) { 1543 throw new UncheckedIOException(e); 1544 } 1545 } 1546 1547 public void visitModifiers(JCModifiers mods) { 1548 try { 1549 printAnnotations(mods.annotations); 1550 printFlags(mods.flags); 1551 } catch (IOException e) { 1552 throw new UncheckedIOException(e); 1553 } 1554 } 1555 1556 public void visitAnnotation(JCAnnotation tree) { 1557 try { 1558 print("@"); 1559 printExpr(tree.annotationType); 1560 if (!tree.args.isEmpty()) { 1561 print("("); 1562 printExprs(tree.args); 1563 print(")"); 1564 } 1565 } catch (IOException e) { 1566 throw new UncheckedIOException(e); 1567 } 1568 } 1569 1570 public void visitAnnotatedType(JCAnnotatedType tree) { 1571 try { 1572 if (tree.underlyingType.hasTag(SELECT)) { 1573 JCFieldAccess access = (JCFieldAccess) tree.underlyingType; 1574 printExpr(access.selected, TreeInfo.postfixPrec); 1575 print("."); 1576 printTypeAnnotations(tree.annotations); 1577 print(access.name); 1578 } else if (tree.underlyingType.hasTag(TYPEARRAY)) { 1579 printBaseElementType(tree); 1580 printBrackets(tree); 1581 } else { 1582 printTypeAnnotations(tree.annotations); 1583 printExpr(tree.underlyingType); 1584 } 1585 } catch (IOException e) { 1586 throw new UncheckedIOException(e); 1587 } 1588 } 1589 1590 public void visitTree(JCTree tree) { 1591 try { 1592 print("(UNKNOWN: " + tree.getTag() + ")"); 1593 println(); 1594 } catch (IOException e) { 1595 throw new UncheckedIOException(e); 1596 } 1597 } 1598 1599 }