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