src/share/classes/com/sun/tools/javac/api/JavacTaskImpl.java

Tue, 24 Jan 2012 15:51:44 -0800

author
jjh
date
Tue, 24 Jan 2012 15:51:44 -0800
changeset 1187
ac36176b7de0
parent 1127
ca49d50318dc
child 1210
62e611704863
permissions
-rw-r--r--

7126832: com.sun.tools.javac.api.ClientCodeWrapper$WrappedJavaFileManager cannot be cast
Reviewed-by: jjg

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

mercurial