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