test/tools/javac/diags/Example.java

Wed, 06 Apr 2011 20:33:44 -0700

author
ohair
date
Wed, 06 Apr 2011 20:33:44 -0700
changeset 962
0ff2bbd38f10
parent 894
23b64ad3eec8
child 1073
f85d980faaf8
permissions
-rw-r--r--

7033660: Update copyright year to 2011 on any files changed in 2011
Reviewed-by: dholmes

     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 com.sun.tools.javac.file.JavacFileManager;
    25 import java.io.*;
    26 import java.util.*;
    27 import java.util.regex.*;
    28 import javax.tools.Diagnostic;
    29 import javax.tools.DiagnosticCollector;
    30 import javax.tools.JavaCompiler;
    31 import javax.tools.JavaCompiler.CompilationTask;
    32 import javax.tools.JavaFileObject;
    33 import javax.tools.StandardJavaFileManager;
    34 import javax.tools.ToolProvider;
    36 // The following two classes are both used, but cannot be imported directly
    37 // import com.sun.tools.javac.Main
    38 // import com.sun.tools.javac.main.Main
    40 import com.sun.tools.javac.util.Context;
    41 import com.sun.tools.javac.util.JavacMessages;
    42 import com.sun.tools.javac.util.JCDiagnostic;
    43 import java.net.URL;
    44 import java.net.URLClassLoader;
    45 import javax.annotation.processing.Processor;
    47 /**
    48  * Class to handle example code designed to illustrate javac diagnostic messages.
    49  */
    50 class Example implements Comparable<Example> {
    51     /* Create an Example from the files found at path.
    52      * The head of the file, up to the first Java code, is scanned
    53      * for information about the test, such as what resource keys it
    54      * generates when run, what options are required to run it, and so on.
    55      */
    56     Example(File file) {
    57         this.file = file;
    58         declaredKeys = new TreeSet<String>();
    59         srcFiles = new ArrayList<File>();
    60         procFiles = new ArrayList<File>();
    61         supportFiles = new ArrayList<File>();
    62         srcPathFiles = new ArrayList<File>();
    64         findFiles(file, srcFiles);
    65         for (File f: srcFiles) {
    66             parse(f);
    67         }
    69         if (infoFile == null)
    70             throw new Error("Example " + file + " has no info file");
    71     }
    73     private void findFiles(File f, List<File> files) {
    74         if (f.isDirectory()) {
    75             for (File c: f.listFiles()) {
    76                 if (files == srcFiles && c.getName().equals("processors"))
    77                     findFiles(c, procFiles);
    78                 else if (files == srcFiles && c.getName().equals("sourcepath")) {
    79                     srcPathDir = c;
    80                     findFiles(c, srcPathFiles);
    81                 } else if (files == srcFiles && c.getName().equals("support"))
    82                     findFiles(c, supportFiles);
    83                 else
    84                     findFiles(c, files);
    85             }
    86         } else if (f.isFile() && f.getName().endsWith(".java")) {
    87             files.add(f);
    88         }
    89     }
    91     private void parse(File f) {
    92         Pattern keyPat = Pattern.compile(" *// *key: *([^ ]+) *");
    93         Pattern optPat = Pattern.compile(" *// *options: *(.*)");
    94         Pattern runPat = Pattern.compile(" *// *run: *(.*)");
    95         Pattern javaPat = Pattern.compile(" *@?[A-Za-z].*");
    96         try {
    97             String[] lines = read(f).split("[\r\n]+");
    98             for (String line: lines) {
    99                 Matcher keyMatch = keyPat.matcher(line);
   100                 if (keyMatch.matches()) {
   101                     foundInfo(f);
   102                     declaredKeys.add(keyMatch.group(1));
   103                     continue;
   104                 }
   105                 Matcher optMatch = optPat.matcher(line);
   106                 if (optMatch.matches()) {
   107                     foundInfo(f);
   108                     options = Arrays.asList(optMatch.group(1).trim().split(" +"));
   109                     continue;
   110                 }
   111                 Matcher runMatch = runPat.matcher(line);
   112                 if (runMatch.matches()) {
   113                     foundInfo(f);
   114                     runOpts = Arrays.asList(runMatch.group(1).trim().split(" +"));
   115                 }
   116                 if (javaPat.matcher(line).matches())
   117                     break;
   118             }
   119         } catch (IOException e) {
   120             throw new Error(e);
   121         }
   122     }
   124     private void foundInfo(File file) {
   125         if (infoFile != null && !infoFile.equals(file))
   126             throw new Error("multiple info files found: " + infoFile + ", " + file);
   127         infoFile = file;
   128     }
   130     String getName() {
   131         return file.getName();
   132     }
   134     /**
   135      * Get the set of resource keys that this test declares it will generate
   136      * when it is run.
   137      */
   138     Set<String> getDeclaredKeys() {
   139         return declaredKeys;
   140     }
   142     /**
   143      * Get the set of resource keys that this test generates when it is run.
   144      * The test will be run if it has not already been run.
   145      */
   146     Set<String> getActualKeys() {
   147         if (actualKeys == null)
   148             actualKeys = run(false);
   149         return actualKeys;
   150     }
   152     /**
   153      * Run the test.  Information in the test header is used to determine
   154      * how to run the test.
   155      */
   156     void run(PrintWriter out, boolean raw, boolean verbose) {
   157         if (out == null)
   158             throw new NullPointerException();
   159         try {
   160             run(out, null, raw, verbose);
   161         } catch (IOException e) {
   162             e.printStackTrace(out);
   163         }
   164     }
   166     Set<String> run(boolean verbose) {
   167         Set<String> keys = new TreeSet<String>();
   168         try {
   169             run(null, keys, true, verbose);
   170         } catch (IOException e) {
   171             e.printStackTrace(System.err);
   172         }
   173         return keys;
   174     }
   176     /**
   177      * Run the test.  Information in the test header is used to determine
   178      * how to run the test.
   179      */
   180     private void run(PrintWriter out, Set<String> keys, boolean raw, boolean verbose)
   181             throws IOException {
   182         ClassLoader loader = getClass().getClassLoader();
   183         if (supportFiles.size() > 0) {
   184             File supportDir = new File(tempDir, "support");
   185             supportDir.mkdirs();
   186             clean(supportDir);
   187             List<String> sOpts = Arrays.asList("-d", supportDir.getPath());
   188             new Jsr199Compiler(verbose).run(null, null, false, sOpts, procFiles);
   189             URLClassLoader ucl =
   190                     new URLClassLoader(new URL[] { supportDir.toURI().toURL() }, loader);
   191             loader = ucl;
   192         }
   194         File classesDir = new File(tempDir, "classes");
   195         classesDir.mkdirs();
   196         clean(classesDir);
   198         List<String> opts = new ArrayList<String>();
   199         opts.add("-d");
   200         opts.add(classesDir.getPath());
   201         if (options != null)
   202             opts.addAll(options);
   204         if (procFiles.size() > 0) {
   205             List<String> pOpts = Arrays.asList("-d", classesDir.getPath());
   206             new Jsr199Compiler(verbose).run(null, null, false, pOpts, procFiles);
   207             opts.add("-classpath"); // avoid using -processorpath for now
   208             opts.add(classesDir.getPath());
   209             createAnnotationServicesFile(classesDir, procFiles);
   210         }
   212         if (srcPathDir != null) {
   213             opts.add("-sourcepath");
   214             opts.add(srcPathDir.getPath());
   215         }
   217         try {
   218             Compiler c = Compiler.getCompiler(runOpts, verbose);
   219             c.run(out, keys, raw, opts, srcFiles);
   220         } catch (IllegalArgumentException e) {
   221             if (out != null) {
   222                 out.println("Invalid value for run tag: " + runOpts);
   223             }
   224         }
   225     }
   227     void createAnnotationServicesFile(File dir, List<File> procFiles) throws IOException {
   228         File servicesDir = new File(new File(dir, "META-INF"), "services");
   229         servicesDir.mkdirs();
   230         File annoServices = new File(servicesDir, Processor.class.getName());
   231         Writer out = new FileWriter(annoServices);
   232         try {
   233             for (File f: procFiles) {
   234                 out.write(f.getName().toString().replace(".java", ""));
   235             }
   236         } finally {
   237             out.close();
   238         }
   239     }
   241     @Override
   242     public int compareTo(Example e) {
   243         return file.compareTo(e.file);
   244     }
   246     @Override
   247     public String toString() {
   248         return file.getPath();
   249     }
   251     /**
   252      * Read the contents of a file.
   253      */
   254     private String read(File f) throws IOException {
   255         byte[] bytes = new byte[(int) f.length()];
   256         DataInputStream in = new DataInputStream(new FileInputStream(f));
   257         try {
   258             in.readFully(bytes);
   259         } finally {
   260             in.close();
   261         }
   262         return new String(bytes);
   263     }
   265     /**
   266      * Clean the contents of a directory.
   267      */
   268     boolean clean(File dir) {
   269         boolean ok = true;
   270         for (File f: dir.listFiles()) {
   271             if (f.isDirectory())
   272                 ok &= clean(f);
   273             ok &= f.delete();
   274         }
   275         return ok;
   276     }
   278     File file;
   279     List<File> srcFiles;
   280     List<File> procFiles;
   281     File srcPathDir;
   282     List<File> srcPathFiles;
   283     List<File> supportFiles;
   284     File infoFile;
   285     private List<String> runOpts;
   286     private List<String> options;
   287     private Set<String> actualKeys;
   288     private Set<String> declaredKeys;
   290     static File tempDir = new File(System.getProperty("java.io.tmpdir"));
   291     static void setTempDir(File tempDir) {
   292         Example.tempDir = tempDir;
   293     }
   295     abstract static class Compiler {
   296         interface Factory {
   297             Compiler getCompiler(List<String> opts, boolean verbose);
   298         }
   300         static class DefaultFactory implements Factory {
   301             public Compiler getCompiler(List<String> opts, boolean verbose) {
   302             String first;
   303             String[] rest;
   304                 if (opts == null || opts.isEmpty()) {
   305                 first = null;
   306                 rest = new String[0];
   307             } else {
   308                 first = opts.get(0);
   309                 rest = opts.subList(1, opts.size()).toArray(new String[opts.size() - 1]);
   310             }
   311             if (first == null || first.equals("jsr199"))
   312                 return new Jsr199Compiler(verbose, rest);
   313             else if (first.equals("simple"))
   314                 return new SimpleCompiler(verbose);
   315             else if (first.equals("backdoor"))
   316                 return new BackdoorCompiler(verbose);
   317             else
   318                 throw new IllegalArgumentException(first);
   319                 }
   320         }
   322         static Factory factory;
   324         static Compiler getCompiler(List<String> opts, boolean verbose) {
   325             if (factory == null)
   326                 factory = new DefaultFactory();
   328             return factory.getCompiler(opts, verbose);
   329         }
   331         protected Compiler(boolean verbose) {
   332             this.verbose = verbose;
   333         }
   335         abstract boolean run(PrintWriter out, Set<String> keys, boolean raw,
   336                 List<String> opts,  List<File> files);
   338         void setSupportClassLoader(ClassLoader cl) {
   339             loader = cl;
   340         }
   342         protected ClassLoader loader;
   343         protected boolean verbose;
   344     }
   346     /**
   347      * Compile using the JSR 199 API.  The diagnostics generated are
   348      * scanned for resource keys.   Not all diagnostic keys are generated
   349      * via the JSR 199 API -- for example, rich diagnostics are not directly
   350      * accessible, and some diagnostics generated by the file manager may
   351      * not be generated (for example, the JSR 199 file manager does not see
   352      * -Xlint:path).
   353      */
   354     static class Jsr199Compiler extends Compiler {
   355         List<String> fmOpts;
   357         Jsr199Compiler(boolean verbose, String... args) {
   358             super(verbose);
   359             for (int i = 0; i < args.length; i++) {
   360                 String arg = args[i];
   361                 if (arg.equals("-filemanager") && (i + 1 < args.length)) {
   362                     fmOpts = Arrays.asList(args[++i].split(","));
   363                 } else
   364                     throw new IllegalArgumentException(arg);
   365             }
   366         }
   368         @Override
   369         boolean run(PrintWriter out, Set<String> keys, boolean raw, List<String> opts, List<File> files) {
   370             if (out != null && keys != null)
   371                 throw new IllegalArgumentException();
   373             if (verbose)
   374                 System.err.println("run_jsr199: " + opts + " " + files);
   376             DiagnosticCollector<JavaFileObject> dc = null;
   377             if (keys != null)
   378                 dc = new DiagnosticCollector<JavaFileObject>();
   380             if (raw) {
   381                 List<String> newOpts = new ArrayList<String>();
   382                 newOpts.add("-XDrawDiagnostics");
   383                 newOpts.addAll(opts);
   384                 opts = newOpts;
   385             }
   387             JavaCompiler c = ToolProvider.getSystemJavaCompiler();
   389             StandardJavaFileManager fm = c.getStandardFileManager(dc, null, null);
   390             if (fmOpts != null)
   391                 fm = new FileManager(fm, fmOpts);
   393             Iterable<? extends JavaFileObject> fos = fm.getJavaFileObjectsFromFiles(files);
   395             CompilationTask t = c.getTask(out, fm, dc, opts, null, fos);
   396             Boolean ok = t.call();
   398             if (keys != null) {
   399                 for (Diagnostic<? extends JavaFileObject> d: dc.getDiagnostics()) {
   400                     scanForKeys((JCDiagnostic) d, keys);
   401                 }
   402             }
   404             return ok;
   405         }
   407         /**
   408          * Scan a diagnostic for resource keys.  This will not detect additional
   409          * sub diagnostics that might be generated by a rich diagnostic formatter.
   410          */
   411         private static void scanForKeys(JCDiagnostic d, Set<String> keys) {
   412             keys.add(d.getCode());
   413             for (Object o: d.getArgs()) {
   414                 if (o instanceof JCDiagnostic) {
   415                     scanForKeys((JCDiagnostic) o, keys);
   416                 }
   417             }
   418             for (JCDiagnostic sd: d.getSubdiagnostics())
   419                 scanForKeys(sd, keys);
   420         }
   421     }
   423     /**
   424      * Run the test using the standard simple entry point.
   425      */
   426     static class SimpleCompiler extends Compiler {
   427         SimpleCompiler(boolean verbose) {
   428             super(verbose);
   429         }
   431         @Override
   432         boolean run(PrintWriter out, Set<String> keys, boolean raw, List<String> opts, List<File> files) {
   433             if (out != null && keys != null)
   434                 throw new IllegalArgumentException();
   436             if (verbose)
   437                 System.err.println("run_simple: " + opts + " " + files);
   439             List<String> args = new ArrayList<String>();
   441             if (keys != null || raw)
   442                 args.add("-XDrawDiagnostics");
   444             args.addAll(opts);
   445             for (File f: files)
   446                 args.add(f.getPath());
   448             StringWriter sw = null;
   449             PrintWriter pw;
   450             if (keys != null) {
   451                 sw = new StringWriter();
   452                 pw = new PrintWriter(sw);
   453             } else
   454                 pw = out;
   456             int rc = com.sun.tools.javac.Main.compile(args.toArray(new String[args.size()]), pw);
   458             if (keys != null) {
   459                 pw.close();
   460                 scanForKeys(sw.toString(), keys);
   461             }
   463             return (rc == 0);
   464         }
   466         private static void scanForKeys(String text, Set<String> keys) {
   467             StringTokenizer st = new StringTokenizer(text, " ,\r\n():");
   468             while (st.hasMoreElements()) {
   469                 String t = st.nextToken();
   470                 if (t.startsWith("compiler."))
   471                     keys.add(t);
   472             }
   473         }
   474     }
   476     static class BackdoorCompiler extends Compiler {
   477         BackdoorCompiler(boolean verbose) {
   478             super(verbose);
   479         }
   481         @Override
   482         boolean run(PrintWriter out, Set<String> keys, boolean raw, List<String> opts, List<File> files) {
   483             if (out != null && keys != null)
   484                 throw new IllegalArgumentException();
   486             if (verbose)
   487                 System.err.println("run_simple: " + opts + " " + files);
   489             List<String> args = new ArrayList<String>();
   491             if (out != null && raw)
   492                 args.add("-XDrawDiagnostics");
   494             args.addAll(opts);
   495             for (File f: files)
   496                 args.add(f.getPath());
   498             StringWriter sw = null;
   499             PrintWriter pw;
   500             if (keys != null) {
   501                 sw = new StringWriter();
   502                 pw = new PrintWriter(sw);
   503             } else
   504                 pw = out;
   506             Context c = new Context();
   507             JavacFileManager.preRegister(c); // can't create it until Log has been set up
   508             MessageTracker.preRegister(c, keys);
   509             com.sun.tools.javac.main.Main m = new com.sun.tools.javac.main.Main("javac", pw);
   510             int rc = m.compile(args.toArray(new String[args.size()]), c);
   512             if (keys != null) {
   513                 pw.close();
   514             }
   516             return (rc == 0);
   517         }
   519         static class MessageTracker extends JavacMessages {
   521             MessageTracker(Context context) {
   522                 super(context);
   523             }
   525             static void preRegister(Context c, final Set<String> keys) {
   526                 if (keys != null) {
   527                     c.put(JavacMessages.messagesKey, new Context.Factory<JavacMessages>() {
   528                         public JavacMessages make(Context c) {
   529                             return new MessageTracker(c) {
   530                                 @Override
   531                                 public String getLocalizedString(Locale l, String key, Object... args) {
   532                                     keys.add(key);
   533                                     return super.getLocalizedString(l, key, args);
   534                                 }
   535                             };
   536                         }
   537                     });
   538                 }
   539             }
   540         }
   542     }
   543 }

mercurial