1 /*
2  * Copyright (c) 2013, 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 8017216 8019422 8019421 8054956
27  * @summary verify start and end positions
28  * @modules java.compiler
29  *          jdk.compiler
30  * @run main TreeEndPosTest
31  */
32 
33 import java.io.ByteArrayOutputStream;
34 import java.io.File;
35 import java.io.IOException;
36 import java.io.PrintWriter;
37 import java.net.URI;
38 import java.util.ArrayList;
39 import java.util.List;
40 import javax.tools.Diagnostic;
41 import javax.tools.DiagnosticCollector;
42 import javax.tools.JavaCompiler;
43 import javax.tools.JavaFileManager;
44 import javax.tools.JavaFileObject;
45 import javax.tools.SimpleJavaFileObject;
46 import javax.tools.ToolProvider;
47 
48 public class TreeEndPosTest {
getJavaFileManager(JavaCompiler compiler, DiagnosticCollector dc)49     private static JavaFileManager getJavaFileManager(JavaCompiler compiler,
50             DiagnosticCollector dc) {
51         return compiler.getStandardFileManager(dc, null, null);
52     }
53 
54     static class JavaSource extends SimpleJavaFileObject {
55 
56         final String source;
57         int startPos;
58         int endPos;
59 
JavaSource(String filename, String source)60         private JavaSource(String filename, String source) {
61             super(URI.create("myfo:/" + filename), JavaFileObject.Kind.SOURCE);
62             this.source = source;
63         }
64 
65         @Override
getCharContent(boolean ignoreEncodingErrors)66         public CharSequence getCharContent(boolean ignoreEncodingErrors) {
67             return source;
68         }
69 
createJavaSource(String preamble, String body, String postamble, String expected)70         static JavaSource createJavaSource(String preamble, String body,
71                 String postamble, String expected) {
72             JavaSource js = createJavaSource(preamble, body, postamble, -1, -1);
73             js.startPos = js.source.indexOf(expected);
74             js.endPos   = js.startPos + expected.length();
75             return js;
76         }
77 
createJavaSource(String body, String expected)78         static JavaSource createJavaSource(String body, String expected) {
79             return createJavaSource(null, body, null, expected);
80         }
81 
createJavaSource(String preamble, String body, String postamble, int start, int end)82         private static JavaSource createJavaSource(String preamble, String body,
83                 String postamble, int start, int end) {
84             final String name = "Bug";
85             StringBuilder code = new StringBuilder();
86             if (preamble != null) {
87                 code.append(preamble);
88             }
89             code.append("public class " + name + "{");
90             if (body != null) {
91                 code.append(body);
92             }
93             code.append("}");
94             if (postamble != null) {
95                 code.append(postamble);
96             }
97             JavaSource js = new JavaSource(name + ".java", code.toString());
98             js.startPos = start;
99             js.endPos = end;
100             return js;
101         }
102     }
103 
main(String... args)104     public static void main(String... args) throws IOException {
105         testUninitializedVariable();
106         testMissingAnnotationValue();
107         testUnresolvableAnnotationAttribute();
108         testFinalVariableWithDefaultConstructor();
109         testFinalVariableWithConstructor();
110     }
111 
testUninitializedVariable()112     static void testUninitializedVariable() throws IOException {
113         compile(JavaSource.createJavaSource("Object o = new A().new B(); class A { }",
114                 "B()"));
115     }
testMissingAnnotationValue()116     static void testMissingAnnotationValue() throws IOException {
117         compile(JavaSource.createJavaSource("@Foo(\"vvvv\")",
118                 null, "@interface Foo { }", "\"vvvv\""));
119     }
120 
testUnresolvableAnnotationAttribute()121     static void testUnresolvableAnnotationAttribute() throws IOException {
122         compile(JavaSource.createJavaSource("@Foo(value=\"vvvv\")",
123                 null, "@interface Foo { }", "value"));
124     }
125 
testFinalVariableWithDefaultConstructor()126     static void testFinalVariableWithDefaultConstructor() throws IOException {
127         compile(JavaSource.createJavaSource("private static final String Foo; public void bar() { }",
128                 "private static final String Foo;"));
129     }
130 
testFinalVariableWithConstructor()131     static void testFinalVariableWithConstructor() throws IOException {
132         compile(JavaSource.createJavaSource("public Bug (){} private static final String Foo; public void bar() { }",
133                 "{}"));
134     }
135 
compile(JavaSource src)136     static void compile(JavaSource src) throws IOException {
137         ByteArrayOutputStream ba = new ByteArrayOutputStream();
138         PrintWriter writer = new PrintWriter(ba);
139         File tempDir = new File(".");
140         JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
141         DiagnosticCollector dc = new DiagnosticCollector();
142         try (JavaFileManager javaFileManager = getJavaFileManager(compiler, dc)) {
143             List<String> options = new ArrayList<>();
144             options.add("-cp");
145             options.add(tempDir.getPath());
146             options.add("-d");
147             options.add(tempDir.getPath());
148             options.add("--should-stop=at=GENERATE");
149 
150             List<JavaFileObject> sources = new ArrayList<>();
151             sources.add(src);
152             JavaCompiler.CompilationTask task =
153                     compiler.getTask(writer, javaFileManager,
154                     dc, options, null,
155                     sources);
156             task.call();
157             for (Diagnostic diagnostic : (List<Diagnostic>) dc.getDiagnostics()) {
158                 long actualStart = diagnostic.getStartPosition();
159                 long actualEnd = diagnostic.getEndPosition();
160                 System.out.println("Source: " + src.source);
161                 System.out.println("Diagnostic: " + diagnostic);
162                 System.out.print("Start position: Expected: " + src.startPos);
163                 System.out.println(", Actual: " + actualStart);
164                 System.out.print("End position: Expected: " + src.endPos);
165                 System.out.println(", Actual: " + actualEnd);
166                 if (src.startPos != actualStart || src.endPos != actualEnd) {
167                     throw new RuntimeException("error: trees don't match");
168                 }
169             }
170         }
171     }
172 }
173