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