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