test/tools/javac/tree/AbstractTreeScannerTest.java

Thu, 31 Aug 2017 15:17:03 +0800

author
aoqi
date
Thu, 31 Aug 2017 15:17:03 +0800
changeset 2525
2eb010b6cb22
parent 1127
ca49d50318dc
parent 0
959103a6100f
permissions
-rw-r--r--

merge

aoqi@0 1 /*
aoqi@0 2 * Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
aoqi@0 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
aoqi@0 4 *
aoqi@0 5 * This code is free software; you can redistribute it and/or modify it
aoqi@0 6 * under the terms of the GNU General Public License version 2 only, as
aoqi@0 7 * published by the Free Software Foundation.
aoqi@0 8 *
aoqi@0 9 * This code is distributed in the hope that it will be useful, but WITHOUT
aoqi@0 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
aoqi@0 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
aoqi@0 12 * version 2 for more details (a copy is included in the LICENSE file that
aoqi@0 13 * accompanied this code).
aoqi@0 14 *
aoqi@0 15 * You should have received a copy of the GNU General Public License version
aoqi@0 16 * 2 along with this work; if not, write to the Free Software Foundation,
aoqi@0 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
aoqi@0 18 *
aoqi@0 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
aoqi@0 20 * or visit www.oracle.com if you need additional information or have any
aoqi@0 21 * questions.
aoqi@0 22 */
aoqi@0 23
aoqi@0 24 import java.io.*;
aoqi@0 25 import java.lang.reflect.*;
aoqi@0 26 import java.util.*;
aoqi@0 27 import javax.tools.*;
aoqi@0 28
aoqi@0 29 import com.sun.source.tree.CompilationUnitTree;
aoqi@0 30 import com.sun.source.tree.Tree;
aoqi@0 31 import com.sun.source.util.JavacTask;
aoqi@0 32 import com.sun.tools.javac.api.JavacTool;
aoqi@0 33 import com.sun.tools.javac.tree.JCTree;
aoqi@0 34 import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
aoqi@0 35 import com.sun.tools.javac.util.List;
aoqi@0 36
aoqi@0 37 public abstract class AbstractTreeScannerTest {
aoqi@0 38
aoqi@0 39 /**
aoqi@0 40 * Run the program. A base directory can be provided for file arguments.
aoqi@0 41 * In jtreg mode, the -r option can be given to change the default base
aoqi@0 42 * directory to the test root directory. For other options, see usage().
aoqi@0 43 * @param baseDir base directory for any file arguments.
aoqi@0 44 * @param args command line args
aoqi@0 45 * @return true if successful or in gui mode
aoqi@0 46 */
aoqi@0 47 boolean run(File baseDir, String... args) {
aoqi@0 48 if (args.length == 0) {
aoqi@0 49 usage(System.out);
aoqi@0 50 return true;
aoqi@0 51 }
aoqi@0 52
aoqi@0 53 ArrayList<File> files = new ArrayList<File>();
aoqi@0 54 for (int i = 0; i < args.length; i++) {
aoqi@0 55 String arg = args[i];
aoqi@0 56 if (arg.equals("-q"))
aoqi@0 57 quiet = true;
aoqi@0 58 else if (arg.equals("-v"))
aoqi@0 59 verbose = true;
aoqi@0 60 else if (arg.equals("-r")) {
aoqi@0 61 File d = baseDir;
aoqi@0 62 while (!new File(d, "TEST.ROOT").exists()) {
aoqi@0 63 d = d.getParentFile();
aoqi@0 64 if (d == null)
aoqi@0 65 throw new Error("cannot find TEST.ROOT");
aoqi@0 66 }
aoqi@0 67 baseDir = d;
aoqi@0 68 }
aoqi@0 69 else if (arg.startsWith("-"))
aoqi@0 70 throw new Error("unknown option: " + arg);
aoqi@0 71 else {
aoqi@0 72 while (i < args.length)
aoqi@0 73 files.add(new File(baseDir, args[i++]));
aoqi@0 74 }
aoqi@0 75 }
aoqi@0 76
aoqi@0 77 for (File file: files) {
aoqi@0 78 if (file.exists())
aoqi@0 79 test(file);
aoqi@0 80 else
aoqi@0 81 error("File not found: " + file);
aoqi@0 82 }
aoqi@0 83
aoqi@0 84 if (fileCount != 1)
aoqi@0 85 System.err.println(fileCount + " files read");
aoqi@0 86 System.err.println(treeCount + " tree nodes compared");
aoqi@0 87 if (errors > 0)
aoqi@0 88 System.err.println(errors + " errors");
aoqi@0 89
aoqi@0 90 return (errors == 0);
aoqi@0 91 }
aoqi@0 92
aoqi@0 93 /**
aoqi@0 94 * Print command line help.
aoqi@0 95 * @param out output stream
aoqi@0 96 */
aoqi@0 97 void usage(PrintStream out) {
aoqi@0 98 out.println("Usage:");
aoqi@0 99 out.println(" java " + getClass().getName() + " options... files...");
aoqi@0 100 out.println("");
aoqi@0 101 out.println("where options include:");
aoqi@0 102 out.println("-q Quiet: don't report on inapplicable files");
aoqi@0 103 out.println("-v Verbose: report on files as they are being read");
aoqi@0 104 out.println("");
aoqi@0 105 out.println("files may be directories or files");
aoqi@0 106 out.println("directories will be scanned recursively");
aoqi@0 107 out.println("non java files, or java files which cannot be parsed, will be ignored");
aoqi@0 108 out.println("");
aoqi@0 109 }
aoqi@0 110
aoqi@0 111 /**
aoqi@0 112 * Test a file. If the file is a directory, it will be recursively scanned
aoqi@0 113 * for java files.
aoqi@0 114 * @param file the file or directory to test
aoqi@0 115 */
aoqi@0 116 void test(File file) {
aoqi@0 117 if (file.isDirectory()) {
aoqi@0 118 for (File f: file.listFiles()) {
aoqi@0 119 test(f);
aoqi@0 120 }
aoqi@0 121 return;
aoqi@0 122 }
aoqi@0 123
aoqi@0 124 if (file.isFile() && file.getName().endsWith(".java")) {
aoqi@0 125 try {
aoqi@0 126 if (verbose)
aoqi@0 127 System.err.println(file);
aoqi@0 128 fileCount++;
aoqi@0 129 treeCount += test(read(file));
aoqi@0 130 } catch (ParseException e) {
aoqi@0 131 if (!quiet) {
aoqi@0 132 error("Error parsing " + file + "\n" + e.getMessage());
aoqi@0 133 }
aoqi@0 134 } catch (IOException e) {
aoqi@0 135 error("Error reading " + file + ": " + e);
aoqi@0 136 }
aoqi@0 137 return;
aoqi@0 138 }
aoqi@0 139
aoqi@0 140 if (!quiet)
aoqi@0 141 error("File " + file + " ignored");
aoqi@0 142 }
aoqi@0 143
aoqi@0 144 abstract int test(JCCompilationUnit t);
aoqi@0 145
aoqi@0 146 // See CR: 6982992 Tests CheckAttributedTree.java, JavacTreeScannerTest.java, and SourceTreeeScannerTest.java timeout
aoqi@0 147 StringWriter sw = new StringWriter();
aoqi@0 148 PrintWriter pw = new PrintWriter(sw);
aoqi@0 149 Reporter r = new Reporter(pw);
aoqi@0 150 JavacTool tool = JavacTool.create();
aoqi@0 151 StandardJavaFileManager fm = tool.getStandardFileManager(r, null, null);
aoqi@0 152
aoqi@0 153 /**
aoqi@0 154 * Read a file.
aoqi@0 155 * @param file the file to be read
aoqi@0 156 * @return the tree for the content of the file
aoqi@0 157 * @throws IOException if any IO errors occur
aoqi@0 158 * @throws TreePosTest.ParseException if any errors occur while parsing the file
aoqi@0 159 */
aoqi@0 160 JCCompilationUnit read(File file) throws IOException, ParseException {
aoqi@0 161 JavacTool tool = JavacTool.create();
aoqi@0 162 r.errors = 0;
aoqi@0 163 Iterable<? extends JavaFileObject> files = fm.getJavaFileObjects(file);
aoqi@0 164 JavacTask task = tool.getTask(pw, fm, r, Collections.<String>emptyList(), null, files);
aoqi@0 165 Iterable<? extends CompilationUnitTree> trees = task.parse();
aoqi@0 166 pw.flush();
aoqi@0 167 if (r.errors > 0)
aoqi@0 168 throw new ParseException(sw.toString());
aoqi@0 169 Iterator<? extends CompilationUnitTree> iter = trees.iterator();
aoqi@0 170 if (!iter.hasNext())
aoqi@0 171 throw new Error("no trees found");
aoqi@0 172 JCCompilationUnit t = (JCCompilationUnit) iter.next();
aoqi@0 173 if (iter.hasNext())
aoqi@0 174 throw new Error("too many trees found");
aoqi@0 175 return t;
aoqi@0 176 }
aoqi@0 177
aoqi@0 178 /**
aoqi@0 179 * Report an error. When the program is complete, the program will either
aoqi@0 180 * exit or throw an Error if any errors have been reported.
aoqi@0 181 * @param msg the error message
aoqi@0 182 */
aoqi@0 183 void error(String msg) {
aoqi@0 184 System.err.println(msg);
aoqi@0 185 errors++;
aoqi@0 186 }
aoqi@0 187
aoqi@0 188 /**
aoqi@0 189 * Report an error. When the program is complete, the program will either
aoqi@0 190 * exit or throw an Error if any errors have been reported.
aoqi@0 191 * @param msg the error message
aoqi@0 192 */
aoqi@0 193 void error(JavaFileObject file, String msg) {
aoqi@0 194 System.err.println(file.getName() + ": " + msg);
aoqi@0 195 errors++;
aoqi@0 196 }
aoqi@0 197
aoqi@0 198 /**
aoqi@0 199 * Report an error for a specific tree node.
aoqi@0 200 * @param file the source file for the tree
aoqi@0 201 * @param t the tree node
aoqi@0 202 * @param label an indication of the error
aoqi@0 203 */
aoqi@0 204 void error(JavaFileObject file, Tree tree, String msg) {
aoqi@0 205 JCTree t = (JCTree) tree;
aoqi@0 206 error(file.getName() + ":" + getLine(file, t) + ": " + msg + " " + trim(t, 64));
aoqi@0 207 }
aoqi@0 208
aoqi@0 209 /**
aoqi@0 210 * Get a trimmed string for a tree node, with normalized white space and limited length.
aoqi@0 211 */
aoqi@0 212 String trim(Tree tree, int len) {
aoqi@0 213 JCTree t = (JCTree) tree;
aoqi@0 214 String s = t.toString().replaceAll("\\s+", " ");
aoqi@0 215 return (s.length() < len) ? s : s.substring(0, len);
aoqi@0 216 }
aoqi@0 217
aoqi@0 218 /** Number of files that have been analyzed. */
aoqi@0 219 int fileCount;
aoqi@0 220 /** Number of trees that have been successfully compared. */
aoqi@0 221 int treeCount;
aoqi@0 222 /** Number of errors reported. */
aoqi@0 223 int errors;
aoqi@0 224 /** Flag: don't report irrelevant files. */
aoqi@0 225 boolean quiet;
aoqi@0 226 /** Flag: report files as they are processed. */
aoqi@0 227 boolean verbose;
aoqi@0 228
aoqi@0 229
aoqi@0 230 /**
aoqi@0 231 * Thrown when errors are found parsing a java file.
aoqi@0 232 */
aoqi@0 233 private static class ParseException extends Exception {
aoqi@0 234 ParseException(String msg) {
aoqi@0 235 super(msg);
aoqi@0 236 }
aoqi@0 237 }
aoqi@0 238
aoqi@0 239 /**
aoqi@0 240 * DiagnosticListener to report diagnostics and count any errors that occur.
aoqi@0 241 */
aoqi@0 242 private static class Reporter implements DiagnosticListener<JavaFileObject> {
aoqi@0 243 Reporter(PrintWriter out) {
aoqi@0 244 this.out = out;
aoqi@0 245 }
aoqi@0 246
aoqi@0 247 public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
aoqi@0 248 out.println(diagnostic);
aoqi@0 249 switch (diagnostic.getKind()) {
aoqi@0 250 case ERROR:
aoqi@0 251 errors++;
aoqi@0 252 }
aoqi@0 253 }
aoqi@0 254 int errors;
aoqi@0 255 PrintWriter out;
aoqi@0 256 }
aoqi@0 257
aoqi@0 258 /**
aoqi@0 259 * Get the set of fields for a tree node that may contain child tree nodes.
aoqi@0 260 * These are the fields that are subtypes of JCTree or List.
aoqi@0 261 * The results are cached, based on the tree's tag.
aoqi@0 262 */
aoqi@0 263 Set<Field> getFields(JCTree tree) {
aoqi@0 264 Set<Field> fields = map.get(tree.getTag());
aoqi@0 265 if (fields == null) {
aoqi@0 266 fields = new HashSet<Field>();
aoqi@0 267 for (Field f: tree.getClass().getFields()) {
aoqi@0 268 Class<?> fc = f.getType();
aoqi@0 269 if (JCTree.class.isAssignableFrom(fc) || List.class.isAssignableFrom(fc))
aoqi@0 270 fields.add(f);
aoqi@0 271 }
aoqi@0 272 map.put(tree.getTag(), fields);
aoqi@0 273 }
aoqi@0 274 return fields;
aoqi@0 275 }
aoqi@0 276 // where
aoqi@0 277 Map<JCTree.Tag, Set<Field>> map = new HashMap<JCTree.Tag,Set<Field>>();
aoqi@0 278
aoqi@0 279 /** Get the line number for the primary position for a tree.
aoqi@0 280 * The code is intended to be simple, although not necessarily efficient.
aoqi@0 281 * However, note that a file manager such as JavacFileManager is likely
aoqi@0 282 * to cache the results of file.getCharContent, avoiding the need to read
aoqi@0 283 * the bits from disk each time this method is called.
aoqi@0 284 */
aoqi@0 285 int getLine(JavaFileObject file, JCTree tree) {
aoqi@0 286 try {
aoqi@0 287 CharSequence cs = file.getCharContent(true);
aoqi@0 288 int line = 1;
aoqi@0 289 for (int i = 0; i < tree.pos; i++) {
aoqi@0 290 if (cs.charAt(i) == '\n') // jtreg tests always use Unix line endings
aoqi@0 291 line++;
aoqi@0 292 }
aoqi@0 293 return line;
aoqi@0 294 } catch (IOException e) {
aoqi@0 295 return -1;
aoqi@0 296 }
aoqi@0 297 }
aoqi@0 298 }

mercurial