test/tools/javac/tree/AbstractTreeScannerTest.java

Tue, 28 Dec 2010 15:54:52 -0800

author
ohair
date
Tue, 28 Dec 2010 15:54:52 -0800
changeset 798
4868a36f6fd8
parent 683
bbc9765d9ec6
child 808
e8719f95f2d0
permissions
-rw-r--r--

6962318: Update copyright year
Reviewed-by: xdono

     1 /*
     2  * Copyright (c) 2010, 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  */
    24 import java.io.*;
    25 import java.lang.reflect.*;
    26 import java.util.*;
    27 import javax.tools.*;
    29 import com.sun.source.tree.CompilationUnitTree;
    30 import com.sun.source.tree.Tree;
    31 import com.sun.source.util.JavacTask;
    32 import com.sun.tools.javac.api.JavacTool;
    33 import com.sun.tools.javac.tree.JCTree;
    34 import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
    35 import com.sun.tools.javac.util.List;
    37 public abstract class AbstractTreeScannerTest {
    39     /**
    40      * Run the program. A base directory can be provided for file arguments.
    41      * In jtreg mode, the -r option can be given to change the default base
    42      * directory to the test root directory. For other options, see usage().
    43      * @param baseDir base directory for any file arguments.
    44      * @param args command line args
    45      * @return true if successful or in gui mode
    46      */
    47     boolean run(File baseDir, String... args) {
    48         if (args.length == 0) {
    49             usage(System.out);
    50             return true;
    51         }
    53         ArrayList<File> files = new ArrayList<File>();
    54         for (int i = 0; i < args.length; i++) {
    55             String arg = args[i];
    56             if (arg.equals("-q"))
    57                 quiet = true;
    58             else if (arg.equals("-v"))
    59                 verbose = true;
    60             else if (arg.equals("-r")) {
    61                 File d = baseDir;
    62                 while (!new File(d, "TEST.ROOT").exists()) {
    63                     d = d.getParentFile();
    64                     if (d == null)
    65                         throw new Error("cannot find TEST.ROOT");
    66                 }
    67                 baseDir = d;
    68             }
    69             else if (arg.startsWith("-"))
    70                 throw new Error("unknown option: " + arg);
    71             else {
    72                 while (i < args.length)
    73                     files.add(new File(baseDir, args[i++]));
    74             }
    75         }
    77         for (File file: files) {
    78             if (file.exists())
    79                 test(file);
    80             else
    81                 error("File not found: " + file);
    82         }
    84         if (fileCount != 1)
    85             System.err.println(fileCount + " files read");
    86         System.err.println(treeCount + " tree nodes compared");
    87         if (errors > 0)
    88             System.err.println(errors + " errors");
    90         return (errors == 0);
    91     }
    93     /**
    94      * Print command line help.
    95      * @param out output stream
    96      */
    97     void usage(PrintStream out) {
    98         out.println("Usage:");
    99         out.println("  java " + getClass().getName() + " options... files...");
   100         out.println("");
   101         out.println("where options include:");
   102         out.println("-q        Quiet: don't report on inapplicable files");
   103         out.println("-v        Verbose: report on files as they are being read");
   104         out.println("");
   105         out.println("files may be directories or files");
   106         out.println("directories will be scanned recursively");
   107         out.println("non java files, or java files which cannot be parsed, will be ignored");
   108         out.println("");
   109     }
   111     /**
   112      * Test a file. If the file is a directory, it will be recursively scanned
   113      * for java files.
   114      * @param file the file or directory to test
   115      */
   116     void test(File file) {
   117         if (file.isDirectory()) {
   118             for (File f: file.listFiles()) {
   119                 test(f);
   120             }
   121             return;
   122         }
   124         if (file.isFile() && file.getName().endsWith(".java")) {
   125             try {
   126                 if (verbose)
   127                     System.err.println(file);
   128                 fileCount++;
   129                 treeCount += test(read(file));
   130             } catch (ParseException e) {
   131                 if (!quiet) {
   132                     error("Error parsing " + file + "\n" + e.getMessage());
   133                 }
   134             } catch (IOException e) {
   135                 error("Error reading " + file + ": " + e);
   136             }
   137             return;
   138         }
   140         if (!quiet)
   141             error("File " + file + " ignored");
   142     }
   144     abstract int test(JCCompilationUnit t);
   146     /**
   147      * Read a file.
   148      * @param file the file to be read
   149      * @return the tree for the content of the file
   150      * @throws IOException if any IO errors occur
   151      * @throws TreePosTest.ParseException if any errors occur while parsing the file
   152      */
   153     JCCompilationUnit read(File file) throws IOException, ParseException {
   154         StringWriter sw = new StringWriter();
   155         PrintWriter pw = new PrintWriter(sw);
   156         Reporter r = new Reporter(pw);
   157         JavacTool tool = JavacTool.create();
   158         StandardJavaFileManager fm = tool.getStandardFileManager(r, null, null);
   159         Iterable<? extends JavaFileObject> files = fm.getJavaFileObjects(file);
   160         JavacTask task = tool.getTask(pw, fm, r, Collections.<String>emptyList(), null, files);
   161         Iterable<? extends CompilationUnitTree> trees = task.parse();
   162         pw.flush();
   163         if (r.errors > 0)
   164             throw new ParseException(sw.toString());
   165         Iterator<? extends CompilationUnitTree> iter = trees.iterator();
   166         if (!iter.hasNext())
   167             throw new Error("no trees found");
   168         JCCompilationUnit t = (JCCompilationUnit) iter.next();
   169         if (iter.hasNext())
   170             throw new Error("too many trees found");
   171         return t;
   172     }
   174     /**
   175      * Report an error. When the program is complete, the program will either
   176      * exit or throw an Error if any errors have been reported.
   177      * @param msg the error message
   178      */
   179     void error(String msg) {
   180         System.err.println(msg);
   181         errors++;
   182     }
   184     /**
   185      * Report an error. When the program is complete, the program will either
   186      * exit or throw an Error if any errors have been reported.
   187      * @param msg the error message
   188      */
   189     void error(JavaFileObject file, String msg) {
   190         System.err.println(file.getName() + ": " + msg);
   191         errors++;
   192     }
   194     /**
   195      *  Report an error for a specific tree node.
   196      *  @param file the source file for the tree
   197      *  @param t    the tree node
   198      *  @param label an indication of the error
   199      */
   200     void error(JavaFileObject file, Tree tree, String msg) {
   201         JCTree t = (JCTree) tree;
   202         error(file.getName() + ":" + getLine(file, t) + ": " + msg + " " + trim(t, 64));
   203     }
   205     /**
   206      * Get a trimmed string for a tree node, with normalized white space and limited length.
   207      */
   208     String trim(Tree tree, int len) {
   209         JCTree t = (JCTree) tree;
   210         String s = t.toString().replaceAll("\\s+", " ");
   211         return (s.length() < len) ? s : s.substring(0, len);
   212     }
   214     /** Number of files that have been analyzed. */
   215     int fileCount;
   216     /** Number of trees that have been successfully compared. */
   217     int treeCount;
   218     /** Number of errors reported. */
   219     int errors;
   220     /** Flag: don't report irrelevant files. */
   221     boolean quiet;
   222     /** Flag: report files as they are processed. */
   223     boolean verbose;
   226     /**
   227      * Thrown when errors are found parsing a java file.
   228      */
   229     private static class ParseException extends Exception {
   230         ParseException(String msg) {
   231             super(msg);
   232         }
   233     }
   235     /**
   236      * DiagnosticListener to report diagnostics and count any errors that occur.
   237      */
   238     private static class Reporter implements DiagnosticListener<JavaFileObject> {
   239         Reporter(PrintWriter out) {
   240             this.out = out;
   241         }
   243         public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
   244             out.println(diagnostic);
   245             switch (diagnostic.getKind()) {
   246                 case ERROR:
   247                     errors++;
   248             }
   249         }
   250         int errors;
   251         PrintWriter out;
   252     }
   254     /**
   255      * Get the set of fields for a tree node that may contain child tree nodes.
   256      * These are the fields that are subtypes of JCTree or List.
   257      * The results are cached, based on the tree's tag.
   258      */
   259     Set<Field> getFields(JCTree tree) {
   260         Set<Field> fields = map.get(tree.getTag());
   261         if (fields == null) {
   262             fields = new HashSet<Field>();
   263             for (Field f: tree.getClass().getFields()) {
   264                 Class<?> fc = f.getType();
   265                 if (JCTree.class.isAssignableFrom(fc) || List.class.isAssignableFrom(fc))
   266                     fields.add(f);
   267             }
   268             map.put(tree.getTag(), fields);
   269         }
   270         return fields;
   271     }
   272     // where
   273     Map<Integer, Set<Field>> map = new HashMap<Integer,Set<Field>>();
   275     /** Get the line number for the primary position for a tree.
   276      * The code is intended to be simple, although not necessarily efficient.
   277      * However, note that a file manager such as JavacFileManager is likely
   278      * to cache the results of file.getCharContent, avoiding the need to read
   279      * the bits from disk each time this method is called.
   280      */
   281     int getLine(JavaFileObject file, JCTree tree) {
   282         try {
   283             CharSequence cs = file.getCharContent(true);
   284             int line = 1;
   285             for (int i = 0; i < tree.pos; i++) {
   286                 if (cs.charAt(i) == '\n') // jtreg tests always use Unix line endings
   287                     line++;
   288             }
   289             return line;
   290         } catch (IOException e) {
   291             return -1;
   292         }
   293     }
   294 }

mercurial