1 /* 2 * Copyright (c) 2011, 2018, 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 public class JavacParserTest extends TestCase { 86 static final JavaCompiler tool = ToolProvider.getSystemJavaCompiler(); 87 static final JavaFileManager fm = tool.getStandardFileManager(null, null, null); 88 89 private JavacParserTest(){} 90 91 public static void main(String... args) throws Exception { 92 try { 93 new JavacParserTest().run(args); 94 } finally { 95 fm.close(); 96 } 97 } 98 99 class MyFileObject extends SimpleJavaFileObject { 100 101 private String text; 102 103 public MyFileObject(String text) { 104 super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE); 105 this.text = text; 106 } 107 108 @Override 109 public CharSequence getCharContent(boolean ignoreEncodingErrors) { 110 return text; 111 } 112 } 113 /* 114 * converts Windows to Unix style LFs for comparing strings 115 */ 116 String normalize(String in) { 117 return in.replace(System.getProperty("line.separator"), "\n"); 118 } 119 120 CompilationUnitTree getCompilationUnitTree(String code) throws IOException { 121 122 JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, null, null, 123 null, Arrays.asList(new MyFileObject(code))); 124 CompilationUnitTree cut = ct.parse().iterator().next(); 125 return cut; 126 } 127 128 List<String> getErroneousTreeValues(ErroneousTree node) { 129 130 List<String> values = new ArrayList<>(); 131 if (node.getErrorTrees() != null) { 132 for (Tree t : node.getErrorTrees()) { 133 values.add(t.toString()); 134 } 135 } else { 136 throw new RuntimeException("ERROR: No Erroneous tree " 137 + "has been created."); 138 } 139 return values; 140 } 141 142 @Test 143 void testPositionForSuperConstructorCalls() throws IOException { 144 assert tool != null; 145 146 String code = "package test; public class Test {public Test() {super();}}"; 147 148 JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, null, null, 149 null, Arrays.asList(new MyFileObject(code))); 150 CompilationUnitTree cut = ct.parse().iterator().next(); 151 SourcePositions pos = Trees.instance(ct).getSourcePositions(); 152 153 MethodTree method = 154 (MethodTree) ((ClassTree) cut.getTypeDecls().get(0)).getMembers().get(0); 155 ExpressionStatementTree es = 156 (ExpressionStatementTree) method.getBody().getStatements().get(0); 157 158 final int esStartPos = code.indexOf(es.toString()); 159 final int esEndPos = esStartPos + es.toString().length(); 160 assertEquals("testPositionForSuperConstructorCalls", 161 esStartPos, pos.getStartPosition(cut, es)); 162 assertEquals("testPositionForSuperConstructorCalls", 163 esEndPos, pos.getEndPosition(cut, es)); 164 165 MethodInvocationTree mit = (MethodInvocationTree) es.getExpression(); 166 167 final int mitStartPos = code.indexOf(mit.toString()); 168 final int mitEndPos = mitStartPos + mit.toString().length(); 169 assertEquals("testPositionForSuperConstructorCalls", 170 mitStartPos, pos.getStartPosition(cut, mit)); 171 assertEquals("testPositionForSuperConstructorCalls", 172 mitEndPos, pos.getEndPosition(cut, mit)); 173 174 final int methodStartPos = mitStartPos; 175 final int methodEndPos = methodStartPos + mit.getMethodSelect().toString().length(); 176 assertEquals("testPositionForSuperConstructorCalls", 177 methodStartPos, pos.getStartPosition(cut, mit.getMethodSelect())); 178 assertEquals("testPositionForSuperConstructorCalls", 179 methodEndPos, pos.getEndPosition(cut, mit.getMethodSelect())); 180 } 181 182 @Test 183 void testPositionForEnumModifiers() throws IOException { 184 final String theString = "public"; 185 String code = "package test; " + theString + " enum Test {A;}"; 186 187 JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, null, null, 188 null, Arrays.asList(new MyFileObject(code))); 189 CompilationUnitTree cut = ct.parse().iterator().next(); 190 SourcePositions pos = Trees.instance(ct).getSourcePositions(); 191 192 ClassTree clazz = (ClassTree) cut.getTypeDecls().get(0); 193 ModifiersTree mt = clazz.getModifiers(); 194 int spos = code.indexOf(theString); 195 int epos = spos + theString.length(); 196 assertEquals("testPositionForEnumModifiers", 197 spos, pos.getStartPosition(cut, mt)); 198 assertEquals("testPositionForEnumModifiers", 199 epos, pos.getEndPosition(cut, mt)); 200 } 201 202 @Test 203 void testNewClassWithEnclosing() throws IOException { 204 205 final String theString = "Test.this.new d()"; 206 String code = "package test; class Test { " + 207 "class d {} private void method() { " + 208 "Object o = " + theString + "; } }"; 209 210 JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, null, null, 211 null, Arrays.asList(new MyFileObject(code))); 212 CompilationUnitTree cut = ct.parse().iterator().next(); 213 SourcePositions pos = Trees.instance(ct).getSourcePositions(); 214 215 ClassTree clazz = (ClassTree) cut.getTypeDecls().get(0); 216 ExpressionTree est = 217 ((VariableTree) ((MethodTree) clazz.getMembers().get(1)).getBody().getStatements().get(0)).getInitializer(); 218 219 final int spos = code.indexOf(theString); 220 final int epos = spos + theString.length(); 221 assertEquals("testNewClassWithEnclosing", 222 spos, pos.getStartPosition(cut, est)); 223 assertEquals("testNewClassWithEnclosing", 224 epos, pos.getEndPosition(cut, est)); 225 } 226 227 @Test 228 void testPreferredPositionForBinaryOp() throws IOException { 229 230 String code = "package test; public class Test {" 231 + "private void test() {" 232 + "Object o = null; boolean b = o != null && o instanceof String;" 233 + "} private Test() {}}"; 234 235 CompilationUnitTree cut = getCompilationUnitTree(code); 236 ClassTree clazz = (ClassTree) cut.getTypeDecls().get(0); 237 MethodTree method = (MethodTree) clazz.getMembers().get(0); 238 VariableTree condSt = (VariableTree) method.getBody().getStatements().get(1); 239 BinaryTree cond = (BinaryTree) condSt.getInitializer(); 240 241 JCTree condJC = (JCTree) cond; 242 int condStartPos = code.indexOf("&&"); 243 assertEquals("testPreferredPositionForBinaryOp", 244 condStartPos, condJC.pos); 245 } 246 247 @Test 248 void testErrorRecoveryForEnhancedForLoop142381() throws IOException { 249 250 String code = "package test; class Test { " + 251 "private void method() { " + 252 "java.util.Set<String> s = null; for (a : s) {} } }"; 253 254 final List<Diagnostic<? extends JavaFileObject>> errors = 255 new LinkedList<Diagnostic<? extends JavaFileObject>>(); 256 257 JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, 258 new DiagnosticListener<JavaFileObject>() { 259 public void report(Diagnostic<? extends JavaFileObject> diagnostic) { 260 errors.add(diagnostic); 261 } 262 }, null, null, Arrays.asList(new MyFileObject(code))); 263 264 CompilationUnitTree cut = ct.parse().iterator().next(); 265 266 ClassTree clazz = (ClassTree) cut.getTypeDecls().get(0); 267 StatementTree forStatement = 268 ((MethodTree) clazz.getMembers().get(0)).getBody().getStatements().get(1); 269 270 assertEquals("testErrorRecoveryForEnhancedForLoop142381", 271 Kind.ENHANCED_FOR_LOOP, forStatement.getKind()); 272 assertFalse("testErrorRecoveryForEnhancedForLoop142381", errors.isEmpty()); 273 } 274 275 @Test 276 void testPositionAnnotationNoPackage187551() throws IOException { 277 278 String code = "\n@interface Test {}"; 279 280 JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, null, null, 281 null, Arrays.asList(new MyFileObject(code))); 282 283 CompilationUnitTree cut = ct.parse().iterator().next(); 284 ClassTree clazz = (ClassTree) cut.getTypeDecls().get(0); 285 Trees t = Trees.instance(ct); 286 287 assertEquals("testPositionAnnotationNoPackage187551", 288 1, t.getSourcePositions().getStartPosition(cut, clazz)); 289 } 290 291 @Test 292 void testPositionMissingStatement() throws IOException { 293 String code = "class C { void t() { if (true) } }"; 294 DiagnosticCollector<JavaFileObject> dc = new DiagnosticCollector<>(); 295 296 JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, dc, null, 297 null, Arrays.asList(new MyFileObject(code))); 298 299 CompilationUnitTree cut = ct.parse().iterator().next(); 300 Trees trees = Trees.instance(ct); 301 SourcePositions positions = trees.getSourcePositions(); 302 303 new TreeScanner<Void, Void>() { 304 @Override 305 public Void visitIf(IfTree it, Void v) { 306 StatementTree st = it.getThenStatement(); 307 int startpos = (int) positions.getStartPosition(cut, st); 308 int endpos = (int) positions.getEndPosition(cut, st); 309 assertEquals("testPositionMissingStatement.execpos", startpos, endpos); 310 assertEquals("testPositionMissingStatement.execkind", 311 Kind.EXPRESSION_STATEMENT, 312 st.getKind()); 313 Tree err = ((ExpressionStatementTree) st).getExpression(); 314 startpos = (int) positions.getStartPosition(cut, err); 315 endpos = (int) positions.getEndPosition(cut, err); 316 assertEquals("testPositionMissingStatement.errpos", startpos, endpos); 317 assertEquals("testPositionMissingStatement.errkind", 318 Kind.ERRONEOUS, 319 err.getKind()); 320 return super.visitIf(it, v); 321 } 322 }.scan(cut, null); 323 324 assertEquals("testPositionMissingStatement.diags", 1, dc.getDiagnostics().size()); 325 Diagnostic<? extends JavaFileObject> d = dc.getDiagnostics().get(0); 326 int startpos = (int) d.getStartPosition(); 327 int pos = (int) d.getPosition(); 328 int endpos = (int) d.getEndPosition(); 329 assertEquals("testPositionMissingStatement.diagspan", startpos, endpos); 330 assertEquals("testPositionMissingStatement.diagpref", startpos, pos); 331 } 332 333 @Test 334 void testPositionsSane1() throws IOException { 335 performPositionsSanityTest("package test; class Test { " + 336 "private void method() { " + 337 "java.util.List<? extends java.util.List<? extends String>> l; " + 338 "} }"); 339 } 340 341 @Test 342 void testPositionsSane2() throws IOException { 343 performPositionsSanityTest("package test; class Test { " + 344 "private void method() { " + 345 "java.util.List<? super java.util.List<? super String>> l; " + 346 "} }"); 347 } 348 349 @Test 350 void testPositionsSane3() throws IOException { 351 performPositionsSanityTest("package test; class Test { " + 352 "private void method() { " + 353 "java.util.List<? super java.util.List<?>> l; } }"); 354 } 355 356 private void performPositionsSanityTest(String code) throws IOException { 357 358 final List<Diagnostic<? extends JavaFileObject>> errors = 359 new LinkedList<Diagnostic<? extends JavaFileObject>>(); 360 361 JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, 362 new DiagnosticListener<JavaFileObject>() { 363 364 public void report(Diagnostic<? extends JavaFileObject> diagnostic) { 365 errors.add(diagnostic); 366 } 367 }, null, null, Arrays.asList(new MyFileObject(code))); 368 369 final CompilationUnitTree cut = ct.parse().iterator().next(); 370 final Trees trees = Trees.instance(ct); 371 372 new TreeScanner<Void, Void>() { 373 374 private long parentStart = 0; 375 private long parentEnd = Integer.MAX_VALUE; 376 377 @Override 378 public Void scan(Tree node, Void p) { 379 if (node == null) { 380 return null; 381 } 382 383 long start = trees.getSourcePositions().getStartPosition(cut, node); 384 385 if (start == (-1)) { 386 return null; // synthetic tree 387 } 388 assertTrue(node.toString() + ":" + start + "/" + parentStart, 389 parentStart <= start); 390 391 long prevParentStart = parentStart; 392 393 parentStart = start; 394 395 long end = trees.getSourcePositions().getEndPosition(cut, node); 396 397 assertTrue(node.toString() + ":" + end + "/" + parentEnd, 398 end <= parentEnd); 399 400 long prevParentEnd = parentEnd; 401 402 parentEnd = end; 403 404 super.scan(node, p); 405 406 parentStart = prevParentStart; 407 parentEnd = prevParentEnd; 408 409 return null; 410 } 411 412 private void assertTrue(String message, boolean b) { 413 if (!b) fail(message); 414 } 415 }.scan(cut, null); 416 } 417 418 @Test 419 void testCorrectWildcardPositions1() throws IOException { 420 performWildcardPositionsTest("package test; import java.util.List; " + 421 "class Test { private void method() { List<? extends List<? extends String>> l; } }", 422 423 Arrays.asList("List<? extends List<? extends String>> l;", 424 "List<? extends List<? extends String>>", 425 "List", 426 "? extends List<? extends String>", 427 "List<? extends String>", 428 "List", 429 "? extends String", 430 "String")); 431 } 432 433 @Test 434 void testCorrectWildcardPositions2() throws IOException { 435 performWildcardPositionsTest("package test; import java.util.List; " 436 + "class Test { private void method() { List<? super List<? super String>> l; } }", 437 Arrays.asList("List<? super List<? super String>> l;", 438 "List<? super List<? super String>>", 439 "List", 440 "? super List<? super String>", 441 "List<? super String>", 442 "List", 443 "? super String", 444 "String")); 445 } 446 447 @Test 448 void testCorrectWildcardPositions3() throws IOException { 449 performWildcardPositionsTest("package test; import java.util.List; " + 450 "class Test { private void method() { List<? super List<?>> l; } }", 451 452 Arrays.asList("List<? super List<?>> l;", 453 "List<? super List<?>>", 454 "List", 455 "? super List<?>", 456 "List<?>", 457 "List", 458 "?")); 459 } 460 461 @Test 462 void testCorrectWildcardPositions4() throws IOException { 463 performWildcardPositionsTest("package test; import java.util.List; " + 464 "class Test { private void method() { " + 465 "List<? extends List<? extends List<? extends String>>> l; } }", 466 467 Arrays.asList("List<? extends List<? extends List<? extends String>>> l;", 468 "List<? extends List<? extends List<? extends String>>>", 469 "List", 470 "? extends List<? extends List<? extends String>>", 471 "List<? extends List<? extends String>>", 472 "List", 473 "? extends List<? extends String>", 474 "List<? extends String>", 475 "List", 476 "? extends String", 477 "String")); 478 } 479 480 @Test 481 void testCorrectWildcardPositions5() throws IOException { 482 performWildcardPositionsTest("package test; import java.util.List; " + 483 "class Test { private void method() { " + 484 "List<? extends List<? extends List<? extends String >>> l; } }", 485 Arrays.asList("List<? extends List<? extends List<? extends String >>> l;", 486 "List<? extends List<? extends List<? extends String >>>", 487 "List", 488 "? extends List<? extends List<? extends String >>", 489 "List<? extends List<? extends String >>", 490 "List", 491 "? extends List<? extends String >", 492 "List<? extends String >", 493 "List", 494 "? extends String", 495 "String")); 496 } 497 498 void performWildcardPositionsTest(final String code, 499 List<String> golden) throws IOException { 500 501 final List<Diagnostic<? extends JavaFileObject>> errors = 502 new LinkedList<Diagnostic<? extends JavaFileObject>>(); 503 504 JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, 505 new DiagnosticListener<JavaFileObject>() { 506 public void report(Diagnostic<? extends JavaFileObject> diagnostic) { 507 errors.add(diagnostic); 508 } 509 }, null, null, Arrays.asList(new MyFileObject(code))); 510 511 final CompilationUnitTree cut = ct.parse().iterator().next(); 512 final List<String> content = new LinkedList<String>(); 513 final Trees trees = Trees.instance(ct); 514 515 new TreeScanner<Void, Void>() { 516 @Override 517 public Void scan(Tree node, Void p) { 518 if (node == null) { 519 return null; 520 } 521 long start = trees.getSourcePositions().getStartPosition(cut, node); 522 523 if (start == (-1)) { 524 return null; // synthetic tree 525 } 526 long end = trees.getSourcePositions().getEndPosition(cut, node); 527 String s = code.substring((int) start, (int) end); 528 content.add(s); 529 530 return super.scan(node, p); 531 } 532 }.scan(((MethodTree) ((ClassTree) cut.getTypeDecls().get(0)).getMembers().get(0)).getBody().getStatements().get(0), null); 533 534 assertEquals("performWildcardPositionsTest",golden.toString(), 535 content.toString()); 536 } 537 538 @Test 539 void testStartPositionForMethodWithoutModifiers() throws IOException { 540 541 String code = "package t; class Test { <T> void t() {} }"; 542 543 JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, null, null, 544 null, Arrays.asList(new MyFileObject(code))); 545 CompilationUnitTree cut = ct.parse().iterator().next(); 546 ClassTree clazz = (ClassTree) cut.getTypeDecls().get(0); 547 MethodTree mt = (MethodTree) clazz.getMembers().get(0); 548 Trees t = Trees.instance(ct); 549 int start = (int) t.getSourcePositions().getStartPosition(cut, mt); 550 int end = (int) t.getSourcePositions().getEndPosition(cut, mt); 551 552 assertEquals("testStartPositionForMethodWithoutModifiers", 553 "<T> void t() {}", code.substring(start, end)); 554 } 555 556 @Test 557 void testVariableInIfThen1() throws IOException { 558 559 String code = "package t; class Test { " + 560 "private static void t(String name) { " + 561 "if (name != null) String nn = name.trim(); } }"; 562 563 DiagnosticCollector<JavaFileObject> coll = 564 new DiagnosticCollector<JavaFileObject>(); 565 566 JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, coll, null, 567 null, Arrays.asList(new MyFileObject(code))); 568 569 ct.parse(); 570 571 List<String> codes = new LinkedList<String>(); 572 573 for (Diagnostic<? extends JavaFileObject> d : coll.getDiagnostics()) { 574 codes.add(d.getCode()); 575 } 576 577 assertEquals("testVariableInIfThen1", 578 Arrays.<String>asList("compiler.err.variable.not.allowed"), 579 codes); 580 } 581 582 @Test 583 void testVariableInIfThen2() throws IOException { 584 585 String code = "package t; class Test { " + 586 "private static void t(String name) { " + 587 "if (name != null) class X {} } }"; 588 DiagnosticCollector<JavaFileObject> coll = 589 new DiagnosticCollector<JavaFileObject>(); 590 JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, coll, null, 591 null, Arrays.asList(new MyFileObject(code))); 592 593 ct.parse(); 594 595 List<String> codes = new LinkedList<String>(); 596 597 for (Diagnostic<? extends JavaFileObject> d : coll.getDiagnostics()) { 598 codes.add(d.getCode()); 599 } 600 601 assertEquals("testVariableInIfThen2", 602 Arrays.<String>asList("compiler.err.class.not.allowed"), codes); 603 } 604 605 @Test 606 void testVariableInIfThen3() throws IOException { 607 608 String code = "package t; class Test { "+ 609 "private static void t() { " + 610 "if (true) abstract class F {} }}"; 611 DiagnosticCollector<JavaFileObject> coll = 612 new DiagnosticCollector<JavaFileObject>(); 613 JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, coll, null, 614 null, Arrays.asList(new MyFileObject(code))); 615 616 ct.parse(); 617 618 List<String> codes = new LinkedList<String>(); 619 620 for (Diagnostic<? extends JavaFileObject> d : coll.getDiagnostics()) { 621 codes.add(d.getCode()); 622 } 623 624 assertEquals("testVariableInIfThen3", 625 Arrays.<String>asList("compiler.err.class.not.allowed"), codes); 626 } 627 628 @Test 629 void testVariableInIfThen4() throws IOException { 630 631 String code = "package t; class Test { "+ 632 "private static void t(String name) { " + 633 "if (name != null) interface X {} } }"; 634 DiagnosticCollector<JavaFileObject> coll = 635 new DiagnosticCollector<JavaFileObject>(); 636 JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, coll, null, 637 null, Arrays.asList(new MyFileObject(code))); 638 639 ct.parse(); 640 641 List<String> codes = new LinkedList<String>(); 642 643 for (Diagnostic<? extends JavaFileObject> d : coll.getDiagnostics()) { 644 codes.add(d.getCode()); 645 } 646 647 assertEquals("testVariableInIfThen4", 648 Arrays.<String>asList("compiler.err.class.not.allowed"), codes); 649 } 650 651 @Test 652 void testVariableInIfThen5() throws IOException { 653 654 String code = "package t; class Test { "+ 655 "private static void t() { " + 656 "if (true) } }"; 657 DiagnosticCollector<JavaFileObject> coll = 658 new DiagnosticCollector<JavaFileObject>(); 659 JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, coll, null, 660 null, Arrays.asList(new MyFileObject(code))); 661 662 ct.parse(); 663 664 List<String> codes = new LinkedList<String>(); 665 666 for (Diagnostic<? extends JavaFileObject> d : coll.getDiagnostics()) { 667 codes.add(d.getCode()); 668 } 669 670 assertEquals("testVariableInIfThen5", 671 Arrays.<String>asList("compiler.err.illegal.start.of.stmt"), 672 codes); 673 } 674 675 // see javac bug #6882235, NB bug #98234: 676 @Test 677 void testMissingExponent() throws IOException { 678 679 String code = "\nclass Test { { System.err.println(0e); } }"; 680 681 JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, null, null, 682 null, Arrays.asList(new MyFileObject(code))); 683 684 assertNotNull(ct.parse().iterator().next()); 685 } 686 687 @Test 688 void testTryResourcePos() throws IOException { 689 690 final String code = "package t; class Test { " + 691 "{ try (java.io.InputStream in = null) { } } }"; 692 693 CompilationUnitTree cut = getCompilationUnitTree(code); 694 695 new TreeScanner<Void, Void>() { 696 @Override 697 public Void visitVariable(VariableTree node, Void p) { 698 if ("in".contentEquals(node.getName())) { 699 JCTree.JCVariableDecl var = (JCTree.JCVariableDecl) node; 700 assertEquals("testTryResourcePos", "in = null) { } } }", 701 code.substring(var.pos)); 702 } 703 return super.visitVariable(node, p); 704 } 705 }.scan(cut, null); 706 } 707 708 @Test 709 void testVarPos() throws IOException { 710 711 final String code = "package t; class Test { " + 712 "{ java.io.InputStream in = null; } }"; 713 714 CompilationUnitTree cut = getCompilationUnitTree(code); 715 716 new TreeScanner<Void, Void>() { 717 718 @Override 719 public Void visitVariable(VariableTree node, Void p) { 720 if ("in".contentEquals(node.getName())) { 721 JCTree.JCVariableDecl var = (JCTree.JCVariableDecl) node; 722 assertEquals("testVarPos","in = null; } }", 723 code.substring(var.pos)); 724 } 725 return super.visitVariable(node, p); 726 } 727 }.scan(cut, null); 728 } 729 730 // expected erroneous tree: int x = y;(ERROR); 731 @Test 732 void testOperatorMissingError() throws IOException { 733 734 String code = "package test; public class ErrorTest { " 735 + "void method() { int x = y z } }"; 736 CompilationUnitTree cut = getCompilationUnitTree(code); 737 final List<String> values = new ArrayList<>(); 738 final List<String> expectedValues = 739 new ArrayList<>(Arrays.asList("[z]")); 740 741 new TreeScanner<Void, Void>() { 742 @Override 743 public Void visitErroneous(ErroneousTree node, Void p) { 744 values.add(getErroneousTreeValues(node).toString()); 745 return null; 746 747 } 748 }.scan(cut, null); 749 750 assertEquals("testOperatorMissingError: The Erroneous tree " 751 + "error values: " + values 752 + " do not match expected error values: " 753 + expectedValues, values, expectedValues); 754 } 755 756 // expected erroneous tree: String s = (ERROR); 757 @Test 758 void testMissingParenthesisError() throws IOException { 759 760 String code = "package test; public class ErrorTest { " 761 + "void f() {String s = new String; } }"; 762 CompilationUnitTree cut = getCompilationUnitTree(code); 763 final List<String> values = new ArrayList<>(); 764 final List<String> expectedValues = 765 new ArrayList<>(Arrays.asList("[new String()]")); 766 767 new TreeScanner<Void, Void>() { 768 @Override 769 public Void visitErroneous(ErroneousTree node, Void p) { 770 values.add(getErroneousTreeValues(node).toString()); 771 return null; 772 } 773 }.scan(cut, null); 774 775 assertEquals("testMissingParenthesisError: The Erroneous tree " 776 + "error values: " + values 777 + " do not match expected error values: " 778 + expectedValues, values, expectedValues); 779 } 780 781 // expected erroneous tree: package test; (ERROR)(ERROR) 782 @Test 783 void testMissingClassError() throws IOException { 784 785 String code = "package Test; clas ErrorTest { " 786 + "void f() {String s = new String(); } }"; 787 CompilationUnitTree cut = getCompilationUnitTree(code); 788 final List<String> values = new ArrayList<>(); 789 final List<String> expectedValues = 790 new ArrayList<>(Arrays.asList("[, clas]", "[]")); 791 792 new TreeScanner<Void, Void>() { 793 @Override 794 public Void visitErroneous(ErroneousTree node, Void p) { 795 values.add(getErroneousTreeValues(node).toString()); 796 return null; 797 } 798 }.scan(cut, null); 799 800 assertEquals("testMissingClassError: The Erroneous tree " 801 + "error values: " + values 802 + " do not match expected error values: " 803 + expectedValues, values, expectedValues); 804 } 805 806 // expected erroneous tree: void m1(int i) {(ERROR);{(ERROR);} 807 @Test 808 void testSwitchError() throws IOException { 809 810 String code = "package test; public class ErrorTest { " 811 + "int numDays; void m1(int i) { switchh {i} { case 1: " 812 + "numDays = 31; break; } } }"; 813 CompilationUnitTree cut = getCompilationUnitTree(code); 814 final List<String> values = new ArrayList<>(); 815 final List<String> expectedValues = 816 new ArrayList<>(Arrays.asList("[switchh]", "[i]")); 817 818 new TreeScanner<Void, Void>() { 819 @Override 820 public Void visitErroneous(ErroneousTree node, Void p) { 821 values.add(getErroneousTreeValues(node).toString()); 822 return null; 823 } 824 }.scan(cut, null); 825 826 assertEquals("testSwitchError: The Erroneous tree " 827 + "error values: " + values 828 + " do not match expected error values: " 829 + expectedValues, values, expectedValues); 830 } 831 832 // expected erroneous tree: class ErrorTest {(ERROR) 833 @Test 834 void testMethodError() throws IOException { 835 836 String code = "package Test; class ErrorTest { " 837 + "static final void f) {String s = new String(); } }"; 838 CompilationUnitTree cut = cut = getCompilationUnitTree(code); 839 840 final List<String> values = new ArrayList<>(); 841 final List<String> expectedValues = 842 new ArrayList<>(Arrays.asList("[\nstatic final void f();]")); 843 844 new TreeScanner<Void, Void>() { 845 @Override 846 public Void visitErroneous(ErroneousTree node, Void p) { 847 values.add(normalize(getErroneousTreeValues(node).toString())); 848 return null; 849 } 850 }.scan(cut, null); 851 852 assertEquals("testMethodError: The Erroneous tree " 853 + "error value: " + values 854 + " does not match expected error values: " 855 + expectedValues, values, expectedValues); 856 } 857 858 /* 859 * The following tests do not work just yet with nb-javac nor javac, 860 * they need further investigation, see CR: 7167356 861 */ 862 863 void testPositionBrokenSource126732a() throws IOException { 864 String[] commands = new String[]{ 865 "return Runnable()", 866 "do { } while (true)", 867 "throw UnsupportedOperationException()", 868 "assert true", 869 "1 + 1",}; 870 871 for (String command : commands) { 872 873 String code = "package test;\n" 874 + "public class Test {\n" 875 + " public static void test() {\n" 876 + " " + command + " {\n" 877 + " new Runnable() {\n" 878 + " };\n" 879 + " }\n" 880 + "}"; 881 JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, null, 882 null, null, Arrays.asList(new MyFileObject(code))); 883 CompilationUnitTree cut = ct.parse().iterator().next(); 884 885 ClassTree clazz = (ClassTree) cut.getTypeDecls().get(0); 886 MethodTree method = (MethodTree) clazz.getMembers().get(0); 887 List<? extends StatementTree> statements = 888 method.getBody().getStatements(); 889 890 StatementTree ret = statements.get(0); 891 StatementTree block = statements.get(1); 892 893 Trees t = Trees.instance(ct); 894 int len = code.indexOf(command + " {") + (command + " ").length(); 895 assertEquals(command, len, 896 t.getSourcePositions().getEndPosition(cut, ret)); 897 assertEquals(command, len, 898 t.getSourcePositions().getStartPosition(cut, block)); 899 } 900 } 901 902 void testPositionBrokenSource126732b() throws IOException { 903 String[] commands = new String[]{ 904 "break", 905 "break A", 906 "continue ", 907 "continue A",}; 908 909 for (String command : commands) { 910 911 String code = "package test;\n" 912 + "public class Test {\n" 913 + " public static void test() {\n" 914 + " while (true) {\n" 915 + " " + command + " {\n" 916 + " new Runnable() {\n" 917 + " };\n" 918 + " }\n" 919 + " }\n" 920 + "}"; 921 922 JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, null, 923 null, null, Arrays.asList(new MyFileObject(code))); 924 CompilationUnitTree cut = ct.parse().iterator().next(); 925 926 ClassTree clazz = (ClassTree) cut.getTypeDecls().get(0); 927 MethodTree method = (MethodTree) clazz.getMembers().get(0); 928 List<? extends StatementTree> statements = 929 ((BlockTree) ((WhileLoopTree) method.getBody().getStatements().get(0)).getStatement()).getStatements(); 930 931 StatementTree ret = statements.get(0); 932 StatementTree block = statements.get(1); 933 934 Trees t = Trees.instance(ct); 935 int len = code.indexOf(command + " {") + (command + " ").length(); 936 assertEquals(command, len, 937 t.getSourcePositions().getEndPosition(cut, ret)); 938 assertEquals(command, len, 939 t.getSourcePositions().getStartPosition(cut, block)); 940 } 941 } 942 943 void testStartPositionEnumConstantInit() throws IOException { 944 945 String code = "package t; enum Test { AAA; }"; 946 947 JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, null, null, 948 null, Arrays.asList(new MyFileObject(code))); 949 CompilationUnitTree cut = ct.parse().iterator().next(); 950 ClassTree clazz = (ClassTree) cut.getTypeDecls().get(0); 951 VariableTree enumAAA = (VariableTree) clazz.getMembers().get(0); 952 Trees t = Trees.instance(ct); 953 int start = (int) t.getSourcePositions().getStartPosition(cut, 954 enumAAA.getInitializer()); 955 956 assertEquals("testStartPositionEnumConstantInit", -1, start); 957 } 958 959 @Test 960 void testVoidLambdaParameter() throws IOException { 961 String code = "package t; class Test { " + 962 "Runnable r = (void v) -> { };" + 963 "}"; 964 DiagnosticCollector<JavaFileObject> coll = 965 new DiagnosticCollector<>(); 966 JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, coll, null, 967 null, Arrays.asList(new MyFileObject(code))); 968 969 CompilationUnitTree cut = ct.parse().iterator().next(); 970 ClassTree clazz = (ClassTree) cut.getTypeDecls().get(0); 971 VariableTree field = (VariableTree) clazz.getMembers().get(0); 972 973 assertEquals("actual kind: " + field.getInitializer().getKind(), 974 field.getInitializer().getKind(), 975 Kind.LAMBDA_EXPRESSION); 976 977 LambdaExpressionTree lambda = (LambdaExpressionTree) field.getInitializer(); 978 979 assertEquals("actual parameters: " + lambda.getParameters().size(), 980 lambda.getParameters().size(), 981 1); 982 983 Tree paramType = lambda.getParameters().get(0).getType(); 984 985 assertEquals("actual parameter type: " + paramType.getKind(), 986 paramType.getKind(), 987 Kind.PRIMITIVE_TYPE); 988 989 TypeKind primitiveTypeKind = ((PrimitiveTypeTree) paramType).getPrimitiveTypeKind(); 990 991 assertEquals("actual parameter type: " + primitiveTypeKind, 992 primitiveTypeKind, 993 TypeKind.VOID); 994 } 995 996 @Test //JDK-8065753 997 void testWrongFirstToken() throws IOException { 998 String code = "<"; 999 String expectedErrors = "Test.java:1:1: compiler.err.expected3: class, interface, enum\n" + 1000 "1 error\n"; 1001 StringWriter out = new StringWriter(); 1002 JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(out, fm, null, 1003 Arrays.asList("-XDrawDiagnostics"), null, Arrays.asList(new MyFileObject(code))); 1004 1005 Result errorCode = ct.doCall(); 1006 assertEquals("the error code is not correct; actual:" + errorCode, Main.Result.ERROR, errorCode); 1007 String actualErrors = normalize(out.toString()); 1008 assertEquals("the error message is not correct, actual: " + actualErrors, expectedErrors, actualErrors); 1009 } 1010 1011 @Test //JDK-8205913 1012 void testForInit() throws IOException { 1013 String code = "class T { void t() { for (n : ns) { } } }"; 1014 String expectedErrors = "Test.java:1:27: compiler.err.bad.initializer: for-loop\n"; 1015 StringWriter out = new StringWriter(); 1016 JavacTask ct = (JavacTask) tool.getTask(out, fm, null, 1017 Arrays.asList("-XDrawDiagnostics"), null, Arrays.asList(new MyFileObject(code))); 1018 1019 Iterable<? extends CompilationUnitTree> cuts = ct.parse(); 1020 boolean[] foundVar = new boolean[1]; 1021 1022 new TreePathScanner<Void, Void>() { 1023 @Override public Void visitVariable(VariableTree vt, Void p) { 1024 assertNotNull(vt.getModifiers()); 1025 assertNotNull(vt.getType()); 1026 assertNotNull(vt.getName()); 1027 assertEquals("name should be <error>", "<error>", vt.getName().toString()); 1028 foundVar[0] = true; 1029 return super.visitVariable(vt, p); 1030 } 1031 }.scan(cuts, null); 1032 1033 if (!foundVar[0]) { 1034 fail("haven't found a variable"); 1035 } 1036 1037 String actualErrors = normalize(out.toString()); 1038 assertEquals("the error message is not correct, actual: " + actualErrors, expectedErrors, actualErrors); 1039 } 1040 1041 @Test 1042 void testTypeParamsWithoutMethod() throws IOException { 1043 assert tool != null; 1044 1045 String code = "package test; class Test { /**javadoc*/ |public <T> |}"; 1046 String[] parts = code.split("\\|"); 1047 1048 code = parts[0] + parts[1] + parts[2]; 1049 1050 JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, null, null, 1051 null, Arrays.asList(new MyFileObject(code))); 1052 Trees trees = Trees.instance(ct); 1053 SourcePositions pos = trees.getSourcePositions(); 1054 CompilationUnitTree cut = ct.parse().iterator().next(); 1055 ClassTree clazz = (ClassTree) cut.getTypeDecls().get(0); 1056 ErroneousTree err = (ErroneousTree) clazz.getMembers().get(0); 1057 MethodTree method = (MethodTree) err.getErrorTrees().get(0); 1058 1059 final int methodStart = parts[0].length(); 1060 final int methodEnd = parts[0].length() + parts[1].length(); 1061 assertEquals("testTypeParamsWithoutMethod", 1062 methodStart, pos.getStartPosition(cut, method)); 1063 assertEquals("testTypeParamsWithoutMethod", 1064 methodEnd, pos.getEndPosition(cut, method)); 1065 1066 TreePath path2Method = new TreePath(new TreePath(new TreePath(cut), clazz), method); 1067 String javadoc = trees.getDocComment(path2Method); 1068 1069 if (!"javadoc".equals(javadoc)) { 1070 throw new AssertionError("Expected javadoc not found, actual javadoc: " + javadoc); 1071 } 1072 } 1073 1074 @Test 1075 void testAnalyzeParensWithComma1() throws IOException { 1076 assert tool != null; 1077 1078 String code = "package test; class Test { FI fi = |(s, |"; 1079 String[] parts = code.split("\\|", 3); 1080 1081 code = parts[0] + parts[1] + parts[2]; 1082 1083 JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, null, null, 1084 null, Arrays.asList(new MyFileObject(code))); 1085 Trees trees = Trees.instance(ct); 1086 SourcePositions pos = trees.getSourcePositions(); 1087 CompilationUnitTree cut = ct.parse().iterator().next(); 1088 boolean[] found = new boolean[1]; 1089 1090 new TreeScanner<Void, Void>() { 1091 @Override 1092 public Void visitLambdaExpression(LambdaExpressionTree tree, Void v) { 1093 found[0] = true; 1094 int lambdaStart = parts[0].length(); 1095 int lambdaEnd = parts[0].length() + parts[1].length(); 1096 assertEquals("testAnalyzeParensWithComma1", 1097 lambdaStart, pos.getStartPosition(cut, tree)); 1098 assertEquals("testAnalyzeParensWithComma1", 1099 lambdaEnd, pos.getEndPosition(cut, tree)); 1100 return null; 1101 } 1102 }.scan(cut, null); 1103 1104 assertTrue("testAnalyzeParensWithComma1", found[0]); 1105 } 1106 1107 @Test 1108 void testAnalyzeParensWithComma2() throws IOException { 1109 assert tool != null; 1110 1111 String code = "package test; class Test { FI fi = |(s, o)|"; 1112 String[] parts = code.split("\\|", 3); 1113 1114 code = parts[0] + parts[1] + parts[2]; 1115 1116 JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, null, null, 1117 null, Arrays.asList(new MyFileObject(code))); 1118 Trees trees = Trees.instance(ct); 1119 SourcePositions pos = trees.getSourcePositions(); 1120 CompilationUnitTree cut = ct.parse().iterator().next(); 1121 boolean[] found = new boolean[1]; 1122 1123 new TreeScanner<Void, Void>() { 1124 @Override 1125 public Void visitLambdaExpression(LambdaExpressionTree tree, Void v) { 1126 found[0] = true; 1127 int lambdaStart = parts[0].length(); 1128 int lambdaEnd = parts[0].length() + parts[1].length(); 1129 assertEquals("testAnalyzeParensWithComma2", 1130 lambdaStart, pos.getStartPosition(cut, tree)); 1131 assertEquals("testAnalyzeParensWithComma2", 1132 lambdaEnd, pos.getEndPosition(cut, tree)); 1133 return null; 1134 } 1135 }.scan(cut, null); 1136 1137 assertTrue("testAnalyzeParensWithComma2", found[0]); 1138 } 1139 1140 void run(String[] args) throws Exception { 1141 int passed = 0, failed = 0; 1142 final Pattern p = (args != null && args.length > 0) 1143 ? Pattern.compile(args[0]) 1144 : null; 1145 for (Method m : this.getClass().getDeclaredMethods()) { 1146 boolean selected = (p == null) 1147 ? m.isAnnotationPresent(Test.class) 1148 : p.matcher(m.getName()).matches(); 1149 if (selected) { 1150 try { 1151 m.invoke(this, (Object[]) null); 1152 System.out.println(m.getName() + ": OK"); 1153 passed++; 1154 } catch (Throwable ex) { 1155 System.out.printf("Test %s failed: %s %n", m, ex.getCause()); 1156 failed++; 1157 } 1158 } 1159 } 1160 System.out.printf("Passed: %d, Failed %d%n", passed, failed); 1161 if (failed > 0) { 1162 throw new RuntimeException("Tests failed: " + failed); 1163 } 1164 if (passed == 0 && failed == 0) { 1165 throw new AssertionError("No test(s) selected: passed = " + 1166 passed + ", failed = " + failed + " ??????????"); 1167 } 1168 } 1169 } 1170 1171 abstract class TestCase { 1172 1173 void assertEquals(String message, int i, int pos) { 1174 if (i != pos) { 1175 fail(message); 1176 } 1177 } 1178 1179 void assertFalse(String message, boolean bvalue) { 1180 if (bvalue == true) { 1181 fail(message); 1182 } 1183 } 1184 1185 void assertTrue(String message, boolean bvalue) { 1186 if (bvalue == false) { 1187 fail(message); 1188 } 1189 } 1190 1191 void assertEquals(String message, int i, long l) { 1192 if (i != l) { 1193 fail(message + ":" + i + ":" + l); 1194 } 1195 } 1196 1197 void assertEquals(String message, Object o1, Object o2) { 1198 if (o1 != null && o2 != null && !o1.equals(o2)) { 1199 fail(message); 1200 } 1201 if (o1 == null && o2 != null) { 1202 fail(message); 1203 } 1204 } 1205 1206 void assertNotNull(Object o) { 1207 if (o == null) { 1208 fail(); 1209 } 1210 } 1211 1212 void fail() { 1213 fail("test failed"); 1214 } 1215 1216 void fail(String message) { 1217 throw new RuntimeException(message); 1218 } 1219 1220 /** 1221 * Indicates that the annotated method is a test method. 1222 */ 1223 @Retention(RetentionPolicy.RUNTIME) 1224 @Target(ElementType.METHOD) 1225 public @interface Test {} 1226 }