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

Mon, 27 Sep 2010 14:20:39 -0700

author
jjg
date
Mon, 27 Sep 2010 14:20:39 -0700
changeset 695
3c9b64e55c5d
parent 582
366a7b9b5627
child 930
cb119107aeea
permissions
-rw-r--r--

6877202: Elements.getDocComment() is not getting JavaDocComments
6861094: javac -Xprint <file> does not print comments
6985205: access to tree positions and doc comments may be lost across annotation processing rounds
Reviewed-by: darcy

     1 /*
     2  * Copyright (c) 2005, 2010, 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 JavacTool tool;
    69     private Main compilerMain;
    70     private JavaCompiler compiler;
    71     private Locale locale;
    72     private String[] args;
    73     private Context context;
    74     private List<JavaFileObject> fileObjects;
    75     private Map<JavaFileObject, JCCompilationUnit> notYetEntered;
    76     private ListBuffer<Env<AttrContext>> genList;
    77     private TaskListener taskListener;
    78     private AtomicBoolean used = new AtomicBoolean();
    79     private Iterable<? extends Processor> processors;
    81     private Integer result = null;
    83     JavacTaskImpl(JavacTool tool,
    84                 Main compilerMain,
    85                 String[] args,
    86                 Context context,
    87                 List<JavaFileObject> fileObjects) {
    88         this.tool = tool;
    89         this.compilerMain = compilerMain;
    90         this.args = args;
    91         this.context = context;
    92         this.fileObjects = fileObjects;
    93         setLocale(Locale.getDefault());
    94         // null checks
    95         compilerMain.getClass();
    96         args.getClass();
    97         context.getClass();
    98         fileObjects.getClass();
    99     }
   101     JavacTaskImpl(JavacTool tool,
   102                 Main compilerMain,
   103                 Iterable<String> flags,
   104                 Context context,
   105                 Iterable<String> classes,
   106                 Iterable<? extends JavaFileObject> fileObjects) {
   107         this(tool, compilerMain, toArray(flags, classes), context, toList(fileObjects));
   108     }
   110     static private String[] toArray(Iterable<String> flags, Iterable<String> classes) {
   111         ListBuffer<String> result = new ListBuffer<String>();
   112         if (flags != null)
   113             for (String flag : flags)
   114                 result.append(flag);
   115         if (classes != null)
   116             for (String cls : classes)
   117                 result.append(cls);
   118         return result.toArray(new String[result.length()]);
   119     }
   121     static private List<JavaFileObject> toList(Iterable<? extends JavaFileObject> fileObjects) {
   122         if (fileObjects == null)
   123             return List.nil();
   124         ListBuffer<JavaFileObject> result = new ListBuffer<JavaFileObject>();
   125         for (JavaFileObject fo : fileObjects)
   126             result.append(fo);
   127         return result.toList();
   128     }
   130     public Boolean call() {
   131         if (!used.getAndSet(true)) {
   132             beginContext();
   133             notYetEntered = new HashMap<JavaFileObject, JCCompilationUnit>();
   134             try {
   135                 compilerMain.setFatalErrors(true);
   136                 result = compilerMain.compile(args, context, fileObjects, processors);
   137             } finally {
   138                 endContext();
   139             }
   140             compilerMain = null;
   141             args = null;
   142             context = null;
   143             fileObjects = null;
   144             notYetEntered = null;
   145             return result == 0;
   146         } else {
   147             throw new IllegalStateException("multiple calls to method 'call'");
   148         }
   149     }
   151     public void setProcessors(Iterable<? extends Processor> processors) {
   152         processors.getClass(); // null check
   153         // not mt-safe
   154         if (used.get())
   155             throw new IllegalStateException();
   156         this.processors = processors;
   157     }
   159     public void setLocale(Locale locale) {
   160         if (used.get())
   161             throw new IllegalStateException();
   162         this.locale = locale;
   163     }
   165     private void prepareCompiler() throws IOException {
   166         if (!used.getAndSet(true)) {
   167             beginContext();
   168             compilerMain.setOptions(Options.instance(context));
   169             compilerMain.filenames = new ListBuffer<File>();
   170             List<File> filenames = compilerMain.processArgs(CommandLine.parse(args));
   171             if (!filenames.isEmpty())
   172                 throw new IllegalArgumentException("Malformed arguments " + filenames.toString(" "));
   173             compiler = JavaCompiler.instance(context);
   174             compiler.keepComments = true;
   175             compiler.genEndPos = true;
   176             // NOTE: this value will be updated after annotation processing
   177             compiler.initProcessAnnotations(processors);
   178             notYetEntered = new HashMap<JavaFileObject, JCCompilationUnit>();
   179             for (JavaFileObject file: fileObjects)
   180                 notYetEntered.put(file, null);
   181             genList = new ListBuffer<Env<AttrContext>>();
   182             // endContext will be called when all classes have been generated
   183             // TODO: should handle the case after each phase if errors have occurred
   184             args = null;
   185         }
   186     }
   188     private void beginContext() {
   189         context.put(JavacTaskImpl.class, this);
   190         if (context.get(TaskListener.class) != null)
   191             context.put(TaskListener.class, (TaskListener)null);
   192         if (taskListener != null)
   193             context.put(TaskListener.class, wrap(taskListener));
   194         tool.beginContext(context);
   195         //initialize compiler's default locale
   196         JavacMessages.instance(context).setCurrentLocale(locale);
   197     }
   198     // where
   199     private TaskListener wrap(final TaskListener tl) {
   200         tl.getClass(); // null check
   201         return new TaskListener() {
   202             public void started(TaskEvent e) {
   203                 try {
   204                     tl.started(e);
   205                 } catch (Throwable t) {
   206                     throw new ClientCodeException(t);
   207                 }
   208             }
   210             public void finished(TaskEvent e) {
   211                 try {
   212                     tl.finished(e);
   213                 } catch (Throwable t) {
   214                     throw new ClientCodeException(t);
   215                 }
   216             }
   218         };
   219     }
   221     private void endContext() {
   222         tool.endContext();
   223     }
   225     /**
   226      * Construct a JavaFileObject from the given file.
   227      *
   228      * <p><b>TODO: this method is useless here</b></p>
   229      *
   230      * @param file a file
   231      * @return a JavaFileObject from the standard file manager.
   232      */
   233     public JavaFileObject asJavaFileObject(File file) {
   234         JavacFileManager fm = (JavacFileManager)context.get(JavaFileManager.class);
   235         return fm.getRegularFile(file);
   236     }
   238     public void setTaskListener(TaskListener taskListener) {
   239         this.taskListener = taskListener;
   240     }
   242     /**
   243      * Parse the specified files returning a list of abstract syntax trees.
   244      *
   245      * @throws java.io.IOException TODO
   246      * @return a list of abstract syntax trees
   247      */
   248     public Iterable<? extends CompilationUnitTree> parse() throws IOException {
   249         try {
   250             prepareCompiler();
   251             List<JCCompilationUnit> units = compiler.parseFiles(fileObjects);
   252             for (JCCompilationUnit unit: units) {
   253                 JavaFileObject file = unit.getSourceFile();
   254                 if (notYetEntered.containsKey(file))
   255                     notYetEntered.put(file, unit);
   256             }
   257             return units;
   258         }
   259         finally {
   260             parsed = true;
   261             if (compiler != null && compiler.log != null)
   262                 compiler.log.flush();
   263         }
   264     }
   266     private boolean parsed = false;
   268     /**
   269      * Translate all the abstract syntax trees to elements.
   270      *
   271      * @throws IOException TODO
   272      * @return a list of elements corresponding to the top level
   273      * classes in the abstract syntax trees
   274      */
   275     public Iterable<? extends TypeElement> enter() throws IOException {
   276         return enter(null);
   277     }
   279     /**
   280      * Translate the given abstract syntax trees to elements.
   281      *
   282      * @param trees a list of abstract syntax trees.
   283      * @throws java.io.IOException TODO
   284      * @return a list of elements corresponding to the top level
   285      * classes in the abstract syntax trees
   286      */
   287     public Iterable<? extends TypeElement> enter(Iterable<? extends CompilationUnitTree> trees)
   288         throws IOException
   289     {
   290         prepareCompiler();
   292         ListBuffer<JCCompilationUnit> roots = null;
   294         if (trees == null) {
   295             // If there are still files which were specified to be compiled
   296             // (i.e. in fileObjects) but which have not yet been entered,
   297             // then we make sure they have been parsed and add them to the
   298             // list to be entered.
   299             if (notYetEntered.size() > 0) {
   300                 if (!parsed)
   301                     parse(); // TODO would be nice to specify files needed to be parsed
   302                 for (JavaFileObject file: fileObjects) {
   303                     JCCompilationUnit unit = notYetEntered.remove(file);
   304                     if (unit != null) {
   305                         if (roots == null)
   306                             roots = new ListBuffer<JCCompilationUnit>();
   307                         roots.append(unit);
   308                     }
   309                 }
   310                 notYetEntered.clear();
   311             }
   312         }
   313         else {
   314             for (CompilationUnitTree cu : trees) {
   315                 if (cu instanceof JCCompilationUnit) {
   316                     if (roots == null)
   317                         roots = new ListBuffer<JCCompilationUnit>();
   318                     roots.append((JCCompilationUnit)cu);
   319                     notYetEntered.remove(cu.getSourceFile());
   320                 }
   321                 else
   322                     throw new IllegalArgumentException(cu.toString());
   323             }
   324         }
   326         if (roots == null)
   327             return List.nil();
   329         try {
   330             List<JCCompilationUnit> units = compiler.enterTrees(roots.toList());
   332             if (notYetEntered.isEmpty())
   333                 compiler = compiler.processAnnotations(units);
   335             ListBuffer<TypeElement> elements = new ListBuffer<TypeElement>();
   336             for (JCCompilationUnit unit : units) {
   337                 for (JCTree node : unit.defs) {
   338                     if (node.getTag() == JCTree.CLASSDEF) {
   339                         JCClassDecl cdef = (JCClassDecl) node;
   340                         if (cdef.sym != null) // maybe null if errors in anno processing
   341                             elements.append(cdef.sym);
   342                     }
   343                 }
   344             }
   345             return elements.toList();
   346         }
   347         finally {
   348             compiler.log.flush();
   349         }
   350     }
   352     /**
   353      * Complete all analysis.
   354      * @throws IOException TODO
   355      */
   356     @Override
   357     public Iterable<? extends Element> analyze() throws IOException {
   358         return analyze(null);
   359     }
   361     /**
   362      * Complete all analysis on the given classes.
   363      * This can be used to ensure that all compile time errors are reported.
   364      * The classes must have previously been returned from {@link #enter}.
   365      * If null is specified, all outstanding classes will be analyzed.
   366      *
   367      * @param classes a list of class elements
   368      */
   369     // This implementation requires that we open up privileges on JavaCompiler.
   370     // An alternative implementation would be to move this code to JavaCompiler and
   371     // wrap it here
   372     public Iterable<? extends Element> analyze(Iterable<? extends TypeElement> classes) throws IOException {
   373         enter(null);  // ensure all classes have been entered
   375         final ListBuffer<Element> results = new ListBuffer<Element>();
   376         try {
   377             if (classes == null) {
   378                 handleFlowResults(compiler.flow(compiler.attribute(compiler.todo)), results);
   379             } else {
   380                 Filter f = new Filter() {
   381                     public void process(Env<AttrContext> env) {
   382                         handleFlowResults(compiler.flow(compiler.attribute(env)), results);
   383                     }
   384                 };
   385                 f.run(compiler.todo, classes);
   386             }
   387         } finally {
   388             compiler.log.flush();
   389         }
   390         return results;
   391     }
   392     // where
   393         private void handleFlowResults(Queue<Env<AttrContext>> queue, ListBuffer<Element> elems) {
   394             for (Env<AttrContext> env: queue) {
   395                 switch (env.tree.getTag()) {
   396                     case JCTree.CLASSDEF:
   397                         JCClassDecl cdef = (JCClassDecl) env.tree;
   398                         if (cdef.sym != null)
   399                             elems.append(cdef.sym);
   400                         break;
   401                     case JCTree.TOPLEVEL:
   402                         JCCompilationUnit unit = (JCCompilationUnit) env.tree;
   403                         if (unit.packge != null)
   404                             elems.append(unit.packge);
   405                         break;
   406                 }
   407             }
   408             genList.addAll(queue);
   409         }
   412     /**
   413      * Generate code.
   414      * @throws IOException TODO
   415      */
   416     @Override
   417     public Iterable<? extends JavaFileObject> generate() throws IOException {
   418         return generate(null);
   419     }
   421     /**
   422      * Generate code corresponding to the given classes.
   423      * The classes must have previously been returned from {@link #enter}.
   424      * If there are classes outstanding to be analyzed, that will be done before
   425      * any classes are generated.
   426      * If null is specified, code will be generated for all outstanding classes.
   427      *
   428      * @param classes a list of class elements
   429      */
   430     public Iterable<? extends JavaFileObject> generate(Iterable<? extends TypeElement> classes) throws IOException {
   431         final ListBuffer<JavaFileObject> results = new ListBuffer<JavaFileObject>();
   432         try {
   433             analyze(null);  // ensure all classes have been parsed, entered, and analyzed
   435             if (classes == null) {
   436                 compiler.generate(compiler.desugar(genList), results);
   437                 genList.clear();
   438             }
   439             else {
   440                 Filter f = new Filter() {
   441                         public void process(Env<AttrContext> env) {
   442                             compiler.generate(compiler.desugar(ListBuffer.of(env)), results);
   443                         }
   444                     };
   445                 f.run(genList, classes);
   446             }
   447             if (genList.isEmpty()) {
   448                 compiler.reportDeferredDiagnostics();
   449                 compiler.log.flush();
   450                 endContext();
   451             }
   452         }
   453         finally {
   454             compiler.log.flush();
   455         }
   456         return results;
   457     }
   459     public TypeMirror getTypeMirror(Iterable<? extends Tree> path) {
   460         // TODO: Should complete attribution if necessary
   461         Tree last = null;
   462         for (Tree node : path)
   463             last = node;
   464         return ((JCTree)last).type;
   465     }
   467     public JavacElements getElements() {
   468         if (context == null)
   469             throw new IllegalStateException();
   470         return JavacElements.instance(context);
   471     }
   473     public JavacTypes getTypes() {
   474         if (context == null)
   475             throw new IllegalStateException();
   476         return JavacTypes.instance(context);
   477     }
   479     public Iterable<? extends Tree> pathFor(CompilationUnitTree unit, Tree node) {
   480         return TreeInfo.pathFor((JCTree) node, (JCTree.JCCompilationUnit) unit).reverse();
   481     }
   483     abstract class Filter {
   484         void run(Queue<Env<AttrContext>> list, Iterable<? extends TypeElement> classes) {
   485             Set<TypeElement> set = new HashSet<TypeElement>();
   486             for (TypeElement item: classes)
   487                 set.add(item);
   489             ListBuffer<Env<AttrContext>> defer = ListBuffer.<Env<AttrContext>>lb();
   490             while (list.peek() != null) {
   491                 Env<AttrContext> env = list.remove();
   492                 ClassSymbol csym = env.enclClass.sym;
   493                 if (csym != null && set.contains(csym.outermostClass()))
   494                     process(env);
   495                 else
   496                     defer = defer.append(env);
   497             }
   499             list.addAll(defer);
   500         }
   502         abstract void process(Env<AttrContext> env);
   503     }
   505     /**
   506      * For internal use only.  This method will be
   507      * removed without warning.
   508      */
   509     public Context getContext() {
   510         return context;
   511     }
   513     /**
   514      * For internal use only.  This method will be
   515      * removed without warning.
   516      */
   517     public void updateContext(Context newContext) {
   518         context = newContext;
   519     }
   521     /**
   522      * For internal use only.  This method will be
   523      * removed without warning.
   524      */
   525     public Type parseType(String expr, TypeElement scope) {
   526         if (expr == null || expr.equals(""))
   527             throw new IllegalArgumentException();
   528         compiler = JavaCompiler.instance(context);
   529         JavaFileObject prev = compiler.log.useSource(null);
   530         ParserFactory parserFactory = ParserFactory.instance(context);
   531         Attr attr = Attr.instance(context);
   532         try {
   533             CharBuffer buf = CharBuffer.wrap((expr+"\u0000").toCharArray(), 0, expr.length());
   534             Parser parser = parserFactory.newParser(buf, false, false, false);
   535             JCTree tree = parser.parseType();
   536             return attr.attribType(tree, (Symbol.TypeSymbol)scope);
   537         } finally {
   538             compiler.log.useSource(prev);
   539         }
   540     }
   542 }

mercurial