Mon, 19 Nov 2012 11:38:49 -0800
8001098: Provide a simple light-weight "plug-in" mechanism for javac
Reviewed-by: mcimadamore
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/share/classes/com/sun/source/util/Plugin.java Mon Nov 19 11:38:49 2012 -0800 1.3 @@ -0,0 +1,64 @@ 1.4 +/* 1.5 + * Copyright (c) 2005, 2012, 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. Oracle designates this 1.11 + * particular file as subject to the "Classpath" exception as provided 1.12 + * by Oracle in the LICENSE file that accompanied this code. 1.13 + * 1.14 + * This code is distributed in the hope that it will be useful, but WITHOUT 1.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1.17 + * version 2 for more details (a copy is included in the LICENSE file that 1.18 + * accompanied this code). 1.19 + * 1.20 + * You should have received a copy of the GNU General Public License version 1.21 + * 2 along with this work; if not, write to the Free Software Foundation, 1.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 1.23 + * 1.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 1.25 + * or visit www.oracle.com if you need additional information or have any 1.26 + * questions. 1.27 + */ 1.28 +package com.sun.source.util; 1.29 + 1.30 +import java.util.ServiceLoader; 1.31 +import javax.tools.StandardLocation; 1.32 + 1.33 +/** 1.34 + * The interface for a javac plug-in. 1.35 + * 1.36 + * <p>The javac plug-in mechanism allows a user to specify one or more plug-ins 1.37 + * on the javac command line, to be started soon after the compilation 1.38 + * has begun. Plug-ins are identified by a user-friendly name. Each plug-in that 1.39 + * is started will be passed an array of strings, which may be used to 1.40 + * provide the plug-in with values for any desired options or other arguments. 1.41 + * 1.42 + * <p>Plug-ins are located via a {@link ServiceLoader}, 1.43 + * using the same class path as annotation processors (i.e. 1.44 + * {@link StandardLocation#PROCESSOR_PATH PROCESSOR_PATH} or 1.45 + * {@code -processorpath}). 1.46 + * 1.47 + * <p>It is expected that a typical plug-in will simply register a 1.48 + * {@link TaskListener} to be informed of events during the execution 1.49 + * of the compilation, and that the rest of the work will be done 1.50 + * by the task listener. 1.51 + * 1.52 + * @since 1.8 1.53 + */ 1.54 +public interface Plugin { 1.55 + /** 1.56 + * Get the user-friendly name of this plug-in. 1.57 + * @return the user-friendly name of the plug-in 1.58 + */ 1.59 + String getName(); 1.60 + 1.61 + /** 1.62 + * Invoke the plug-in for a given compilation task. 1.63 + * @param task The compilation task that has just been started 1.64 + * @param args Arguments, if any, for the plug-in 1.65 + */ 1.66 + void call(JavacTask task, String... args); 1.67 +}
2.1 --- a/src/share/classes/com/sun/source/util/Trees.java Sat Nov 17 19:01:03 2012 +0000 2.2 +++ b/src/share/classes/com/sun/source/util/Trees.java Mon Nov 19 11:38:49 2012 -0800 2.3 @@ -58,7 +58,9 @@ 2.4 * @throws IllegalArgumentException if the task does not support the Trees API. 2.5 */ 2.6 public static Trees instance(CompilationTask task) { 2.7 - if (!task.getClass().getName().equals("com.sun.tools.javac.api.JavacTaskImpl")) 2.8 + String taskClassName = task.getClass().getName(); 2.9 + if (!taskClassName.equals("com.sun.tools.javac.api.JavacTaskImpl") 2.10 + && !taskClassName.equals("com.sun.tools.javac.api.BasicJavacTask")) 2.11 throw new IllegalArgumentException(); 2.12 return getJavacTrees(CompilationTask.class, task); 2.13 }
3.1 --- a/src/share/classes/com/sun/tools/javac/api/BasicJavacTask.java Sat Nov 17 19:01:03 2012 +0000 3.2 +++ b/src/share/classes/com/sun/tools/javac/api/BasicJavacTask.java Mon Nov 19 11:38:49 2012 -0800 3.3 @@ -140,6 +140,14 @@ 3.4 * For internal use only. This method will be 3.5 * removed without warning. 3.6 */ 3.7 + public Context getContext() { 3.8 + return context; 3.9 + } 3.10 + 3.11 + /** 3.12 + * For internal use only. This method will be 3.13 + * removed without warning. 3.14 + */ 3.15 public void updateContext(Context newContext) { 3.16 context = newContext; 3.17 }
4.1 --- a/src/share/classes/com/sun/tools/javac/api/JavacTaskImpl.java Sat Nov 17 19:01:03 2012 +0000 4.2 +++ b/src/share/classes/com/sun/tools/javac/api/JavacTaskImpl.java Mon Nov 19 11:38:49 2012 -0800 4.3 @@ -489,22 +489,6 @@ 4.4 * For internal use only. This method will be 4.5 * removed without warning. 4.6 */ 4.7 - public Context getContext() { 4.8 - return context; 4.9 - } 4.10 - 4.11 - /** 4.12 - * For internal use only. This method will be 4.13 - * removed without warning. 4.14 - */ 4.15 - public void updateContext(Context newContext) { 4.16 - context = newContext; 4.17 - } 4.18 - 4.19 - /** 4.20 - * For internal use only. This method will be 4.21 - * removed without warning. 4.22 - */ 4.23 public Type parseType(String expr, TypeElement scope) { 4.24 if (expr == null || expr.equals("")) 4.25 throw new IllegalArgumentException();
5.1 --- a/src/share/classes/com/sun/tools/javac/api/JavacTrees.java Sat Nov 17 19:01:03 2012 +0000 5.2 +++ b/src/share/classes/com/sun/tools/javac/api/JavacTrees.java Mon Nov 19 11:38:49 2012 -0800 5.3 @@ -121,9 +121,9 @@ 5.4 5.5 // called reflectively from Trees.instance(CompilationTask task) 5.6 public static JavacTrees instance(JavaCompiler.CompilationTask task) { 5.7 - if (!(task instanceof JavacTaskImpl)) 5.8 + if (!(task instanceof BasicJavacTask)) 5.9 throw new IllegalArgumentException(); 5.10 - return instance(((JavacTaskImpl)task).getContext()); 5.11 + return instance(((BasicJavacTask)task).getContext()); 5.12 } 5.13 5.14 // called reflectively from Trees.instance(ProcessingEnvironment env)
6.1 --- a/src/share/classes/com/sun/tools/javac/main/JavaCompiler.java Sat Nov 17 19:01:03 2012 +0000 6.2 +++ b/src/share/classes/com/sun/tools/javac/main/JavaCompiler.java Mon Nov 19 11:38:49 2012 -0800 6.3 @@ -1040,7 +1040,8 @@ 6.4 if (options.isSet(PROC, "none")) { 6.5 processAnnotations = false; 6.6 } else if (procEnvImpl == null) { 6.7 - procEnvImpl = new JavacProcessingEnvironment(context, processors); 6.8 + procEnvImpl = JavacProcessingEnvironment.instance(context); 6.9 + procEnvImpl.setProcessors(processors); 6.10 processAnnotations = procEnvImpl.atLeastOneProcessor(); 6.11 6.12 if (processAnnotations) {
7.1 --- a/src/share/classes/com/sun/tools/javac/main/Main.java Sat Nov 17 19:01:03 2012 +0000 7.2 +++ b/src/share/classes/com/sun/tools/javac/main/Main.java Mon Nov 19 11:38:49 2012 -0800 7.3 @@ -33,24 +33,29 @@ 7.4 import java.security.MessageDigest; 7.5 import java.util.Arrays; 7.6 import java.util.Collection; 7.7 +import java.util.Iterator; 7.8 import java.util.LinkedHashSet; 7.9 +import java.util.ServiceLoader; 7.10 import java.util.Set; 7.11 + 7.12 +import javax.annotation.processing.Processor; 7.13 import javax.tools.JavaFileManager; 7.14 import javax.tools.JavaFileObject; 7.15 -import javax.annotation.processing.Processor; 7.16 7.17 +import com.sun.source.util.JavacTask; 7.18 +import com.sun.source.util.Plugin; 7.19 import com.sun.tools.javac.code.Source; 7.20 import com.sun.tools.javac.file.CacheFSInfo; 7.21 import com.sun.tools.javac.file.JavacFileManager; 7.22 import com.sun.tools.javac.jvm.Target; 7.23 +import com.sun.tools.javac.processing.AnnotationProcessingError; 7.24 +import com.sun.tools.javac.processing.JavacProcessingEnvironment; 7.25 import com.sun.tools.javac.util.*; 7.26 +import com.sun.tools.javac.util.Log.PrefixKind; 7.27 import com.sun.tools.javac.util.Log.WriterKind; 7.28 -import com.sun.tools.javac.util.Log.PrefixKind; 7.29 -import com.sun.tools.javac.processing.AnnotationProcessingError; 7.30 - 7.31 import static com.sun.tools.javac.main.Option.*; 7.32 7.33 -/** This class provides a commandline interface to the GJC compiler. 7.34 +/** This class provides a command line interface to the javac compiler. 7.35 * 7.36 * <p><b>This is NOT part of any supported API. 7.37 * If you write code that depends on this, you do so at your own risk. 7.38 @@ -423,6 +428,42 @@ 7.39 if (batchMode) 7.40 CacheFSInfo.preRegister(context); 7.41 7.42 + // invoke any available plugins 7.43 + String plugins = options.get(PLUGIN); 7.44 + if (plugins != null) { 7.45 + JavacProcessingEnvironment pEnv = JavacProcessingEnvironment.instance(context); 7.46 + ClassLoader cl = pEnv.getProcessorClassLoader(); 7.47 + ServiceLoader<Plugin> sl = ServiceLoader.load(Plugin.class, cl); 7.48 + Set<List<String>> pluginsToCall = new LinkedHashSet<List<String>>(); 7.49 + for (String plugin: plugins.split("\\x00")) { 7.50 + pluginsToCall.add(List.from(plugin.split("\\s+"))); 7.51 + } 7.52 + JavacTask task = null; 7.53 + Iterator<Plugin> iter = sl.iterator(); 7.54 + while (iter.hasNext()) { 7.55 + Plugin plugin = iter.next(); 7.56 + for (List<String> p: pluginsToCall) { 7.57 + if (plugin.getName().equals(p.head)) { 7.58 + pluginsToCall.remove(p); 7.59 + try { 7.60 + if (task == null) 7.61 + task = JavacTask.instance(pEnv); 7.62 + plugin.call(task, p.tail.toArray(new String[p.tail.size()])); 7.63 + } catch (Throwable ex) { 7.64 + if (apiMode) 7.65 + throw new RuntimeException(ex); 7.66 + pluginMessage(ex); 7.67 + return Result.SYSERR; 7.68 + } 7.69 + 7.70 + } 7.71 + } 7.72 + } 7.73 + for (List<String> p: pluginsToCall) { 7.74 + log.printLines(PrefixKind.JAVAC, "msg.plugin.not.found", p.head); 7.75 + } 7.76 + } 7.77 + 7.78 fileManager = context.get(JavaFileManager.class); 7.79 7.80 comp = JavaCompiler.instance(context); 7.81 @@ -537,6 +578,14 @@ 7.82 ex.getCause().printStackTrace(log.getWriter(WriterKind.NOTICE)); 7.83 } 7.84 7.85 + /** Print a message reporting an uncaught exception from an 7.86 + * annotation processor. 7.87 + */ 7.88 + void pluginMessage(Throwable ex) { 7.89 + log.printLines(PrefixKind.JAVAC, "msg.plugin.uncaught.exception"); 7.90 + ex.printStackTrace(log.getWriter(WriterKind.NOTICE)); 7.91 + } 7.92 + 7.93 /** Display the location and checksum of a class. */ 7.94 void showClass(String className) { 7.95 PrintWriter pw = log.getWriter(WriterKind.NOTICE);
8.1 --- a/src/share/classes/com/sun/tools/javac/main/Option.java Sat Nov 17 19:01:03 2012 +0000 8.2 +++ b/src/share/classes/com/sun/tools/javac/main/Option.java Mon Nov 19 11:38:49 2012 -0800 8.3 @@ -393,6 +393,16 @@ 8.4 /* -Xjcov produces tables to support the code coverage tool jcov. */ 8.5 XJCOV("-Xjcov", null, HIDDEN, BASIC), 8.6 8.7 + PLUGIN("-Xplugin:", "opt.arg.plugin", "opt.plugin", EXTENDED, BASIC) { 8.8 + @Override 8.9 + public boolean process(OptionHelper helper, String option) { 8.10 + String p = option.substring(option.indexOf(':') + 1); 8.11 + String prev = helper.get(PLUGIN); 8.12 + helper.put(PLUGIN.text, (prev == null) ? p : prev + '\0' + p.trim()); 8.13 + return false; 8.14 + } 8.15 + }, 8.16 + 8.17 /* This is a back door to the compiler's option table. 8.18 * -XDx=y sets the option x to the value y. 8.19 * -XDx sets the option x to the value x.
9.1 --- a/src/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java Sat Nov 17 19:01:03 2012 +0000 9.2 +++ b/src/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java Mon Nov 19 11:38:49 2012 -0800 9.3 @@ -145,6 +145,7 @@ 9.4 Source source; 9.5 9.6 private ClassLoader processorClassLoader; 9.7 + private SecurityException processorClassLoaderException; 9.8 9.9 /** 9.10 * JavacMessages object used for localization 9.11 @@ -155,7 +156,15 @@ 9.12 9.13 private Context context; 9.14 9.15 - public JavacProcessingEnvironment(Context context, Iterable<? extends Processor> processors) { 9.16 + /** Get the JavacProcessingEnvironment instance for this context. */ 9.17 + public static JavacProcessingEnvironment instance(Context context) { 9.18 + JavacProcessingEnvironment instance = context.get(JavacProcessingEnvironment.class); 9.19 + if (instance == null) 9.20 + instance = new JavacProcessingEnvironment(context); 9.21 + return instance; 9.22 + } 9.23 + 9.24 + protected JavacProcessingEnvironment(Context context) { 9.25 this.context = context; 9.26 log = Log.instance(context); 9.27 source = Source.instance(context); 9.28 @@ -184,6 +193,11 @@ 9.29 unmatchedProcessorOptions = initUnmatchedProcessorOptions(); 9.30 messages = JavacMessages.instance(context); 9.31 taskListener = MultiTaskListener.instance(context); 9.32 + initProcessorClassLoader(); 9.33 + } 9.34 + 9.35 + public void setProcessors(Iterable<? extends Processor> processors) { 9.36 + Assert.checkNull(discoveredProcs); 9.37 initProcessorIterator(context, processors); 9.38 } 9.39 9.40 @@ -199,6 +213,23 @@ 9.41 return Collections.unmodifiableSet(platformAnnotations); 9.42 } 9.43 9.44 + private void initProcessorClassLoader() { 9.45 + JavaFileManager fileManager = context.get(JavaFileManager.class); 9.46 + try { 9.47 + // If processorpath is not explicitly set, use the classpath. 9.48 + processorClassLoader = fileManager.hasLocation(ANNOTATION_PROCESSOR_PATH) 9.49 + ? fileManager.getClassLoader(ANNOTATION_PROCESSOR_PATH) 9.50 + : fileManager.getClassLoader(CLASS_PATH); 9.51 + 9.52 + if (processorClassLoader != null && processorClassLoader instanceof Closeable) { 9.53 + JavaCompiler compiler = JavaCompiler.instance(context); 9.54 + compiler.closeables = compiler.closeables.prepend((Closeable) processorClassLoader); 9.55 + } 9.56 + } catch (SecurityException e) { 9.57 + processorClassLoaderException = e; 9.58 + } 9.59 + } 9.60 + 9.61 private void initProcessorIterator(Context context, Iterable<? extends Processor> processors) { 9.62 Log log = Log.instance(context); 9.63 Iterator<? extends Processor> processorIterator; 9.64 @@ -217,18 +248,7 @@ 9.65 processorIterator = processors.iterator(); 9.66 } else { 9.67 String processorNames = options.get(PROCESSOR); 9.68 - JavaFileManager fileManager = context.get(JavaFileManager.class); 9.69 - try { 9.70 - // If processorpath is not explicitly set, use the classpath. 9.71 - processorClassLoader = fileManager.hasLocation(ANNOTATION_PROCESSOR_PATH) 9.72 - ? fileManager.getClassLoader(ANNOTATION_PROCESSOR_PATH) 9.73 - : fileManager.getClassLoader(CLASS_PATH); 9.74 - 9.75 - if (processorClassLoader != null && processorClassLoader instanceof Closeable) { 9.76 - JavaCompiler compiler = JavaCompiler.instance(context); 9.77 - compiler.closeables = compiler.closeables.prepend((Closeable) processorClassLoader); 9.78 - } 9.79 - 9.80 + if (processorClassLoaderException == null) { 9.81 /* 9.82 * If the "-processor" option is used, search the appropriate 9.83 * path for the named class. Otherwise, use a service 9.84 @@ -239,14 +259,15 @@ 9.85 } else { 9.86 processorIterator = new ServiceIterator(processorClassLoader, log); 9.87 } 9.88 - } catch (SecurityException e) { 9.89 + } else { 9.90 /* 9.91 * A security exception will occur if we can't create a classloader. 9.92 * Ignore the exception if, with hindsight, we didn't need it anyway 9.93 * (i.e. no processor was specified either explicitly, or implicitly, 9.94 * in service configuration file.) Otherwise, we cannot continue. 9.95 */ 9.96 - processorIterator = handleServiceLoaderUnavailability("proc.cant.create.loader", e); 9.97 + processorIterator = handleServiceLoaderUnavailability("proc.cant.create.loader", 9.98 + processorClassLoaderException); 9.99 } 9.100 } 9.101 discoveredProcs = new DiscoveredProcessors(processorIterator); 9.102 @@ -1473,13 +1494,19 @@ 9.103 } 9.104 9.105 /** 9.106 - * For internal use only. This method will be 9.107 - * removed without warning. 9.108 + * For internal use only. This method may be removed without warning. 9.109 */ 9.110 public Context getContext() { 9.111 return context; 9.112 } 9.113 9.114 + /** 9.115 + * For internal use only. This method may be removed without warning. 9.116 + */ 9.117 + public ClassLoader getProcessorClassLoader() { 9.118 + return processorClassLoader; 9.119 + } 9.120 + 9.121 public String toString() { 9.122 return "javac ProcessingEnvironment"; 9.123 }
10.1 --- a/src/share/classes/com/sun/tools/javac/resources/javac.properties Sat Nov 17 19:01:03 2012 +0000 10.2 +++ b/src/share/classes/com/sun/tools/javac/resources/javac.properties Mon Nov 19 11:38:49 2012 -0800 10.3 @@ -99,6 +99,10 @@ 10.4 <release> 10.5 javac.opt.arg.number=\ 10.6 <number> 10.7 +javac.opt.plugin=\ 10.8 + Name and optional arguments for a plug-in to be run 10.9 +javac.opt.arg.plugin=\ 10.10 + "name args" 10.11 10.12 ## extended options 10.13 10.14 @@ -185,6 +189,8 @@ 10.15 not a directory: {0} 10.16 javac.err.file.not.file=\ 10.17 not a file: {0} 10.18 +javac.msg.plugin.not.found=\ 10.19 + plug-in not found: {0} 10.20 ## messages 10.21 10.22 javac.msg.usage.header=\ 10.23 @@ -212,6 +218,10 @@ 10.24 \n\nAn annotation processor threw an uncaught exception.\n\ 10.25 Consult the following stack trace for details.\n 10.26 10.27 +javac.msg.plugin.uncaught.exception=\ 10.28 +\n\nA plugin threw an uncaught exception.\n\ 10.29 +Consult the following stack trace for details.\n 10.30 + 10.31 javac.msg.resource=\ 10.32 \n\nThe system is out of resources.\n\ 10.33 Consult the following stack trace for details.\n
11.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 11.2 +++ b/test/tools/javac/plugin/showtype/Identifiers.java Mon Nov 19 11:38:49 2012 -0800 11.3 @@ -0,0 +1,7 @@ 11.4 +/* /nodynamiccopyright */ 11.5 + 11.6 +public class Identifiers { 11.7 + public double E = Math.E; 11.8 + public double PI = Math.PI; 11.9 + public double PIE = PI + E; 11.10 +}
12.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 12.2 +++ b/test/tools/javac/plugin/showtype/Identifiers.out Mon Nov 19 11:38:49 2012 -0800 12.3 @@ -0,0 +1,21 @@ 12.4 +Identifiers.java:3: Note: type is ()void 12.5 +public class Identifiers { 12.6 + ^ 12.7 +Identifiers.java:4: Note: type is double 12.8 + public double E = Math.E; 12.9 + ^ 12.10 +Identifiers.java:4: Note: type is java.lang.Math 12.11 + public double E = Math.E; 12.12 + ^ 12.13 +Identifiers.java:5: Note: type is double 12.14 + public double PI = Math.PI; 12.15 + ^ 12.16 +Identifiers.java:5: Note: type is java.lang.Math 12.17 + public double PI = Math.PI; 12.18 + ^ 12.19 +Identifiers.java:6: Note: type is double 12.20 + public double PIE = PI + E; 12.21 + ^ 12.22 +Identifiers.java:6: Note: type is double 12.23 + public double PIE = PI + E; 12.24 + ^
13.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 13.2 +++ b/test/tools/javac/plugin/showtype/Identifiers_PI.out Mon Nov 19 11:38:49 2012 -0800 13.3 @@ -0,0 +1,6 @@ 13.4 +Identifiers.java:5: Note: type is double 13.5 + public double PI = Math.PI; 13.6 + ^ 13.7 +Identifiers.java:6: Note: type is double 13.8 + public double PIE = PI + E; 13.9 + ^
14.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 14.2 +++ b/test/tools/javac/plugin/showtype/ShowTypePlugin.java Mon Nov 19 11:38:49 2012 -0800 14.3 @@ -0,0 +1,106 @@ 14.4 +/* 14.5 + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. 14.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 14.7 + * 14.8 + * This code is free software; you can redistribute it and/or modify it 14.9 + * under the terms of the GNU General Public License version 2 only, as 14.10 + * published by the Free Software Foundation. 14.11 + * 14.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 14.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14.15 + * version 2 for more details (a copy is included in the LICENSE file that 14.16 + * accompanied this code). 14.17 + * 14.18 + * You should have received a copy of the GNU General Public License version 14.19 + * 2 along with this work; if not, write to the Free Software Foundation, 14.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 14.21 + * 14.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 14.23 + * or visit www.oracle.com if you need additional information or have any 14.24 + * questions. 14.25 + */ 14.26 + 14.27 +import com.sun.source.tree.CompilationUnitTree; 14.28 +import com.sun.source.tree.IdentifierTree; 14.29 +import com.sun.source.tree.MemberSelectTree; 14.30 +import com.sun.source.tree.Tree; 14.31 +import com.sun.source.util.JavacTask; 14.32 +import com.sun.source.util.Plugin; 14.33 +import com.sun.source.util.TaskEvent; 14.34 +import com.sun.source.util.TaskListener; 14.35 +import com.sun.source.util.TreePathScanner; 14.36 +import com.sun.source.util.Trees; 14.37 +import java.util.regex.Pattern; 14.38 +import javax.lang.model.type.TypeMirror; 14.39 +import javax.tools.Diagnostic.Kind; 14.40 + 14.41 +public class ShowTypePlugin implements Plugin { 14.42 + 14.43 + public String getName() { 14.44 + return "showtype"; 14.45 + } 14.46 + 14.47 + public void call(JavacTask task, String... args) { 14.48 + Pattern pattern = null; 14.49 + if (args.length == 1) 14.50 + pattern = Pattern.compile(args[0]); 14.51 + task.addTaskListener(new PostAnalyzeTaskListener(task, pattern)); 14.52 + } 14.53 + 14.54 + private static class PostAnalyzeTaskListener implements TaskListener { 14.55 + private final ShowTypeTreeVisitor visitor; 14.56 + 14.57 + PostAnalyzeTaskListener(JavacTask task, Pattern pattern) { 14.58 + visitor = new ShowTypeTreeVisitor(task, pattern); 14.59 + } 14.60 + 14.61 + @Override 14.62 + public void started(TaskEvent taskEvent) { } 14.63 + 14.64 + @Override 14.65 + public void finished(TaskEvent taskEvent) { 14.66 + if (taskEvent.getKind().equals(TaskEvent.Kind.ANALYZE)) { 14.67 + CompilationUnitTree compilationUnit = taskEvent.getCompilationUnit(); 14.68 + visitor.scan(compilationUnit, null); 14.69 + } 14.70 + } 14.71 + } 14.72 + 14.73 + private static class ShowTypeTreeVisitor extends TreePathScanner<Void, Void> { 14.74 + private final Trees trees; 14.75 + private final Pattern pattern; 14.76 + private CompilationUnitTree currCompUnit; 14.77 + 14.78 + ShowTypeTreeVisitor(JavacTask task, Pattern pattern) { 14.79 + trees = Trees.instance(task); 14.80 + this.pattern = pattern; 14.81 + } 14.82 + 14.83 + @Override 14.84 + public Void visitCompilationUnit(CompilationUnitTree tree, Void ignore) { 14.85 + currCompUnit = tree; 14.86 + return super.visitCompilationUnit(tree, ignore); 14.87 + } 14.88 + 14.89 + @Override 14.90 + public Void visitIdentifier(IdentifierTree tree, Void ignore) { 14.91 + show(tree, tree.getName()); 14.92 + return super.visitIdentifier(tree, ignore); 14.93 + } 14.94 + 14.95 + @Override 14.96 + public Void visitMemberSelect(MemberSelectTree tree, Void ignore) { 14.97 + show(tree, tree.getIdentifier()); 14.98 + return super.visitMemberSelect(tree, ignore); 14.99 + } 14.100 + 14.101 + void show(Tree tree, CharSequence name) { 14.102 + if (pattern == null || pattern.matcher(name).matches()) { 14.103 + TypeMirror type = trees.getTypeMirror(getCurrentPath()); 14.104 + trees.printMessage(Kind.NOTE, "type is " + type, tree, currCompUnit); 14.105 + } 14.106 + } 14.107 + } 14.108 + 14.109 +}
15.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 15.2 +++ b/test/tools/javac/plugin/showtype/Test.java Mon Nov 19 11:38:49 2012 -0800 15.3 @@ -0,0 +1,171 @@ 15.4 + 15.5 +import java.io.File; 15.6 +import java.io.FileWriter; 15.7 +import java.io.IOException; 15.8 +import java.io.PrintWriter; 15.9 +import java.io.StringWriter; 15.10 +import java.nio.charset.Charset; 15.11 +import java.nio.file.Files; 15.12 +import java.util.Arrays; 15.13 +import java.util.List; 15.14 +import java.util.Locale; 15.15 +import java.util.Objects; 15.16 +import javax.tools.JavaCompiler; 15.17 +import javax.tools.JavaFileManager; 15.18 +import javax.tools.JavaFileObject; 15.19 +import javax.tools.StandardJavaFileManager; 15.20 +import javax.tools.StandardLocation; 15.21 +import javax.tools.ToolProvider; 15.22 + 15.23 +/* 15.24 + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. 15.25 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 15.26 + * 15.27 + * This code is free software; you can redistribute it and/or modify it 15.28 + * under the terms of the GNU General Public License version 2 only, as 15.29 + * published by the Free Software Foundation. 15.30 + * 15.31 + * This code is distributed in the hope that it will be useful, but WITHOUT 15.32 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 15.33 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15.34 + * version 2 for more details (a copy is included in the LICENSE file that 15.35 + * accompanied this code). 15.36 + * 15.37 + * You should have received a copy of the GNU General Public License version 15.38 + * 2 along with this work; if not, write to the Free Software Foundation, 15.39 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 15.40 + * 15.41 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 15.42 + * or visit www.oracle.com if you need additional information or have any 15.43 + * questions. 15.44 + */ 15.45 + 15.46 +/** 15.47 + * @test 15.48 + * @bug 8001098 15.49 + * @summary Provide a simple light-weight "plug-in" mechanism for javac 15.50 + */ 15.51 + 15.52 +public class Test { 15.53 + public static void main(String... args) throws Exception { 15.54 + new Test().run(); 15.55 + } 15.56 + 15.57 + final File testSrc; 15.58 + final File pluginSrc; 15.59 + final File pluginClasses ; 15.60 + final File pluginJar; 15.61 + final List<String> ref1; 15.62 + final List<String> ref2; 15.63 + final JavaCompiler compiler; 15.64 + final StandardJavaFileManager fm; 15.65 + 15.66 + Test() throws Exception { 15.67 + testSrc = new File(System.getProperty("test.src")); 15.68 + pluginSrc = new File(testSrc, "ShowTypePlugin.java"); 15.69 + pluginClasses = new File("plugin"); 15.70 + pluginJar = new File("plugin.jar"); 15.71 + ref1 = readFile(testSrc, "Identifiers.out"); 15.72 + ref2 = readFile(testSrc, "Identifiers_PI.out"); 15.73 + compiler = ToolProvider.getSystemJavaCompiler(); 15.74 + fm = compiler.getStandardFileManager(null, null, null); 15.75 + } 15.76 + 15.77 + void run() throws Exception { 15.78 + // compile the plugin explicitly, to a non-standard directory 15.79 + // so that we don't find it on the wrong path by accident 15.80 + pluginClasses.mkdirs(); 15.81 + compile("-d", pluginClasses.getPath(), pluginSrc.getPath()); 15.82 + writeFile(new File(pluginClasses, "META-INF/services/com.sun.source.util.Plugin"), 15.83 + "ShowTypePlugin\n"); 15.84 + jar("cf", pluginJar.getPath(), "-C", pluginClasses.getPath(), "."); 15.85 + 15.86 + testCommandLine("-Xplugin:showtype", ref1); 15.87 + testCommandLine("-Xplugin:showtype PI", ref2); 15.88 + testAPI("-Xplugin:showtype", ref1); 15.89 + testAPI("-Xplugin:showtype PI", ref2); 15.90 + 15.91 + if (errors > 0) 15.92 + throw new Exception(errors + " errors occurred"); 15.93 + } 15.94 + 15.95 + void testAPI(String opt, List<String> ref) throws Exception { 15.96 + File identifiers = new File(testSrc, "Identifiers.java"); 15.97 + fm.setLocation(StandardLocation.ANNOTATION_PROCESSOR_PATH, Arrays.asList(pluginJar)); 15.98 + fm.setLocation(StandardLocation.CLASS_OUTPUT, Arrays.asList(new File("."))); 15.99 + List<String> options = Arrays.asList(opt); 15.100 + Iterable<? extends JavaFileObject> files = fm.getJavaFileObjects(identifiers); 15.101 + 15.102 + System.err.println("test api: " + options + " " + files); 15.103 + 15.104 + StringWriter sw = new StringWriter(); 15.105 + PrintWriter pw = new PrintWriter(sw); 15.106 + boolean ok = compiler.getTask(pw, fm, null, options, null, files).call(); 15.107 + String out = sw.toString(); 15.108 + System.err.println(out); 15.109 + if (!ok) 15.110 + error("testCommandLine: compilation failed"); 15.111 + checkOutput(out, ref); 15.112 + } 15.113 + 15.114 + void testCommandLine(String opt, List<String> ref) { 15.115 + File identifiers = new File(testSrc, "Identifiers.java"); 15.116 + String[] args = { 15.117 + "-d", ".", 15.118 + "-processorpath", pluginJar.getPath(), 15.119 + opt, 15.120 + identifiers.getPath() }; 15.121 + 15.122 + System.err.println("test command line: " + Arrays.asList(args)); 15.123 + 15.124 + StringWriter sw = new StringWriter(); 15.125 + PrintWriter pw = new PrintWriter(sw); 15.126 + int rc = com.sun.tools.javac.Main.compile(args, pw); 15.127 + String out = sw.toString(); 15.128 + System.err.println(out); 15.129 + if (rc != 0) 15.130 + error("testCommandLine: compilation failed"); 15.131 + checkOutput(out, ref); 15.132 + } 15.133 + 15.134 + private void checkOutput(String out, List<String> ref) { 15.135 + List<String> lines = Arrays.asList(out 15.136 + .replaceAll(".*?([A-Za-z.]+:[0-9]+: .*)", "$1") // remove file directory 15.137 + .split("[\r\n]+")); // allow for newline formats 15.138 + if (!lines.equals(ref)) { 15.139 + error("unexpected output"); 15.140 + } 15.141 + } 15.142 + 15.143 + private void compile(String... args) throws Exception { 15.144 + System.err.println("compile: " + Arrays.asList(args)); 15.145 + int rc = com.sun.tools.javac.Main.compile(args); 15.146 + if (rc != 0) 15.147 + throw new Exception("compiled failed, rc=" + rc); 15.148 + } 15.149 + 15.150 + private void jar(String... args) throws Exception { 15.151 + System.err.println("jar: " + Arrays.asList(args)); 15.152 + boolean ok = new sun.tools.jar.Main(System.out, System.err, "jar").run(args); 15.153 + if (!ok) 15.154 + throw new Exception("jar failed"); 15.155 + } 15.156 + 15.157 + private List<String> readFile(File dir, String name) throws IOException { 15.158 + return Files.readAllLines(new File(dir, name).toPath(), Charset.defaultCharset()); 15.159 + } 15.160 + 15.161 + private void writeFile(File f, String body) throws IOException { 15.162 + f.getParentFile().mkdirs(); 15.163 + try (FileWriter out = new FileWriter(f)) { 15.164 + out.write(body); 15.165 + } 15.166 + } 15.167 + 15.168 + private void error(String msg) { 15.169 + System.err.println(msg); 15.170 + errors++; 15.171 + } 15.172 + 15.173 + int errors; 15.174 +}