Thu, 04 Feb 2010 10:14:28 -0800
6923080: TreeScanner.visitNewClass should scan tree.typeargs
Reviewed-by: darcy
1.1 --- a/src/share/classes/com/sun/tools/javac/code/TypeAnnotations.java Wed Feb 03 16:58:57 2010 -0800 1.2 +++ b/src/share/classes/com/sun/tools/javac/code/TypeAnnotations.java Thu Feb 04 10:14:28 2010 -0800 1.3 @@ -240,13 +240,6 @@ 1.4 return p; 1.5 } 1.6 1.7 - @Override 1.8 - public void visitApply(JCMethodInvocation tree) { 1.9 - scan(tree.meth); 1.10 - scan(tree.typeargs); 1.11 - scan(tree.args); 1.12 - } 1.13 - 1.14 private void setTypeAnnotationPos(List<JCTypeAnnotation> annotations, TypeAnnotationPosition position) { 1.15 for (JCTypeAnnotation anno : annotations) { 1.16 anno.annotation_position = position;
2.1 --- a/src/share/classes/com/sun/tools/javac/comp/MemberEnter.java Wed Feb 03 16:58:57 2010 -0800 2.2 +++ b/src/share/classes/com/sun/tools/javac/comp/MemberEnter.java Thu Feb 04 10:14:28 2010 -0800 2.3 @@ -1065,11 +1065,6 @@ 2.4 super.visitNewArray(tree); 2.5 } 2.6 @Override 2.7 - public void visitApply(JCMethodInvocation tree) { 2.8 - super.visitApply(tree); 2.9 - scan(tree.typeargs); 2.10 - } 2.11 - @Override 2.12 public void visitMethodDef(JCMethodDecl tree) { 2.13 annotate(tree, tree.receiverAnnotations); 2.14 super.visitMethodDef(tree);
3.1 --- a/src/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java Wed Feb 03 16:58:57 2010 -0800 3.2 +++ b/src/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java Thu Feb 04 10:14:28 2010 -0800 3.3 @@ -1295,10 +1295,6 @@ 3.4 node.sym = null; 3.5 super.visitIdent(node); 3.6 } 3.7 - public void visitApply(JCMethodInvocation node) { 3.8 - scan(node.typeargs); 3.9 - super.visitApply(node); 3.10 - } 3.11 }; 3.12 3.13
4.1 --- a/src/share/classes/com/sun/tools/javac/tree/TreeScanner.java Wed Feb 03 16:58:57 2010 -0800 4.2 +++ b/src/share/classes/com/sun/tools/javac/tree/TreeScanner.java Thu Feb 04 10:14:28 2010 -0800 4.3 @@ -193,6 +193,7 @@ 4.4 } 4.5 4.6 public void visitApply(JCMethodInvocation tree) { 4.7 + scan(tree.typeargs); 4.8 scan(tree.meth); 4.9 scan(tree.args); 4.10 } 4.11 @@ -200,6 +201,7 @@ 4.12 public void visitNewClass(JCNewClass tree) { 4.13 scan(tree.encl); 4.14 scan(tree.clazz); 4.15 + scan(tree.typeargs); 4.16 scan(tree.args); 4.17 scan(tree.def); 4.18 }
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 5.2 +++ b/test/tools/javac/tree/T6923080.java Thu Feb 04 10:14:28 2010 -0800 5.3 @@ -0,0 +1,40 @@ 5.4 +/* 5.5 + * Copyright 2010 Sun Microsystems, Inc. All Rights Reserved. 5.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 5.7 + * 5.8 + * This code is free software; you can redistribute it and/or modify it 5.9 + * under the terms of the GNU General Public License version 2 only, as 5.10 + * published by the Free Software Foundation. 5.11 + * 5.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 5.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 5.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 5.15 + * version 2 for more details (a copy is included in the LICENSE file that 5.16 + * accompanied this code). 5.17 + * 5.18 + * You should have received a copy of the GNU General Public License version 5.19 + * 2 along with this work; if not, write to the Free Software Foundation, 5.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 5.21 + * 5.22 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, 5.23 + * CA 95054 USA or visit www.sun.com if you need additional information or 5.24 + * have any questions. 5.25 + */ 5.26 + 5.27 +/* 5.28 + * This file is not a regular test, but is processed by ./TreeScannerTest.java, 5.29 + * which verifies the operation of the javac TreeScanner. 5.30 + * @bug 6923080 5.31 + * @summary TreeScanner.visitNewClass should scan tree.typeargs 5.32 + */ 5.33 +class T6923080 { 5.34 + void test() { 5.35 + C c = new <Integer>C(); // exercises TreeScanner.visitNewClass 5.36 + Object o = c.<Float>m(); // exercises TreeScanner.visitApply 5.37 + } 5.38 + 5.39 + static class C { 5.40 + <T> C() { } 5.41 + <T> T m() { return null; } 5.42 + } 5.43 +}
6.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 6.2 +++ b/test/tools/javac/tree/TreeScannerTest.java Thu Feb 04 10:14:28 2010 -0800 6.3 @@ -0,0 +1,387 @@ 6.4 +/* 6.5 + * Copyright 2010 Sun Microsystems, Inc. All Rights Reserved. 6.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 6.7 + * 6.8 + * This code is free software; you can redistribute it and/or modify it 6.9 + * under the terms of the GNU General Public License version 2 only, as 6.10 + * published by the Free Software Foundation. 6.11 + * 6.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 6.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 6.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 6.15 + * version 2 for more details (a copy is included in the LICENSE file that 6.16 + * accompanied this code). 6.17 + * 6.18 + * You should have received a copy of the GNU General Public License version 6.19 + * 2 along with this work; if not, write to the Free Software Foundation, 6.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 6.21 + * 6.22 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, 6.23 + * CA 95054 USA or visit www.sun.com if you need additional information or 6.24 + * have any questions. 6.25 + */ 6.26 + 6.27 + 6.28 +/** 6.29 + * Utility and test program to check javac's internal TreeScanner class. 6.30 + * The program can be run standalone, or as a jtreg test. For info on 6.31 + * command line args, run program with no args. 6.32 + * 6.33 + * <p> 6.34 + * jtreg: Note that by using the -r switch in the test description below, this test 6.35 + * will process all java files in the langtools/test directory, thus implicitly 6.36 + * covering any new language features that may be tested in this test suite. 6.37 + */ 6.38 + 6.39 +/* 6.40 + * @test 6.41 + * @bug 6923080 6.42 + * @summary TreeScanner.visitNewClass should scan tree.typeargs 6.43 + * @run main TreeScannerTest -q -r . 6.44 + */ 6.45 + 6.46 +import java.io.*; 6.47 +import java.lang.reflect.*; 6.48 +import java.util.*; 6.49 +import javax.tools.*; 6.50 + 6.51 +import com.sun.source.tree.CompilationUnitTree; 6.52 +import com.sun.source.util.JavacTask; 6.53 +import com.sun.tools.javac.api.JavacTool; 6.54 +import com.sun.tools.javac.tree.*; 6.55 +import com.sun.tools.javac.tree.JCTree.*; 6.56 +import com.sun.tools.javac.util.List; 6.57 + 6.58 +public class TreeScannerTest { 6.59 + /** 6.60 + * Main entry point. 6.61 + * If test.src is set, program runs in jtreg mode, and will throw an Error 6.62 + * if any errors arise, otherwise System.exit will be used. In jtreg mode, 6.63 + * the default base directory for file args is the value of ${test.src}. 6.64 + * In jtreg mode, the -r option can be given to change the default base 6.65 + * directory to the root test directory. 6.66 + */ 6.67 + public static void main(String... args) { 6.68 + String testSrc = System.getProperty("test.src"); 6.69 + File baseDir = (testSrc == null) ? null : new File(testSrc); 6.70 + boolean ok = new TreeScannerTest().run(baseDir, args); 6.71 + if (!ok) { 6.72 + if (testSrc != null) // jtreg mode 6.73 + throw new Error("failed"); 6.74 + else 6.75 + System.exit(1); 6.76 + } 6.77 + } 6.78 + 6.79 + /** 6.80 + * Run the program. A base directory can be provided for file arguments. 6.81 + * In jtreg mode, the -r option can be given to change the default base 6.82 + * directory to the test root directory. For other options, see usage(). 6.83 + * @param baseDir base directory for any file arguments. 6.84 + * @param args command line args 6.85 + * @return true if successful or in gui mode 6.86 + */ 6.87 + boolean run(File baseDir, String... args) { 6.88 + if (args.length == 0) { 6.89 + usage(System.out); 6.90 + return true; 6.91 + } 6.92 + 6.93 + ArrayList<File> files = new ArrayList<File>(); 6.94 + for (int i = 0; i < args.length; i++) { 6.95 + String arg = args[i]; 6.96 + if (arg.equals("-q")) 6.97 + quiet = true; 6.98 + else if (arg.equals("-v")) 6.99 + verbose = true; 6.100 + else if (arg.equals("-r")) { 6.101 + File d = baseDir; 6.102 + while (!new File(d, "TEST.ROOT").exists()) { 6.103 + d = d.getParentFile(); 6.104 + if (d == null) 6.105 + throw new Error("cannot find TEST.ROOT"); 6.106 + } 6.107 + baseDir = d; 6.108 + } 6.109 + else if (arg.startsWith("-")) 6.110 + throw new Error("unknown option: " + arg); 6.111 + else { 6.112 + while (i < args.length) 6.113 + files.add(new File(baseDir, args[i++])); 6.114 + } 6.115 + } 6.116 + 6.117 + for (File file: files) { 6.118 + if (file.exists()) 6.119 + test(file); 6.120 + else 6.121 + error("File not found: " + file); 6.122 + } 6.123 + 6.124 + if (fileCount != 1) 6.125 + System.err.println(fileCount + " files read"); 6.126 + if (errors > 0) 6.127 + System.err.println(errors + " errors"); 6.128 + 6.129 + return (errors == 0); 6.130 + } 6.131 + 6.132 + /** 6.133 + * Print command line help. 6.134 + * @param out output stream 6.135 + */ 6.136 + void usage(PrintStream out) { 6.137 + out.println("Usage:"); 6.138 + out.println(" java TreeScannerTest options... files..."); 6.139 + out.println(""); 6.140 + out.println("where options include:"); 6.141 + out.println("-q Quiet: don't report on inapplicable files"); 6.142 + out.println("-v Verbose: report on files as they are being read"); 6.143 + out.println(""); 6.144 + out.println("files may be directories or files"); 6.145 + out.println("directories will be scanned recursively"); 6.146 + out.println("non java files, or java files which cannot be parsed, will be ignored"); 6.147 + out.println(""); 6.148 + } 6.149 + 6.150 + /** 6.151 + * Test a file. If the file is a directory, it will be recursively scanned 6.152 + * for java files. 6.153 + * @param file the file or directory to test 6.154 + */ 6.155 + void test(File file) { 6.156 + if (file.isDirectory()) { 6.157 + for (File f: file.listFiles()) { 6.158 + test(f); 6.159 + } 6.160 + return; 6.161 + } 6.162 + 6.163 + if (file.isFile() && file.getName().endsWith(".java")) { 6.164 + try { 6.165 + if (verbose) 6.166 + System.err.println(file); 6.167 + fileCount++; 6.168 + ScanTester t = new ScanTester(); 6.169 + t.test(read(file)); 6.170 + } catch (ParseException e) { 6.171 + if (!quiet) { 6.172 + error("Error parsing " + file + "\n" + e.getMessage()); 6.173 + } 6.174 + } catch (IOException e) { 6.175 + error("Error reading " + file + ": " + e); 6.176 + } 6.177 + return; 6.178 + } 6.179 + 6.180 + if (!quiet) 6.181 + error("File " + file + " ignored"); 6.182 + } 6.183 + 6.184 + /** 6.185 + * Read a file. 6.186 + * @param file the file to be read 6.187 + * @return the tree for the content of the file 6.188 + * @throws IOException if any IO errors occur 6.189 + * @throws TreePosTest.ParseException if any errors occur while parsing the file 6.190 + */ 6.191 + JCCompilationUnit read(File file) throws IOException, ParseException { 6.192 + StringWriter sw = new StringWriter(); 6.193 + PrintWriter pw = new PrintWriter(sw); 6.194 + Reporter r = new Reporter(pw); 6.195 + JavacTool tool = JavacTool.create(); 6.196 + StandardJavaFileManager fm = tool.getStandardFileManager(r, null, null); 6.197 + Iterable<? extends JavaFileObject> files = fm.getJavaFileObjects(file); 6.198 + JavacTask task = tool.getTask(pw, fm, r, Collections.<String>emptyList(), null, files); 6.199 + Iterable<? extends CompilationUnitTree> trees = task.parse(); 6.200 + pw.flush(); 6.201 + if (r.errors > 0) 6.202 + throw new ParseException(sw.toString()); 6.203 + Iterator<? extends CompilationUnitTree> iter = trees.iterator(); 6.204 + if (!iter.hasNext()) 6.205 + throw new Error("no trees found"); 6.206 + JCCompilationUnit t = (JCCompilationUnit) iter.next(); 6.207 + if (iter.hasNext()) 6.208 + throw new Error("too many trees found"); 6.209 + return t; 6.210 + } 6.211 + 6.212 + /** 6.213 + * Report an error. When the program is complete, the program will either 6.214 + * exit or throw an Error if any errors have been reported. 6.215 + * @param msg the error message 6.216 + */ 6.217 + void error(String msg) { 6.218 + System.err.println(msg); 6.219 + errors++; 6.220 + } 6.221 + 6.222 + /** 6.223 + * Report an error for a specific tree node. 6.224 + * @param file the source file for the tree 6.225 + * @param t the tree node 6.226 + * @param label an indication of the error 6.227 + */ 6.228 + void error(JavaFileObject file, JCTree t, String msg) { 6.229 + error(file.getName() + ":" + getLine(file, t) + ": " + msg + " " + trim(t, 64)); 6.230 + } 6.231 + 6.232 + /** 6.233 + * Get a trimmed string for a tree node, with normalized white space and limited length. 6.234 + */ 6.235 + String trim(JCTree t, int len) { 6.236 + String s = t.toString().replaceAll("[\r\n]+", " ").replaceAll(" +", " "); 6.237 + return (s.length() < len) ? s : s.substring(0, len); 6.238 + } 6.239 + 6.240 + /** Number of files that have been analyzed. */ 6.241 + int fileCount; 6.242 + /** Number of errors reported. */ 6.243 + int errors; 6.244 + /** Flag: don't report irrelevant files. */ 6.245 + boolean quiet; 6.246 + /** Flag: report files as they are processed. */ 6.247 + boolean verbose; 6.248 + 6.249 + /** 6.250 + * Main class for testing operation of tree scanner. 6.251 + * The set of nodes found by the scanner are compared 6.252 + * against the set of nodes found by reflection. 6.253 + */ 6.254 + private class ScanTester extends TreeScanner { 6.255 + /** Main entry method for the class. */ 6.256 + void test(JCCompilationUnit tree) { 6.257 + sourcefile = tree.sourcefile; 6.258 + found = new HashSet<JCTree>(); 6.259 + scan(tree); 6.260 + expect = new HashSet<JCTree>(); 6.261 + reflectiveScan(tree); 6.262 + if (found.equals(expect)) 6.263 + return; 6.264 + 6.265 + error("Differences found for " + tree.sourcefile.getName()); 6.266 + 6.267 + if (found.size() != expect.size()) 6.268 + error("Size mismatch; found: " + found.size() + ", expected: " + expect.size()); 6.269 + 6.270 + Set<JCTree> missing = new HashSet<JCTree>(); 6.271 + missing.addAll(expect); 6.272 + missing.removeAll(found); 6.273 + for (JCTree t: missing) 6.274 + error(tree.sourcefile, t, "missing"); 6.275 + 6.276 + Set<JCTree> excess = new HashSet<JCTree>(); 6.277 + excess.addAll(found); 6.278 + excess.removeAll(expect); 6.279 + for (JCTree t: excess) 6.280 + error(tree.sourcefile, t, "unexpected"); 6.281 + } 6.282 + 6.283 + /** Record all tree nodes found by scanner. */ 6.284 + @Override 6.285 + public void scan(JCTree tree) { 6.286 + if (tree == null) 6.287 + return; 6.288 + System.err.println("FOUND: " + tree.getTag() + " " + trim(tree, 64)); 6.289 + found.add(tree); 6.290 + super.scan(tree); 6.291 + } 6.292 + 6.293 + /** record all tree nodes found by reflection. */ 6.294 + public void reflectiveScan(Object o) { 6.295 + if (o == null) 6.296 + return; 6.297 + if (o instanceof JCTree) { 6.298 + JCTree tree = (JCTree) o; 6.299 + System.err.println("EXPECT: " + tree.getTag() + " " + trim(tree, 64)); 6.300 + expect.add(tree); 6.301 + for (Field f: getFields(tree)) { 6.302 + try { 6.303 + //System.err.println("FIELD: " + f.getName()); 6.304 + reflectiveScan(f.get(tree)); 6.305 + } catch (IllegalAccessException e) { 6.306 + error(e.toString()); 6.307 + } 6.308 + } 6.309 + } else if (o instanceof List) { 6.310 + List<?> list = (List<?>) o; 6.311 + for (Object item: list) 6.312 + reflectiveScan(item); 6.313 + } else 6.314 + error("unexpected item: " + o); 6.315 + } 6.316 + 6.317 + JavaFileObject sourcefile; 6.318 + Set<JCTree> found; 6.319 + Set<JCTree> expect; 6.320 + } 6.321 + 6.322 + /** 6.323 + * Thrown when errors are found parsing a java file. 6.324 + */ 6.325 + private static class ParseException extends Exception { 6.326 + ParseException(String msg) { 6.327 + super(msg); 6.328 + } 6.329 + } 6.330 + 6.331 + /** 6.332 + * DiagnosticListener to report diagnostics and count any errors that occur. 6.333 + */ 6.334 + private static class Reporter implements DiagnosticListener<JavaFileObject> { 6.335 + Reporter(PrintWriter out) { 6.336 + this.out = out; 6.337 + } 6.338 + 6.339 + public void report(Diagnostic<? extends JavaFileObject> diagnostic) { 6.340 + out.println(diagnostic); 6.341 + switch (diagnostic.getKind()) { 6.342 + case ERROR: 6.343 + errors++; 6.344 + } 6.345 + } 6.346 + int errors; 6.347 + PrintWriter out; 6.348 + } 6.349 + 6.350 + /** 6.351 + * Get the set of fields for a tree node that may contain child tree nodes. 6.352 + * These are the fields that are subtypes of JCTree or List. 6.353 + * The results are cached, based on the tree's tag. 6.354 + */ 6.355 + Set<Field> getFields(JCTree tree) { 6.356 + Set<Field> fields = map.get(tree.getTag()); 6.357 + if (fields == null) { 6.358 + fields = new HashSet<Field>(); 6.359 + for (Field f: tree.getClass().getFields()) { 6.360 + Class<?> fc = f.getType(); 6.361 + if (JCTree.class.isAssignableFrom(fc) || List.class.isAssignableFrom(fc)) 6.362 + fields.add(f); 6.363 + } 6.364 + map.put(tree.getTag(), fields); 6.365 + } 6.366 + return fields; 6.367 + } 6.368 + // where 6.369 + Map<Integer, Set<Field>> map = new HashMap<Integer,Set<Field>>(); 6.370 + 6.371 + /** Get the line number for the primary position for a tree. 6.372 + * The code is intended to be simple, although not necessarily efficient. 6.373 + * However, note that a file manager such as JavacFileManager is likely 6.374 + * to cache the results of file.getCharContent, avoiding the need to read 6.375 + * the bits from disk each time this method is called. 6.376 + */ 6.377 + int getLine(JavaFileObject file, JCTree tree) { 6.378 + try { 6.379 + CharSequence cs = file.getCharContent(true); 6.380 + int line = 1; 6.381 + for (int i = 0; i < tree.pos; i++) { 6.382 + if (cs.charAt(i) == '\n') // jtreg tests always use Unix line endings 6.383 + line++; 6.384 + } 6.385 + return line; 6.386 + } catch (IOException e) { 6.387 + return -1; 6.388 + } 6.389 + } 6.390 +}