test/tools/javac/tree/AbstractTreeScannerTest.java

Mon, 14 Nov 2011 15:11:10 -0800

author
ksrini
date
Mon, 14 Nov 2011 15:11:10 -0800
changeset 1138
7375d4979bd3
parent 1127
ca49d50318dc
child 2525
2eb010b6cb22
permissions
-rw-r--r--

7106166: (javac) re-factor EndPos parser
Reviewed-by: jjg

     1 /*
     2  * Copyright (c) 2010, 2011, 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     // See CR:  6982992 Tests CheckAttributedTree.java, JavacTreeScannerTest.java, and SourceTreeeScannerTest.java timeout
   147     StringWriter sw = new StringWriter();
   148     PrintWriter pw = new PrintWriter(sw);
   149     Reporter r = new Reporter(pw);
   150     JavacTool tool = JavacTool.create();
   151     StandardJavaFileManager fm = tool.getStandardFileManager(r, null, null);
   153     /**
   154      * Read a file.
   155      * @param file the file to be read
   156      * @return the tree for the content of the file
   157      * @throws IOException if any IO errors occur
   158      * @throws TreePosTest.ParseException if any errors occur while parsing the file
   159      */
   160     JCCompilationUnit read(File file) throws IOException, ParseException {
   161         JavacTool tool = JavacTool.create();
   162         r.errors = 0;
   163         Iterable<? extends JavaFileObject> files = fm.getJavaFileObjects(file);
   164         JavacTask task = tool.getTask(pw, fm, r, Collections.<String>emptyList(), null, files);
   165         Iterable<? extends CompilationUnitTree> trees = task.parse();
   166         pw.flush();
   167         if (r.errors > 0)
   168             throw new ParseException(sw.toString());
   169         Iterator<? extends CompilationUnitTree> iter = trees.iterator();
   170         if (!iter.hasNext())
   171             throw new Error("no trees found");
   172         JCCompilationUnit t = (JCCompilationUnit) iter.next();
   173         if (iter.hasNext())
   174             throw new Error("too many trees found");
   175         return t;
   176     }
   178     /**
   179      * Report an error. When the program is complete, the program will either
   180      * exit or throw an Error if any errors have been reported.
   181      * @param msg the error message
   182      */
   183     void error(String msg) {
   184         System.err.println(msg);
   185         errors++;
   186     }
   188     /**
   189      * Report an error. When the program is complete, the program will either
   190      * exit or throw an Error if any errors have been reported.
   191      * @param msg the error message
   192      */
   193     void error(JavaFileObject file, String msg) {
   194         System.err.println(file.getName() + ": " + msg);
   195         errors++;
   196     }
   198     /**
   199      *  Report an error for a specific tree node.
   200      *  @param file the source file for the tree
   201      *  @param t    the tree node
   202      *  @param label an indication of the error
   203      */
   204     void error(JavaFileObject file, Tree tree, String msg) {
   205         JCTree t = (JCTree) tree;
   206         error(file.getName() + ":" + getLine(file, t) + ": " + msg + " " + trim(t, 64));
   207     }
   209     /**
   210      * Get a trimmed string for a tree node, with normalized white space and limited length.
   211      */
   212     String trim(Tree tree, int len) {
   213         JCTree t = (JCTree) tree;
   214         String s = t.toString().replaceAll("\\s+", " ");
   215         return (s.length() < len) ? s : s.substring(0, len);
   216     }
   218     /** Number of files that have been analyzed. */
   219     int fileCount;
   220     /** Number of trees that have been successfully compared. */
   221     int treeCount;
   222     /** Number of errors reported. */
   223     int errors;
   224     /** Flag: don't report irrelevant files. */
   225     boolean quiet;
   226     /** Flag: report files as they are processed. */
   227     boolean verbose;
   230     /**
   231      * Thrown when errors are found parsing a java file.
   232      */
   233     private static class ParseException extends Exception {
   234         ParseException(String msg) {
   235             super(msg);
   236         }
   237     }
   239     /**
   240      * DiagnosticListener to report diagnostics and count any errors that occur.
   241      */
   242     private static class Reporter implements DiagnosticListener<JavaFileObject> {
   243         Reporter(PrintWriter out) {
   244             this.out = out;
   245         }
   247         public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
   248             out.println(diagnostic);
   249             switch (diagnostic.getKind()) {
   250                 case ERROR:
   251                     errors++;
   252             }
   253         }
   254         int errors;
   255         PrintWriter out;
   256     }
   258     /**
   259      * Get the set of fields for a tree node that may contain child tree nodes.
   260      * These are the fields that are subtypes of JCTree or List.
   261      * The results are cached, based on the tree's tag.
   262      */
   263     Set<Field> getFields(JCTree tree) {
   264         Set<Field> fields = map.get(tree.getTag());
   265         if (fields == null) {
   266             fields = new HashSet<Field>();
   267             for (Field f: tree.getClass().getFields()) {
   268                 Class<?> fc = f.getType();
   269                 if (JCTree.class.isAssignableFrom(fc) || List.class.isAssignableFrom(fc))
   270                     fields.add(f);
   271             }
   272             map.put(tree.getTag(), fields);
   273         }
   274         return fields;
   275     }
   276     // where
   277     Map<JCTree.Tag, Set<Field>> map = new HashMap<JCTree.Tag,Set<Field>>();
   279     /** Get the line number for the primary position for a tree.
   280      * The code is intended to be simple, although not necessarily efficient.
   281      * However, note that a file manager such as JavacFileManager is likely
   282      * to cache the results of file.getCharContent, avoiding the need to read
   283      * the bits from disk each time this method is called.
   284      */
   285     int getLine(JavaFileObject file, JCTree tree) {
   286         try {
   287             CharSequence cs = file.getCharContent(true);
   288             int line = 1;
   289             for (int i = 0; i < tree.pos; i++) {
   290                 if (cs.charAt(i) == '\n') // jtreg tests always use Unix line endings
   291                     line++;
   292             }
   293             return line;
   294         } catch (IOException e) {
   295             return -1;
   296         }
   297     }
   298 }

mercurial