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 8205418 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 import com.sun.source.tree.CompilationUnitTree; 48 import com.sun.source.tree.Tree; 49 import com.sun.source.tree.Tree.Kind; 50 import com.sun.source.util.JavacTask; 51 import com.sun.source.util.SourcePositions; 52 import com.sun.source.util.TreeScanner; 53 import com.sun.source.util.Trees; 54 55 public class TreeEndPosTest { getJavaFileManager(JavaCompiler compiler, DiagnosticCollector dc)56 private static JavaFileManager getJavaFileManager(JavaCompiler compiler, 57 DiagnosticCollector dc) { 58 return compiler.getStandardFileManager(dc, null, null); 59 } 60 61 static class JavaSource extends SimpleJavaFileObject { 62 63 final String source; 64 int startPos; 65 int endPos; 66 JavaSource(String filename, String source)67 private JavaSource(String filename, String source) { 68 super(URI.create("myfo:/" + filename), JavaFileObject.Kind.SOURCE); 69 this.source = source; 70 } 71 72 @Override getCharContent(boolean ignoreEncodingErrors)73 public CharSequence getCharContent(boolean ignoreEncodingErrors) { 74 return source; 75 } 76 createJavaSource(String preamble, String body, String postamble, String expected)77 static JavaSource createJavaSource(String preamble, String body, 78 String postamble, String expected) { 79 JavaSource js = createJavaSource(preamble, body, postamble, -1, -1); 80 js.startPos = js.source.indexOf(expected); 81 js.endPos = js.startPos + expected.length(); 82 return js; 83 } 84 createJavaSource(String body, String expected)85 static JavaSource createJavaSource(String body, String expected) { 86 return createJavaSource(null, body, null, expected); 87 } 88 createJavaSource(String preamble, String body, String postamble, int start, int end)89 private static JavaSource createJavaSource(String preamble, String body, 90 String postamble, int start, int end) { 91 final String name = "Bug"; 92 StringBuilder code = new StringBuilder(); 93 if (preamble != null) { 94 code.append(preamble); 95 } 96 code.append("public class " + name + "{"); 97 if (body != null) { 98 code.append(body); 99 } 100 code.append("}"); 101 if (postamble != null) { 102 code.append(postamble); 103 } 104 JavaSource js = new JavaSource(name + ".java", code.toString()); 105 js.startPos = start; 106 js.endPos = end; 107 return js; 108 } 109 createFullJavaSource(String code)110 static JavaSource createFullJavaSource(String code) { 111 final String name = "Bug"; 112 String[] parts = code.split("\\|", 3); 113 JavaSource js = new JavaSource(name + ".java", parts[0] + parts[1] + parts[2]); 114 js.startPos = parts[0].length(); 115 js.endPos = parts[0].length() + parts[1].length(); 116 return js; 117 } 118 } 119 main(String... args)120 public static void main(String... args) throws IOException { 121 testUninitializedVariable(); 122 testMissingAnnotationValue(); 123 testUnresolvableAnnotationAttribute(); 124 testFinalVariableWithDefaultConstructor(); 125 testFinalVariableWithConstructor(); 126 testWholeTextSpan(); 127 } 128 testUninitializedVariable()129 static void testUninitializedVariable() throws IOException { 130 compile(JavaSource.createJavaSource("Object o = new A().new BT(); class A { }", 131 "BT")); 132 } testMissingAnnotationValue()133 static void testMissingAnnotationValue() throws IOException { 134 compile(JavaSource.createJavaSource("@Foo(\"vvvv\")", 135 null, "@interface Foo { }", "\"vvvv\"")); 136 } 137 testUnresolvableAnnotationAttribute()138 static void testUnresolvableAnnotationAttribute() throws IOException { 139 compile(JavaSource.createJavaSource("@Foo(value=\"vvvv\")", 140 null, "@interface Foo { }", "value")); 141 } 142 testFinalVariableWithDefaultConstructor()143 static void testFinalVariableWithDefaultConstructor() throws IOException { 144 compile(JavaSource.createJavaSource("private static final String Foo; public void bar() { }", 145 "private static final String Foo;")); 146 } 147 testFinalVariableWithConstructor()148 static void testFinalVariableWithConstructor() throws IOException { 149 compile(JavaSource.createJavaSource("public Bug (){} private static final String Foo; public void bar() { }", 150 "{}")); 151 } 152 testWholeTextSpan()153 static void testWholeTextSpan() throws IOException { 154 treeSpan(JavaSource.createFullJavaSource("|class X |")); 155 } 156 compile(JavaSource src)157 static void compile(JavaSource src) throws IOException { 158 ByteArrayOutputStream ba = new ByteArrayOutputStream(); 159 PrintWriter writer = new PrintWriter(ba); 160 File tempDir = new File("."); 161 JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); 162 DiagnosticCollector dc = new DiagnosticCollector(); 163 try (JavaFileManager javaFileManager = getJavaFileManager(compiler, dc)) { 164 List<String> options = new ArrayList<>(); 165 options.add("-cp"); 166 options.add(tempDir.getPath()); 167 options.add("-d"); 168 options.add(tempDir.getPath()); 169 options.add("--should-stop=at=GENERATE"); 170 171 List<JavaFileObject> sources = new ArrayList<>(); 172 sources.add(src); 173 JavaCompiler.CompilationTask task = 174 compiler.getTask(writer, javaFileManager, 175 dc, options, null, 176 sources); 177 task.call(); 178 for (Diagnostic diagnostic : (List<Diagnostic>) dc.getDiagnostics()) { 179 long actualStart = diagnostic.getStartPosition(); 180 long actualEnd = diagnostic.getEndPosition(); 181 System.out.println("Source: " + src.source); 182 System.out.println("Diagnostic: " + diagnostic); 183 System.out.print("Start position: Expected: " + src.startPos); 184 System.out.println(", Actual: " + actualStart); 185 System.out.print("End position: Expected: " + src.endPos); 186 System.out.println(", Actual: " + actualEnd); 187 if (src.startPos != actualStart || src.endPos != actualEnd) { 188 throw new RuntimeException("error: trees don't match"); 189 } 190 } 191 } 192 } 193 treeSpan(JavaSource src)194 static void treeSpan(JavaSource src) throws IOException { 195 ByteArrayOutputStream ba = new ByteArrayOutputStream(); 196 PrintWriter writer = new PrintWriter(ba); 197 File tempDir = new File("."); 198 JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); 199 DiagnosticCollector dc = new DiagnosticCollector(); 200 try (JavaFileManager javaFileManager = getJavaFileManager(compiler, dc)) { 201 List<String> options = new ArrayList<>(); 202 options.add("-cp"); 203 options.add(tempDir.getPath()); 204 options.add("-d"); 205 options.add(tempDir.getPath()); 206 options.add("--should-stop=at=GENERATE"); 207 208 List<JavaFileObject> sources = new ArrayList<>(); 209 sources.add(src); 210 JavacTask task = (JavacTask) compiler.getTask(writer, javaFileManager, 211 dc, options, null, 212 sources); 213 SourcePositions sp = Trees.instance(task).getSourcePositions(); 214 boolean[] found = new boolean[1]; 215 new TreeScanner<Void, Void>() { 216 CompilationUnitTree cut; 217 @Override 218 public Void scan(Tree tree, Void p) { 219 if (tree == null) 220 return null; 221 if (tree.getKind() == Kind.COMPILATION_UNIT) { 222 cut = (CompilationUnitTree) tree; 223 } 224 found[0] |= (sp.getStartPosition(cut, tree) == src.startPos) && 225 (sp.getEndPosition(cut, tree) == src.endPos); 226 return super.scan(tree, p); 227 } 228 }.scan(task.parse(), null); 229 230 if (!found[0]) { 231 throw new IllegalStateException(); 232 } 233 } 234 } 235 } 236