1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/share/classes/com/sun/tools/javac/api/JavacTaskImpl.java Wed Apr 27 01:34:52 2016 +0800 1.3 @@ -0,0 +1,512 @@ 1.4 +/* 1.5 + * Copyright (c) 2005, 2013, 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 + 1.29 +package com.sun.tools.javac.api; 1.30 + 1.31 +import java.io.File; 1.32 +import java.io.IOException; 1.33 +import java.nio.CharBuffer; 1.34 +import java.util.*; 1.35 +import java.util.concurrent.atomic.AtomicBoolean; 1.36 + 1.37 +import javax.annotation.processing.Processor; 1.38 +import javax.lang.model.element.Element; 1.39 +import javax.lang.model.element.TypeElement; 1.40 +import javax.lang.model.type.TypeMirror; 1.41 +import javax.tools.*; 1.42 + 1.43 +import com.sun.source.tree.*; 1.44 +import com.sun.source.util.*; 1.45 +import com.sun.tools.javac.code.*; 1.46 +import com.sun.tools.javac.code.Symbol.*; 1.47 +import com.sun.tools.javac.comp.*; 1.48 +import com.sun.tools.javac.file.JavacFileManager; 1.49 +import com.sun.tools.javac.main.*; 1.50 +import com.sun.tools.javac.main.JavaCompiler; 1.51 +import com.sun.tools.javac.model.*; 1.52 +import com.sun.tools.javac.parser.Parser; 1.53 +import com.sun.tools.javac.parser.ParserFactory; 1.54 +import com.sun.tools.javac.tree.*; 1.55 +import com.sun.tools.javac.tree.JCTree.*; 1.56 +import com.sun.tools.javac.util.*; 1.57 +import com.sun.tools.javac.util.List; 1.58 + 1.59 +/** 1.60 + * Provides access to functionality specific to the JDK Java Compiler, javac. 1.61 + * 1.62 + * <p><b>This is NOT part of any supported API. 1.63 + * If you write code that depends on this, you do so at your own 1.64 + * risk. This code and its internal interfaces are subject to change 1.65 + * or deletion without notice.</b></p> 1.66 + * 1.67 + * @author Peter von der Ahé 1.68 + * @author Jonathan Gibbons 1.69 + */ 1.70 +public class JavacTaskImpl extends BasicJavacTask { 1.71 + private Main compilerMain; 1.72 + private JavaCompiler compiler; 1.73 + private Locale locale; 1.74 + private String[] args; 1.75 + private String[] classNames; 1.76 + private List<JavaFileObject> fileObjects; 1.77 + private Map<JavaFileObject, JCCompilationUnit> notYetEntered; 1.78 + private ListBuffer<Env<AttrContext>> genList; 1.79 + private final AtomicBoolean used = new AtomicBoolean(); 1.80 + private Iterable<? extends Processor> processors; 1.81 + 1.82 + private Main.Result result = null; 1.83 + 1.84 + JavacTaskImpl(Main compilerMain, 1.85 + String[] args, 1.86 + String[] classNames, 1.87 + Context context, 1.88 + List<JavaFileObject> fileObjects) { 1.89 + super(null, false); 1.90 + this.compilerMain = compilerMain; 1.91 + this.args = args; 1.92 + this.classNames = classNames; 1.93 + this.context = context; 1.94 + this.fileObjects = fileObjects; 1.95 + setLocale(Locale.getDefault()); 1.96 + // null checks 1.97 + compilerMain.getClass(); 1.98 + args.getClass(); 1.99 + fileObjects.getClass(); 1.100 + } 1.101 + 1.102 + JavacTaskImpl(Main compilerMain, 1.103 + Iterable<String> args, 1.104 + Context context, 1.105 + Iterable<String> classes, 1.106 + Iterable<? extends JavaFileObject> fileObjects) { 1.107 + this(compilerMain, toArray(args), toArray(classes), context, toList(fileObjects)); 1.108 + } 1.109 + 1.110 + static private String[] toArray(Iterable<String> iter) { 1.111 + ListBuffer<String> result = new ListBuffer<String>(); 1.112 + if (iter != null) 1.113 + for (String s : iter) 1.114 + result.append(s); 1.115 + return result.toArray(new String[result.length()]); 1.116 + } 1.117 + 1.118 + static private List<JavaFileObject> toList(Iterable<? extends JavaFileObject> fileObjects) { 1.119 + if (fileObjects == null) 1.120 + return List.nil(); 1.121 + ListBuffer<JavaFileObject> result = new ListBuffer<JavaFileObject>(); 1.122 + for (JavaFileObject fo : fileObjects) 1.123 + result.append(fo); 1.124 + return result.toList(); 1.125 + } 1.126 + 1.127 + public Main.Result doCall() { 1.128 + if (!used.getAndSet(true)) { 1.129 + initContext(); 1.130 + notYetEntered = new HashMap<JavaFileObject, JCCompilationUnit>(); 1.131 + compilerMain.setAPIMode(true); 1.132 + result = compilerMain.compile(args, classNames, context, fileObjects, processors); 1.133 + cleanup(); 1.134 + return result; 1.135 + } else { 1.136 + throw new IllegalStateException("multiple calls to method 'call'"); 1.137 + } 1.138 + } 1.139 + 1.140 + public Boolean call() { 1.141 + return doCall().isOK(); 1.142 + } 1.143 + 1.144 + public void setProcessors(Iterable<? extends Processor> processors) { 1.145 + processors.getClass(); // null check 1.146 + // not mt-safe 1.147 + if (used.get()) 1.148 + throw new IllegalStateException(); 1.149 + this.processors = processors; 1.150 + } 1.151 + 1.152 + public void setLocale(Locale locale) { 1.153 + if (used.get()) 1.154 + throw new IllegalStateException(); 1.155 + this.locale = locale; 1.156 + } 1.157 + 1.158 + private void prepareCompiler() throws IOException { 1.159 + if (used.getAndSet(true)) { 1.160 + if (compiler == null) 1.161 + throw new IllegalStateException(); 1.162 + } else { 1.163 + initContext(); 1.164 + compilerMain.log = Log.instance(context); 1.165 + compilerMain.setOptions(Options.instance(context)); 1.166 + compilerMain.filenames = new LinkedHashSet<File>(); 1.167 + Collection<File> filenames = compilerMain.processArgs(CommandLine.parse(args), classNames); 1.168 + if (filenames != null && !filenames.isEmpty()) 1.169 + throw new IllegalArgumentException("Malformed arguments " + toString(filenames, " ")); 1.170 + compiler = JavaCompiler.instance(context); 1.171 + compiler.keepComments = true; 1.172 + compiler.genEndPos = true; 1.173 + // NOTE: this value will be updated after annotation processing 1.174 + compiler.initProcessAnnotations(processors); 1.175 + notYetEntered = new HashMap<JavaFileObject, JCCompilationUnit>(); 1.176 + for (JavaFileObject file: fileObjects) 1.177 + notYetEntered.put(file, null); 1.178 + genList = new ListBuffer<Env<AttrContext>>(); 1.179 + // endContext will be called when all classes have been generated 1.180 + // TODO: should handle the case after each phase if errors have occurred 1.181 + args = null; 1.182 + classNames = null; 1.183 + } 1.184 + } 1.185 + 1.186 + <T> String toString(Iterable<T> items, String sep) { 1.187 + String currSep = ""; 1.188 + StringBuilder sb = new StringBuilder(); 1.189 + for (T item: items) { 1.190 + sb.append(currSep); 1.191 + sb.append(item.toString()); 1.192 + currSep = sep; 1.193 + } 1.194 + return sb.toString(); 1.195 + } 1.196 + 1.197 + private void initContext() { 1.198 + context.put(JavacTask.class, this); 1.199 + //initialize compiler's default locale 1.200 + context.put(Locale.class, locale); 1.201 + } 1.202 + 1.203 + void cleanup() { 1.204 + if (compiler != null) 1.205 + compiler.close(); 1.206 + compiler = null; 1.207 + compilerMain = null; 1.208 + args = null; 1.209 + classNames = null; 1.210 + context = null; 1.211 + fileObjects = null; 1.212 + notYetEntered = null; 1.213 + } 1.214 + 1.215 + /** 1.216 + * Construct a JavaFileObject from the given file. 1.217 + * 1.218 + * <p><b>TODO: this method is useless here</b></p> 1.219 + * 1.220 + * @param file a file 1.221 + * @return a JavaFileObject from the standard file manager. 1.222 + */ 1.223 + public JavaFileObject asJavaFileObject(File file) { 1.224 + JavacFileManager fm = (JavacFileManager)context.get(JavaFileManager.class); 1.225 + return fm.getRegularFile(file); 1.226 + } 1.227 + 1.228 + /** 1.229 + * Parse the specified files returning a list of abstract syntax trees. 1.230 + * 1.231 + * @throws java.io.IOException TODO 1.232 + * @return a list of abstract syntax trees 1.233 + */ 1.234 + public Iterable<? extends CompilationUnitTree> parse() throws IOException { 1.235 + try { 1.236 + prepareCompiler(); 1.237 + List<JCCompilationUnit> units = compiler.parseFiles(fileObjects); 1.238 + for (JCCompilationUnit unit: units) { 1.239 + JavaFileObject file = unit.getSourceFile(); 1.240 + if (notYetEntered.containsKey(file)) 1.241 + notYetEntered.put(file, unit); 1.242 + } 1.243 + return units; 1.244 + } 1.245 + finally { 1.246 + parsed = true; 1.247 + if (compiler != null && compiler.log != null) 1.248 + compiler.log.flush(); 1.249 + } 1.250 + } 1.251 + 1.252 + private boolean parsed = false; 1.253 + 1.254 + /** 1.255 + * Translate all the abstract syntax trees to elements. 1.256 + * 1.257 + * @throws IOException TODO 1.258 + * @return a list of elements corresponding to the top level 1.259 + * classes in the abstract syntax trees 1.260 + */ 1.261 + public Iterable<? extends TypeElement> enter() throws IOException { 1.262 + return enter(null); 1.263 + } 1.264 + 1.265 + /** 1.266 + * Translate the given abstract syntax trees to elements. 1.267 + * 1.268 + * @param trees a list of abstract syntax trees. 1.269 + * @throws java.io.IOException TODO 1.270 + * @return a list of elements corresponding to the top level 1.271 + * classes in the abstract syntax trees 1.272 + */ 1.273 + public Iterable<? extends TypeElement> enter(Iterable<? extends CompilationUnitTree> trees) 1.274 + throws IOException 1.275 + { 1.276 + if (trees == null && notYetEntered != null && notYetEntered.isEmpty()) 1.277 + return List.nil(); 1.278 + 1.279 + prepareCompiler(); 1.280 + 1.281 + ListBuffer<JCCompilationUnit> roots = null; 1.282 + 1.283 + if (trees == null) { 1.284 + // If there are still files which were specified to be compiled 1.285 + // (i.e. in fileObjects) but which have not yet been entered, 1.286 + // then we make sure they have been parsed and add them to the 1.287 + // list to be entered. 1.288 + if (notYetEntered.size() > 0) { 1.289 + if (!parsed) 1.290 + parse(); // TODO would be nice to specify files needed to be parsed 1.291 + for (JavaFileObject file: fileObjects) { 1.292 + JCCompilationUnit unit = notYetEntered.remove(file); 1.293 + if (unit != null) { 1.294 + if (roots == null) 1.295 + roots = new ListBuffer<JCCompilationUnit>(); 1.296 + roots.append(unit); 1.297 + } 1.298 + } 1.299 + notYetEntered.clear(); 1.300 + } 1.301 + } 1.302 + else { 1.303 + for (CompilationUnitTree cu : trees) { 1.304 + if (cu instanceof JCCompilationUnit) { 1.305 + if (roots == null) 1.306 + roots = new ListBuffer<JCCompilationUnit>(); 1.307 + roots.append((JCCompilationUnit)cu); 1.308 + notYetEntered.remove(cu.getSourceFile()); 1.309 + } 1.310 + else 1.311 + throw new IllegalArgumentException(cu.toString()); 1.312 + } 1.313 + } 1.314 + 1.315 + if (roots == null) 1.316 + return List.nil(); 1.317 + 1.318 + try { 1.319 + List<JCCompilationUnit> units = compiler.enterTrees(roots.toList()); 1.320 + 1.321 + if (notYetEntered.isEmpty()) 1.322 + compiler = compiler.processAnnotations(units); 1.323 + 1.324 + ListBuffer<TypeElement> elements = new ListBuffer<TypeElement>(); 1.325 + for (JCCompilationUnit unit : units) { 1.326 + for (JCTree node : unit.defs) { 1.327 + if (node.hasTag(JCTree.Tag.CLASSDEF)) { 1.328 + JCClassDecl cdef = (JCClassDecl) node; 1.329 + if (cdef.sym != null) // maybe null if errors in anno processing 1.330 + elements.append(cdef.sym); 1.331 + } 1.332 + } 1.333 + } 1.334 + return elements.toList(); 1.335 + } 1.336 + finally { 1.337 + compiler.log.flush(); 1.338 + } 1.339 + } 1.340 + 1.341 + /** 1.342 + * Complete all analysis. 1.343 + * @throws IOException TODO 1.344 + */ 1.345 + @Override 1.346 + public Iterable<? extends Element> analyze() throws IOException { 1.347 + return analyze(null); 1.348 + } 1.349 + 1.350 + /** 1.351 + * Complete all analysis on the given classes. 1.352 + * This can be used to ensure that all compile time errors are reported. 1.353 + * The classes must have previously been returned from {@link #enter}. 1.354 + * If null is specified, all outstanding classes will be analyzed. 1.355 + * 1.356 + * @param classes a list of class elements 1.357 + */ 1.358 + // This implementation requires that we open up privileges on JavaCompiler. 1.359 + // An alternative implementation would be to move this code to JavaCompiler and 1.360 + // wrap it here 1.361 + public Iterable<? extends Element> analyze(Iterable<? extends TypeElement> classes) throws IOException { 1.362 + enter(null); // ensure all classes have been entered 1.363 + 1.364 + final ListBuffer<Element> results = new ListBuffer<Element>(); 1.365 + try { 1.366 + if (classes == null) { 1.367 + handleFlowResults(compiler.flow(compiler.attribute(compiler.todo)), results); 1.368 + } else { 1.369 + Filter f = new Filter() { 1.370 + public void process(Env<AttrContext> env) { 1.371 + handleFlowResults(compiler.flow(compiler.attribute(env)), results); 1.372 + } 1.373 + }; 1.374 + f.run(compiler.todo, classes); 1.375 + } 1.376 + } finally { 1.377 + compiler.log.flush(); 1.378 + } 1.379 + return results; 1.380 + } 1.381 + // where 1.382 + private void handleFlowResults(Queue<Env<AttrContext>> queue, ListBuffer<Element> elems) { 1.383 + for (Env<AttrContext> env: queue) { 1.384 + switch (env.tree.getTag()) { 1.385 + case CLASSDEF: 1.386 + JCClassDecl cdef = (JCClassDecl) env.tree; 1.387 + if (cdef.sym != null) 1.388 + elems.append(cdef.sym); 1.389 + break; 1.390 + case TOPLEVEL: 1.391 + JCCompilationUnit unit = (JCCompilationUnit) env.tree; 1.392 + if (unit.packge != null) 1.393 + elems.append(unit.packge); 1.394 + break; 1.395 + } 1.396 + } 1.397 + genList.addAll(queue); 1.398 + } 1.399 + 1.400 + 1.401 + /** 1.402 + * Generate code. 1.403 + * @throws IOException TODO 1.404 + */ 1.405 + @Override 1.406 + public Iterable<? extends JavaFileObject> generate() throws IOException { 1.407 + return generate(null); 1.408 + } 1.409 + 1.410 + /** 1.411 + * Generate code corresponding to the given classes. 1.412 + * The classes must have previously been returned from {@link #enter}. 1.413 + * If there are classes outstanding to be analyzed, that will be done before 1.414 + * any classes are generated. 1.415 + * If null is specified, code will be generated for all outstanding classes. 1.416 + * 1.417 + * @param classes a list of class elements 1.418 + */ 1.419 + public Iterable<? extends JavaFileObject> generate(Iterable<? extends TypeElement> classes) throws IOException { 1.420 + final ListBuffer<JavaFileObject> results = new ListBuffer<JavaFileObject>(); 1.421 + try { 1.422 + analyze(null); // ensure all classes have been parsed, entered, and analyzed 1.423 + 1.424 + if (classes == null) { 1.425 + compiler.generate(compiler.desugar(genList), results); 1.426 + genList.clear(); 1.427 + } 1.428 + else { 1.429 + Filter f = new Filter() { 1.430 + public void process(Env<AttrContext> env) { 1.431 + compiler.generate(compiler.desugar(ListBuffer.of(env)), results); 1.432 + } 1.433 + }; 1.434 + f.run(genList, classes); 1.435 + } 1.436 + if (genList.isEmpty()) { 1.437 + compiler.reportDeferredDiagnostics(); 1.438 + cleanup(); 1.439 + } 1.440 + } 1.441 + finally { 1.442 + if (compiler != null) 1.443 + compiler.log.flush(); 1.444 + } 1.445 + return results; 1.446 + } 1.447 + 1.448 + public TypeMirror getTypeMirror(Iterable<? extends Tree> path) { 1.449 + // TODO: Should complete attribution if necessary 1.450 + Tree last = null; 1.451 + for (Tree node : path) 1.452 + last = node; 1.453 + return ((JCTree)last).type; 1.454 + } 1.455 + 1.456 + public JavacElements getElements() { 1.457 + if (context == null) 1.458 + throw new IllegalStateException(); 1.459 + return JavacElements.instance(context); 1.460 + } 1.461 + 1.462 + public JavacTypes getTypes() { 1.463 + if (context == null) 1.464 + throw new IllegalStateException(); 1.465 + return JavacTypes.instance(context); 1.466 + } 1.467 + 1.468 + public Iterable<? extends Tree> pathFor(CompilationUnitTree unit, Tree node) { 1.469 + return TreeInfo.pathFor((JCTree) node, (JCTree.JCCompilationUnit) unit).reverse(); 1.470 + } 1.471 + 1.472 + abstract class Filter { 1.473 + void run(Queue<Env<AttrContext>> list, Iterable<? extends TypeElement> classes) { 1.474 + Set<TypeElement> set = new HashSet<TypeElement>(); 1.475 + for (TypeElement item: classes) 1.476 + set.add(item); 1.477 + 1.478 + ListBuffer<Env<AttrContext>> defer = new ListBuffer<>(); 1.479 + while (list.peek() != null) { 1.480 + Env<AttrContext> env = list.remove(); 1.481 + ClassSymbol csym = env.enclClass.sym; 1.482 + if (csym != null && set.contains(csym.outermostClass())) 1.483 + process(env); 1.484 + else 1.485 + defer = defer.append(env); 1.486 + } 1.487 + 1.488 + list.addAll(defer); 1.489 + } 1.490 + 1.491 + abstract void process(Env<AttrContext> env); 1.492 + } 1.493 + 1.494 + /** 1.495 + * For internal use only. This method will be 1.496 + * removed without warning. 1.497 + */ 1.498 + public Type parseType(String expr, TypeElement scope) { 1.499 + if (expr == null || expr.equals("")) 1.500 + throw new IllegalArgumentException(); 1.501 + compiler = JavaCompiler.instance(context); 1.502 + JavaFileObject prev = compiler.log.useSource(null); 1.503 + ParserFactory parserFactory = ParserFactory.instance(context); 1.504 + Attr attr = Attr.instance(context); 1.505 + try { 1.506 + CharBuffer buf = CharBuffer.wrap((expr+"\u0000").toCharArray(), 0, expr.length()); 1.507 + Parser parser = parserFactory.newParser(buf, false, false, false); 1.508 + JCTree tree = parser.parseType(); 1.509 + return attr.attribType(tree, (Symbol.TypeSymbol)scope); 1.510 + } finally { 1.511 + compiler.log.useSource(prev); 1.512 + } 1.513 + } 1.514 + 1.515 +}