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