1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/test/tools/javac/diags/ArgTypeCompilerFactory.java Wed Jan 26 13:45:25 2011 -0800 1.3 @@ -0,0 +1,346 @@ 1.4 +/* 1.5 + * Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved. 1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 1.7 + * 1.8 + * This code is free software; you can redistribute it and/or modify it 1.9 + * under the terms of the GNU General Public License version 2 only, as 1.10 + * published by the Free Software Foundation. 1.11 + * 1.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 1.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1.15 + * version 2 for more details (a copy is included in the LICENSE file that 1.16 + * accompanied this code). 1.17 + * 1.18 + * You should have received a copy of the GNU General Public License version 1.19 + * 2 along with this work; if not, write to the Free Software Foundation, 1.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 1.21 + * 1.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 1.23 + * or visit www.oracle.com if you need additional information or have any 1.24 + * questions. 1.25 + */ 1.26 + 1.27 +import java.io.*; 1.28 +import java.util.*; 1.29 +import java.util.List; 1.30 +import javax.tools.*; 1.31 + 1.32 +import com.sun.tools.javac.api.*; 1.33 +import com.sun.tools.javac.api.DiagnosticFormatter.Configuration.DiagnosticPart; 1.34 +import com.sun.tools.javac.api.Formattable.LocalizedString; 1.35 +import com.sun.tools.javac.code.Flags.Flag; 1.36 +import com.sun.tools.javac.code.Kinds.KindName; 1.37 +import com.sun.tools.javac.code.*; 1.38 +import com.sun.tools.javac.file.*; 1.39 +import com.sun.tools.javac.main.Main; 1.40 +import com.sun.tools.javac.parser.Token; 1.41 +import com.sun.tools.javac.util.*; 1.42 +import com.sun.tools.javac.util.AbstractDiagnosticFormatter.SimpleConfiguration; 1.43 +import javax.lang.model.SourceVersion; 1.44 + 1.45 +/** 1.46 + * Compiler factory for instances of Example.Compiler that use custom 1.47 + * DiagnosticFormatter and Messages objects to track the types of args 1.48 + * when when localizing diagnostics. 1.49 + * The compiler objects only support "output" mode, not "check" mode. 1.50 + */ 1.51 +class ArgTypeCompilerFactory implements Example.Compiler.Factory { 1.52 + // Same code as Example.Compiler.DefaultFactory, but the names resolve differently 1.53 + public Example.Compiler getCompiler(List<String> opts, boolean verbose) { 1.54 + String first; 1.55 + String[] rest; 1.56 + if (opts == null || opts.isEmpty()) { 1.57 + first = null; 1.58 + rest = new String[0]; 1.59 + } else { 1.60 + first = opts.get(0); 1.61 + rest = opts.subList(1, opts.size()).toArray(new String[opts.size() - 1]); 1.62 + } 1.63 + if (first == null || first.equals("jsr199")) 1.64 + return new Jsr199Compiler(verbose, rest); 1.65 + else if (first.equals("simple")) 1.66 + return new SimpleCompiler(verbose); 1.67 + else if (first.equals("backdoor")) 1.68 + return new BackdoorCompiler(verbose); 1.69 + else 1.70 + throw new IllegalArgumentException(first); 1.71 + } 1.72 + 1.73 + /** 1.74 + * Compile using the JSR 199 API. The diagnostics generated are 1.75 + * scanned for resource keys. Not all diagnostic keys are generated 1.76 + * via the JSR 199 API -- for example, rich diagnostics are not directly 1.77 + * accessible, and some diagnostics generated by the file manager may 1.78 + * not be generated (for example, the JSR 199 file manager does not see 1.79 + * -Xlint:path). 1.80 + */ 1.81 + static class Jsr199Compiler extends Example.Compiler { 1.82 + List<String> fmOpts; 1.83 + 1.84 + Jsr199Compiler(boolean verbose, String... args) { 1.85 + super(verbose); 1.86 + for (int i = 0; i < args.length; i++) { 1.87 + String arg = args[i]; 1.88 + if (arg.equals("-filemanager") && (i + 1 < args.length)) { 1.89 + fmOpts = Arrays.asList(args[++i].split(",")); 1.90 + } else 1.91 + throw new IllegalArgumentException(arg); 1.92 + } 1.93 + } 1.94 + 1.95 + @Override 1.96 + boolean run(PrintWriter out, Set<String> keys, boolean raw, List<String> opts, List<File> files) { 1.97 + assert out != null && keys == null; 1.98 + 1.99 + if (verbose) 1.100 + System.err.println("run_jsr199: " + opts + " " + files); 1.101 + 1.102 + JavacTool tool = JavacTool.create(); 1.103 + 1.104 + StandardJavaFileManager fm = tool.getStandardFileManager(null, null, null); 1.105 + if (fmOpts != null) 1.106 + fm = new FileManager(fm, fmOpts); 1.107 + 1.108 + Iterable<? extends JavaFileObject> fos = fm.getJavaFileObjectsFromFiles(files); 1.109 + 1.110 + JavacTaskImpl t = (JavacTaskImpl) tool.getTask(out, fm, null, opts, null, fos); 1.111 + Context c = t.getContext(); 1.112 + ArgTypeMessages.preRegister(c); 1.113 + Options options = Options.instance(c); 1.114 + Log.instance(c).setDiagnosticFormatter(new ArgTypeDiagnosticFormatter(options)); 1.115 + Boolean ok = t.call(); 1.116 + 1.117 + return ok; 1.118 + } 1.119 + } 1.120 + 1.121 + /** 1.122 + * Run the test using the standard simple entry point. 1.123 + */ 1.124 + static class SimpleCompiler extends Example.Compiler { 1.125 + SimpleCompiler(boolean verbose) { 1.126 + super(verbose); 1.127 + } 1.128 + 1.129 + @Override 1.130 + boolean run(PrintWriter out, Set<String> keys, boolean raw, List<String> opts, List<File> files) { 1.131 + assert out != null && keys == null; 1.132 + 1.133 + if (verbose) 1.134 + System.err.println("run_simple: " + opts + " " + files); 1.135 + 1.136 + List<String> args = new ArrayList<String>(); 1.137 + 1.138 + args.addAll(opts); 1.139 + for (File f: files) 1.140 + args.add(f.getPath()); 1.141 + 1.142 + Main main = new Main("javac", out); 1.143 + Context c = new Context() { 1.144 + @Override public void clear() { 1.145 + ((JavacFileManager) get(JavaFileManager.class)).close(); 1.146 + super.clear(); 1.147 + } 1.148 + }; 1.149 + JavacFileManager.preRegister(c); // can't create it until Log has been set up 1.150 + ArgTypeDiagnosticFormatter.preRegister(c); 1.151 + ArgTypeMessages.preRegister(c); 1.152 + int result = main.compile(args.toArray(new String[args.size()]), c); 1.153 + 1.154 + return (result == 0); 1.155 + } 1.156 + } 1.157 + 1.158 + static class BackdoorCompiler extends Example.Compiler { 1.159 + BackdoorCompiler(boolean verbose) { 1.160 + super(verbose); 1.161 + } 1.162 + 1.163 + @Override 1.164 + boolean run(PrintWriter out, Set<String> keys, boolean raw, List<String> opts, List<File> files) { 1.165 + assert out != null && keys == null; 1.166 + 1.167 + if (verbose) 1.168 + System.err.println("run_simple: " + opts + " " + files); 1.169 + 1.170 + List<String> args = new ArrayList<String>(opts); 1.171 + for (File f: files) 1.172 + args.add(f.getPath()); 1.173 + 1.174 + Context c = new Context(); 1.175 + JavacFileManager.preRegister(c); // can't create it until Log has been set up 1.176 + ArgTypeDiagnosticFormatter.preRegister(c); 1.177 + ArgTypeMessages.preRegister(c); 1.178 + com.sun.tools.javac.main.Main m = new com.sun.tools.javac.main.Main("javac", out); 1.179 + int rc = m.compile(args.toArray(new String[args.size()]), c); 1.180 + 1.181 + return (rc == 0); 1.182 + } 1.183 + 1.184 + } 1.185 + 1.186 + 1.187 + // <editor-fold defaultstate="collapsed" desc="Custom Javac components"> 1.188 + 1.189 + /** 1.190 + * Diagnostic formatter which reports formats a diag as a series of lines 1.191 + * containing a key, and a possibly empty set of descriptive strings for the 1.192 + * arg types. 1.193 + */ 1.194 + static class ArgTypeDiagnosticFormatter extends AbstractDiagnosticFormatter { 1.195 + static void preRegister(final Context context) { 1.196 + context.put(Log.logKey, new Context.Factory<Log>() { 1.197 + public Log make() { 1.198 + Log log = new Log(context) { }; 1.199 + Options options = Options.instance(context); 1.200 + log.setDiagnosticFormatter(new ArgTypeDiagnosticFormatter(options)); 1.201 + return log; 1.202 + } 1.203 + }); 1.204 + 1.205 + } 1.206 + 1.207 + ArgTypeDiagnosticFormatter(Options options) { 1.208 + super(null, new SimpleConfiguration(options, 1.209 + EnumSet.of(DiagnosticPart.SUMMARY, 1.210 + DiagnosticPart.DETAILS, 1.211 + DiagnosticPart.SUBDIAGNOSTICS))); 1.212 + } 1.213 + 1.214 + @Override 1.215 + protected String formatDiagnostic(JCDiagnostic d, Locale locale) { 1.216 + return formatMessage(d, locale); 1.217 + } 1.218 + 1.219 + @Override 1.220 + public String formatMessage(JCDiagnostic d, Locale l) { 1.221 + StringBuilder buf = new StringBuilder(); 1.222 + formatMessage(d, buf); 1.223 + return buf.toString(); 1.224 + } 1.225 + 1.226 + private void formatMessage(JCDiagnostic d, StringBuilder buf) { 1.227 + String key = d.getCode(); 1.228 + Object[] args = d.getArgs(); 1.229 + // report the primary arg types, without recursing into diag fragments 1.230 + buf.append(getKeyArgsString(key, args)); 1.231 + // report details for any diagnostic fragments 1.232 + for (Object arg: args) { 1.233 + if (arg instanceof JCDiagnostic) { 1.234 + buf.append("\n"); 1.235 + formatMessage((JCDiagnostic) arg, buf); 1.236 + } 1.237 + } 1.238 + // report details for any subdiagnostics 1.239 + for (String s: formatSubdiagnostics(d, null)) { 1.240 + buf.append("\n"); 1.241 + buf.append(s); 1.242 + } 1.243 + } 1.244 + 1.245 + @Override 1.246 + public boolean isRaw() { 1.247 + return true; 1.248 + } 1.249 + } 1.250 + 1.251 + /** 1.252 + * Diagnostic formatter which "localizes" a message as a line 1.253 + * containing a key, and a possibly empty set of descriptive strings for the 1.254 + * arg types. 1.255 + */ 1.256 + static class ArgTypeMessages extends JavacMessages { 1.257 + static void preRegister(final Context c) { 1.258 + c.put(JavacMessages.messagesKey, new Context.Factory<JavacMessages>() { 1.259 + public JavacMessages make() { 1.260 + return new ArgTypeMessages(c) { 1.261 + @Override 1.262 + public String getLocalizedString(Locale l, String key, Object... args) { 1.263 + return getKeyArgsString(key, args); 1.264 + } 1.265 + }; 1.266 + } 1.267 + }); 1.268 + } 1.269 + 1.270 + ArgTypeMessages(Context context) { 1.271 + super(context); 1.272 + } 1.273 + } 1.274 + 1.275 + /** 1.276 + * Utility method to generate a string for key and args 1.277 + */ 1.278 + static String getKeyArgsString(String key, Object... args) { 1.279 + StringBuilder buf = new StringBuilder(); 1.280 + buf.append(key); 1.281 + String sep = ": "; 1.282 + for (Object o : args) { 1.283 + buf.append(sep); 1.284 + buf.append(getArgTypeOrStringValue(o)); 1.285 + sep = ", "; 1.286 + } 1.287 + return buf.toString(); 1.288 + } 1.289 + 1.290 + static boolean showStringValues = false; 1.291 + 1.292 + static String getArgTypeOrStringValue(Object o) { 1.293 + if (showStringValues && o instanceof String) 1.294 + return "\"" + o + "\""; 1.295 + return getArgType(o); 1.296 + } 1.297 + 1.298 + static String getArgType(Object o) { 1.299 + if (o == null) 1.300 + return "null"; 1.301 + if (o instanceof Name) 1.302 + return "name"; 1.303 + if (o instanceof Boolean) 1.304 + return "boolean"; 1.305 + if (o instanceof Integer) 1.306 + return "number"; 1.307 + if (o instanceof String) 1.308 + return "string"; 1.309 + if (o instanceof Flag) 1.310 + return "modifier"; 1.311 + if (o instanceof KindName) 1.312 + return "symbol kind"; 1.313 + if (o instanceof Token) 1.314 + return "token"; 1.315 + if (o instanceof Symbol) 1.316 + return "symbol"; 1.317 + if (o instanceof Type) 1.318 + return "type"; 1.319 + if (o instanceof List) { 1.320 + List<?> l = (List<?>) o; 1.321 + if (l.isEmpty()) 1.322 + return "list"; 1.323 + else 1.324 + return "list of " + getArgType(l.get(0)); 1.325 + } 1.326 + if (o instanceof ListBuffer) 1.327 + return getArgType(((ListBuffer) o).toList()); 1.328 + if (o instanceof Set) { 1.329 + Set<?> s = (Set<?>) o; 1.330 + if (s.isEmpty()) 1.331 + return "set"; 1.332 + else 1.333 + return "set of " + getArgType(s.iterator().next()); 1.334 + } 1.335 + if (o instanceof SourceVersion) 1.336 + return "source version"; 1.337 + if (o instanceof FileObject || o instanceof File) 1.338 + return "file name"; 1.339 + if (o instanceof JCDiagnostic) 1.340 + return "message segment"; 1.341 + if (o instanceof LocalizedString) 1.342 + return "message segment"; // only instance is "no arguments" 1.343 + String s = o.getClass().getSimpleName(); 1.344 + return (s.isEmpty() ? o.getClass().getName() : s); 1.345 + } 1.346 + 1.347 + // </editor-fold> 1.348 + 1.349 +}