Home » openjdk-7 » com.sun.tools » javac » api » [javadoc | source]

    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    */
   25   
   26   package com.sun.tools.javac.api;
   27   
   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;
   33   
   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;
   39   
   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;
   55   
   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 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;
   80   
   81       private Integer result = null;
   82   
   83       JavacTaskImpl(Main compilerMain,
   84                   String[] args,
   85                   Context context,
   86                   List<JavaFileObject> fileObjects) {
   87           this.ccw = ClientCodeWrapper.instance(context);
   88           this.compilerMain = compilerMain;
   89           this.args = args;
   90           this.context = context;
   91           this.fileObjects = fileObjects;
   92           setLocale(Locale.getDefault());
   93           // null checks
   94           compilerMain.getClass();
   95           args.getClass();
   96           fileObjects.getClass();
   97       }
   98   
   99       JavacTaskImpl(Main compilerMain,
  100                   Iterable<String> flags,
  101                   Context context,
  102                   Iterable<String> classes,
  103                   Iterable<? extends JavaFileObject> fileObjects) {
  104           this(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               initContext();
  130               notYetEntered = new HashMap<JavaFileObject, JCCompilationUnit>();
  131               compilerMain.setAPIMode(true);
  132               result = compilerMain.compile(args, context, fileObjects, processors);
  133               cleanup();
  134               return result == 0;
  135           } else {
  136               throw new IllegalStateException("multiple calls to method 'call'");
  137           }
  138       }
  139   
  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       }
  147   
  148       public void setLocale(Locale locale) {
  149           if (used.get())
  150               throw new IllegalStateException();
  151           this.locale = locale;
  152       }
  153   
  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 ListBuffer<File>();
  162               List<File> filenames = compilerMain.processArgs(CommandLine.parse(args));
  163               if (!filenames.isEmpty())
  164                   throw new IllegalArgumentException("Malformed arguments " + filenames.toString(" "));
  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           }
  178       }
  179   
  180       private void initContext() {
  181           context.put(JavacTaskImpl.class, this);
  182           if (context.get(TaskListener.class) != null)
  183               context.put(TaskListener.class, (TaskListener)null);
  184           if (taskListener != null)
  185               context.put(TaskListener.class, ccw.wrap(taskListener));
  186           //initialize compiler's default locale
  187           context.put(Locale.class, locale);
  188       }
  189   
  190       void cleanup() {
  191           if (compiler != null)
  192               compiler.close();
  193           compiler = null;
  194           compilerMain = null;
  195           args = null;
  196           context = null;
  197           fileObjects = null;
  198           notYetEntered = null;
  199       }
  200   
  201       /**
  202        * Construct a JavaFileObject from the given file.
  203        *
  204        * <p><b>TODO: this method is useless here</b></p>
  205        *
  206        * @param file a file
  207        * @return a JavaFileObject from the standard file manager.
  208        */
  209       public JavaFileObject asJavaFileObject(File file) {
  210           JavacFileManager fm = (JavacFileManager)context.get(JavaFileManager.class);
  211           return fm.getRegularFile(file);
  212       }
  213   
  214       public void setTaskListener(TaskListener taskListener) {
  215           this.taskListener = taskListener;
  216       }
  217   
  218       /**
  219        * Parse the specified files returning a list of abstract syntax trees.
  220        *
  221        * @throws java.io.IOException TODO
  222        * @return a list of abstract syntax trees
  223        */
  224       public Iterable<? extends CompilationUnitTree> parse() throws IOException {
  225           try {
  226               prepareCompiler();
  227               List<JCCompilationUnit> units = compiler.parseFiles(fileObjects);
  228               for (JCCompilationUnit unit: units) {
  229                   JavaFileObject file = unit.getSourceFile();
  230                   if (notYetEntered.containsKey(file))
  231                       notYetEntered.put(file, unit);
  232               }
  233               return units;
  234           }
  235           finally {
  236               parsed = true;
  237               if (compiler != null && compiler.log != null)
  238                   compiler.log.flush();
  239           }
  240       }
  241   
  242       private boolean parsed = false;
  243   
  244       /**
  245        * Translate all the abstract syntax trees to elements.
  246        *
  247        * @throws IOException TODO
  248        * @return a list of elements corresponding to the top level
  249        * classes in the abstract syntax trees
  250        */
  251       public Iterable<? extends TypeElement> enter() throws IOException {
  252           return enter(null);
  253       }
  254   
  255       /**
  256        * Translate the given abstract syntax trees to elements.
  257        *
  258        * @param trees a list of abstract syntax trees.
  259        * @throws java.io.IOException TODO
  260        * @return a list of elements corresponding to the top level
  261        * classes in the abstract syntax trees
  262        */
  263       public Iterable<? extends TypeElement> enter(Iterable<? extends CompilationUnitTree> trees)
  264           throws IOException
  265       {
  266           prepareCompiler();
  267   
  268           ListBuffer<JCCompilationUnit> roots = null;
  269   
  270           if (trees == null) {
  271               // If there are still files which were specified to be compiled
  272               // (i.e. in fileObjects) but which have not yet been entered,
  273               // then we make sure they have been parsed and add them to the
  274               // list to be entered.
  275               if (notYetEntered.size() > 0) {
  276                   if (!parsed)
  277                       parse(); // TODO would be nice to specify files needed to be parsed
  278                   for (JavaFileObject file: fileObjects) {
  279                       JCCompilationUnit unit = notYetEntered.remove(file);
  280                       if (unit != null) {
  281                           if (roots == null)
  282                               roots = new ListBuffer<JCCompilationUnit>();
  283                           roots.append(unit);
  284                       }
  285                   }
  286                   notYetEntered.clear();
  287               }
  288           }
  289           else {
  290               for (CompilationUnitTree cu : trees) {
  291                   if (cu instanceof JCCompilationUnit) {
  292                       if (roots == null)
  293                           roots = new ListBuffer<JCCompilationUnit>();
  294                       roots.append((JCCompilationUnit)cu);
  295                       notYetEntered.remove(cu.getSourceFile());
  296                   }
  297                   else
  298                       throw new IllegalArgumentException(cu.toString());
  299               }
  300           }
  301   
  302           if (roots == null)
  303               return List.nil();
  304   
  305           try {
  306               List<JCCompilationUnit> units = compiler.enterTrees(roots.toList());
  307   
  308               if (notYetEntered.isEmpty())
  309                   compiler = compiler.processAnnotations(units);
  310   
  311               ListBuffer<TypeElement> elements = new ListBuffer<TypeElement>();
  312               for (JCCompilationUnit unit : units) {
  313                   for (JCTree node : unit.defs) {
  314                       if (node.getTag() == JCTree.CLASSDEF) {
  315                           JCClassDecl cdef = (JCClassDecl) node;
  316                           if (cdef.sym != null) // maybe null if errors in anno processing
  317                               elements.append(cdef.sym);
  318                       }
  319                   }
  320               }
  321               return elements.toList();
  322           }
  323           finally {
  324               compiler.log.flush();
  325           }
  326       }
  327   
  328       /**
  329        * Complete all analysis.
  330        * @throws IOException TODO
  331        */
  332       @Override
  333       public Iterable<? extends Element> analyze() throws IOException {
  334           return analyze(null);
  335       }
  336   
  337       /**
  338        * Complete all analysis on the given classes.
  339        * This can be used to ensure that all compile time errors are reported.
  340        * The classes must have previously been returned from {@link #enter}.
  341        * If null is specified, all outstanding classes will be analyzed.
  342        *
  343        * @param classes a list of class elements
  344        */
  345       // This implementation requires that we open up privileges on JavaCompiler.
  346       // An alternative implementation would be to move this code to JavaCompiler and
  347       // wrap it here
  348       public Iterable<? extends Element> analyze(Iterable<? extends TypeElement> classes) throws IOException {
  349           enter(null);  // ensure all classes have been entered
  350   
  351           final ListBuffer<Element> results = new ListBuffer<Element>();
  352           try {
  353               if (classes == null) {
  354                   handleFlowResults(compiler.flow(compiler.attribute(compiler.todo)), results);
  355               } else {
  356                   Filter f = new Filter() {
  357                       public void process(Env<AttrContext> env) {
  358                           handleFlowResults(compiler.flow(compiler.attribute(env)), results);
  359                       }
  360                   };
  361                   f.run(compiler.todo, classes);
  362               }
  363           } finally {
  364               compiler.log.flush();
  365           }
  366           return results;
  367       }
  368       // where
  369           private void handleFlowResults(Queue<Env<AttrContext>> queue, ListBuffer<Element> elems) {
  370               for (Env<AttrContext> env: queue) {
  371                   switch (env.tree.getTag()) {
  372                       case JCTree.CLASSDEF:
  373                           JCClassDecl cdef = (JCClassDecl) env.tree;
  374                           if (cdef.sym != null)
  375                               elems.append(cdef.sym);
  376                           break;
  377                       case JCTree.TOPLEVEL:
  378                           JCCompilationUnit unit = (JCCompilationUnit) env.tree;
  379                           if (unit.packge != null)
  380                               elems.append(unit.packge);
  381                           break;
  382                   }
  383               }
  384               genList.addAll(queue);
  385           }
  386   
  387   
  388       /**
  389        * Generate code.
  390        * @throws IOException TODO
  391        */
  392       @Override
  393       public Iterable<? extends JavaFileObject> generate() throws IOException {
  394           return generate(null);
  395       }
  396   
  397       /**
  398        * Generate code corresponding to the given classes.
  399        * The classes must have previously been returned from {@link #enter}.
  400        * If there are classes outstanding to be analyzed, that will be done before
  401        * any classes are generated.
  402        * If null is specified, code will be generated for all outstanding classes.
  403        *
  404        * @param classes a list of class elements
  405        */
  406       public Iterable<? extends JavaFileObject> generate(Iterable<? extends TypeElement> classes) throws IOException {
  407           final ListBuffer<JavaFileObject> results = new ListBuffer<JavaFileObject>();
  408           try {
  409               analyze(null);  // ensure all classes have been parsed, entered, and analyzed
  410   
  411               if (classes == null) {
  412                   compiler.generate(compiler.desugar(genList), results);
  413                   genList.clear();
  414               }
  415               else {
  416                   Filter f = new Filter() {
  417                           public void process(Env<AttrContext> env) {
  418                               compiler.generate(compiler.desugar(ListBuffer.of(env)), results);
  419                           }
  420                       };
  421                   f.run(genList, classes);
  422               }
  423               if (genList.isEmpty()) {
  424                   compiler.reportDeferredDiagnostics();
  425                   cleanup();
  426               }
  427           }
  428           finally {
  429               if (compiler != null)
  430                   compiler.log.flush();
  431           }
  432           return results;
  433       }
  434   
  435       public TypeMirror getTypeMirror(Iterable<? extends Tree> path) {
  436           // TODO: Should complete attribution if necessary
  437           Tree last = null;
  438           for (Tree node : path)
  439               last = node;
  440           return ((JCTree)last).type;
  441       }
  442   
  443       public JavacElements getElements() {
  444           if (context == null)
  445               throw new IllegalStateException();
  446           return JavacElements.instance(context);
  447       }
  448   
  449       public JavacTypes getTypes() {
  450           if (context == null)
  451               throw new IllegalStateException();
  452           return JavacTypes.instance(context);
  453       }
  454   
  455       public Iterable<? extends Tree> pathFor(CompilationUnitTree unit, Tree node) {
  456           return TreeInfo.pathFor((JCTree) node, (JCTree.JCCompilationUnit) unit).reverse();
  457       }
  458   
  459       abstract class Filter {
  460           void run(Queue<Env<AttrContext>> list, Iterable<? extends TypeElement> classes) {
  461               Set<TypeElement> set = new HashSet<TypeElement>();
  462               for (TypeElement item: classes)
  463                   set.add(item);
  464   
  465               ListBuffer<Env<AttrContext>> defer = ListBuffer.<Env<AttrContext>>lb();
  466               while (list.peek() != null) {
  467                   Env<AttrContext> env = list.remove();
  468                   ClassSymbol csym = env.enclClass.sym;
  469                   if (csym != null && set.contains(csym.outermostClass()))
  470                       process(env);
  471                   else
  472                       defer = defer.append(env);
  473               }
  474   
  475               list.addAll(defer);
  476           }
  477   
  478           abstract void process(Env<AttrContext> env);
  479       }
  480   
  481       /**
  482        * For internal use only.  This method will be
  483        * removed without warning.
  484        */
  485       public Context getContext() {
  486           return context;
  487       }
  488   
  489       /**
  490        * For internal use only.  This method will be
  491        * removed without warning.
  492        */
  493       public void updateContext(Context newContext) {
  494           context = newContext;
  495       }
  496   
  497       /**
  498        * For internal use only.  This method will be
  499        * removed without warning.
  500        */
  501       public Type parseType(String expr, TypeElement scope) {
  502           if (expr == null || expr.equals(""))
  503               throw new IllegalArgumentException();
  504           compiler = JavaCompiler.instance(context);
  505           JavaFileObject prev = compiler.log.useSource(null);
  506           ParserFactory parserFactory = ParserFactory.instance(context);
  507           Attr attr = Attr.instance(context);
  508           try {
  509               CharBuffer buf = CharBuffer.wrap((expr+"\u0000").toCharArray(), 0, expr.length());
  510               Parser parser = parserFactory.newParser(buf, false, false, false);
  511               JCTree tree = parser.parseType();
  512               return attr.attribType(tree, (Symbol.TypeSymbol)scope);
  513           } finally {
  514               compiler.log.useSource(prev);
  515           }
  516       }
  517   
  518   }

Home » openjdk-7 » com.sun.tools » javac » api » [javadoc | source]