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

Fri, 26 Jun 2009 18:51:39 -0700

author
jjg
date
Fri, 26 Jun 2009 18:51:39 -0700
changeset 308
03944ee4fac4
parent 136
8eafba4f61be
child 554
9d9f26857129
permissions
-rw-r--r--

6843077: JSR 308: Annotations on types
Reviewed-by: jjg, mcimadamore, darcy
Contributed-by: mernst@cs.washington.edu, mali@csail.mit.edu, mpapi@csail.mit.edu

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

mercurial