test/tools/javac/doctree/DocCommentTester.java

Wed, 13 Aug 2014 14:50:00 -0700

author
katleman
date
Wed, 13 Aug 2014 14:50:00 -0700
changeset 2549
0b6cc4ea670f
parent 1419
a25c53e12bd0
child 2525
2eb010b6cb22
permissions
-rw-r--r--

Added tag jdk8u40-b01 for changeset bf89a471779d

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

mercurial