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