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