1 /*
  2  * Copyright (c) 2005, 2019, 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.  Oracle designates this
  8  * particular file as subject to the "Classpath" exception as provided
  9  * by Oracle in the LICENSE file that accompanied this code.
 10  *
 11  * This code is distributed in the hope that it will be useful, but WITHOUT
 12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 14  * version 2 for more details (a copy is included in the LICENSE file that
 15  * accompanied this code).
 16  *
 17  * You should have received a copy of the GNU General Public License version
 18  * 2 along with this work; if not, write to the Free Software Foundation,
 19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 20  *
 21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 22  * or visit www.oracle.com if you need additional information or have any
 23  * questions.
 24  */
 25 
 26 package com.sun.tools.javac.api;
 27 
 28 import java.lang.module.Configuration;
 29 import java.lang.module.ModuleFinder;
 30 import java.util.Collection;
 31 import java.util.LinkedHashSet;
 32 import java.util.Locale;
 33 import java.util.Objects;
 34 import java.util.ServiceLoader;
 35 import java.util.Set;
 36 
 37 import javax.annotation.processing.Processor;
 38 import javax.lang.model.element.Element;
 39 import javax.lang.model.type.TypeMirror;
 40 import javax.lang.model.util.Elements;
 41 import javax.lang.model.util.Types;
 42 import javax.tools.JavaFileObject;
 43 
 44 import com.sun.source.tree.CompilationUnitTree;
 45 import com.sun.source.tree.Tree;
 46 import com.sun.source.util.JavacTask;
 47 import com.sun.source.util.ParameterNameProvider;
 48 import com.sun.source.util.Plugin;
 49 import com.sun.source.util.TaskListener;
 50 import com.sun.tools.doclint.DocLint;
 51 import com.sun.tools.javac.code.MissingInfoHandler;
 52 import com.sun.tools.javac.main.JavaCompiler;
 53 import com.sun.tools.javac.model.JavacElements;
 54 import com.sun.tools.javac.model.JavacTypes;
 55 import com.sun.tools.javac.platform.PlatformDescription;
 56 import com.sun.tools.javac.platform.PlatformDescription.PluginInfo;
 57 import com.sun.tools.javac.processing.JavacProcessingEnvironment;
 58 import com.sun.tools.javac.resources.CompilerProperties.Errors;
 59 import com.sun.tools.javac.resources.CompilerProperties.Warnings;
 60 import com.sun.tools.javac.tree.JCTree;
 61 import com.sun.tools.javac.util.Context;
 62 import com.sun.tools.javac.util.DefinedBy;
 63 import com.sun.tools.javac.util.DefinedBy.Api;
 64 import com.sun.tools.javac.util.List;
 65 import com.sun.tools.javac.util.Log;
 66 import com.sun.tools.javac.util.ModuleHelper;
 67 import com.sun.tools.javac.util.Options;
 68 import com.sun.tools.javac.util.PropagatedException;
 69 
 70 /**
 71  * Provides basic functionality for implementations of JavacTask.
 72  *
 73  * <p><b>This is NOT part of any supported API.
 74  * If you write code that depends on this, you do so at your own
 75  * risk.  This code and its internal interfaces are subject to change
 76  * or deletion without notice.</b></p>
 77  */
 78 public class BasicJavacTask extends JavacTask {
 79     protected Context context;
 80     protected Options options;
 81     private TaskListener taskListener;
 82 
 83     public static JavacTask instance(Context context) {
 84         JavacTask instance = context.get(JavacTask.class);
 85         if (instance == null)
 86             instance = new BasicJavacTask(context, true);
 87         return instance;
 88     }
 89 
 90     @SuppressWarnings("this-escape")
 91     public BasicJavacTask(Context c, boolean register) {
 92         context = c;
 93         options = Options.instance(c);
 94         if (register)
 95             context.put(JavacTask.class, this);
 96     }
 97 
 98     @Override @DefinedBy(Api.COMPILER_TREE)
 99     public Iterable<? extends CompilationUnitTree> parse() {
100         throw new IllegalStateException();
101     }
102 
103     @Override @DefinedBy(Api.COMPILER_TREE)
104     public Iterable<? extends Element> analyze() {
105         throw new IllegalStateException();
106     }
107 
108     @Override @DefinedBy(Api.COMPILER_TREE)
109     public Iterable<? extends JavaFileObject> generate() {
110         throw new IllegalStateException();
111     }
112 
113     @Override @DefinedBy(Api.COMPILER_TREE)
114     public void setTaskListener(TaskListener tl) {
115         MultiTaskListener mtl = MultiTaskListener.instance(context);
116         if (taskListener != null)
117             mtl.remove(taskListener);
118         if (tl != null)
119             mtl.add(tl);
120         taskListener = tl;
121     }
122 
123     @Override @DefinedBy(Api.COMPILER_TREE)
124     public void addTaskListener(TaskListener taskListener) {
125         MultiTaskListener mtl = MultiTaskListener.instance(context);
126         mtl.add(taskListener);
127     }
128 
129     @Override @DefinedBy(Api.COMPILER_TREE)
130     public void removeTaskListener(TaskListener taskListener) {
131         MultiTaskListener mtl = MultiTaskListener.instance(context);
132         mtl.remove(taskListener);
133     }
134 
135     @Override
136     public void setParameterNameProvider(ParameterNameProvider handler) {
137         MissingInfoHandler.instance(context).setDelegate(handler);
138     }
139 
140     public Collection<TaskListener> getTaskListeners() {
141         MultiTaskListener mtl = MultiTaskListener.instance(context);
142         return mtl.getTaskListeners();
143     }
144 
145     @Override @DefinedBy(Api.COMPILER_TREE)
146     public TypeMirror getTypeMirror(Iterable<? extends Tree> path) {
147         // TODO: Should complete attribution if necessary
148         Tree last = null;
149         for (Tree node : path) {
150             last = Objects.requireNonNull(node);
151         }
152         if (last == null) {
153             throw new IllegalArgumentException("empty path");
154         }
155         return ((JCTree) last).type;
156     }
157 
158     @Override @DefinedBy(Api.COMPILER_TREE)
159     public Elements getElements() {
160         if (context == null)
161             throw new IllegalStateException();
162         return JavacElements.instance(context);
163     }
164 
165     @Override @DefinedBy(Api.COMPILER_TREE)
166     public Types getTypes() {
167         if (context == null)
168             throw new IllegalStateException();
169         return JavacTypes.instance(context);
170     }
171 
172     @Override @DefinedBy(Api.COMPILER)
173     public void addModules(Iterable<String> moduleNames) {
174         throw new IllegalStateException();
175     }
176 
177     @Override @DefinedBy(Api.COMPILER)
178     public void setProcessors(Iterable<? extends Processor> processors) {
179         throw new IllegalStateException();
180     }
181 
182     @Override @DefinedBy(Api.COMPILER)
183     public void setLocale(Locale locale) {
184         throw new IllegalStateException();
185     }
186 
187     @Override @DefinedBy(Api.COMPILER)
188     public Boolean call() {
189         throw new IllegalStateException();
190     }
191 
192     /**
193      * For internal use only.
194      * This method will be removed without warning.
195      * @return the context
196      */
197     public Context getContext() {
198         return context;
199     }
200 
201     public void initPlugins(Set<List<String>> pluginOpts) {
202         PlatformDescription platformProvider = context.get(PlatformDescription.class);
203 
204         if (platformProvider != null) {
205             for (PluginInfo<Plugin> pluginDesc : platformProvider.getPlugins()) {
206                 java.util.List<String> options =
207                         pluginDesc.getOptions().entrySet().stream()
208                                 .map(e -> e.getKey() + "=" + e.getValue())
209                                 .toList();
210                 try {
211                     initPlugin(pluginDesc.getPlugin(), options.toArray(new String[options.size()]));
212                 } catch (RuntimeException ex) {
213                     throw new PropagatedException(ex);
214                 }
215             }
216         }
217 
218         Set<List<String>> pluginsToCall = new LinkedHashSet<>(pluginOpts);
219         JavacProcessingEnvironment pEnv = JavacProcessingEnvironment.instance(context);
220         ServiceLoader<Plugin> sl = pEnv.getServiceLoader(Plugin.class);
221         Set<Plugin> autoStart = new LinkedHashSet<>();
222         for (Plugin plugin : sl) {
223             if (plugin.autoStart()) {
224                 autoStart.add(plugin);
225             }
226             for (List<String> p : pluginsToCall) {
227                 if (plugin.getName().equals(p.head)) {
228                     pluginsToCall.remove(p);
229                     autoStart.remove(plugin);
230                     try {
231                         initPlugin(plugin, p.tail.toArray(new String[p.tail.size()]));
232                     } catch (RuntimeException ex) {
233                         throw new PropagatedException(ex);
234                     }
235                     break;
236                 }
237             }
238         }
239         for (List<String> p : pluginsToCall) {
240             Log.instance(context).error(Errors.PluginNotFound(p.head));
241         }
242         for (Plugin plugin : autoStart) {
243             try {
244                 initPlugin(plugin, new String[0]);
245             } catch (RuntimeException ex) {
246                 throw new PropagatedException(ex);
247             }
248 
249         }
250     }
251 
252     private void initPlugin(Plugin p, String... args) {
253         Module m = p.getClass().getModule();
254         if (m.isNamed() && options.isSet("accessInternalAPI")) {
255             ModuleHelper.addExports(getClass().getModule(), m);
256         }
257         p.init(this, args);
258     }
259 
260     public void initDocLint(List<String> docLintOpts) {
261         if (docLintOpts.isEmpty())
262             return;
263         try {
264             DocLint.newDocLint().init(this, docLintOpts.toArray(new String[docLintOpts.size()]));
265             JavaCompiler.instance(context).keepComments = true;
266         } catch (IllegalStateException e) {
267             Log.instance(context).warning(Warnings.DoclintNotAvailable);
268         }
269     }
270 }