langtools/src/share/classes/com/sun/tools/javac/api/JavacTaskImpl.java
changeset 10 06bc494ca11e
child 731 1dd22bdb9ca5
equal deleted inserted replaced
0:fd16c54261b3 10:06bc494ca11e
       
     1 /*
       
     2  * Copyright 2005-2006 Sun Microsystems, Inc.  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.  Sun designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
       
    22  * CA 95054 USA or visit www.sun.com if you need additional information or
       
    23  * have any questions.
       
    24  */
       
    25 
       
    26 package com.sun.tools.javac.api;
       
    27 
       
    28 import java.io.File;
       
    29 import java.io.IOException;
       
    30 import java.util.*;
       
    31 import java.util.concurrent.atomic.AtomicBoolean;
       
    32 
       
    33 import javax.annotation.processing.Processor;
       
    34 import javax.lang.model.element.Element;
       
    35 import javax.lang.model.element.TypeElement;
       
    36 import javax.lang.model.type.TypeMirror;
       
    37 import javax.tools.*;
       
    38 
       
    39 import com.sun.source.tree.Tree;
       
    40 import com.sun.source.tree.*;
       
    41 import com.sun.source.util.*;
       
    42 import com.sun.tools.javac.code.*;
       
    43 import com.sun.tools.javac.code.Symbol.*;
       
    44 import com.sun.tools.javac.comp.*;
       
    45 import com.sun.tools.javac.main.*;
       
    46 import com.sun.tools.javac.model.*;
       
    47 import com.sun.tools.javac.parser.Parser;
       
    48 import com.sun.tools.javac.parser.Scanner;
       
    49 import com.sun.tools.javac.tree.*;
       
    50 import com.sun.tools.javac.tree.JCTree.*;
       
    51 import com.sun.tools.javac.util.*;
       
    52 import com.sun.tools.javac.util.List;
       
    53 import com.sun.tools.javac.main.JavaCompiler;
       
    54 
       
    55 /**
       
    56  * Provides access to functionality specific to the Sun Java Compiler, javac.
       
    57  *
       
    58  * <p><b>This is NOT part of any API supported by Sun Microsystems.
       
    59  * If you write code that depends on this, you do so at your own
       
    60  * risk.  This code and its internal interfaces are subject to change
       
    61  * or deletion without notice.</b></p>
       
    62  *
       
    63  * @author Peter von der Ah&eacute;
       
    64  * @author Jonathan Gibbons
       
    65  */
       
    66 public class JavacTaskImpl extends JavacTask {
       
    67     private JavacTool tool;
       
    68     private Main compilerMain;
       
    69     private JavaCompiler compiler;
       
    70     private String[] args;
       
    71     private Context context;
       
    72     private List<JavaFileObject> fileObjects;
       
    73     private Map<JavaFileObject, JCCompilationUnit> notYetEntered;
       
    74     private ListBuffer<Env<AttrContext>> genList;
       
    75     private TaskListener taskListener;
       
    76     private AtomicBoolean used = new AtomicBoolean();
       
    77     private Iterable<? extends Processor> processors;
       
    78 
       
    79     private Integer result = null;
       
    80 
       
    81     JavacTaskImpl(JavacTool tool,
       
    82                 Main compilerMain,
       
    83                 String[] args,
       
    84                 Context context,
       
    85                 List<JavaFileObject> fileObjects) {
       
    86         this.tool = tool;
       
    87         this.compilerMain = compilerMain;
       
    88         this.args = args;
       
    89         this.context = context;
       
    90         this.fileObjects = fileObjects;
       
    91         // null checks
       
    92         compilerMain.getClass();
       
    93         args.getClass();
       
    94         context.getClass();
       
    95         fileObjects.getClass();
       
    96     }
       
    97 
       
    98     JavacTaskImpl(JavacTool tool,
       
    99                 Main compilerMain,
       
   100                 Iterable<String> flags,
       
   101                 Context context,
       
   102                 Iterable<String> classes,
       
   103                 Iterable<? extends JavaFileObject> fileObjects) {
       
   104         this(tool, compilerMain, toArray(flags, classes), context, toList(fileObjects));
       
   105     }
       
   106 
       
   107     static private String[] toArray(Iterable<String> flags, Iterable<String> classes) {
       
   108         ListBuffer<String> result = new ListBuffer<String>();
       
   109         if (flags != null)
       
   110             for (String flag : flags)
       
   111                 result.append(flag);
       
   112         if (classes != null)
       
   113             for (String cls : classes)
       
   114                 result.append(cls);
       
   115         return result.toArray(new String[result.length()]);
       
   116     }
       
   117 
       
   118     static private List<JavaFileObject> toList(Iterable<? extends JavaFileObject> fileObjects) {
       
   119         if (fileObjects == null)
       
   120             return List.nil();
       
   121         ListBuffer<JavaFileObject> result = new ListBuffer<JavaFileObject>();
       
   122         for (JavaFileObject fo : fileObjects)
       
   123             result.append(fo);
       
   124         return result.toList();
       
   125     }
       
   126 
       
   127     public Boolean call() {
       
   128         if (!used.getAndSet(true)) {
       
   129             beginContext();
       
   130             try {
       
   131                 compilerMain.setFatalErrors(true);
       
   132                 result = compilerMain.compile(args, context, fileObjects, processors);
       
   133             } finally {
       
   134                 endContext();
       
   135             }
       
   136             compilerMain = null;
       
   137             args = null;
       
   138             context = null;
       
   139             fileObjects = null;
       
   140             return result == 0;
       
   141         } else {
       
   142             throw new IllegalStateException("multiple calls to method 'call'");
       
   143         }
       
   144     }
       
   145 
       
   146     public void setProcessors(Iterable<? extends Processor> processors) {
       
   147         processors.getClass(); // null check
       
   148         // not mt-safe
       
   149         if (used.get())
       
   150             throw new IllegalStateException();
       
   151         this.processors = processors;
       
   152     }
       
   153 
       
   154     public void setLocale(Locale locale) {
       
   155         // locale argument is ignored, see RFE 6443132
       
   156         if (used.get())
       
   157             throw new IllegalStateException();
       
   158     }
       
   159 
       
   160     private void prepareCompiler() throws IOException {
       
   161         if (!used.getAndSet(true)) {
       
   162             beginContext();
       
   163             compilerMain.setOptions(Options.instance(context));
       
   164             compilerMain.filenames = new ListBuffer<File>();
       
   165             List<File> filenames = compilerMain.processArgs(CommandLine.parse(args));
       
   166             if (!filenames.isEmpty())
       
   167                 throw new IllegalArgumentException("Malformed arguments " + filenames.toString(" "));
       
   168             compiler = JavaCompiler.instance(context);
       
   169             // force the use of the scanner that captures Javadoc comments
       
   170             com.sun.tools.javac.parser.DocCommentScanner.Factory.preRegister(context);
       
   171             compiler.keepComments = true;
       
   172             compiler.genEndPos = true;
       
   173             // NOTE: this value will be updated after annotation processing
       
   174             compiler.initProcessAnnotations(processors);
       
   175             notYetEntered = new HashMap<JavaFileObject, JCCompilationUnit>();
       
   176             for (JavaFileObject file: fileObjects)
       
   177                 notYetEntered.put(file, null);
       
   178             genList = new ListBuffer<Env<AttrContext>>();
       
   179             // endContext will be called when all classes have been generated
       
   180             // TODO: should handle the case after each phase if errors have occurred
       
   181             args = null;
       
   182         }
       
   183     }
       
   184 
       
   185     private void beginContext() {
       
   186         context.put(JavacTaskImpl.class, this);
       
   187         if (context.get(TaskListener.class) != null)
       
   188             context.put(TaskListener.class, (TaskListener)null);
       
   189         if (taskListener != null)
       
   190             context.put(TaskListener.class, wrap(taskListener));
       
   191         tool.beginContext(context);
       
   192     }
       
   193     // where
       
   194     private TaskListener wrap(final TaskListener tl) {
       
   195         tl.getClass(); // null check
       
   196         return new TaskListener() {
       
   197             public void started(TaskEvent e) {
       
   198                 try {
       
   199                     tl.started(e);
       
   200                 } catch (Throwable t) {
       
   201                     throw new ClientCodeException(t);
       
   202                 }
       
   203             }
       
   204 
       
   205             public void finished(TaskEvent e) {
       
   206                 try {
       
   207                     tl.finished(e);
       
   208                 } catch (Throwable t) {
       
   209                     throw new ClientCodeException(t);
       
   210                 }
       
   211             }
       
   212 
       
   213         };
       
   214     }
       
   215 
       
   216     private void endContext() {
       
   217         tool.endContext();
       
   218     }
       
   219 
       
   220     /**
       
   221      * Construct a JavaFileObject from the given file.
       
   222      *
       
   223      * <p><b>TODO: this method is useless here</b></p>
       
   224      *
       
   225      * @param file a file
       
   226      * @return a JavaFileObject from the standard file manager.
       
   227      */
       
   228     public JavaFileObject asJavaFileObject(File file) {
       
   229         JavacFileManager fm = (JavacFileManager)context.get(JavaFileManager.class);
       
   230         return fm.getRegularFile(file);
       
   231     }
       
   232 
       
   233     public void setTaskListener(TaskListener taskListener) {
       
   234         this.taskListener = taskListener;
       
   235     }
       
   236 
       
   237     /**
       
   238      * Parse the specified files returning a list of abstract syntax trees.
       
   239      *
       
   240      * @throws java.io.IOException TODO
       
   241      * @return a list of abstract syntax trees
       
   242      */
       
   243     public Iterable<? extends CompilationUnitTree> parse() throws IOException {
       
   244         try {
       
   245             prepareCompiler();
       
   246             List<JCCompilationUnit> units = compiler.parseFiles(fileObjects);
       
   247             for (JCCompilationUnit unit: units) {
       
   248                 JavaFileObject file = unit.getSourceFile();
       
   249                 if (notYetEntered.containsKey(file))
       
   250                     notYetEntered.put(file, unit);
       
   251             }
       
   252             return units;
       
   253         }
       
   254         finally {
       
   255             parsed = true;
       
   256             if (compiler != null && compiler.log != null)
       
   257                 compiler.log.flush();
       
   258         }
       
   259     }
       
   260 
       
   261     private boolean parsed = false;
       
   262 
       
   263     /**
       
   264      * Translate all the abstract syntax trees to elements.
       
   265      *
       
   266      * @throws IOException TODO
       
   267      * @return a list of elements corresponding to the top level
       
   268      * classes in the abstract syntax trees
       
   269      */
       
   270     public Iterable<? extends TypeElement> enter() throws IOException {
       
   271         return enter(null);
       
   272     }
       
   273 
       
   274     /**
       
   275      * Translate the given abstract syntax trees to elements.
       
   276      *
       
   277      * @param trees a list of abstract syntax trees.
       
   278      * @throws java.io.IOException TODO
       
   279      * @return a list of elements corresponding to the top level
       
   280      * classes in the abstract syntax trees
       
   281      */
       
   282     public Iterable<? extends TypeElement> enter(Iterable<? extends CompilationUnitTree> trees)
       
   283         throws IOException
       
   284     {
       
   285         prepareCompiler();
       
   286 
       
   287         ListBuffer<JCCompilationUnit> roots = null;
       
   288 
       
   289         if (trees == null) {
       
   290             // If there are still files which were specified to be compiled
       
   291             // (i.e. in fileObjects) but which have not yet been entered,
       
   292             // then we make sure they have been parsed and add them to the
       
   293             // list to be entered.
       
   294             if (notYetEntered.size() > 0) {
       
   295                 if (!parsed)
       
   296                     parse(); // TODO would be nice to specify files needed to be parsed
       
   297                 for (JavaFileObject file: fileObjects) {
       
   298                     JCCompilationUnit unit = notYetEntered.remove(file);
       
   299                     if (unit != null) {
       
   300                         if (roots == null)
       
   301                             roots = new ListBuffer<JCCompilationUnit>();
       
   302                         roots.append(unit);
       
   303                     }
       
   304                 }
       
   305                 notYetEntered.clear();
       
   306             }
       
   307         }
       
   308         else {
       
   309             for (CompilationUnitTree cu : trees) {
       
   310                 if (cu instanceof JCCompilationUnit) {
       
   311                     if (roots == null)
       
   312                         roots = new ListBuffer<JCCompilationUnit>();
       
   313                     roots.append((JCCompilationUnit)cu);
       
   314                     notYetEntered.remove(cu.getSourceFile());
       
   315                 }
       
   316                 else
       
   317                     throw new IllegalArgumentException(cu.toString());
       
   318             }
       
   319         }
       
   320 
       
   321         if (roots == null)
       
   322             return List.nil();
       
   323 
       
   324         try {
       
   325             List<JCCompilationUnit> units = compiler.enterTrees(roots.toList());
       
   326 
       
   327             if (notYetEntered.isEmpty())
       
   328                 compiler = compiler.processAnnotations(units);
       
   329 
       
   330             ListBuffer<TypeElement> elements = new ListBuffer<TypeElement>();
       
   331             for (JCCompilationUnit unit : units) {
       
   332                 for (JCTree node : unit.defs)
       
   333                     if (node.getTag() == JCTree.CLASSDEF)
       
   334                         elements.append(((JCTree.JCClassDecl) node).sym);
       
   335             }
       
   336             return elements.toList();
       
   337         }
       
   338         finally {
       
   339             compiler.log.flush();
       
   340         }
       
   341     }
       
   342 
       
   343     /**
       
   344      * Complete all analysis.
       
   345      * @throws IOException TODO
       
   346      */
       
   347     @Override
       
   348     public Iterable<? extends Element> analyze() throws IOException {
       
   349         return analyze(null);
       
   350     }
       
   351 
       
   352     /**
       
   353      * Complete all analysis on the given classes.
       
   354      * This can be used to ensure that all compile time errors are reported.
       
   355      * The classes must have previously been returned from {@link #enter}.
       
   356      * If null is specified, all outstanding classes will be analyzed.
       
   357      *
       
   358      * @param classes a list of class elements
       
   359      */
       
   360     // This implementation requires that we open up privileges on JavaCompiler.
       
   361     // An alternative implementation would be to move this code to JavaCompiler and
       
   362     // wrap it here
       
   363     public Iterable<? extends Element> analyze(Iterable<? extends TypeElement> classes) throws IOException {
       
   364         enter(null);  // ensure all classes have been entered
       
   365 
       
   366         final ListBuffer<Element> results = new ListBuffer<Element>();
       
   367         try {
       
   368             if (classes == null) {
       
   369                 handleFlowResults(compiler.flow(compiler.attribute(compiler.todo)), results);
       
   370             } else {
       
   371                 Filter f = new Filter() {
       
   372                     public void process(Env<AttrContext> env) {
       
   373                         handleFlowResults(compiler.flow(compiler.attribute(env)), results);
       
   374                     }
       
   375                 };
       
   376                 f.run(compiler.todo, classes);
       
   377             }
       
   378         } finally {
       
   379             compiler.log.flush();
       
   380         }
       
   381         return results;
       
   382     }
       
   383     // where
       
   384         private void handleFlowResults(List<Env<AttrContext>> list, ListBuffer<Element> elems) {
       
   385             for (Env<AttrContext> env: list) {
       
   386                 switch (env.tree.getTag()) {
       
   387                     case JCTree.CLASSDEF:
       
   388                         JCClassDecl cdef = (JCClassDecl) env.tree;
       
   389                         if (cdef.sym != null)
       
   390                             elems.append(cdef.sym);
       
   391                         break;
       
   392                     case JCTree.TOPLEVEL:
       
   393                         JCCompilationUnit unit = (JCCompilationUnit) env.tree;
       
   394                         if (unit.packge != null)
       
   395                             elems.append(unit.packge);
       
   396                         break;
       
   397                 }
       
   398             }
       
   399             genList.appendList(list);
       
   400         }
       
   401 
       
   402 
       
   403     /**
       
   404      * Generate code.
       
   405      * @throws IOException TODO
       
   406      */
       
   407     @Override
       
   408     public Iterable<? extends JavaFileObject> generate() throws IOException {
       
   409         return generate(null);
       
   410     }
       
   411 
       
   412     /**
       
   413      * Generate code corresponding to the given classes.
       
   414      * The classes must have previously been returned from {@link #enter}.
       
   415      * If there are classes outstanding to be analyzed, that will be done before
       
   416      * any classes are generated.
       
   417      * If null is specified, code will be generated for all outstanding classes.
       
   418      *
       
   419      * @param classes a list of class elements
       
   420      */
       
   421     public Iterable<? extends JavaFileObject> generate(Iterable<? extends TypeElement> classes) throws IOException {
       
   422         final ListBuffer<JavaFileObject> results = new ListBuffer<JavaFileObject>();
       
   423         try {
       
   424             analyze(null);  // ensure all classes have been parsed, entered, and analyzed
       
   425 
       
   426             if (classes == null) {
       
   427                 compiler.generate(compiler.desugar(genList.toList()), results);
       
   428                 genList.clear();
       
   429             }
       
   430             else {
       
   431                 Filter f = new Filter() {
       
   432                         public void process(Env<AttrContext> env) {
       
   433                             compiler.generate(compiler.desugar(List.of(env)), results);
       
   434                         }
       
   435                     };
       
   436                 f.run(genList, classes);
       
   437             }
       
   438             if (genList.isEmpty()) {
       
   439                 compiler.reportDeferredDiagnostics();
       
   440                 compiler.log.flush();
       
   441                 endContext();
       
   442             }
       
   443         }
       
   444         finally {
       
   445             compiler.log.flush();
       
   446         }
       
   447         return results;
       
   448     }
       
   449 
       
   450     public TypeMirror getTypeMirror(Iterable<? extends Tree> path) {
       
   451         // TODO: Should complete attribution if necessary
       
   452         Tree last = null;
       
   453         for (Tree node : path)
       
   454             last = node;
       
   455         return ((JCTree)last).type;
       
   456     }
       
   457 
       
   458     public JavacElements getElements() {
       
   459         if (context == null)
       
   460             throw new IllegalStateException();
       
   461         return JavacElements.instance(context);
       
   462     }
       
   463 
       
   464     public JavacTypes getTypes() {
       
   465         if (context == null)
       
   466             throw new IllegalStateException();
       
   467         return JavacTypes.instance(context);
       
   468     }
       
   469 
       
   470     public Iterable<? extends Tree> pathFor(CompilationUnitTree unit, Tree node) {
       
   471         return TreeInfo.pathFor((JCTree) node, (JCTree.JCCompilationUnit) unit).reverse();
       
   472     }
       
   473 
       
   474     abstract class Filter {
       
   475         void run(ListBuffer<Env<AttrContext>> list, Iterable<? extends TypeElement> classes) {
       
   476             Set<TypeElement> set = new HashSet<TypeElement>();
       
   477             for (TypeElement item: classes)
       
   478                 set.add(item);
       
   479 
       
   480             List<Env<AttrContext>> defer = List.<Env<AttrContext>>nil();
       
   481             while (list.nonEmpty()) {
       
   482                 Env<AttrContext> env = list.next();
       
   483                 ClassSymbol csym = env.enclClass.sym;
       
   484                 if (csym != null && set.contains(csym.outermostClass()))
       
   485                     process(env);
       
   486                 else
       
   487                     defer = defer.prepend(env);
       
   488             }
       
   489 
       
   490             for (List<Env<AttrContext>> l = defer; l.nonEmpty(); l = l.tail)
       
   491                 list.prepend(l.head);
       
   492         }
       
   493 
       
   494         abstract void process(Env<AttrContext> env);
       
   495     }
       
   496 
       
   497     /**
       
   498      * For internal use by Sun Microsystems only.  This method will be
       
   499      * removed without warning.
       
   500      */
       
   501     public Context getContext() {
       
   502         return context;
       
   503     }
       
   504 
       
   505     /**
       
   506      * For internal use by Sun Microsystems only.  This method will be
       
   507      * removed without warning.
       
   508      */
       
   509     public void updateContext(Context newContext) {
       
   510         context = newContext;
       
   511     }
       
   512 
       
   513     /**
       
   514      * For internal use by Sun Microsystems only.  This method will be
       
   515      * removed without warning.
       
   516      */
       
   517     public Type parseType(String expr, TypeElement scope) {
       
   518         if (expr == null || expr.equals(""))
       
   519             throw new IllegalArgumentException();
       
   520         compiler = JavaCompiler.instance(context);
       
   521         JavaFileObject prev = compiler.log.useSource(null);
       
   522         Scanner.Factory scannerFactory = Scanner.Factory.instance(context);
       
   523         Parser.Factory parserFactory = Parser.Factory.instance(context);
       
   524         Attr attr = Attr.instance(context);
       
   525         try {
       
   526             Scanner scanner = scannerFactory.newScanner((expr+"\u0000").toCharArray(),
       
   527                                                         expr.length());
       
   528             Parser parser = parserFactory.newParser(scanner, false, false);
       
   529             JCTree tree = parser.type();
       
   530             return attr.attribType(tree, (Symbol.TypeSymbol)scope);
       
   531         } finally {
       
   532             compiler.log.useSource(prev);
       
   533         }
       
   534     }
       
   535 
       
   536 }