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