1 /* 2 * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.sun.tools.javac.tree; 27 28 import java.io.Writer; 29 30 import com.sun.source.doctree.*; 31 import com.sun.source.doctree.AttributeTree.ValueKind; 32 import com.sun.tools.javac.util.Convert; 33 import java.io.IOException; 34 import java.util.List; 35 36 /** 37 * Prints out a doc comment tree. 38 * 39 * <p><b>This is NOT part of any supported API. 40 * If you write code that depends on this, you do so at your own risk. 41 * This code and its internal interfaces are subject to change or 42 * deletion without notice.</b> 43 */ 44 public class DocPretty implements DocTreeVisitor<Void,Void> { 45 46 /** 47 * The output stream on which trees are printed. 48 */ 49 final Writer out; 50 51 /** 52 * The left margin. 53 */ 54 int lmargin = 0; 55 DocPretty(Writer out)56 public DocPretty(Writer out) { 57 this.out = out; 58 } 59 60 /** Visitor method: print expression tree. 61 */ print(DocTree tree)62 public void print(DocTree tree) throws IOException { 63 try { 64 if (tree == null) 65 print("/*missing*/"); 66 else { 67 tree.accept(this, null); 68 } 69 } catch (UncheckedIOException ex) { 70 throw new IOException(ex.getMessage(), ex); 71 } 72 } 73 74 /** 75 * Print string, replacing all non-ascii character with unicode escapes. 76 */ print(Object s)77 protected void print(Object s) throws IOException { 78 out.write(Convert.escapeUnicode(s.toString())); 79 } 80 81 /** 82 * Print list. 83 */ print(List<? extends DocTree> list)84 public void print(List<? extends DocTree> list) throws IOException { 85 for (DocTree t: list) { 86 print(t); 87 } 88 } 89 90 /** 91 * Print list., with separators 92 */ print(List<? extends DocTree> list, String sep)93 protected void print(List<? extends DocTree> list, String sep) throws IOException { 94 if (list.isEmpty()) 95 return; 96 boolean first = true; 97 for (DocTree t: list) { 98 if (!first) 99 print(sep); 100 print(t); 101 first = false; 102 } 103 } 104 105 /** Print new line. 106 */ println()107 protected void println() throws IOException { 108 out.write(lineSep); 109 } 110 printTagName(DocTree node)111 protected void printTagName(DocTree node) throws IOException { 112 out.write("@"); 113 out.write(node.getKind().tagName); 114 } 115 116 final String lineSep = System.getProperty("line.separator"); 117 118 /************************************************************************** 119 * Traversal methods 120 *************************************************************************/ 121 122 /** Exception to propagate IOException through visitXXX methods */ 123 private static class UncheckedIOException extends Error { 124 static final long serialVersionUID = -4032692679158424751L; UncheckedIOException(IOException e)125 UncheckedIOException(IOException e) { 126 super(e.getMessage(), e); 127 } 128 } 129 130 visitAttribute(AttributeTree node, Void p)131 public Void visitAttribute(AttributeTree node, Void p) { 132 try { 133 print(node.getName()); 134 String quote; 135 switch (node.getValueKind()) { 136 case EMPTY: 137 quote = null; 138 break; 139 case UNQUOTED: 140 quote = ""; 141 break; 142 case SINGLE: 143 quote = "'"; 144 break; 145 case DOUBLE: 146 quote = "\""; 147 break; 148 default: 149 throw new AssertionError(); 150 } 151 if (quote != null) { 152 print("=" + quote); 153 print(node.getValue()); 154 print(quote); 155 } 156 } catch (IOException e) { 157 throw new UncheckedIOException(e); 158 } 159 return null; 160 } 161 visitAuthor(AuthorTree node, Void p)162 public Void visitAuthor(AuthorTree node, Void p) { 163 try { 164 printTagName(node); 165 print(" "); 166 print(node.getName()); 167 } catch (IOException e) { 168 throw new UncheckedIOException(e); 169 } 170 return null; 171 } 172 visitComment(CommentTree node, Void p)173 public Void visitComment(CommentTree node, Void p) { 174 try { 175 print(node.getBody()); 176 } catch (IOException e) { 177 throw new UncheckedIOException(e); 178 } 179 return null; 180 } 181 visitDeprecated(DeprecatedTree node, Void p)182 public Void visitDeprecated(DeprecatedTree node, Void p) { 183 try { 184 printTagName(node); 185 if (!node.getBody().isEmpty()) { 186 print(" "); 187 print(node.getBody()); 188 } 189 } catch (IOException e) { 190 throw new UncheckedIOException(e); 191 } 192 return null; 193 } 194 visitDocComment(DocCommentTree node, Void p)195 public Void visitDocComment(DocCommentTree node, Void p) { 196 try { 197 List<? extends DocTree> fs = node.getFirstSentence(); 198 List<? extends DocTree> b = node.getBody(); 199 List<? extends DocTree> t = node.getBlockTags(); 200 print(fs); 201 if (!fs.isEmpty() && !b.isEmpty()) 202 print(" "); 203 print(b); 204 if ((!fs.isEmpty() || !b.isEmpty()) && !t.isEmpty()) 205 print("\n"); 206 print(t, "\n"); 207 } catch (IOException e) { 208 throw new UncheckedIOException(e); 209 } 210 return null; 211 } 212 visitDocRoot(DocRootTree node, Void p)213 public Void visitDocRoot(DocRootTree node, Void p) { 214 try { 215 print("{"); 216 printTagName(node); 217 print("}"); 218 } catch (IOException e) { 219 throw new UncheckedIOException(e); 220 } 221 return null; 222 } 223 visitEndElement(EndElementTree node, Void p)224 public Void visitEndElement(EndElementTree node, Void p) { 225 try { 226 print("</"); 227 print(node.getName()); 228 print(">"); 229 } catch (IOException e) { 230 throw new UncheckedIOException(e); 231 } 232 return null; 233 } 234 visitEntity(EntityTree node, Void p)235 public Void visitEntity(EntityTree node, Void p) { 236 try { 237 print("&"); 238 print(node.getName()); 239 print(";"); 240 } catch (IOException e) { 241 throw new UncheckedIOException(e); 242 } 243 return null; 244 } 245 visitErroneous(ErroneousTree node, Void p)246 public Void visitErroneous(ErroneousTree node, Void p) { 247 try { 248 print(node.getBody()); 249 } catch (IOException e) { 250 throw new UncheckedIOException(e); 251 } 252 return null; 253 } 254 visitIdentifier(IdentifierTree node, Void p)255 public Void visitIdentifier(IdentifierTree node, Void p) { 256 try { 257 print(node.getName()); 258 } catch (IOException e) { 259 throw new UncheckedIOException(e); 260 } 261 return null; 262 } 263 visitInheritDoc(InheritDocTree node, Void p)264 public Void visitInheritDoc(InheritDocTree node, Void p) { 265 try { 266 print("{"); 267 printTagName(node); 268 print("}"); 269 } catch (IOException e) { 270 throw new UncheckedIOException(e); 271 } 272 return null; 273 } 274 visitLink(LinkTree node, Void p)275 public Void visitLink(LinkTree node, Void p) { 276 try { 277 print("{"); 278 printTagName(node); 279 print(" "); 280 print(node.getReference()); 281 if (!node.getLabel().isEmpty()) { 282 print(" "); 283 print(node.getLabel()); 284 } 285 print("}"); 286 } catch (IOException e) { 287 throw new UncheckedIOException(e); 288 } 289 return null; 290 } 291 visitLiteral(LiteralTree node, Void p)292 public Void visitLiteral(LiteralTree node, Void p) { 293 try { 294 print("{"); 295 printTagName(node); 296 print(" "); 297 print(node.getBody()); 298 print("}"); 299 } catch (IOException e) { 300 throw new UncheckedIOException(e); 301 } 302 return null; 303 } 304 visitParam(ParamTree node, Void p)305 public Void visitParam(ParamTree node, Void p) { 306 try { 307 printTagName(node); 308 print(" "); 309 if (node.isTypeParameter()) print("<"); 310 print(node.getName()); 311 if (node.isTypeParameter()) print(">"); 312 if (!node.getDescription().isEmpty()) { 313 print(" "); 314 print(node.getDescription()); 315 } 316 } catch (IOException e) { 317 throw new UncheckedIOException(e); 318 } 319 return null; 320 } 321 visitReference(ReferenceTree node, Void p)322 public Void visitReference(ReferenceTree node, Void p) { 323 try { 324 print(node.getSignature()); 325 } catch (IOException e) { 326 throw new UncheckedIOException(e); 327 } 328 return null; 329 } 330 visitReturn(ReturnTree node, Void p)331 public Void visitReturn(ReturnTree node, Void p) { 332 try { 333 printTagName(node); 334 print(" "); 335 print(node.getDescription()); 336 } catch (IOException e) { 337 throw new UncheckedIOException(e); 338 } 339 return null; 340 } 341 visitSee(SeeTree node, Void p)342 public Void visitSee(SeeTree node, Void p) { 343 try { 344 printTagName(node); 345 boolean first = true; 346 boolean needSep = true; 347 for (DocTree t: node.getReference()) { 348 if (needSep) print(" "); 349 needSep = (first && (t instanceof ReferenceTree)); 350 first = false; 351 print(t); 352 } 353 } catch (IOException e) { 354 throw new UncheckedIOException(e); 355 } 356 return null; 357 } 358 visitSerial(SerialTree node, Void p)359 public Void visitSerial(SerialTree node, Void p) { 360 try { 361 printTagName(node); 362 if (!node.getDescription().isEmpty()) { 363 print(" "); 364 print(node.getDescription()); 365 } 366 } catch (IOException e) { 367 throw new UncheckedIOException(e); 368 } 369 return null; 370 } 371 visitSerialData(SerialDataTree node, Void p)372 public Void visitSerialData(SerialDataTree node, Void p) { 373 try { 374 printTagName(node); 375 if (!node.getDescription().isEmpty()) { 376 print(" "); 377 print(node.getDescription()); 378 } 379 } catch (IOException e) { 380 throw new UncheckedIOException(e); 381 } 382 return null; 383 } 384 visitSerialField(SerialFieldTree node, Void p)385 public Void visitSerialField(SerialFieldTree node, Void p) { 386 try { 387 printTagName(node); 388 print(" "); 389 print(node.getName()); 390 print(" "); 391 print(node.getType()); 392 if (!node.getDescription().isEmpty()) { 393 print(" "); 394 print(node.getDescription()); 395 } 396 } catch (IOException e) { 397 throw new UncheckedIOException(e); 398 } 399 return null; 400 } 401 visitSince(SinceTree node, Void p)402 public Void visitSince(SinceTree node, Void p) { 403 try { 404 printTagName(node); 405 print(" "); 406 print(node.getBody()); 407 } catch (IOException e) { 408 throw new UncheckedIOException(e); 409 } 410 return null; 411 } 412 visitStartElement(StartElementTree node, Void p)413 public Void visitStartElement(StartElementTree node, Void p) { 414 try { 415 print("<"); 416 print(node.getName()); 417 List<? extends DocTree> attrs = node.getAttributes(); 418 if (!attrs.isEmpty()) { 419 print(" "); 420 print(attrs); 421 DocTree last = node.getAttributes().get(attrs.size() - 1); 422 if (node.isSelfClosing() && last instanceof AttributeTree 423 && ((AttributeTree) last).getValueKind() == ValueKind.UNQUOTED) 424 print(" "); 425 } 426 if (node.isSelfClosing()) 427 print("/"); 428 print(">"); 429 } catch (IOException e) { 430 throw new UncheckedIOException(e); 431 } 432 return null; 433 } 434 visitText(TextTree node, Void p)435 public Void visitText(TextTree node, Void p) { 436 try { 437 print(node.getBody()); 438 } catch (IOException e) { 439 throw new UncheckedIOException(e); 440 } 441 return null; 442 } 443 visitThrows(ThrowsTree node, Void p)444 public Void visitThrows(ThrowsTree node, Void p) { 445 try { 446 printTagName(node); 447 print(" "); 448 print(node.getExceptionName()); 449 if (!node.getDescription().isEmpty()) { 450 print(" "); 451 print(node.getDescription()); 452 } 453 } catch (IOException e) { 454 throw new UncheckedIOException(e); 455 } 456 return null; 457 } 458 visitUnknownBlockTag(UnknownBlockTagTree node, Void p)459 public Void visitUnknownBlockTag(UnknownBlockTagTree node, Void p) { 460 try { 461 print("@"); 462 print(node.getTagName()); 463 print(" "); 464 print(node.getContent()); 465 } catch (IOException e) { 466 throw new UncheckedIOException(e); 467 } 468 return null; 469 } 470 visitUnknownInlineTag(UnknownInlineTagTree node, Void p)471 public Void visitUnknownInlineTag(UnknownInlineTagTree node, Void p) { 472 try { 473 print("{"); 474 print("@"); 475 print(node.getTagName()); 476 print(" "); 477 print(node.getContent()); 478 print("}"); 479 } catch (IOException e) { 480 throw new UncheckedIOException(e); 481 } 482 return null; 483 } 484 visitValue(ValueTree node, Void p)485 public Void visitValue(ValueTree node, Void p) { 486 try { 487 print("{"); 488 printTagName(node); 489 if (node.getReference() != null) { 490 print(" "); 491 print(node.getReference()); 492 } 493 print("}"); 494 } catch (IOException e) { 495 throw new UncheckedIOException(e); 496 } 497 return null; 498 } 499 visitVersion(VersionTree node, Void p)500 public Void visitVersion(VersionTree node, Void p) { 501 try { 502 printTagName(node); 503 print(" "); 504 print(node.getBody()); 505 } catch (IOException e) { 506 throw new UncheckedIOException(e); 507 } 508 return null; 509 } 510 visitOther(DocTree node, Void p)511 public Void visitOther(DocTree node, Void p) { 512 try { 513 print("(UNKNOWN: " + node + ")"); 514 println(); 515 } catch (IOException e) { 516 throw new UncheckedIOException(e); 517 } 518 return null; 519 } 520 } 521