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 }