test/tools/javac/diags/ArgTypeCompilerFactory.java

Wed, 26 Jan 2011 13:45:25 -0800

author
jjg
date
Wed, 26 Jan 2011 13:45:25 -0800
changeset 842
3da26790ccb7
child 893
8f0dcb9499db
permissions
-rw-r--r--

7013272: Automatically generate info about how compiler resource keys are used
Reviewed-by: mcimadamore

     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.util.*;
    26 import java.util.List;
    27 import javax.tools.*;
    29 import com.sun.tools.javac.api.*;
    30 import com.sun.tools.javac.api.DiagnosticFormatter.Configuration.DiagnosticPart;
    31 import com.sun.tools.javac.api.Formattable.LocalizedString;
    32 import com.sun.tools.javac.code.Flags.Flag;
    33 import com.sun.tools.javac.code.Kinds.KindName;
    34 import com.sun.tools.javac.code.*;
    35 import com.sun.tools.javac.file.*;
    36 import com.sun.tools.javac.main.Main;
    37 import com.sun.tools.javac.parser.Token;
    38 import com.sun.tools.javac.util.*;
    39 import com.sun.tools.javac.util.AbstractDiagnosticFormatter.SimpleConfiguration;
    40 import javax.lang.model.SourceVersion;
    42 /**
    43  * Compiler factory for instances of Example.Compiler that use custom
    44  * DiagnosticFormatter and Messages objects to track the types of args
    45  * when when localizing diagnostics.
    46  * The compiler objects only support "output" mode, not "check" mode.
    47  */
    48 class ArgTypeCompilerFactory implements Example.Compiler.Factory {
    49     // Same code as Example.Compiler.DefaultFactory, but the names resolve differently
    50     public Example.Compiler getCompiler(List<String> opts, boolean verbose) {
    51         String first;
    52         String[] rest;
    53         if (opts == null || opts.isEmpty()) {
    54             first = null;
    55             rest = new String[0];
    56         } else {
    57             first = opts.get(0);
    58             rest = opts.subList(1, opts.size()).toArray(new String[opts.size() - 1]);
    59         }
    60         if (first == null || first.equals("jsr199"))
    61             return new Jsr199Compiler(verbose, rest);
    62         else if (first.equals("simple"))
    63             return new SimpleCompiler(verbose);
    64         else if (first.equals("backdoor"))
    65             return new BackdoorCompiler(verbose);
    66         else
    67             throw new IllegalArgumentException(first);
    68     }
    70     /**
    71      * Compile using the JSR 199 API.  The diagnostics generated are
    72      * scanned for resource keys.   Not all diagnostic keys are generated
    73      * via the JSR 199 API -- for example, rich diagnostics are not directly
    74      * accessible, and some diagnostics generated by the file manager may
    75      * not be generated (for example, the JSR 199 file manager does not see
    76      * -Xlint:path).
    77      */
    78     static class Jsr199Compiler extends Example.Compiler {
    79         List<String> fmOpts;
    81         Jsr199Compiler(boolean verbose, String... args) {
    82             super(verbose);
    83             for (int i = 0; i < args.length; i++) {
    84                 String arg = args[i];
    85                 if (arg.equals("-filemanager") && (i + 1 < args.length)) {
    86                     fmOpts = Arrays.asList(args[++i].split(","));
    87                 } else
    88                     throw new IllegalArgumentException(arg);
    89             }
    90         }
    92         @Override
    93         boolean run(PrintWriter out, Set<String> keys, boolean raw, List<String> opts, List<File> files) {
    94             assert out != null && keys == null;
    96             if (verbose)
    97                 System.err.println("run_jsr199: " + opts + " " + files);
    99             JavacTool tool = JavacTool.create();
   101             StandardJavaFileManager fm = tool.getStandardFileManager(null, null, null);
   102             if (fmOpts != null)
   103                 fm = new FileManager(fm, fmOpts);
   105             Iterable<? extends JavaFileObject> fos = fm.getJavaFileObjectsFromFiles(files);
   107             JavacTaskImpl t = (JavacTaskImpl) tool.getTask(out, fm, null, opts, null, fos);
   108             Context c = t.getContext();
   109             ArgTypeMessages.preRegister(c);
   110             Options options = Options.instance(c);
   111             Log.instance(c).setDiagnosticFormatter(new ArgTypeDiagnosticFormatter(options));
   112             Boolean ok = t.call();
   114             return ok;
   115         }
   116     }
   118     /**
   119      * Run the test using the standard simple entry point.
   120      */
   121     static class SimpleCompiler extends Example.Compiler {
   122         SimpleCompiler(boolean verbose) {
   123             super(verbose);
   124         }
   126         @Override
   127         boolean run(PrintWriter out, Set<String> keys, boolean raw, List<String> opts, List<File> files) {
   128             assert out != null && keys == null;
   130             if (verbose)
   131                 System.err.println("run_simple: " + opts + " " + files);
   133             List<String> args = new ArrayList<String>();
   135             args.addAll(opts);
   136             for (File f: files)
   137                 args.add(f.getPath());
   139             Main main = new Main("javac", out);
   140             Context c = new Context() {
   141                 @Override public void clear() {
   142                     ((JavacFileManager) get(JavaFileManager.class)).close();
   143                     super.clear();
   144                 }
   145             };
   146             JavacFileManager.preRegister(c); // can't create it until Log has been set up
   147             ArgTypeDiagnosticFormatter.preRegister(c);
   148             ArgTypeMessages.preRegister(c);
   149             int result = main.compile(args.toArray(new String[args.size()]), c);
   151             return (result == 0);
   152         }
   153     }
   155     static class BackdoorCompiler extends Example.Compiler {
   156         BackdoorCompiler(boolean verbose) {
   157             super(verbose);
   158         }
   160         @Override
   161         boolean run(PrintWriter out, Set<String> keys, boolean raw, List<String> opts, List<File> files) {
   162             assert out != null && keys == null;
   164             if (verbose)
   165                 System.err.println("run_simple: " + opts + " " + files);
   167             List<String> args = new ArrayList<String>(opts);
   168             for (File f: files)
   169                 args.add(f.getPath());
   171             Context c = new Context();
   172             JavacFileManager.preRegister(c); // can't create it until Log has been set up
   173             ArgTypeDiagnosticFormatter.preRegister(c);
   174             ArgTypeMessages.preRegister(c);
   175             com.sun.tools.javac.main.Main m = new com.sun.tools.javac.main.Main("javac", out);
   176             int rc = m.compile(args.toArray(new String[args.size()]), c);
   178             return (rc == 0);
   179         }
   181     }
   184     // <editor-fold defaultstate="collapsed" desc="Custom Javac components">
   186     /**
   187      * Diagnostic formatter which reports formats a diag as a series of lines
   188      * containing a key, and a possibly empty set of descriptive strings for the
   189      * arg types.
   190      */
   191     static class ArgTypeDiagnosticFormatter extends AbstractDiagnosticFormatter {
   192         static void preRegister(final Context context) {
   193             context.put(Log.logKey, new Context.Factory<Log>() {
   194                 public Log make() {
   195                     Log log = new Log(context) { };
   196                     Options options = Options.instance(context);
   197                     log.setDiagnosticFormatter(new ArgTypeDiagnosticFormatter(options));
   198                     return log;
   199                 }
   200             });
   202         }
   204         ArgTypeDiagnosticFormatter(Options options) {
   205             super(null, new SimpleConfiguration(options,
   206                     EnumSet.of(DiagnosticPart.SUMMARY,
   207                     DiagnosticPart.DETAILS,
   208                     DiagnosticPart.SUBDIAGNOSTICS)));
   209         }
   211         @Override
   212         protected String formatDiagnostic(JCDiagnostic d, Locale locale) {
   213             return formatMessage(d, locale);
   214         }
   216         @Override
   217         public String formatMessage(JCDiagnostic d, Locale l) {
   218             StringBuilder buf = new StringBuilder();
   219             formatMessage(d, buf);
   220             return buf.toString();
   221         }
   223         private void formatMessage(JCDiagnostic d, StringBuilder buf) {
   224             String key = d.getCode();
   225             Object[] args = d.getArgs();
   226             // report the primary arg types, without recursing into diag fragments
   227             buf.append(getKeyArgsString(key, args));
   228             // report details for any diagnostic fragments
   229             for (Object arg: args) {
   230                 if (arg instanceof JCDiagnostic) {
   231                     buf.append("\n");
   232                     formatMessage((JCDiagnostic) arg, buf);
   233                 }
   234             }
   235             // report details for any subdiagnostics
   236             for (String s: formatSubdiagnostics(d, null)) {
   237                 buf.append("\n");
   238                 buf.append(s);
   239             }
   240         }
   242         @Override
   243         public boolean isRaw() {
   244             return true;
   245         }
   246     }
   248     /**
   249      * Diagnostic formatter which "localizes" a message as a line
   250      * containing a key, and a possibly empty set of descriptive strings for the
   251      * arg types.
   252      */
   253     static class ArgTypeMessages extends JavacMessages {
   254         static void preRegister(final Context c) {
   255             c.put(JavacMessages.messagesKey, new Context.Factory<JavacMessages>() {
   256                 public JavacMessages make() {
   257                     return new ArgTypeMessages(c) {
   258                         @Override
   259                         public String getLocalizedString(Locale l, String key, Object... args) {
   260                             return getKeyArgsString(key, args);
   261                         }
   262                     };
   263                 }
   264             });
   265         }
   267         ArgTypeMessages(Context context) {
   268             super(context);
   269         }
   270     }
   272     /**
   273      * Utility method to generate a string for key and args
   274      */
   275     static String getKeyArgsString(String key, Object... args) {
   276         StringBuilder buf = new StringBuilder();
   277         buf.append(key);
   278         String sep = ": ";
   279         for (Object o : args) {
   280             buf.append(sep);
   281             buf.append(getArgTypeOrStringValue(o));
   282             sep = ", ";
   283         }
   284         return buf.toString();
   285     }
   287     static boolean showStringValues = false;
   289     static String getArgTypeOrStringValue(Object o) {
   290         if (showStringValues && o instanceof String)
   291             return "\"" + o + "\"";
   292         return getArgType(o);
   293     }
   295     static String getArgType(Object o) {
   296         if (o == null)
   297             return "null";
   298         if (o instanceof Name)
   299             return "name";
   300         if (o instanceof Boolean)
   301             return "boolean";
   302         if (o instanceof Integer)
   303             return "number";
   304         if (o instanceof String)
   305             return "string";
   306         if (o instanceof Flag)
   307             return "modifier";
   308         if (o instanceof KindName)
   309             return "symbol kind";
   310         if (o instanceof Token)
   311             return "token";
   312         if (o instanceof Symbol)
   313             return "symbol";
   314         if (o instanceof Type)
   315             return "type";
   316         if (o instanceof List) {
   317             List<?> l = (List<?>) o;
   318             if (l.isEmpty())
   319                 return "list";
   320             else
   321                 return "list of " + getArgType(l.get(0));
   322         }
   323         if (o instanceof ListBuffer)
   324             return getArgType(((ListBuffer) o).toList());
   325         if (o instanceof Set) {
   326             Set<?> s = (Set<?>) o;
   327             if (s.isEmpty())
   328                 return "set";
   329             else
   330                 return "set of " + getArgType(s.iterator().next());
   331         }
   332         if (o instanceof SourceVersion)
   333             return "source version";
   334         if (o instanceof FileObject || o instanceof File)
   335             return "file name";
   336         if (o instanceof JCDiagnostic)
   337             return "message segment";
   338         if (o instanceof LocalizedString)
   339             return "message segment";  // only instance is "no arguments"
   340         String s = o.getClass().getSimpleName();
   341         return (s.isEmpty() ? o.getClass().getName() : s);
   342     }
   344     // </editor-fold>
   346 }

mercurial