1 /*
   2  * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 /*
  25  * @test
  26  * @bug 7073631 7159445 7156633 8028235 8065753 8205418 8205913
  27  * @summary tests error and diagnostics positions
  28  * @author  Jan Lahoda
  29  * @modules jdk.compiler/com.sun.tools.javac.api
  30  *          jdk.compiler/com.sun.tools.javac.main
  31  *          jdk.compiler/com.sun.tools.javac.tree
  32  */
  33 
  34 import com.sun.source.tree.BinaryTree;
  35 import com.sun.source.tree.BlockTree;
  36 import com.sun.source.tree.ClassTree;
  37 import com.sun.source.tree.CompilationUnitTree;
  38 import com.sun.source.tree.ErroneousTree;
  39 import com.sun.source.tree.ExpressionStatementTree;
  40 import com.sun.source.tree.ExpressionTree;
  41 import com.sun.source.tree.IfTree;
  42 import com.sun.source.tree.LambdaExpressionTree;
  43 import com.sun.source.tree.MethodInvocationTree;
  44 import com.sun.source.tree.MethodTree;
  45 import com.sun.source.tree.ModifiersTree;
  46 import com.sun.source.tree.PrimitiveTypeTree;
  47 import com.sun.source.tree.StatementTree;
  48 import com.sun.source.tree.Tree;
  49 import com.sun.source.tree.Tree.Kind;
  50 import com.sun.source.tree.VariableTree;
  51 import com.sun.source.tree.WhileLoopTree;
  52 import com.sun.source.util.JavacTask;
  53 import com.sun.source.util.SourcePositions;
  54 import com.sun.source.util.TreePath;
  55 import com.sun.source.util.TreePathScanner;
  56 import com.sun.source.util.TreeScanner;
  57 import com.sun.source.util.Trees;
  58 import com.sun.tools.javac.api.JavacTaskImpl;
  59 import com.sun.tools.javac.main.Main;
  60 import com.sun.tools.javac.main.Main.Result;
  61 import com.sun.tools.javac.tree.JCTree;
  62 import java.io.IOException;
  63 import java.io.StringWriter;
  64 import java.lang.annotation.ElementType;
  65 import java.lang.annotation.Retention;
  66 import java.lang.annotation.RetentionPolicy;
  67 import java.lang.annotation.Target;
  68 import java.lang.reflect.Method;
  69 import java.net.URI;
  70 import java.util.ArrayList;
  71 import java.util.Arrays;
  72 import java.util.LinkedList;
  73 import java.util.List;
  74 import java.util.regex.Pattern;
  75 import javax.lang.model.type.TypeKind;
  76 import javax.tools.Diagnostic;
  77 import javax.tools.DiagnosticCollector;
  78 import javax.tools.DiagnosticListener;
  79 import javax.tools.JavaCompiler;
  80 import javax.tools.JavaFileManager;
  81 import javax.tools.JavaFileObject;
  82 import javax.tools.SimpleJavaFileObject;
  83 import javax.tools.ToolProvider;
  84 
  85 import com.sun.source.tree.CaseTree;
  86 import com.sun.source.util.TreePathScanner;
  87 
  88 public class JavacParserTest extends TestCase {
  89     static final JavaCompiler tool = ToolProvider.getSystemJavaCompiler();
  90     static final JavaFileManager fm = tool.getStandardFileManager(null, null, null);
  91     public static final String SOURCE_VERSION =
  92         Integer.toString(Runtime.version().feature());
  93 
  94     private JavacParserTest(){}
  95 
  96     public static void main(String... args) throws Exception {
  97         try (fm) {
  98             new JavacParserTest().run(args);
  99         }
 100     }
 101 
 102     class MyFileObject extends SimpleJavaFileObject {
 103 
 104         private String text;
 105 
 106         public MyFileObject(String text) {
 107             super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
 108             this.text = text;
 109         }
 110 
 111         @Override
 112         public CharSequence getCharContent(boolean ignoreEncodingErrors) {
 113             return text;
 114         }
 115     }
 116     /*
 117      * converts Windows to Unix style LFs for comparing strings
 118      */
 119     String normalize(String in) {
 120         return in.replace(System.getProperty("line.separator"), "\n");
 121     }
 122 
 123     CompilationUnitTree getCompilationUnitTree(String code) throws IOException {
 124 
 125         JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, null, null,
 126                 null, Arrays.asList(new MyFileObject(code)));
 127         CompilationUnitTree cut = ct.parse().iterator().next();
 128         return cut;
 129     }
 130 
 131     List<String> getErroneousTreeValues(ErroneousTree node) {
 132 
 133         List<String> values = new ArrayList<>();
 134         if (node.getErrorTrees() != null) {
 135             for (Tree t : node.getErrorTrees()) {
 136                 values.add(t.toString());
 137             }
 138         } else {
 139             throw new RuntimeException("ERROR: No Erroneous tree "
 140                     + "has been created.");
 141         }
 142         return values;
 143     }
 144 
 145     @Test
 146     void testPositionForSuperConstructorCalls() throws IOException {
 147         assert tool != null;
 148 
 149         String code = "package test; public class Test {public Test() {super();}}";
 150 
 151         JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, null, null,
 152                 null, Arrays.asList(new MyFileObject(code)));
 153         CompilationUnitTree cut = ct.parse().iterator().next();
 154         SourcePositions pos = Trees.instance(ct).getSourcePositions();
 155 
 156         MethodTree method =
 157                 (MethodTree) ((ClassTree) cut.getTypeDecls().get(0)).getMembers().get(0);
 158         ExpressionStatementTree es =
 159                 (ExpressionStatementTree) method.getBody().getStatements().get(0);
 160 
 161         final int esStartPos = code.indexOf(es.toString());
 162         final int esEndPos = esStartPos + es.toString().length();
 163         assertEquals("testPositionForSuperConstructorCalls",
 164                 esStartPos, pos.getStartPosition(cut, es));
 165         assertEquals("testPositionForSuperConstructorCalls",
 166                 esEndPos, pos.getEndPosition(cut, es));
 167 
 168         MethodInvocationTree mit = (MethodInvocationTree) es.getExpression();
 169 
 170         final int mitStartPos = code.indexOf(mit.toString());
 171         final int mitEndPos = mitStartPos + mit.toString().length();
 172         assertEquals("testPositionForSuperConstructorCalls",
 173                 mitStartPos, pos.getStartPosition(cut, mit));
 174         assertEquals("testPositionForSuperConstructorCalls",
 175                 mitEndPos, pos.getEndPosition(cut, mit));
 176 
 177         final int methodStartPos = mitStartPos;
 178         final int methodEndPos = methodStartPos + mit.getMethodSelect().toString().length();
 179         assertEquals("testPositionForSuperConstructorCalls",
 180                 methodStartPos, pos.getStartPosition(cut, mit.getMethodSelect()));
 181         assertEquals("testPositionForSuperConstructorCalls",
 182                 methodEndPos, pos.getEndPosition(cut, mit.getMethodSelect()));
 183     }
 184 
 185     @Test
 186     void testPositionForEnumModifiers() throws IOException {
 187         final String theString = "public";
 188         String code = "package test; " + theString + " enum Test {A;}";
 189 
 190         JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, null, null,
 191                 null, Arrays.asList(new MyFileObject(code)));
 192         CompilationUnitTree cut = ct.parse().iterator().next();
 193         SourcePositions pos = Trees.instance(ct).getSourcePositions();
 194 
 195         ClassTree clazz = (ClassTree) cut.getTypeDecls().get(0);
 196         ModifiersTree mt = clazz.getModifiers();
 197         int spos = code.indexOf(theString);
 198         int epos = spos + theString.length();
 199         assertEquals("testPositionForEnumModifiers",
 200                 spos, pos.getStartPosition(cut, mt));
 201         assertEquals("testPositionForEnumModifiers",
 202                 epos, pos.getEndPosition(cut, mt));
 203     }
 204 
 205     @Test
 206     void testNewClassWithEnclosing() throws IOException {
 207 
 208         final String theString = "Test.this.new d()";
 209         String code = "package test; class Test { " +
 210                 "class d {} private void method() { " +
 211                 "Object o = " + theString + "; } }";
 212 
 213         JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, null, null,
 214                 null, Arrays.asList(new MyFileObject(code)));
 215         CompilationUnitTree cut = ct.parse().iterator().next();
 216         SourcePositions pos = Trees.instance(ct).getSourcePositions();
 217 
 218         ClassTree clazz = (ClassTree) cut.getTypeDecls().get(0);
 219         ExpressionTree est =
 220                 ((VariableTree) ((MethodTree) clazz.getMembers().get(1)).getBody().getStatements().get(0)).getInitializer();
 221 
 222         final int spos = code.indexOf(theString);
 223         final int epos = spos + theString.length();
 224         assertEquals("testNewClassWithEnclosing",
 225                 spos, pos.getStartPosition(cut, est));
 226         assertEquals("testNewClassWithEnclosing",
 227                 epos, pos.getEndPosition(cut, est));
 228     }
 229 
 230     @Test
 231     void testPreferredPositionForBinaryOp() throws IOException {
 232 
 233         String code = "package test; public class Test {"
 234                 + "private void test() {"
 235                 + "Object o = null; boolean b = o != null && o instanceof String;"
 236                 + "} private Test() {}}";
 237 
 238         CompilationUnitTree cut = getCompilationUnitTree(code);
 239         ClassTree clazz = (ClassTree) cut.getTypeDecls().get(0);
 240         MethodTree method = (MethodTree) clazz.getMembers().get(0);
 241         VariableTree condSt = (VariableTree) method.getBody().getStatements().get(1);
 242         BinaryTree cond = (BinaryTree) condSt.getInitializer();
 243 
 244         JCTree condJC = (JCTree) cond;
 245         int condStartPos = code.indexOf("&&");
 246         assertEquals("testPreferredPositionForBinaryOp",
 247                 condStartPos, condJC.pos);
 248     }
 249 
 250     @Test
 251     void testErrorRecoveryForEnhancedForLoop142381() throws IOException {
 252 
 253         String code = "package test; class Test { " +
 254                 "private void method() { " +
 255                 "java.util.Set<String> s = null; for (a : s) {} } }";
 256 
 257         final List<Diagnostic<? extends JavaFileObject>> errors =
 258                 new LinkedList<Diagnostic<? extends JavaFileObject>>();
 259 
 260         JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm,
 261                 new DiagnosticListener<JavaFileObject>() {
 262             public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
 263                 errors.add(diagnostic);
 264             }
 265         }, null, null, Arrays.asList(new MyFileObject(code)));
 266 
 267         CompilationUnitTree cut = ct.parse().iterator().next();
 268 
 269         ClassTree clazz = (ClassTree) cut.getTypeDecls().get(0);
 270         StatementTree forStatement =
 271                 ((MethodTree) clazz.getMembers().get(0)).getBody().getStatements().get(1);
 272 
 273         assertEquals("testErrorRecoveryForEnhancedForLoop142381",
 274                 Kind.ENHANCED_FOR_LOOP, forStatement.getKind());
 275         assertFalse("testErrorRecoveryForEnhancedForLoop142381", errors.isEmpty());
 276     }
 277 
 278     @Test
 279     void testPositionAnnotationNoPackage187551() throws IOException {
 280 
 281         String code = "\n@interface Test {}";
 282 
 283         JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, null, null,
 284                 null, Arrays.asList(new MyFileObject(code)));
 285 
 286         CompilationUnitTree cut = ct.parse().iterator().next();
 287         ClassTree clazz = (ClassTree) cut.getTypeDecls().get(0);
 288         Trees t = Trees.instance(ct);
 289 
 290         assertEquals("testPositionAnnotationNoPackage187551",
 291                 1, t.getSourcePositions().getStartPosition(cut, clazz));
 292     }
 293 
 294     @Test
 295     void testPositionMissingStatement() throws IOException {
 296         String code = "class C { void t() { if (true) } }";
 297         DiagnosticCollector<JavaFileObject> dc = new DiagnosticCollector<>();
 298 
 299         JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, dc, null,
 300                 null, Arrays.asList(new MyFileObject(code)));
 301 
 302         CompilationUnitTree cut = ct.parse().iterator().next();
 303         Trees trees = Trees.instance(ct);
 304         SourcePositions positions = trees.getSourcePositions();
 305 
 306         new TreeScanner<Void, Void>() {
 307             @Override
 308             public Void visitIf(IfTree it, Void v) {
 309                 StatementTree st = it.getThenStatement();
 310                 int startpos = (int) positions.getStartPosition(cut, st);
 311                 int endpos = (int) positions.getEndPosition(cut, st);
 312                 assertEquals("testPositionMissingStatement.execpos", startpos, endpos);
 313                 assertEquals("testPositionMissingStatement.execkind",
 314                              Kind.EXPRESSION_STATEMENT,
 315                              st.getKind());
 316                 Tree err = ((ExpressionStatementTree) st).getExpression();
 317                 startpos = (int) positions.getStartPosition(cut, err);
 318                 endpos = (int) positions.getEndPosition(cut, err);
 319                 assertEquals("testPositionMissingStatement.errpos", startpos, endpos);
 320                 assertEquals("testPositionMissingStatement.errkind",
 321                              Kind.ERRONEOUS,
 322                              err.getKind());
 323                 return super.visitIf(it, v);
 324             }
 325         }.scan(cut, null);
 326 
 327         assertEquals("testPositionMissingStatement.diags", 1, dc.getDiagnostics().size());
 328         Diagnostic<? extends JavaFileObject> d = dc.getDiagnostics().get(0);
 329         int startpos = (int) d.getStartPosition();
 330         int pos = (int) d.getPosition();
 331         int endpos = (int) d.getEndPosition();
 332         assertEquals("testPositionMissingStatement.diagspan", startpos, endpos);
 333         assertEquals("testPositionMissingStatement.diagpref", startpos, pos);
 334     }
 335 
 336     @Test
 337     void testPositionsSane1() throws IOException {
 338         performPositionsSanityTest("package test; class Test { " +
 339                 "private void method() { " +
 340                 "java.util.List<? extends java.util.List<? extends String>> l; " +
 341                 "} }");
 342     }
 343 
 344     @Test
 345     void testPositionsSane2() throws IOException {
 346         performPositionsSanityTest("package test; class Test { " +
 347                 "private void method() { " +
 348                 "java.util.List<? super java.util.List<? super String>> l; " +
 349                 "} }");
 350     }
 351 
 352     @Test
 353     void testPositionsSane3() throws IOException {
 354         performPositionsSanityTest("package test; class Test { " +
 355                 "private void method() { " +
 356                 "java.util.List<? super java.util.List<?>> l; } }");
 357     }
 358 
 359     private void performPositionsSanityTest(String code) throws IOException {
 360 
 361         final List<Diagnostic<? extends JavaFileObject>> errors =
 362                 new LinkedList<Diagnostic<? extends JavaFileObject>>();
 363 
 364         JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm,
 365                 new DiagnosticListener<JavaFileObject>() {
 366 
 367             public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
 368                 errors.add(diagnostic);
 369             }
 370         }, null, null, Arrays.asList(new MyFileObject(code)));
 371 
 372         final CompilationUnitTree cut = ct.parse().iterator().next();
 373         final Trees trees = Trees.instance(ct);
 374 
 375         new TreeScanner<Void, Void>() {
 376 
 377             private long parentStart = 0;
 378             private long parentEnd = Integer.MAX_VALUE;
 379 
 380             @Override
 381             public Void scan(Tree node, Void p) {
 382                 if (node == null) {
 383                     return null;
 384                 }
 385 
 386                 long start = trees.getSourcePositions().getStartPosition(cut, node);
 387 
 388                 if (start == (-1)) {
 389                     return null; // synthetic tree
 390                 }
 391                 assertTrue(node.toString() + ":" + start + "/" + parentStart,
 392                         parentStart <= start);
 393 
 394                 long prevParentStart = parentStart;
 395 
 396                 parentStart = start;
 397 
 398                 long end = trees.getSourcePositions().getEndPosition(cut, node);
 399 
 400                 assertTrue(node.toString() + ":" + end + "/" + parentEnd,
 401                         end <= parentEnd);
 402 
 403                 long prevParentEnd = parentEnd;
 404 
 405                 parentEnd = end;
 406 
 407                 super.scan(node, p);
 408 
 409                 parentStart = prevParentStart;
 410                 parentEnd = prevParentEnd;
 411 
 412                 return null;
 413             }
 414 
 415             private void assertTrue(String message, boolean b) {
 416                 if (!b) fail(message);
 417             }
 418         }.scan(cut, null);
 419     }
 420 
 421     @Test
 422     void testCorrectWildcardPositions1() throws IOException {
 423         performWildcardPositionsTest("package test; import java.util.List; " +
 424                 "class Test { private void method() { List<? extends List<? extends String>> l; } }",
 425 
 426                 Arrays.asList("List<? extends List<? extends String>> l;",
 427                 "List<? extends List<? extends String>>",
 428                 "List",
 429                 "? extends List<? extends String>",
 430                 "List<? extends String>",
 431                 "List",
 432                 "? extends String",
 433                 "String"));
 434     }
 435 
 436     @Test
 437     void testCorrectWildcardPositions2() throws IOException {
 438         performWildcardPositionsTest("package test; import java.util.List; "
 439                 + "class Test { private void method() { List<? super List<? super String>> l; } }",
 440                 Arrays.asList("List<? super List<? super String>> l;",
 441                 "List<? super List<? super String>>",
 442                 "List",
 443                 "? super List<? super String>",
 444                 "List<? super String>",
 445                 "List",
 446                 "? super String",
 447                 "String"));
 448     }
 449 
 450     @Test
 451     void testCorrectWildcardPositions3() throws IOException {
 452         performWildcardPositionsTest("package test; import java.util.List; " +
 453                 "class Test { private void method() { List<? super List<?>> l; } }",
 454 
 455                 Arrays.asList("List<? super List<?>> l;",
 456                 "List<? super List<?>>",
 457                 "List",
 458                 "? super List<?>",
 459                 "List<?>",
 460                 "List",
 461                 "?"));
 462     }
 463 
 464     @Test
 465     void testCorrectWildcardPositions4() throws IOException {
 466         performWildcardPositionsTest("package test; import java.util.List; " +
 467                 "class Test { private void method() { " +
 468                 "List<? extends List<? extends List<? extends String>>> l; } }",
 469 
 470                 Arrays.asList("List<? extends List<? extends List<? extends String>>> l;",
 471                 "List<? extends List<? extends List<? extends String>>>",
 472                 "List",
 473                 "? extends List<? extends List<? extends String>>",
 474                 "List<? extends List<? extends String>>",
 475                 "List",
 476                 "? extends List<? extends String>",
 477                 "List<? extends String>",
 478                 "List",
 479                 "? extends String",
 480                 "String"));
 481     }
 482 
 483     @Test
 484     void testCorrectWildcardPositions5() throws IOException {
 485         performWildcardPositionsTest("package test; import java.util.List; " +
 486                 "class Test { private void method() { " +
 487                 "List<? extends List<? extends List<? extends String   >>> l; } }",
 488                 Arrays.asList("List<? extends List<? extends List<? extends String   >>> l;",
 489                 "List<? extends List<? extends List<? extends String   >>>",
 490                 "List",
 491                 "? extends List<? extends List<? extends String   >>",
 492                 "List<? extends List<? extends String   >>",
 493                 "List",
 494                 "? extends List<? extends String   >",
 495                 "List<? extends String   >",
 496                 "List",
 497                 "? extends String",
 498                 "String"));
 499     }
 500 
 501     void performWildcardPositionsTest(final String code,
 502             List<String> golden) throws IOException {
 503 
 504         final List<Diagnostic<? extends JavaFileObject>> errors =
 505                 new LinkedList<Diagnostic<? extends JavaFileObject>>();
 506 
 507         JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm,
 508                 new DiagnosticListener<JavaFileObject>() {
 509                     public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
 510                         errors.add(diagnostic);
 511                     }
 512                 }, null, null, Arrays.asList(new MyFileObject(code)));
 513 
 514         final CompilationUnitTree cut = ct.parse().iterator().next();
 515         final List<String> content = new LinkedList<String>();
 516         final Trees trees = Trees.instance(ct);
 517 
 518         new TreeScanner<Void, Void>() {
 519             @Override
 520             public Void scan(Tree node, Void p) {
 521                 if (node == null) {
 522                     return null;
 523                 }
 524                 long start = trees.getSourcePositions().getStartPosition(cut, node);
 525 
 526                 if (start == (-1)) {
 527                     return null; // synthetic tree
 528                 }
 529                 long end = trees.getSourcePositions().getEndPosition(cut, node);
 530                 String s = code.substring((int) start, (int) end);
 531                 content.add(s);
 532 
 533                 return super.scan(node, p);
 534             }
 535         }.scan(((MethodTree) ((ClassTree) cut.getTypeDecls().get(0)).getMembers().get(0)).getBody().getStatements().get(0), null);
 536 
 537         assertEquals("performWildcardPositionsTest",golden.toString(),
 538                 content.toString());
 539     }
 540 
 541     @Test
 542     void testStartPositionForMethodWithoutModifiers() throws IOException {
 543 
 544         String code = "package t; class Test { <T> void t() {} }";
 545 
 546         JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, null, null,
 547                 null, Arrays.asList(new MyFileObject(code)));
 548         CompilationUnitTree cut = ct.parse().iterator().next();
 549         ClassTree clazz = (ClassTree) cut.getTypeDecls().get(0);
 550         MethodTree mt = (MethodTree) clazz.getMembers().get(0);
 551         Trees t = Trees.instance(ct);
 552         int start = (int) t.getSourcePositions().getStartPosition(cut, mt);
 553         int end = (int) t.getSourcePositions().getEndPosition(cut, mt);
 554 
 555         assertEquals("testStartPositionForMethodWithoutModifiers",
 556                 "<T> void t() {}", code.substring(start, end));
 557     }
 558 
 559     @Test
 560     void testVariableInIfThen1() throws IOException {
 561 
 562         String code = "package t; class Test { " +
 563                 "private static void t(String name) { " +
 564                 "if (name != null) String nn = name.trim(); } }";
 565 
 566         DiagnosticCollector<JavaFileObject> coll =
 567                 new DiagnosticCollector<JavaFileObject>();
 568 
 569         JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, coll, null,
 570                 null, Arrays.asList(new MyFileObject(code)));
 571 
 572         ct.parse();
 573 
 574         List<String> codes = new LinkedList<String>();
 575 
 576         for (Diagnostic<? extends JavaFileObject> d : coll.getDiagnostics()) {
 577             codes.add(d.getCode());
 578         }
 579 
 580         assertEquals("testVariableInIfThen1",
 581                 Arrays.<String>asList("compiler.err.variable.not.allowed"),
 582                 codes);
 583     }
 584 
 585     @Test
 586    void testVariableInIfThen2() throws IOException {
 587 
 588         String code = "package t; class Test { " +
 589                 "private static void t(String name) { " +
 590                 "if (name != null) class X {} } }";
 591         DiagnosticCollector<JavaFileObject> coll =
 592                 new DiagnosticCollector<JavaFileObject>();
 593         JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, coll, null,
 594                 null, Arrays.asList(new MyFileObject(code)));
 595 
 596         ct.parse();
 597 
 598         List<String> codes = new LinkedList<String>();
 599 
 600         for (Diagnostic<? extends JavaFileObject> d : coll.getDiagnostics()) {
 601             codes.add(d.getCode());
 602         }
 603 
 604         assertEquals("testVariableInIfThen2",
 605                 Arrays.<String>asList("compiler.err.class.not.allowed"), codes);
 606     }
 607 
 608     @Test
 609     void testVariableInIfThen3() throws IOException {
 610 
 611         String code = "package t; class Test { "+
 612                 "private static void t() { " +
 613                 "if (true) abstract class F {} }}";
 614         DiagnosticCollector<JavaFileObject> coll =
 615                 new DiagnosticCollector<JavaFileObject>();
 616         JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, coll, null,
 617                 null, Arrays.asList(new MyFileObject(code)));
 618 
 619         ct.parse();
 620 
 621         List<String> codes = new LinkedList<String>();
 622 
 623         for (Diagnostic<? extends JavaFileObject> d : coll.getDiagnostics()) {
 624             codes.add(d.getCode());
 625         }
 626 
 627         assertEquals("testVariableInIfThen3",
 628                 Arrays.<String>asList("compiler.err.class.not.allowed"), codes);
 629     }
 630 
 631     @Test
 632     void testVariableInIfThen4() throws IOException {
 633 
 634         String code = "package t; class Test { "+
 635                 "private static void t(String name) { " +
 636                 "if (name != null) interface X {} } }";
 637         DiagnosticCollector<JavaFileObject> coll =
 638                 new DiagnosticCollector<JavaFileObject>();
 639         JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, coll, null,
 640                 null, Arrays.asList(new MyFileObject(code)));
 641 
 642         ct.parse();
 643 
 644         List<String> codes = new LinkedList<String>();
 645 
 646         for (Diagnostic<? extends JavaFileObject> d : coll.getDiagnostics()) {
 647             codes.add(d.getCode());
 648         }
 649 
 650         assertEquals("testVariableInIfThen4",
 651                 Arrays.<String>asList("compiler.err.class.not.allowed"), codes);
 652     }
 653 
 654     @Test
 655     void testVariableInIfThen5() throws IOException {
 656 
 657         String code = "package t; class Test { "+
 658                 "private static void t() { " +
 659                 "if (true) } }";
 660         DiagnosticCollector<JavaFileObject> coll =
 661                 new DiagnosticCollector<JavaFileObject>();
 662         JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, coll, null,
 663                 null, Arrays.asList(new MyFileObject(code)));
 664 
 665         ct.parse();
 666 
 667         List<String> codes = new LinkedList<String>();
 668 
 669         for (Diagnostic<? extends JavaFileObject> d : coll.getDiagnostics()) {
 670             codes.add(d.getCode());
 671         }
 672 
 673         assertEquals("testVariableInIfThen5",
 674                 Arrays.<String>asList("compiler.err.illegal.start.of.stmt"),
 675                 codes);
 676     }
 677 
 678     // see javac bug #6882235, NB bug #98234:
 679     @Test
 680     void testMissingExponent() throws IOException {
 681 
 682         String code = "\nclass Test { { System.err.println(0e); } }";
 683 
 684         JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, null, null,
 685                 null, Arrays.asList(new MyFileObject(code)));
 686 
 687         assertNotNull(ct.parse().iterator().next());
 688     }
 689 
 690     @Test
 691     void testTryResourcePos() throws IOException {
 692 
 693         final String code = "package t; class Test { " +
 694                 "{ try (java.io.InputStream in = null) { } } }";
 695 
 696         CompilationUnitTree cut = getCompilationUnitTree(code);
 697 
 698         new TreeScanner<Void, Void>() {
 699             @Override
 700             public Void visitVariable(VariableTree node, Void p) {
 701                 if ("in".contentEquals(node.getName())) {
 702                     JCTree.JCVariableDecl var = (JCTree.JCVariableDecl) node;
 703                     assertEquals("testTryResourcePos", "in = null) { } } }",
 704                             code.substring(var.pos));
 705                 }
 706                 return super.visitVariable(node, p);
 707             }
 708         }.scan(cut, null);
 709     }
 710 
 711     @Test
 712     void testVarPos() throws IOException {
 713 
 714         final String code = "package t; class Test { " +
 715                 "{ java.io.InputStream in = null; } }";
 716 
 717         CompilationUnitTree cut = getCompilationUnitTree(code);
 718 
 719         new TreeScanner<Void, Void>() {
 720 
 721             @Override
 722             public Void visitVariable(VariableTree node, Void p) {
 723                 if ("in".contentEquals(node.getName())) {
 724                     JCTree.JCVariableDecl var = (JCTree.JCVariableDecl) node;
 725                     assertEquals("testVarPos","in = null; } }",
 726                             code.substring(var.pos));
 727                 }
 728                 return super.visitVariable(node, p);
 729             }
 730         }.scan(cut, null);
 731     }
 732 
 733     // expected erroneous tree: int x = y;(ERROR);
 734     @Test
 735     void testOperatorMissingError() throws IOException {
 736 
 737         String code = "package test; public class ErrorTest { "
 738                 + "void method() { int x = y  z } }";
 739         CompilationUnitTree cut = getCompilationUnitTree(code);
 740         final List<String> values = new ArrayList<>();
 741         final List<String> expectedValues =
 742                 new ArrayList<>(Arrays.asList("[z]"));
 743 
 744         new TreeScanner<Void, Void>() {
 745             @Override
 746             public Void visitErroneous(ErroneousTree node, Void p) {
 747                 values.add(getErroneousTreeValues(node).toString());
 748                 return null;
 749 
 750             }
 751         }.scan(cut, null);
 752 
 753         assertEquals("testOperatorMissingError: The Erroneous tree "
 754                 + "error values: " + values
 755                 + " do not match expected error values: "
 756                 + expectedValues, values, expectedValues);
 757     }
 758 
 759     // expected erroneous tree:  String s = (ERROR);
 760     @Test
 761     void testMissingParenthesisError() throws IOException {
 762 
 763         String code = "package test; public class ErrorTest { "
 764                 + "void f() {String s = new String; } }";
 765         CompilationUnitTree cut = getCompilationUnitTree(code);
 766         final List<String> values = new ArrayList<>();
 767         final List<String> expectedValues =
 768                 new ArrayList<>(Arrays.asList("[new String()]"));
 769 
 770         new TreeScanner<Void, Void>() {
 771             @Override
 772             public Void visitErroneous(ErroneousTree node, Void p) {
 773                 values.add(getErroneousTreeValues(node).toString());
 774                 return null;
 775             }
 776         }.scan(cut, null);
 777 
 778         assertEquals("testMissingParenthesisError: The Erroneous tree "
 779                 + "error values: " + values
 780                 + " do not match expected error values: "
 781                 + expectedValues, values, expectedValues);
 782     }
 783 
 784     // expected erroneous tree: package test; (ERROR)(ERROR)
 785     @Test
 786     void testMissingClassError() throws IOException {
 787 
 788         String code = "package Test; clas ErrorTest {  "
 789                 + "void f() {String s = new String(); } }";
 790         CompilationUnitTree cut = getCompilationUnitTree(code);
 791         final List<String> values = new ArrayList<>();
 792         final List<String> expectedValues =
 793                 new ArrayList<>(Arrays.asList("[, clas]", "[]"));
 794 
 795         new TreeScanner<Void, Void>() {
 796             @Override
 797             public Void visitErroneous(ErroneousTree node, Void p) {
 798                 values.add(getErroneousTreeValues(node).toString());
 799                 return null;
 800             }
 801         }.scan(cut, null);
 802 
 803         assertEquals("testMissingClassError: The Erroneous tree "
 804                 + "error values: " + values
 805                 + " do not match expected error values: "
 806                 + expectedValues, values, expectedValues);
 807     }
 808 
 809     // expected erroneous tree: void m1(int i) {(ERROR);{(ERROR);}
 810     @Test
 811     void testSwitchError() throws IOException {
 812 
 813         String code = "package test; public class ErrorTest { "
 814                 + "int numDays; void m1(int i) { switchh {i} { case 1: "
 815                 + "numDays = 31; break; } } }";
 816         CompilationUnitTree cut = getCompilationUnitTree(code);
 817         final List<String> values = new ArrayList<>();
 818         final List<String> expectedValues =
 819                 new ArrayList<>(Arrays.asList("[switchh]", "[i]"));
 820 
 821         new TreeScanner<Void, Void>() {
 822             @Override
 823             public Void visitErroneous(ErroneousTree node, Void p) {
 824                 values.add(getErroneousTreeValues(node).toString());
 825                 return null;
 826             }
 827         }.scan(cut, null);
 828 
 829         assertEquals("testSwitchError: The Erroneous tree "
 830                 + "error values: " + values
 831                 + " do not match expected error values: "
 832                 + expectedValues, values, expectedValues);
 833     }
 834 
 835     // expected erroneous tree: class ErrorTest {(ERROR)
 836     @Test
 837     void testMethodError() throws IOException {
 838 
 839         String code = "package Test; class ErrorTest {  "
 840                 + "static final void f) {String s = new String(); } }";
 841         CompilationUnitTree cut = cut = getCompilationUnitTree(code);
 842 
 843         final List<String> values = new ArrayList<>();
 844         final List<String> expectedValues =
 845                 new ArrayList<>(Arrays.asList("[\nstatic final void f();]"));
 846 
 847         new TreeScanner<Void, Void>() {
 848             @Override
 849             public Void visitErroneous(ErroneousTree node, Void p) {
 850                 values.add(normalize(getErroneousTreeValues(node).toString()));
 851                 return null;
 852             }
 853         }.scan(cut, null);
 854 
 855         assertEquals("testMethodError: The Erroneous tree "
 856                 + "error value: " + values
 857                 + " does not match expected error values: "
 858                 + expectedValues, values, expectedValues);
 859     }
 860 
 861     /*
 862      * The following tests do not work just yet with nb-javac nor javac,
 863      * they need further investigation, see CR: 7167356
 864      */
 865 
 866     void testPositionBrokenSource126732a() throws IOException {
 867         String[] commands = new String[]{
 868             "return Runnable()",
 869             "do { } while (true)",
 870             "throw UnsupportedOperationException()",
 871             "assert true",
 872             "1 + 1",};
 873 
 874         for (String command : commands) {
 875 
 876             String code = "package test;\n"
 877                     + "public class Test {\n"
 878                     + "    public static void test() {\n"
 879                     + "        " + command + " {\n"
 880                     + "                new Runnable() {\n"
 881                     + "        };\n"
 882                     + "    }\n"
 883                     + "}";
 884             JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, null,
 885                     null, null, Arrays.asList(new MyFileObject(code)));
 886             CompilationUnitTree cut = ct.parse().iterator().next();
 887 
 888             ClassTree clazz = (ClassTree) cut.getTypeDecls().get(0);
 889             MethodTree method = (MethodTree) clazz.getMembers().get(0);
 890             List<? extends StatementTree> statements =
 891                     method.getBody().getStatements();
 892 
 893             StatementTree ret = statements.get(0);
 894             StatementTree block = statements.get(1);
 895 
 896             Trees t = Trees.instance(ct);
 897             int len = code.indexOf(command + " {") + (command + " ").length();
 898             assertEquals(command, len,
 899                     t.getSourcePositions().getEndPosition(cut, ret));
 900             assertEquals(command, len,
 901                     t.getSourcePositions().getStartPosition(cut, block));
 902         }
 903     }
 904 
 905     void testPositionBrokenSource126732b() throws IOException {
 906         String[] commands = new String[]{
 907             "break",
 908             "break A",
 909             "continue ",
 910             "continue A",};
 911 
 912         for (String command : commands) {
 913 
 914             String code = "package test;\n"
 915                     + "public class Test {\n"
 916                     + "    public static void test() {\n"
 917                     + "        while (true) {\n"
 918                     + "            " + command + " {\n"
 919                     + "                new Runnable() {\n"
 920                     + "        };\n"
 921                     + "        }\n"
 922                     + "    }\n"
 923                     + "}";
 924 
 925             JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, null,
 926                     null, null, Arrays.asList(new MyFileObject(code)));
 927             CompilationUnitTree cut = ct.parse().iterator().next();
 928 
 929             ClassTree clazz = (ClassTree) cut.getTypeDecls().get(0);
 930             MethodTree method = (MethodTree) clazz.getMembers().get(0);
 931             List<? extends StatementTree> statements =
 932                     ((BlockTree) ((WhileLoopTree) method.getBody().getStatements().get(0)).getStatement()).getStatements();
 933 
 934             StatementTree ret = statements.get(0);
 935             StatementTree block = statements.get(1);
 936 
 937             Trees t = Trees.instance(ct);
 938             int len = code.indexOf(command + " {") + (command + " ").length();
 939             assertEquals(command, len,
 940                     t.getSourcePositions().getEndPosition(cut, ret));
 941             assertEquals(command, len,
 942                     t.getSourcePositions().getStartPosition(cut, block));
 943         }
 944     }
 945 
 946     void testStartPositionEnumConstantInit() throws IOException {
 947 
 948         String code = "package t; enum Test { AAA; }";
 949 
 950         JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, null, null,
 951                 null, Arrays.asList(new MyFileObject(code)));
 952         CompilationUnitTree cut = ct.parse().iterator().next();
 953         ClassTree clazz = (ClassTree) cut.getTypeDecls().get(0);
 954         VariableTree enumAAA = (VariableTree) clazz.getMembers().get(0);
 955         Trees t = Trees.instance(ct);
 956         int start = (int) t.getSourcePositions().getStartPosition(cut,
 957                 enumAAA.getInitializer());
 958 
 959         assertEquals("testStartPositionEnumConstantInit", -1, start);
 960     }
 961 
 962     @Test
 963     void testVoidLambdaParameter() throws IOException {
 964         String code = "package t; class Test { " +
 965                 "Runnable r = (void v) -> { };" +
 966                 "}";
 967         DiagnosticCollector<JavaFileObject> coll =
 968                 new DiagnosticCollector<>();
 969         JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, coll, null,
 970                 null, Arrays.asList(new MyFileObject(code)));
 971 
 972         CompilationUnitTree cut = ct.parse().iterator().next();
 973         ClassTree clazz = (ClassTree) cut.getTypeDecls().get(0);
 974         VariableTree field = (VariableTree) clazz.getMembers().get(0);
 975 
 976         assertEquals("actual kind: " + field.getInitializer().getKind(),
 977                      field.getInitializer().getKind(),
 978                      Kind.LAMBDA_EXPRESSION);
 979 
 980         LambdaExpressionTree lambda = (LambdaExpressionTree) field.getInitializer();
 981 
 982         assertEquals("actual parameters: " + lambda.getParameters().size(),
 983                      lambda.getParameters().size(),
 984                      1);
 985 
 986         Tree paramType = lambda.getParameters().get(0).getType();
 987 
 988         assertEquals("actual parameter type: " + paramType.getKind(),
 989                      paramType.getKind(),
 990                      Kind.PRIMITIVE_TYPE);
 991 
 992         TypeKind primitiveTypeKind = ((PrimitiveTypeTree) paramType).getPrimitiveTypeKind();
 993 
 994         assertEquals("actual parameter type: " + primitiveTypeKind,
 995                      primitiveTypeKind,
 996                      TypeKind.VOID);
 997     }
 998 
 999     @Test //JDK-8065753
1000     void testWrongFirstToken() throws IOException {
1001         String code = "<";
1002         String expectedErrors = "Test.java:1:1: compiler.err.expected3: class, interface, enum\n" +
1003                                 "1 error\n";
1004         StringWriter out = new StringWriter();
1005         JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(out, fm, null,
1006                 Arrays.asList("-XDrawDiagnostics"), null, Arrays.asList(new MyFileObject(code)));
1007 
1008         Result errorCode = ct.doCall();
1009         assertEquals("the error code is not correct; actual:" + errorCode, Main.Result.ERROR, errorCode);
1010         String actualErrors = normalize(out.toString());
1011         assertEquals("the error message is not correct, actual: " + actualErrors, expectedErrors, actualErrors);
1012     }
1013 
1014     @Test //JDK-8205913
1015     void testForInit() throws IOException {
1016         String code = "class T { void t() { for (n : ns) { } } }";
1017         String expectedErrors = "Test.java:1:27: compiler.err.bad.initializer: for-loop\n";
1018         StringWriter out = new StringWriter();
1019         JavacTask ct = (JavacTask) tool.getTask(out, fm, null,
1020                 Arrays.asList("-XDrawDiagnostics"), null, Arrays.asList(new MyFileObject(code)));
1021 
1022         Iterable<? extends CompilationUnitTree> cuts = ct.parse();
1023         boolean[] foundVar = new boolean[1];
1024 
1025         new TreePathScanner<Void, Void>() {
1026             @Override public Void visitVariable(VariableTree vt, Void p) {
1027                 assertNotNull(vt.getModifiers());
1028                 assertNotNull(vt.getType());
1029                 assertNotNull(vt.getName());
1030                 assertEquals("name should be <error>", "<error>", vt.getName().toString());
1031                 foundVar[0] = true;
1032                 return super.visitVariable(vt, p);
1033             }
1034         }.scan(cuts, null);
1035 
1036         if (!foundVar[0]) {
1037             fail("haven't found a variable");
1038         }
1039 
1040         String actualErrors = normalize(out.toString());
1041         assertEquals("the error message is not correct, actual: " + actualErrors, expectedErrors, actualErrors);
1042     }
1043 
1044     @Test //JDK-821742
1045     void testCompDeclVarType() throws IOException {
1046         String code = "package test; public class Test {"
1047                 + "private void test() {"
1048                 + "var v1 = 10,v2 = 12;"
1049                 + "} private Test() {}}";
1050 
1051         JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, null,
1052                 null, null, Arrays.asList(new MyFileObject(code)));
1053         CompilationUnitTree cut = ct.parse().iterator().next();
1054         ct.enter();
1055         ct.analyze();
1056         ClassTree clazz = (ClassTree) cut.getTypeDecls().get(0);
1057         MethodTree method = (MethodTree) clazz.getMembers().get(0);
1058         VariableTree stmt1 = (VariableTree) method.getBody().getStatements().get(0);
1059         VariableTree stmt2 = (VariableTree) method.getBody().getStatements().get(1);
1060         Tree v1Type = stmt1.getType();
1061         Tree v2Type = stmt2.getType();
1062         assertEquals("Implicit type for v1 is not correct: ", Kind.PRIMITIVE_TYPE, v1Type.getKind());
1063         assertEquals("Implicit type for v2 is not correct: ", Kind.PRIMITIVE_TYPE, v2Type.getKind());
1064     }
1065 
1066     @Test
1067     void testCaseBodyStatements() throws IOException {
1068         String code = "class C {" +
1069                       "    void t(int i) {" +
1070                       "        switch (i) {" +
1071                       "            case 0 -> i++;" +
1072                       "            case 1 -> { i++; }" +
1073                       "            case 2 -> throw new RuntimeException();" +
1074                       "            case 3 -> if (true) ;" +
1075                       "            default -> i++;" +
1076                       "        }" +
1077                       "        switch (i) {" +
1078                       "            case 0: i++; break;" +
1079                       "            case 1: { i++; break;}" +
1080                       "            case 2: throw new RuntimeException();" +
1081                       "            case 3: if (true) ; break;" +
1082                       "            default: i++; break;" +
1083                       "        }" +
1084                       "        int j = switch (i) {" +
1085                       "            case 0 -> i + 1;" +
1086                       "            case 1 -> { yield i + 1; }" +
1087                       "            default -> throw new RuntimeException();" +
1088                       "        };" +
1089                       "        int k = switch (i) {" +
1090                       "            case 0: yield i + 1;" +
1091                       "            case 1: { yield i + 1; }" +
1092                       "            default: throw new RuntimeException();" +
1093                       "        };" +
1094                       "    }" +
1095                       "}";
1096         String expectedErrors = "Test.java:1:178: compiler.err.switch.case.unexpected.statement\n";
1097         StringWriter out = new StringWriter();
1098         JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(out, fm, null,
1099                 Arrays.asList("-XDrawDiagnostics"),
1100                 null, Arrays.asList(new MyFileObject(code)));
1101 
1102         CompilationUnitTree cut = ct.parse().iterator().next();
1103         Trees trees = Trees.instance(ct);
1104         List<String> spans = new ArrayList<>();
1105 
1106         new TreePathScanner<Void, Void>() {
1107             @Override
1108             public Void visitCase(CaseTree tree, Void v) {
1109                 if (tree.getBody() != null) {
1110                     int start = (int) trees.getSourcePositions().getStartPosition(cut, tree.getBody());
1111                     int end = (int) trees.getSourcePositions().getEndPosition(cut, tree.getBody());
1112                     spans.add(code.substring(start, end));
1113                 } else {
1114                     spans.add("<null>");
1115                 }
1116                 return super.visitCase(tree, v);
1117             }
1118         }.scan(cut, null);
1119 
1120         List<String> expectedSpans = List.of(
1121                 "i++;", "{ i++; }", "throw new RuntimeException();", "if (true) ;", "i++;",
1122                 "<null>", "<null>", "<null>", "<null>", "<null>",
1123                 "i + 1"/*TODO semicolon?*/, "{ yield i + 1; }", "throw new RuntimeException();",
1124                 "<null>", "<null>", "<null>");
1125         assertEquals("the error spans are not correct; actual:" + spans, expectedSpans, spans);
1126         String toString = normalize(cut.toString());
1127         String expectedToString =
1128                 "\n" +
1129                 "class C {\n" +
1130                 "    \n" +
1131                 "    void t(int i) {\n" +
1132                 "        switch (i) {\n" +
1133                 "        case 0 -> i++;\n" +
1134                 "        case 1 -> {\n" +
1135                 "            i++;\n" +
1136                 "        }\n" +
1137                 "        case 2 -> throw new RuntimeException();\n" +
1138                 "        case 3 -> if (true) ;\n" +
1139                 "        default -> i++;\n" +
1140                 "        }\n" +
1141                 "        switch (i) {\n" +
1142                 "        case 0:\n" +
1143                 "            i++;\n" +
1144                 "            break;\n" +
1145                 "        \n" +
1146                 "        case 1:\n" +
1147                 "            {\n" +
1148                 "                i++;\n" +
1149                 "                break;\n" +
1150                 "            }\n" +
1151                 "        \n" +
1152                 "        case 2:\n" +
1153                 "            throw new RuntimeException();\n" +
1154                 "        \n" +
1155                 "        case 3:\n" +
1156                 "            if (true) ;\n" +
1157                 "            break;\n" +
1158                 "        \n" +
1159                 "        default:\n" +
1160                 "            i++;\n" +
1161                 "            break;\n" +
1162                 "        \n" +
1163                 "        }\n" +
1164                 "        int j = switch (i) {\n" +
1165                 "        case 0 -> yield i + 1;\n" +
1166                 "        case 1 -> {\n" +
1167                 "            yield i + 1;\n" +
1168                 "        }\n" +
1169                 "        default -> throw new RuntimeException();\n" +
1170                 "        };\n" +
1171                 "        int k = switch (i) {\n" +
1172                 "        case 0:\n" +
1173                 "            yield i + 1;\n" +
1174                 "        \n" +
1175                 "        case 1:\n" +
1176                 "            {\n" +
1177                 "                yield i + 1;\n" +
1178                 "            }\n" +
1179                 "        \n" +
1180                 "        default:\n" +
1181                 "            throw new RuntimeException();\n" +
1182                 "        \n" +
1183                 "        };\n" +
1184                 "    }\n" +
1185                 "}";
1186         System.err.println("toString:");
1187         System.err.println(toString);
1188         System.err.println("expectedToString:");
1189         System.err.println(expectedToString);
1190         assertEquals("the error spans are not correct; actual:" + toString, expectedToString, toString);
1191         String actualErrors = normalize(out.toString());
1192         assertEquals("the error message is not correct, actual: " + actualErrors, expectedErrors, actualErrors);
1193     }
1194 
1195     @Test
1196     void testTypeParamsWithoutMethod() throws IOException {
1197         assert tool != null;
1198 
1199         String code = "package test; class Test { /**javadoc*/ |public <T> |}";
1200         String[] parts = code.split("\\|");
1201 
1202         code = parts[0] + parts[1] + parts[2];
1203 
1204         JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, null, null,
1205                 null, Arrays.asList(new MyFileObject(code)));
1206         Trees trees = Trees.instance(ct);
1207         SourcePositions pos = trees.getSourcePositions();
1208         CompilationUnitTree cut = ct.parse().iterator().next();
1209         ClassTree clazz = (ClassTree) cut.getTypeDecls().get(0);
1210         ErroneousTree err = (ErroneousTree) clazz.getMembers().get(0);
1211         MethodTree method = (MethodTree) err.getErrorTrees().get(0);
1212 
1213         final int methodStart = parts[0].length();
1214         final int methodEnd = parts[0].length() + parts[1].length();
1215         assertEquals("testTypeParamsWithoutMethod",
1216                 methodStart, pos.getStartPosition(cut, method));
1217         assertEquals("testTypeParamsWithoutMethod",
1218                 methodEnd, pos.getEndPosition(cut, method));
1219 
1220         TreePath path2Method = new TreePath(new TreePath(new TreePath(cut), clazz), method);
1221         String javadoc = trees.getDocComment(path2Method);
1222 
1223         if (!"javadoc".equals(javadoc)) {
1224             throw new AssertionError("Expected javadoc not found, actual javadoc: " + javadoc);
1225         }
1226     }
1227 
1228     @Test
1229     void testAnalyzeParensWithComma1() throws IOException {
1230         assert tool != null;
1231 
1232         String code = "package test; class Test { FI fi = |(s, |";
1233         String[] parts = code.split("\\|", 3);
1234 
1235         code = parts[0] + parts[1] + parts[2];
1236 
1237         JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, null, null,
1238                 null, Arrays.asList(new MyFileObject(code)));
1239         Trees trees = Trees.instance(ct);
1240         SourcePositions pos = trees.getSourcePositions();
1241         CompilationUnitTree cut = ct.parse().iterator().next();
1242         boolean[] found = new boolean[1];
1243 
1244         new TreeScanner<Void, Void>() {
1245             @Override
1246             public Void visitLambdaExpression(LambdaExpressionTree tree, Void v) {
1247                 found[0] = true;
1248                 int lambdaStart = parts[0].length();
1249                 int lambdaEnd = parts[0].length() + parts[1].length();
1250                 assertEquals("testAnalyzeParensWithComma1",
1251                         lambdaStart, pos.getStartPosition(cut, tree));
1252                 assertEquals("testAnalyzeParensWithComma1",
1253                         lambdaEnd, pos.getEndPosition(cut, tree));
1254                 return null;
1255             }
1256         }.scan(cut, null);
1257 
1258         assertTrue("testAnalyzeParensWithComma1", found[0]);
1259     }
1260 
1261     @Test
1262     void testAnalyzeParensWithComma2() throws IOException {
1263         assert tool != null;
1264 
1265         String code = "package test; class Test { FI fi = |(s, o)|";
1266         String[] parts = code.split("\\|", 3);
1267 
1268         code = parts[0] + parts[1] + parts[2];
1269 
1270         JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, null, null,
1271                 null, Arrays.asList(new MyFileObject(code)));
1272         Trees trees = Trees.instance(ct);
1273         SourcePositions pos = trees.getSourcePositions();
1274         CompilationUnitTree cut = ct.parse().iterator().next();
1275         boolean[] found = new boolean[1];
1276 
1277         new TreeScanner<Void, Void>() {
1278             @Override
1279             public Void visitLambdaExpression(LambdaExpressionTree tree, Void v) {
1280                 found[0] = true;
1281                 int lambdaStart = parts[0].length();
1282                 int lambdaEnd = parts[0].length() + parts[1].length();
1283                 assertEquals("testAnalyzeParensWithComma2",
1284                         lambdaStart, pos.getStartPosition(cut, tree));
1285                 assertEquals("testAnalyzeParensWithComma2",
1286                         lambdaEnd, pos.getEndPosition(cut, tree));
1287                 return null;
1288             }
1289         }.scan(cut, null);
1290 
1291         assertTrue("testAnalyzeParensWithComma2", found[0]);
1292     }
1293 
1294     @Test
1295     void testBrokenEnum1() throws IOException {
1296         assert tool != null;
1297 
1298         String code = "package test; class Test { enum E { A, B, C. D, E, F; } }";
1299         StringWriter output = new StringWriter();
1300         JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(output, fm, null, List.of("-XDrawDiagnostics"),
1301                 null, Arrays.asList(new MyFileObject(code)));
1302         CompilationUnitTree cut = ct.parse().iterator().next();
1303         List<String> actual = List.of(output.toString().split("\r?\n"));
1304         List<String> expected = List.of("Test.java:1:44: compiler.err.expected3: ',', '}', ';'");
1305 
1306         assertEquals("The expected and actual errors do not match, actual errors: " + actual,
1307                      actual,
1308                      expected);
1309 
1310         String actualAST = cut.toString().replaceAll("\r*\n", "\n");
1311         String expectedAST = "package test;\n" +
1312                              "\n" +
1313                              "class Test {\n" +
1314                              "    \n" +
1315                              "    enum E {\n" +
1316                              "        /*public static final*/ A /* = new E() */ /*enum*/ ,\n" +
1317                              "        /*public static final*/ B /* = new E() */ /*enum*/ ,\n" +
1318                              "        /*public static final*/ C /* = new E() */ /*enum*/ ,\n" +
1319                              "        /*public static final*/ D /* = new E() */ /*enum*/ ,\n" +
1320                              "        /*public static final*/ E /* = new E() */ /*enum*/ ,\n" +
1321                              "        /*public static final*/ F /* = new E() */ /*enum*/ ;\n" +
1322                              "        (ERROR) <error>;\n" +
1323                              "    }\n" +
1324                              "}";
1325         assertEquals("The expected and actual AST do not match, actual AST: " + actualAST,
1326                      actualAST,
1327                      expectedAST);
1328     }
1329 
1330     @Test
1331     void testBrokenEnum2() throws IOException {
1332         assert tool != null;
1333 
1334         String code = "package test; class Test { enum E { A, B, C void t() {} } }";
1335         StringWriter output = new StringWriter();
1336         JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(output, fm, null, List.of("-XDrawDiagnostics"),
1337                 null, Arrays.asList(new MyFileObject(code)));
1338         CompilationUnitTree cut = ct.parse().iterator().next();
1339         List<String> actual = List.of(output.toString().split("\r?\n"));
1340         List<String> expected = List.of("Test.java:1:44: compiler.err.expected3: ',', '}', ';'");
1341 
1342         assertEquals("The expected and actual errors do not match, actual errors: " + actual,
1343                      actual,
1344                      expected);
1345 
1346         String actualAST = cut.toString().replaceAll("\r*\n", "\n");
1347         String expectedAST = "package test;\n" +
1348                              "\n" +
1349                              "class Test {\n" +
1350                              "    \n" +
1351                              "    enum E {\n" +
1352                              "        /*public static final*/ A /* = new E() */ /*enum*/ ,\n" +
1353                              "        /*public static final*/ B /* = new E() */ /*enum*/ ,\n" +
1354                              "        /*public static final*/ C /* = new E() */ /*enum*/ ;\n" +
1355                              "        \n" +
1356                              "        void t() {\n" +
1357                              "        }\n" +
1358                              "    }\n" +
1359                              "}";
1360         assertEquals("The expected and actual AST do not match, actual AST: " + actualAST,
1361                      actualAST,
1362                      expectedAST);
1363     }
1364 
1365     @Test
1366     void testBrokenEnum3() throws IOException {
1367         assert tool != null;
1368 
1369         String code = "package test; class Test { enum E { , void t() {} } }";
1370         StringWriter output = new StringWriter();
1371         JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(output, fm, null, List.of("-XDrawDiagnostics"),
1372                 null, Arrays.asList(new MyFileObject(code)));
1373         CompilationUnitTree cut = ct.parse().iterator().next();
1374         List<String> actual = List.of(output.toString().split("\r?\n"));
1375         List<String> expected = List.of("Test.java:1:38: compiler.err.expected2: '}', ';'");
1376 
1377         assertEquals("The expected and actual errors do not match, actual errors: " + actual,
1378                      actual,
1379                      expected);
1380 
1381         String actualAST = cut.toString().replaceAll("\r*\n", "\n");
1382         String expectedAST = "package test;\n" +
1383                              "\n" +
1384                              "class Test {\n" +
1385                              "    \n" +
1386                              "    enum E {\n" +
1387                              ";\n" +
1388                              "        \n" +
1389                              "        void t() {\n" +
1390                              "        }\n" +
1391                              "    }\n" +
1392                              "}";
1393         assertEquals("The expected and actual AST do not match, actual AST: " + actualAST,
1394                      actualAST,
1395                      expectedAST);
1396     }
1397 
1398     @Test
1399     void testBrokenEnum4() throws IOException {
1400         assert tool != null;
1401 
1402         String code = "package test; class Test { enum E { A, B, C, void t() {} } }";
1403         StringWriter output = new StringWriter();
1404         JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(output, fm, null, List.of("-XDrawDiagnostics"),
1405                 null, Arrays.asList(new MyFileObject(code)));
1406         CompilationUnitTree cut = ct.parse().iterator().next();
1407         List<String> actual = List.of(output.toString().split("\r?\n"));
1408         List<String> expected = List.of("Test.java:1:46: compiler.err.enum.constant.expected");
1409 
1410         assertEquals("The expected and actual errors do not match, actual errors: " + actual,
1411                      actual,
1412                      expected);
1413 
1414         String actualAST = cut.toString().replaceAll("\r*\n", "\n");
1415         String expectedAST = "package test;\n" +
1416                              "\n" +
1417                              "class Test {\n" +
1418                              "    \n" +
1419                              "    enum E {\n" +
1420                              "        /*public static final*/ A /* = new E() */ /*enum*/ ,\n" +
1421                              "        /*public static final*/ B /* = new E() */ /*enum*/ ,\n" +
1422                              "        /*public static final*/ C /* = new E() */ /*enum*/ ;\n" +
1423                              "        \n" +
1424                              "        void t() {\n" +
1425                              "        }\n" +
1426                              "    }\n" +
1427                              "}";
1428         assertEquals("The expected and actual AST do not match, actual AST: " + actualAST,
1429                      actualAST,
1430                      expectedAST);
1431     }
1432 
1433     @Test
1434     void testBrokenEnum5() throws IOException {
1435         assert tool != null;
1436 
1437         String code = "package test; class Test { enum E { A; void t() {} B; } }";
1438         StringWriter output = new StringWriter();
1439         JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(output, fm, null, List.of("-XDrawDiagnostics"),
1440                 null, Arrays.asList(new MyFileObject(code)));
1441         CompilationUnitTree cut = ct.parse().iterator().next();
1442         List<String> actual = List.of(output.toString().split("\r?\n"));
1443         List<String> expected = List.of("Test.java:1:52: compiler.err.enum.constant.not.expected");
1444 
1445         assertEquals("The expected and actual errors do not match, actual errors: " + actual,
1446                      actual,
1447                      expected);
1448 
1449         String actualAST = cut.toString().replaceAll("\r*\n", "\n");
1450         String expectedAST = "package test;\n" +
1451                              "\n" +
1452                              "class Test {\n" +
1453                              "    \n" +
1454                              "    enum E {\n" +
1455                              "        /*public static final*/ A /* = new E() */ /*enum*/ ,\n" +
1456                              "        /*public static final*/ B /* = new E() */ /*enum*/ ;\n" +
1457                              "        \n" +
1458                              "        void t() {\n" +
1459                              "        }\n" +
1460                              "    }\n" +
1461                              "}";
1462         assertEquals("The expected and actual AST do not match, actual AST: " + actualAST,
1463                      actualAST,
1464                      expectedAST);
1465     }
1466 
1467     void run(String[] args) throws Exception {
1468         int passed = 0, failed = 0;
1469         final Pattern p = (args != null && args.length > 0)
1470                 ? Pattern.compile(args[0])
1471                 : null;
1472         for (Method m : this.getClass().getDeclaredMethods()) {
1473             boolean selected = (p == null)
1474                     ? m.isAnnotationPresent(Test.class)
1475                     : p.matcher(m.getName()).matches();
1476             if (selected) {
1477                 try {
1478                     m.invoke(this, (Object[]) null);
1479                     System.out.println(m.getName() + ": OK");
1480                     passed++;
1481                 } catch (Throwable ex) {
1482                     System.out.printf("Test %s failed: %s %n", m, ex.getCause());
1483                     failed++;
1484                 }
1485             }
1486         }
1487         System.out.printf("Passed: %d, Failed %d%n", passed, failed);
1488         if (failed > 0) {
1489             throw new RuntimeException("Tests failed: " + failed);
1490         }
1491         if (passed == 0 && failed == 0) {
1492             throw new AssertionError("No test(s) selected: passed = " +
1493                     passed + ", failed = " + failed + " ??????????");
1494         }
1495     }
1496 }
1497 
1498 abstract class TestCase {
1499 
1500     void assertEquals(String message, int i, int pos) {
1501         if (i != pos) {
1502             fail(message);
1503         }
1504     }
1505 
1506     void assertFalse(String message, boolean bvalue) {
1507         if (bvalue == true) {
1508             fail(message);
1509         }
1510     }
1511 
1512     void assertTrue(String message, boolean bvalue) {
1513         if (bvalue == false) {
1514             fail(message);
1515         }
1516     }
1517 
1518     void assertEquals(String message, int i, long l) {
1519         if (i != l) {
1520             fail(message + ":" + i + ":" + l);
1521         }
1522     }
1523 
1524     void assertEquals(String message, Object o1, Object o2) {
1525         if (o1 != null && o2 != null && !o1.equals(o2)) {
1526             fail(message);
1527         }
1528         if (o1 == null && o2 != null) {
1529             fail(message);
1530         }
1531     }
1532 
1533     void assertNotNull(Object o) {
1534         if (o == null) {
1535             fail();
1536         }
1537     }
1538 
1539     void fail() {
1540         fail("test failed");
1541     }
1542 
1543     void fail(String message) {
1544         throw new RuntimeException(message);
1545     }
1546 
1547     /**
1548      * Indicates that the annotated method is a test method.
1549      */
1550     @Retention(RetentionPolicy.RUNTIME)
1551     @Target(ElementType.METHOD)
1552     public @interface Test {}
1553 }