test/tools/javac/doctree/DocCommentTester.java

Thu, 31 Aug 2017 15:17:03 +0800

author
aoqi
date
Thu, 31 Aug 2017 15:17:03 +0800
changeset 2525
2eb010b6cb22
parent 1419
a25c53e12bd0
parent 0
959103a6100f
permissions
-rw-r--r--

merge

aoqi@0 1 /*
aoqi@0 2 * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
aoqi@0 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
aoqi@0 4 *
aoqi@0 5 * This code is free software; you can redistribute it and/or modify it
aoqi@0 6 * under the terms of the GNU General Public License version 2 only, as
aoqi@0 7 * published by the Free Software Foundation.
aoqi@0 8 *
aoqi@0 9 * This code is distributed in the hope that it will be useful, but WITHOUT
aoqi@0 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
aoqi@0 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
aoqi@0 12 * version 2 for more details (a copy is included in the LICENSE file that
aoqi@0 13 * accompanied this code).
aoqi@0 14 *
aoqi@0 15 * You should have received a copy of the GNU General Public License version
aoqi@0 16 * 2 along with this work; if not, write to the Free Software Foundation,
aoqi@0 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
aoqi@0 18 *
aoqi@0 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
aoqi@0 20 * or visit www.oracle.com if you need additional information or have any
aoqi@0 21 * questions.
aoqi@0 22 */
aoqi@0 23
aoqi@0 24 import java.io.File;
aoqi@0 25 import java.io.FileWriter;
aoqi@0 26 import java.io.IOException;
aoqi@0 27 import java.io.PrintWriter;
aoqi@0 28 import java.io.StringWriter;
aoqi@0 29 import java.io.Writer;
aoqi@0 30 import java.util.ArrayList;
aoqi@0 31 import java.util.List;
aoqi@0 32 import java.util.regex.Matcher;
aoqi@0 33 import java.util.regex.Pattern;
aoqi@0 34
aoqi@0 35 import javax.lang.model.element.Name;
aoqi@0 36 import javax.tools.JavaFileObject;
aoqi@0 37 import javax.tools.StandardJavaFileManager;
aoqi@0 38
aoqi@0 39 import com.sun.source.doctree.*;
aoqi@0 40 import com.sun.source.tree.ClassTree;
aoqi@0 41 import com.sun.source.tree.CompilationUnitTree;
aoqi@0 42 import com.sun.source.tree.MethodTree;
aoqi@0 43 import com.sun.source.tree.Tree;
aoqi@0 44 import com.sun.source.tree.VariableTree;
aoqi@0 45 import com.sun.source.util.DocTreeScanner;
aoqi@0 46 import com.sun.source.util.DocTrees;
aoqi@0 47 import com.sun.source.util.JavacTask;
aoqi@0 48 import com.sun.source.util.TreePath;
aoqi@0 49 import com.sun.source.util.TreePathScanner;
aoqi@0 50 import com.sun.tools.javac.api.JavacTool;
aoqi@0 51 import com.sun.tools.javac.tree.DCTree;
aoqi@0 52 import com.sun.tools.javac.tree.DCTree.DCDocComment;
aoqi@0 53 import com.sun.tools.javac.tree.DCTree.DCErroneous;
aoqi@0 54 import com.sun.tools.javac.tree.DocPretty;
aoqi@0 55
aoqi@0 56 public class DocCommentTester {
aoqi@0 57
aoqi@0 58 public static void main(String... args) throws Exception {
aoqi@0 59 new DocCommentTester().run(args);
aoqi@0 60 }
aoqi@0 61
aoqi@0 62 public void run(String... args) throws Exception {
aoqi@0 63 String testSrc = System.getProperty("test.src");
aoqi@0 64
aoqi@0 65 List<File> files = new ArrayList<File>();
aoqi@0 66 for (String arg: args)
aoqi@0 67 files.add(new File(testSrc, arg));
aoqi@0 68
aoqi@0 69 JavacTool javac = JavacTool.create();
aoqi@0 70 StandardJavaFileManager fm = javac.getStandardFileManager(null, null, null);
aoqi@0 71
aoqi@0 72 Iterable<? extends JavaFileObject> fos = fm.getJavaFileObjectsFromFiles(files);
aoqi@0 73
aoqi@0 74 JavacTask t = javac.getTask(null, fm, null, null, null, fos);
aoqi@0 75 final DocTrees trees = DocTrees.instance(t);
aoqi@0 76
aoqi@0 77 final Checker[] checkers = {
aoqi@0 78 new ASTChecker(this, trees),
aoqi@0 79 new PosChecker(this, trees),
aoqi@0 80 new PrettyChecker(this, trees)
aoqi@0 81 };
aoqi@0 82
aoqi@0 83 DeclScanner d = new DeclScanner() {
aoqi@0 84 @Override
aoqi@0 85 public Void visitCompilationUnit(CompilationUnitTree tree, Void ignore) {
aoqi@0 86 for (Checker c: checkers)
aoqi@0 87 c.visitCompilationUnit(tree);
aoqi@0 88 return super.visitCompilationUnit(tree, ignore);
aoqi@0 89 }
aoqi@0 90
aoqi@0 91 @Override
aoqi@0 92 void visitDecl(Tree tree, Name name) {
aoqi@0 93 TreePath path = getCurrentPath();
aoqi@0 94 String dc = trees.getDocComment(path);
aoqi@0 95 if (dc != null) {
aoqi@0 96 for (Checker c : checkers) {
aoqi@0 97 try {
aoqi@0 98 System.err.println(path.getLeaf().getKind()
aoqi@0 99 + " " + name
aoqi@0 100 + " " + c.getClass().getSimpleName());
aoqi@0 101
aoqi@0 102 c.check(path, name);
aoqi@0 103
aoqi@0 104 System.err.println();
aoqi@0 105 } catch (Exception e) {
aoqi@0 106 error("Exception " + e);
aoqi@0 107 e.printStackTrace(System.err);
aoqi@0 108 }
aoqi@0 109 }
aoqi@0 110 }
aoqi@0 111 }
aoqi@0 112 };
aoqi@0 113
aoqi@0 114 Iterable<? extends CompilationUnitTree> units = t.parse();
aoqi@0 115 for (CompilationUnitTree unit: units) {
aoqi@0 116 d.scan(unit, null);
aoqi@0 117 }
aoqi@0 118
aoqi@0 119 if (errors > 0)
aoqi@0 120 throw new Exception(errors + " errors occurred");
aoqi@0 121 }
aoqi@0 122
aoqi@0 123 static abstract class DeclScanner extends TreePathScanner<Void, Void> {
aoqi@0 124 abstract void visitDecl(Tree tree, Name name);
aoqi@0 125
aoqi@0 126 @Override
aoqi@0 127 public Void visitClass(ClassTree tree, Void ignore) {
aoqi@0 128 super.visitClass(tree, ignore);
aoqi@0 129 visitDecl(tree, tree.getSimpleName());
aoqi@0 130 return null;
aoqi@0 131 }
aoqi@0 132
aoqi@0 133 @Override
aoqi@0 134 public Void visitMethod(MethodTree tree, Void ignore) {
aoqi@0 135 super.visitMethod(tree, ignore);
aoqi@0 136 visitDecl(tree, tree.getName());
aoqi@0 137 return null;
aoqi@0 138 }
aoqi@0 139
aoqi@0 140 @Override
aoqi@0 141 public Void visitVariable(VariableTree tree, Void ignore) {
aoqi@0 142 super.visitVariable(tree, ignore);
aoqi@0 143 visitDecl(tree, tree.getName());
aoqi@0 144 return null;
aoqi@0 145 }
aoqi@0 146 }
aoqi@0 147
aoqi@0 148 /**
aoqi@0 149 * Base class for checkers to check the doc comment on a declaration
aoqi@0 150 * (when present.)
aoqi@0 151 */
aoqi@0 152 abstract class Checker {
aoqi@0 153 final DocTrees trees;
aoqi@0 154
aoqi@0 155 Checker(DocTrees trees) {
aoqi@0 156 this.trees = trees;
aoqi@0 157 }
aoqi@0 158
aoqi@0 159 void visitCompilationUnit(CompilationUnitTree tree) { }
aoqi@0 160
aoqi@0 161 abstract void check(TreePath tree, Name name) throws Exception;
aoqi@0 162
aoqi@0 163 void error(String msg) {
aoqi@0 164 DocCommentTester.this.error(msg);
aoqi@0 165 }
aoqi@0 166 }
aoqi@0 167
aoqi@0 168 void error(String msg) {
aoqi@0 169 System.err.println("Error: " + msg);
aoqi@0 170 errors++;
aoqi@0 171 }
aoqi@0 172
aoqi@0 173 int errors;
aoqi@0 174
aoqi@0 175 /**
aoqi@0 176 * Verify the structure of the DocTree AST by comparing it against golden text.
aoqi@0 177 */
aoqi@0 178 static class ASTChecker extends Checker {
aoqi@0 179 static final String NEWLINE = System.getProperty("line.separator");
aoqi@0 180 Printer printer = new Printer();
aoqi@0 181 String source;
aoqi@0 182
aoqi@0 183 ASTChecker(DocCommentTester test, DocTrees t) {
aoqi@0 184 test.super(t);
aoqi@0 185 }
aoqi@0 186
aoqi@0 187 @Override
aoqi@0 188 void visitCompilationUnit(CompilationUnitTree tree) {
aoqi@0 189 try {
aoqi@0 190 source = tree.getSourceFile().getCharContent(true).toString();
aoqi@0 191 } catch (IOException e) {
aoqi@0 192 source = "";
aoqi@0 193 }
aoqi@0 194 }
aoqi@0 195
aoqi@0 196 void check(TreePath path, Name name) {
aoqi@0 197 StringWriter out = new StringWriter();
aoqi@0 198 DocCommentTree dc = trees.getDocCommentTree(path);
aoqi@0 199 printer.print(dc, out);
aoqi@0 200 out.flush();
aoqi@0 201 String found = out.toString().replace(NEWLINE, "\n");
aoqi@0 202
aoqi@0 203 // Look for the first block comment after the first occurrence of name
aoqi@0 204 int start = source.indexOf("\n/*\n", findName(source, name));
aoqi@0 205 int end = source.indexOf("\n*/\n", start);
aoqi@0 206 String expect = source.substring(start + 4, end + 1);
aoqi@0 207 if (!found.equals(expect)) {
aoqi@0 208 System.err.println("Expect:\n" + expect);
aoqi@0 209 System.err.println("Found:\n" + found);
aoqi@0 210 error("AST mismatch for " + name);
aoqi@0 211 }
aoqi@0 212 }
aoqi@0 213
aoqi@0 214 /**
aoqi@0 215 * This main program is to set up the golden comments used by this
aoqi@0 216 * checker.
aoqi@0 217 * Usage:
aoqi@0 218 * java DocCommentTester$ASTChecker -o dir file...
aoqi@0 219 * The given files are written to the output directory with their
aoqi@0 220 * golden comments updated. The intent is that the files should
aoqi@0 221 * then be compared with the originals, e.g. with meld, and if the
aoqi@0 222 * changes are approved, the new files can be used to replace the old.
aoqi@0 223 */
aoqi@0 224 public static void main(String... args) throws Exception {
aoqi@0 225 List<File> files = new ArrayList<File>();
aoqi@0 226 File o = null;
aoqi@0 227 for (int i = 0; i < args.length; i++) {
aoqi@0 228 String arg = args[i];
aoqi@0 229 if (arg.equals("-o"))
aoqi@0 230 o = new File(args[++i]);
aoqi@0 231 else if (arg.startsWith("-"))
aoqi@0 232 throw new IllegalArgumentException(arg);
aoqi@0 233 else {
aoqi@0 234 files.add(new File(arg));
aoqi@0 235 }
aoqi@0 236 }
aoqi@0 237
aoqi@0 238 if (o == null)
aoqi@0 239 throw new IllegalArgumentException("no output dir specified");
aoqi@0 240 final File outDir = o;
aoqi@0 241
aoqi@0 242 JavacTool javac = JavacTool.create();
aoqi@0 243 StandardJavaFileManager fm = javac.getStandardFileManager(null, null, null);
aoqi@0 244 Iterable<? extends JavaFileObject> fos = fm.getJavaFileObjectsFromFiles(files);
aoqi@0 245
aoqi@0 246 JavacTask t = javac.getTask(null, fm, null, null, null, fos);
aoqi@0 247 final DocTrees trees = DocTrees.instance(t);
aoqi@0 248
aoqi@0 249 DeclScanner d = new DeclScanner() {
aoqi@0 250 Printer p = new Printer();
aoqi@0 251 String source;
aoqi@0 252
aoqi@0 253 @Override
aoqi@0 254 public Void visitCompilationUnit(CompilationUnitTree tree, Void ignore) {
aoqi@0 255 System.err.println("processing " + tree.getSourceFile().getName());
aoqi@0 256 try {
aoqi@0 257 source = tree.getSourceFile().getCharContent(true).toString();
aoqi@0 258 } catch (IOException e) {
aoqi@0 259 source = "";
aoqi@0 260 }
aoqi@0 261
aoqi@0 262 // remove existing gold by removing all block comments after the first '{'.
aoqi@0 263 int start = source.indexOf("{");
aoqi@0 264 while ((start = source.indexOf("\n/*\n", start)) != -1) {
aoqi@0 265 int end = source.indexOf("\n*/\n");
aoqi@0 266 source = source.substring(0, start + 1) + source.substring(end + 4);
aoqi@0 267 }
aoqi@0 268
aoqi@0 269 // process decls in compilation unit
aoqi@0 270 super.visitCompilationUnit(tree, ignore);
aoqi@0 271
aoqi@0 272 // write the modified source
aoqi@0 273 File f = new File(tree.getSourceFile().getName());
aoqi@0 274 File outFile = new File(outDir, f.getName());
aoqi@0 275 try {
aoqi@0 276 FileWriter out = new FileWriter(outFile);
aoqi@0 277 try {
aoqi@0 278 out.write(source);
aoqi@0 279 } finally {
aoqi@0 280 out.close();
aoqi@0 281 }
aoqi@0 282 } catch (IOException e) {
aoqi@0 283 System.err.println("Can't write " + tree.getSourceFile().getName()
aoqi@0 284 + " to " + outFile + ": " + e);
aoqi@0 285 }
aoqi@0 286 return null;
aoqi@0 287 }
aoqi@0 288
aoqi@0 289 @Override
aoqi@0 290 void visitDecl(Tree tree, Name name) {
aoqi@0 291 DocTree dc = trees.getDocCommentTree(getCurrentPath());
aoqi@0 292 if (dc != null) {
aoqi@0 293 StringWriter out = new StringWriter();
aoqi@0 294 p.print(dc, out);
aoqi@0 295 String found = out.toString();
aoqi@0 296
aoqi@0 297 // Look for the empty line after the first occurrence of name
aoqi@0 298 int pos = source.indexOf("\n\n", findName(source, name));
aoqi@0 299
aoqi@0 300 // Insert the golden comment
aoqi@0 301 source = source.substring(0, pos)
aoqi@0 302 + "\n/*\n"
aoqi@0 303 + found
aoqi@0 304 + "*/"
aoqi@0 305 + source.substring(pos);
aoqi@0 306 }
aoqi@0 307 }
aoqi@0 308
aoqi@0 309 };
aoqi@0 310
aoqi@0 311 Iterable<? extends CompilationUnitTree> units = t.parse();
aoqi@0 312 for (CompilationUnitTree unit: units) {
aoqi@0 313 d.scan(unit, null);
aoqi@0 314 }
aoqi@0 315 }
aoqi@0 316
aoqi@0 317 static int findName(String source, Name name) {
aoqi@0 318 Pattern p = Pattern.compile("\\s" + name + "[(;]");
aoqi@0 319 Matcher m = p.matcher(source);
aoqi@0 320 if (!m.find())
aoqi@0 321 throw new Error("cannot find " + name);
aoqi@0 322 return m.start();
aoqi@0 323 }
aoqi@0 324
aoqi@0 325 static class Printer implements DocTreeVisitor<Void, Void> {
aoqi@0 326 PrintWriter out;
aoqi@0 327
aoqi@0 328 void print(DocTree tree, Writer out) {
aoqi@0 329 this.out = (out instanceof PrintWriter)
aoqi@0 330 ? (PrintWriter) out : new PrintWriter(out);
aoqi@0 331 tree.accept(this, null);
aoqi@0 332 this.out.flush();
aoqi@0 333 }
aoqi@0 334
aoqi@0 335 public Void visitAttribute(AttributeTree node, Void p) {
aoqi@0 336 header(node);
aoqi@0 337 indent(+1);
aoqi@0 338 print("name", node.getName().toString());
aoqi@0 339 print("vkind", node.getValueKind().toString());
aoqi@0 340 print("value", node.getValue());
aoqi@0 341 indent(-1);
aoqi@0 342 indent();
aoqi@0 343 out.println("]");
aoqi@0 344 return null;
aoqi@0 345 }
aoqi@0 346
aoqi@0 347 public Void visitAuthor(AuthorTree node, Void p) {
aoqi@0 348 header(node);
aoqi@0 349 indent(+1);
aoqi@0 350 print("name", node.getName());
aoqi@0 351 indent(-1);
aoqi@0 352 indent();
aoqi@0 353 out.println("]");
aoqi@0 354 return null;
aoqi@0 355 }
aoqi@0 356
aoqi@0 357 public Void visitComment(CommentTree node, Void p) {
aoqi@0 358 header(node, compress(node.getBody()));
aoqi@0 359 return null;
aoqi@0 360 }
aoqi@0 361
aoqi@0 362 public Void visitDeprecated(DeprecatedTree node, Void p) {
aoqi@0 363 header(node);
aoqi@0 364 indent(+1);
aoqi@0 365 print("body", node.getBody());
aoqi@0 366 indent(-1);
aoqi@0 367 indent();
aoqi@0 368 out.println("]");
aoqi@0 369 return null;
aoqi@0 370 }
aoqi@0 371
aoqi@0 372 public Void visitDocComment(DocCommentTree node, Void p) {
aoqi@0 373 header(node);
aoqi@0 374 indent(+1);
aoqi@0 375 print("firstSentence", node.getFirstSentence());
aoqi@0 376 print("body", node.getBody());
aoqi@0 377 print("block tags", node.getBlockTags());
aoqi@0 378 indent(-1);
aoqi@0 379 indent();
aoqi@0 380 out.println("]");
aoqi@0 381 return null;
aoqi@0 382 }
aoqi@0 383
aoqi@0 384 public Void visitDocRoot(DocRootTree node, Void p) {
aoqi@0 385 header(node, "");
aoqi@0 386 return null;
aoqi@0 387 }
aoqi@0 388
aoqi@0 389 public Void visitEndElement(EndElementTree node, Void p) {
aoqi@0 390 header(node, node.getName().toString());
aoqi@0 391 return null;
aoqi@0 392 }
aoqi@0 393
aoqi@0 394 public Void visitEntity(EntityTree node, Void p) {
aoqi@0 395 header(node, node.getName().toString());
aoqi@0 396 return null;
aoqi@0 397 }
aoqi@0 398
aoqi@0 399 public Void visitErroneous(ErroneousTree node, Void p) {
aoqi@0 400 header(node);
aoqi@0 401 indent(+1);
aoqi@0 402 print("code", ((DCErroneous) node).diag.getCode());
aoqi@0 403 print("body", compress(node.getBody()));
aoqi@0 404 indent(-1);
aoqi@0 405 indent();
aoqi@0 406 out.println("]");
aoqi@0 407 return null;
aoqi@0 408 }
aoqi@0 409
aoqi@0 410 public Void visitIdentifier(IdentifierTree node, Void p) {
aoqi@0 411 header(node, compress(node.getName().toString()));
aoqi@0 412 return null;
aoqi@0 413 }
aoqi@0 414
aoqi@0 415 public Void visitInheritDoc(InheritDocTree node, Void p) {
aoqi@0 416 header(node, "");
aoqi@0 417 return null;
aoqi@0 418 }
aoqi@0 419
aoqi@0 420 public Void visitLink(LinkTree node, Void p) {
aoqi@0 421 header(node);
aoqi@0 422 indent(+1);
aoqi@0 423 print("reference", node.getReference());
aoqi@0 424 print("body", node.getLabel());
aoqi@0 425 indent(-1);
aoqi@0 426 indent();
aoqi@0 427 out.println("]");
aoqi@0 428 return null;
aoqi@0 429 }
aoqi@0 430
aoqi@0 431 public Void visitLiteral(LiteralTree node, Void p) {
aoqi@0 432 header(node, compress(node.getBody().getBody()));
aoqi@0 433 return null;
aoqi@0 434 }
aoqi@0 435
aoqi@0 436 public Void visitParam(ParamTree node, Void p) {
aoqi@0 437 header(node);
aoqi@0 438 indent(+1);
aoqi@0 439 print("name", node.getName());
aoqi@0 440 print("description", node.getDescription());
aoqi@0 441 indent(-1);
aoqi@0 442 indent();
aoqi@0 443 out.println("]");
aoqi@0 444 return null;
aoqi@0 445 }
aoqi@0 446
aoqi@0 447 public Void visitReference(ReferenceTree node, Void p) {
aoqi@0 448 header(node, compress(node.getSignature()));
aoqi@0 449 return null;
aoqi@0 450 }
aoqi@0 451
aoqi@0 452 public Void visitReturn(ReturnTree node, Void p) {
aoqi@0 453 header(node);
aoqi@0 454 indent(+1);
aoqi@0 455 print("description", node.getDescription());
aoqi@0 456 indent(-1);
aoqi@0 457 indent();
aoqi@0 458 out.println("]");
aoqi@0 459 return null;
aoqi@0 460 }
aoqi@0 461
aoqi@0 462 public Void visitSee(SeeTree node, Void p) {
aoqi@0 463 header(node);
aoqi@0 464 indent(+1);
aoqi@0 465 print("reference", node.getReference());
aoqi@0 466 indent(-1);
aoqi@0 467 indent();
aoqi@0 468 out.println("]");
aoqi@0 469 return null;
aoqi@0 470 }
aoqi@0 471
aoqi@0 472 public Void visitSerial(SerialTree node, Void p) {
aoqi@0 473 header(node);
aoqi@0 474 indent(+1);
aoqi@0 475 print("description", node.getDescription());
aoqi@0 476 indent(-1);
aoqi@0 477 indent();
aoqi@0 478 out.println("]");
aoqi@0 479 return null;
aoqi@0 480 }
aoqi@0 481
aoqi@0 482 public Void visitSerialData(SerialDataTree node, Void p) {
aoqi@0 483 header(node);
aoqi@0 484 indent(+1);
aoqi@0 485 print("description", node.getDescription());
aoqi@0 486 indent(-1);
aoqi@0 487 indent();
aoqi@0 488 out.println("]");
aoqi@0 489 return null;
aoqi@0 490 }
aoqi@0 491
aoqi@0 492 public Void visitSerialField(SerialFieldTree node, Void p) {
aoqi@0 493 header(node);
aoqi@0 494 indent(+1);
aoqi@0 495 print("name", node.getName());
aoqi@0 496 print("type", node.getType());
aoqi@0 497 print("description", node.getDescription());
aoqi@0 498 indent(-1);
aoqi@0 499 indent();
aoqi@0 500 out.println("]");
aoqi@0 501 return null;
aoqi@0 502 }
aoqi@0 503
aoqi@0 504 public Void visitSince(SinceTree node, Void p) {
aoqi@0 505 header(node);
aoqi@0 506 indent(+1);
aoqi@0 507 print("body", node.getBody());
aoqi@0 508 indent(-1);
aoqi@0 509 indent();
aoqi@0 510 out.println("]");
aoqi@0 511 return null;
aoqi@0 512 }
aoqi@0 513
aoqi@0 514 public Void visitStartElement(StartElementTree node, Void p) {
aoqi@0 515 header(node);
aoqi@0 516 indent(+1);
aoqi@0 517 indent();
aoqi@0 518 out.println("name:" + node.getName());
aoqi@0 519 print("attributes", node.getAttributes());
aoqi@0 520 indent(-1);
aoqi@0 521 indent();
aoqi@0 522 out.println("]");
aoqi@0 523 return null;
aoqi@0 524 }
aoqi@0 525
aoqi@0 526 public Void visitText(TextTree node, Void p) {
aoqi@0 527 header(node, compress(node.getBody()));
aoqi@0 528 return null;
aoqi@0 529 }
aoqi@0 530
aoqi@0 531 public Void visitThrows(ThrowsTree node, Void p) {
aoqi@0 532 header(node);
aoqi@0 533 indent(+1);
aoqi@0 534 print("exceptionName", node.getExceptionName());
aoqi@0 535 print("description", node.getDescription());
aoqi@0 536 indent(-1);
aoqi@0 537 indent();
aoqi@0 538 out.println("]");
aoqi@0 539 return null;
aoqi@0 540 }
aoqi@0 541
aoqi@0 542 public Void visitUnknownBlockTag(UnknownBlockTagTree node, Void p) {
aoqi@0 543 header(node);
aoqi@0 544 indent(+1);
aoqi@0 545 indent();
aoqi@0 546 out.println("tag:" + node.getTagName());
aoqi@0 547 print("content", node.getContent());
aoqi@0 548 indent(-1);
aoqi@0 549 indent();
aoqi@0 550 out.println("]");
aoqi@0 551 return null;
aoqi@0 552 }
aoqi@0 553
aoqi@0 554 public Void visitUnknownInlineTag(UnknownInlineTagTree node, Void p) {
aoqi@0 555 header(node);
aoqi@0 556 indent(+1);
aoqi@0 557 indent();
aoqi@0 558 out.println("tag:" + node.getTagName());
aoqi@0 559 print("content", node.getContent());
aoqi@0 560 indent(-1);
aoqi@0 561 indent();
aoqi@0 562 out.println("]");
aoqi@0 563 return null;
aoqi@0 564 }
aoqi@0 565
aoqi@0 566 public Void visitValue(ValueTree node, Void p) {
aoqi@0 567 header(node);
aoqi@0 568 indent(+1);
aoqi@0 569 print("reference", node.getReference());
aoqi@0 570 indent(-1);
aoqi@0 571 indent();
aoqi@0 572 out.println("]");
aoqi@0 573 return null;
aoqi@0 574 }
aoqi@0 575
aoqi@0 576 public Void visitVersion(VersionTree node, Void p) {
aoqi@0 577 header(node);
aoqi@0 578 indent(+1);
aoqi@0 579 print("body", node.getBody());
aoqi@0 580 indent(-1);
aoqi@0 581 indent();
aoqi@0 582 out.println("]");
aoqi@0 583 return null;
aoqi@0 584 }
aoqi@0 585
aoqi@0 586 public Void visitOther(DocTree node, Void p) {
aoqi@0 587 throw new UnsupportedOperationException("Not supported yet.");
aoqi@0 588 }
aoqi@0 589
aoqi@0 590 void header(DocTree node) {
aoqi@0 591 indent();
aoqi@0 592 out.println(simpleClassName(node) + "[" + node.getKind() + ", pos:" + ((DCTree) node).pos);
aoqi@0 593 }
aoqi@0 594
aoqi@0 595 void header(DocTree node, String rest) {
aoqi@0 596 indent();
aoqi@0 597 out.println(simpleClassName(node) + "[" + node.getKind() + ", pos:" + ((DCTree) node).pos
aoqi@0 598 + (rest.isEmpty() ? "" : ", " + rest)
aoqi@0 599 + "]");
aoqi@0 600 }
aoqi@0 601
aoqi@0 602 String simpleClassName(DocTree node) {
aoqi@0 603 return node.getClass().getSimpleName().replaceAll("DC(.*)", "$1");
aoqi@0 604 }
aoqi@0 605
aoqi@0 606 void print(String name, DocTree item) {
aoqi@0 607 indent();
aoqi@0 608 if (item == null)
aoqi@0 609 out.println(name + ": null");
aoqi@0 610 else {
aoqi@0 611 out.println(name + ":");
aoqi@0 612 indent(+1);
aoqi@0 613 item.accept(this, null);
aoqi@0 614 indent(-1);
aoqi@0 615 }
aoqi@0 616 }
aoqi@0 617
aoqi@0 618 void print(String name, String s) {
aoqi@0 619 indent();
aoqi@0 620 out.println(name + ": " + s);
aoqi@0 621 }
aoqi@0 622
aoqi@0 623 void print(String name, List<? extends DocTree> list) {
aoqi@0 624 indent();
aoqi@0 625 if (list == null)
aoqi@0 626 out.println(name + ": null");
aoqi@0 627 else if (list.isEmpty())
aoqi@0 628 out.println(name + ": empty");
aoqi@0 629 else {
aoqi@0 630 out.println(name + ": " + list.size());
aoqi@0 631 indent(+1);
aoqi@0 632 for (DocTree tree: list) {
aoqi@0 633 tree.accept(this, null);
aoqi@0 634 }
aoqi@0 635 indent(-1);
aoqi@0 636 }
aoqi@0 637 }
aoqi@0 638
aoqi@0 639 int indent = 0;
aoqi@0 640
aoqi@0 641 void indent() {
aoqi@0 642 for (int i = 0; i < indent; i++) {
aoqi@0 643 out.print(" ");
aoqi@0 644 }
aoqi@0 645 }
aoqi@0 646
aoqi@0 647 void indent(int n) {
aoqi@0 648 indent += n;
aoqi@0 649 }
aoqi@0 650
aoqi@0 651 String compress(String s) {
aoqi@0 652 s = s.replace("\n", "|").replace(" ", "_");
aoqi@0 653 return (s.length() < 32)
aoqi@0 654 ? s
aoqi@0 655 : s.substring(0, 16) + "..." + s.substring(16);
aoqi@0 656 }
aoqi@0 657
aoqi@0 658 String quote(String s) {
aoqi@0 659 if (s.contains("\""))
aoqi@0 660 return "'" + s + "'";
aoqi@0 661 else if (s.contains("'") || s.contains(" "))
aoqi@0 662 return '"' + s + '"';
aoqi@0 663 else
aoqi@0 664 return s;
aoqi@0 665 }
aoqi@0 666
aoqi@0 667
aoqi@0 668 }
aoqi@0 669 }
aoqi@0 670
aoqi@0 671 /**
aoqi@0 672 * Verify the reported tree positions by comparing the characters found
aoqi@0 673 * at and after the reported position with the beginning of the pretty-
aoqi@0 674 * printed text.
aoqi@0 675 */
aoqi@0 676 static class PosChecker extends Checker {
aoqi@0 677 PosChecker(DocCommentTester test, DocTrees t) {
aoqi@0 678 test.super(t);
aoqi@0 679 }
aoqi@0 680
aoqi@0 681 @Override
aoqi@0 682 void check(TreePath path, Name name) throws Exception {
aoqi@0 683 JavaFileObject fo = path.getCompilationUnit().getSourceFile();
aoqi@0 684 final CharSequence cs = fo.getCharContent(true);
aoqi@0 685
aoqi@0 686 final DCDocComment dc = (DCDocComment) trees.getDocCommentTree(path);
aoqi@0 687 DCTree t = (DCTree) trees.getDocCommentTree(path);
aoqi@0 688
aoqi@0 689 DocTreeScanner scanner = new DocTreeScanner<Void,Void>() {
aoqi@0 690 @Override
aoqi@0 691 public Void scan(DocTree node, Void ignore) {
aoqi@0 692 if (node != null) {
aoqi@0 693 try {
aoqi@0 694 String expect = getExpectText(node);
aoqi@0 695 long pos = ((DCTree) node).getSourcePosition(dc);
aoqi@0 696 String found = getFoundText(cs, (int) pos, expect.length());
aoqi@0 697 if (!found.equals(expect)) {
aoqi@0 698 System.err.println("expect: " + expect);
aoqi@0 699 System.err.println("found: " + found);
aoqi@0 700 error("mismatch");
aoqi@0 701 }
aoqi@0 702
aoqi@0 703 } catch (StringIndexOutOfBoundsException e) {
aoqi@0 704 error(node.getClass() + ": " + e.toString());
aoqi@0 705 e.printStackTrace();
aoqi@0 706 }
aoqi@0 707 }
aoqi@0 708 return super.scan(node, ignore);
aoqi@0 709 }
aoqi@0 710 };
aoqi@0 711
aoqi@0 712 scanner.scan(t, null);
aoqi@0 713 }
aoqi@0 714
aoqi@0 715 String getExpectText(DocTree t) {
aoqi@0 716 StringWriter sw = new StringWriter();
aoqi@0 717 DocPretty p = new DocPretty(sw);
aoqi@0 718 try { p.print(t); } catch (IOException never) { }
aoqi@0 719 String s = sw.toString();
aoqi@0 720 if (s.length() <= 1)
aoqi@0 721 return s;
aoqi@0 722 int ws = s.replaceAll("\\s+", " ").indexOf(" ");
aoqi@0 723 if (ws != -1) s = s.substring(0, ws);
aoqi@0 724 return (s.length() < 5) ? s : s.substring(0, 5);
aoqi@0 725 }
aoqi@0 726
aoqi@0 727 String getFoundText(CharSequence cs, int pos, int len) {
aoqi@0 728 return (pos == -1) ? "" : cs.subSequence(pos, Math.min(pos + len, cs.length())).toString();
aoqi@0 729 }
aoqi@0 730 }
aoqi@0 731
aoqi@0 732 /**
aoqi@0 733 * Verify the pretty printed text against a normalized form of the
aoqi@0 734 * original doc comment.
aoqi@0 735 */
aoqi@0 736 static class PrettyChecker extends Checker {
aoqi@0 737
aoqi@0 738 PrettyChecker(DocCommentTester test, DocTrees t) {
aoqi@0 739 test.super(t);
aoqi@0 740 }
aoqi@0 741
aoqi@0 742 @Override
aoqi@0 743 void check(TreePath path, Name name) throws Exception {
aoqi@0 744 String raw = trees.getDocComment(path);
aoqi@0 745 String normRaw = normalize(raw);
aoqi@0 746
aoqi@0 747 StringWriter out = new StringWriter();
aoqi@0 748 DocPretty dp = new DocPretty(out);
aoqi@0 749 dp.print(trees.getDocCommentTree(path));
aoqi@0 750 String pretty = out.toString();
aoqi@0 751
aoqi@0 752 if (!pretty.equals(normRaw)) {
aoqi@0 753 error("mismatch");
aoqi@0 754 System.err.println("*** expected:");
aoqi@0 755 System.err.println(normRaw.replace(" ", "_"));
aoqi@0 756 System.err.println("*** found:");
aoqi@0 757 System.err.println(pretty.replace(" ", "_"));
aoqi@0 758 // throw new Error();
aoqi@0 759 }
aoqi@0 760 }
aoqi@0 761
aoqi@0 762 /**
aoqi@0 763 * Normalize white space in places where the tree does not preserve it.
aoqi@0 764 */
aoqi@0 765 String normalize(String s) {
aoqi@0 766 return s.trim()
aoqi@0 767 .replaceFirst("\\.\\s++([^@])", ". $1")
aoqi@0 768 .replaceFirst("\\.\\s*\\n *@", ".\n@")
aoqi@0 769 .replaceFirst("\\s+<(/?p|pre|h[1-6])>", " <$1>")
aoqi@0 770 .replaceAll("\\{@docRoot\\s+\\}", "{@docRoot}")
aoqi@0 771 .replaceAll("\\{@inheritDoc\\s+\\}", "{@inheritDoc}")
aoqi@0 772 .replaceAll("(\\{@value\\s+[^}]+)\\s+(\\})", "$1$2")
aoqi@0 773 .replaceAll("\n[ \t]+@", "\n@");
aoqi@0 774 }
aoqi@0 775
aoqi@0 776 }
aoqi@0 777
aoqi@0 778 }
aoqi@0 779

mercurial