test/tools/javac/diags/Example.java

Sat, 06 Oct 2012 10:35:38 +0100

author
mcimadamore
date
Sat, 06 Oct 2012 10:35:38 +0100
changeset 1352
d4b3cb1ece84
parent 1097
497571d34112
child 1409
33abf479f202
permissions
-rw-r--r--

7177386: Add attribution support for method references
Summary: Add type-checking/lookup routines for method references
Reviewed-by: jjg, dlsmith

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

mercurial