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

Tue, 19 Feb 2013 17:53:16 +0000

author
vromero
date
Tue, 19 Feb 2013 17:53:16 +0000
changeset 1591
dc8b7aa7cef3
parent 1455
75ab654b5cd5
child 1603
6118072811e5
permissions
-rw-r--r--

8006212: javac, convert jtreg tests from shell script to java
Reviewed-by: jjg

     1 /*
     2  * Copyright (c) 2005, 2013, 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.main.JavaCompiler;
    48 import com.sun.tools.javac.model.*;
    49 import com.sun.tools.javac.parser.Parser;
    50 import com.sun.tools.javac.parser.ParserFactory;
    51 import com.sun.tools.javac.tree.*;
    52 import com.sun.tools.javac.tree.JCTree.*;
    53 import com.sun.tools.javac.util.*;
    54 import com.sun.tools.javac.util.List;
    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 BasicJavacTask {
    68     private Main compilerMain;
    69     private JavaCompiler compiler;
    70     private Locale locale;
    71     private String[] args;
    72     private String[] classNames;
    73     private List<JavaFileObject> fileObjects;
    74     private Map<JavaFileObject, JCCompilationUnit> notYetEntered;
    75     private ListBuffer<Env<AttrContext>> genList;
    76     private final AtomicBoolean used = new AtomicBoolean();
    77     private Iterable<? extends Processor> processors;
    79     private Main.Result result = null;
    81     JavacTaskImpl(Main compilerMain,
    82                 String[] args,
    83                 String[] classNames,
    84                 Context context,
    85                 List<JavaFileObject> fileObjects) {
    86         super(null, false);
    87         this.compilerMain = compilerMain;
    88         this.args = args;
    89         this.classNames = classNames;
    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     }
    99     JavacTaskImpl(Main compilerMain,
   100                 Iterable<String> args,
   101                 Context context,
   102                 Iterable<String> classes,
   103                 Iterable<? extends JavaFileObject> fileObjects) {
   104         this(compilerMain, toArray(args), toArray(classes), context, toList(fileObjects));
   105     }
   107     static private String[] toArray(Iterable<String> iter) {
   108         ListBuffer<String> result = new ListBuffer<String>();
   109         if (iter != null)
   110             for (String s : iter)
   111                 result.append(s);
   112         return result.toArray(new String[result.length()]);
   113     }
   115     static private List<JavaFileObject> toList(Iterable<? extends JavaFileObject> fileObjects) {
   116         if (fileObjects == null)
   117             return List.nil();
   118         ListBuffer<JavaFileObject> result = new ListBuffer<JavaFileObject>();
   119         for (JavaFileObject fo : fileObjects)
   120             result.append(fo);
   121         return result.toList();
   122     }
   124     public Main.Result doCall() {
   125         if (!used.getAndSet(true)) {
   126             initContext();
   127             notYetEntered = new HashMap<JavaFileObject, JCCompilationUnit>();
   128             compilerMain.setAPIMode(true);
   129             result = compilerMain.compile(args, classNames, context, fileObjects, processors);
   130             cleanup();
   131             return result;
   132         } else {
   133             throw new IllegalStateException("multiple calls to method 'call'");
   134         }
   135     }
   137     public Boolean call() {
   138         return doCall().isOK();
   139     }
   141     public void setProcessors(Iterable<? extends Processor> processors) {
   142         processors.getClass(); // null check
   143         // not mt-safe
   144         if (used.get())
   145             throw new IllegalStateException();
   146         this.processors = processors;
   147     }
   149     public void setLocale(Locale locale) {
   150         if (used.get())
   151             throw new IllegalStateException();
   152         this.locale = locale;
   153     }
   155     private void prepareCompiler() throws IOException {
   156         if (used.getAndSet(true)) {
   157             if (compiler == null)
   158                 throw new IllegalStateException();
   159         } else {
   160             initContext();
   161             compilerMain.setOptions(Options.instance(context));
   162             compilerMain.filenames = new LinkedHashSet<File>();
   163             Collection<File> filenames = compilerMain.processArgs(CommandLine.parse(args), classNames);
   164             if (!filenames.isEmpty())
   165                 throw new IllegalArgumentException("Malformed arguments " + toString(filenames, " "));
   166             compiler = JavaCompiler.instance(context);
   167             compiler.keepComments = true;
   168             compiler.genEndPos = true;
   169             // NOTE: this value will be updated after annotation processing
   170             compiler.initProcessAnnotations(processors);
   171             notYetEntered = new HashMap<JavaFileObject, JCCompilationUnit>();
   172             for (JavaFileObject file: fileObjects)
   173                 notYetEntered.put(file, null);
   174             genList = new ListBuffer<Env<AttrContext>>();
   175             // endContext will be called when all classes have been generated
   176             // TODO: should handle the case after each phase if errors have occurred
   177             args = null;
   178             classNames = null;
   179         }
   180     }
   182     <T> String toString(Iterable<T> items, String sep) {
   183         String currSep = "";
   184         StringBuilder sb = new StringBuilder();
   185         for (T item: items) {
   186             sb.append(currSep);
   187             sb.append(item.toString());
   188             currSep = sep;
   189         }
   190         return sb.toString();
   191     }
   193     private void initContext() {
   194         context.put(JavacTask.class, this);
   195         //initialize compiler's default locale
   196         context.put(Locale.class, locale);
   197     }
   199     void cleanup() {
   200         if (compiler != null)
   201             compiler.close();
   202         compiler = null;
   203         compilerMain = null;
   204         args = null;
   205         classNames = null;
   206         context = null;
   207         fileObjects = null;
   208         notYetEntered = null;
   209     }
   211     /**
   212      * Construct a JavaFileObject from the given file.
   213      *
   214      * <p><b>TODO: this method is useless here</b></p>
   215      *
   216      * @param file a file
   217      * @return a JavaFileObject from the standard file manager.
   218      */
   219     public JavaFileObject asJavaFileObject(File file) {
   220         JavacFileManager fm = (JavacFileManager)context.get(JavaFileManager.class);
   221         return fm.getRegularFile(file);
   222     }
   224     /**
   225      * Parse the specified files returning a list of abstract syntax trees.
   226      *
   227      * @throws java.io.IOException TODO
   228      * @return a list of abstract syntax trees
   229      */
   230     public Iterable<? extends CompilationUnitTree> parse() throws IOException {
   231         try {
   232             prepareCompiler();
   233             List<JCCompilationUnit> units = compiler.parseFiles(fileObjects);
   234             for (JCCompilationUnit unit: units) {
   235                 JavaFileObject file = unit.getSourceFile();
   236                 if (notYetEntered.containsKey(file))
   237                     notYetEntered.put(file, unit);
   238             }
   239             return units;
   240         }
   241         finally {
   242             parsed = true;
   243             if (compiler != null && compiler.log != null)
   244                 compiler.log.flush();
   245         }
   246     }
   248     private boolean parsed = false;
   250     /**
   251      * Translate all the abstract syntax trees to elements.
   252      *
   253      * @throws IOException TODO
   254      * @return a list of elements corresponding to the top level
   255      * classes in the abstract syntax trees
   256      */
   257     public Iterable<? extends TypeElement> enter() throws IOException {
   258         return enter(null);
   259     }
   261     /**
   262      * Translate the given abstract syntax trees to elements.
   263      *
   264      * @param trees a list of abstract syntax trees.
   265      * @throws java.io.IOException TODO
   266      * @return a list of elements corresponding to the top level
   267      * classes in the abstract syntax trees
   268      */
   269     public Iterable<? extends TypeElement> enter(Iterable<? extends CompilationUnitTree> trees)
   270         throws IOException
   271     {
   272         if (trees == null && notYetEntered != null && notYetEntered.isEmpty())
   273             return List.nil();
   275         prepareCompiler();
   277         ListBuffer<JCCompilationUnit> roots = null;
   279         if (trees == null) {
   280             // If there are still files which were specified to be compiled
   281             // (i.e. in fileObjects) but which have not yet been entered,
   282             // then we make sure they have been parsed and add them to the
   283             // list to be entered.
   284             if (notYetEntered.size() > 0) {
   285                 if (!parsed)
   286                     parse(); // TODO would be nice to specify files needed to be parsed
   287                 for (JavaFileObject file: fileObjects) {
   288                     JCCompilationUnit unit = notYetEntered.remove(file);
   289                     if (unit != null) {
   290                         if (roots == null)
   291                             roots = new ListBuffer<JCCompilationUnit>();
   292                         roots.append(unit);
   293                     }
   294                 }
   295                 notYetEntered.clear();
   296             }
   297         }
   298         else {
   299             for (CompilationUnitTree cu : trees) {
   300                 if (cu instanceof JCCompilationUnit) {
   301                     if (roots == null)
   302                         roots = new ListBuffer<JCCompilationUnit>();
   303                     roots.append((JCCompilationUnit)cu);
   304                     notYetEntered.remove(cu.getSourceFile());
   305                 }
   306                 else
   307                     throw new IllegalArgumentException(cu.toString());
   308             }
   309         }
   311         if (roots == null)
   312             return List.nil();
   314         try {
   315             List<JCCompilationUnit> units = compiler.enterTrees(roots.toList());
   317             if (notYetEntered.isEmpty())
   318                 compiler = compiler.processAnnotations(units);
   320             ListBuffer<TypeElement> elements = new ListBuffer<TypeElement>();
   321             for (JCCompilationUnit unit : units) {
   322                 for (JCTree node : unit.defs) {
   323                     if (node.hasTag(JCTree.Tag.CLASSDEF)) {
   324                         JCClassDecl cdef = (JCClassDecl) node;
   325                         if (cdef.sym != null) // maybe null if errors in anno processing
   326                             elements.append(cdef.sym);
   327                     }
   328                 }
   329             }
   330             return elements.toList();
   331         }
   332         finally {
   333             compiler.log.flush();
   334         }
   335     }
   337     /**
   338      * Complete all analysis.
   339      * @throws IOException TODO
   340      */
   341     @Override
   342     public Iterable<? extends Element> analyze() throws IOException {
   343         return analyze(null);
   344     }
   346     /**
   347      * Complete all analysis on the given classes.
   348      * This can be used to ensure that all compile time errors are reported.
   349      * The classes must have previously been returned from {@link #enter}.
   350      * If null is specified, all outstanding classes will be analyzed.
   351      *
   352      * @param classes a list of class elements
   353      */
   354     // This implementation requires that we open up privileges on JavaCompiler.
   355     // An alternative implementation would be to move this code to JavaCompiler and
   356     // wrap it here
   357     public Iterable<? extends Element> analyze(Iterable<? extends TypeElement> classes) throws IOException {
   358         enter(null);  // ensure all classes have been entered
   360         final ListBuffer<Element> results = new ListBuffer<Element>();
   361         try {
   362             if (classes == null) {
   363                 handleFlowResults(compiler.flow(compiler.attribute(compiler.todo)), results);
   364             } else {
   365                 Filter f = new Filter() {
   366                     public void process(Env<AttrContext> env) {
   367                         handleFlowResults(compiler.flow(compiler.attribute(env)), results);
   368                     }
   369                 };
   370                 f.run(compiler.todo, classes);
   371             }
   372         } finally {
   373             compiler.log.flush();
   374         }
   375         return results;
   376     }
   377     // where
   378         private void handleFlowResults(Queue<Env<AttrContext>> queue, ListBuffer<Element> elems) {
   379             for (Env<AttrContext> env: queue) {
   380                 switch (env.tree.getTag()) {
   381                     case CLASSDEF:
   382                         JCClassDecl cdef = (JCClassDecl) env.tree;
   383                         if (cdef.sym != null)
   384                             elems.append(cdef.sym);
   385                         break;
   386                     case TOPLEVEL:
   387                         JCCompilationUnit unit = (JCCompilationUnit) env.tree;
   388                         if (unit.packge != null)
   389                             elems.append(unit.packge);
   390                         break;
   391                 }
   392             }
   393             genList.addAll(queue);
   394         }
   397     /**
   398      * Generate code.
   399      * @throws IOException TODO
   400      */
   401     @Override
   402     public Iterable<? extends JavaFileObject> generate() throws IOException {
   403         return generate(null);
   404     }
   406     /**
   407      * Generate code corresponding to the given classes.
   408      * The classes must have previously been returned from {@link #enter}.
   409      * If there are classes outstanding to be analyzed, that will be done before
   410      * any classes are generated.
   411      * If null is specified, code will be generated for all outstanding classes.
   412      *
   413      * @param classes a list of class elements
   414      */
   415     public Iterable<? extends JavaFileObject> generate(Iterable<? extends TypeElement> classes) throws IOException {
   416         final ListBuffer<JavaFileObject> results = new ListBuffer<JavaFileObject>();
   417         try {
   418             analyze(null);  // ensure all classes have been parsed, entered, and analyzed
   420             if (classes == null) {
   421                 compiler.generate(compiler.desugar(genList), results);
   422                 genList.clear();
   423             }
   424             else {
   425                 Filter f = new Filter() {
   426                         public void process(Env<AttrContext> env) {
   427                             compiler.generate(compiler.desugar(ListBuffer.of(env)), results);
   428                         }
   429                     };
   430                 f.run(genList, classes);
   431             }
   432             if (genList.isEmpty()) {
   433                 compiler.reportDeferredDiagnostics();
   434                 cleanup();
   435             }
   436         }
   437         finally {
   438             if (compiler != null)
   439                 compiler.log.flush();
   440         }
   441         return results;
   442     }
   444     public TypeMirror getTypeMirror(Iterable<? extends Tree> path) {
   445         // TODO: Should complete attribution if necessary
   446         Tree last = null;
   447         for (Tree node : path)
   448             last = node;
   449         return ((JCTree)last).type;
   450     }
   452     public JavacElements getElements() {
   453         if (context == null)
   454             throw new IllegalStateException();
   455         return JavacElements.instance(context);
   456     }
   458     public JavacTypes getTypes() {
   459         if (context == null)
   460             throw new IllegalStateException();
   461         return JavacTypes.instance(context);
   462     }
   464     public Iterable<? extends Tree> pathFor(CompilationUnitTree unit, Tree node) {
   465         return TreeInfo.pathFor((JCTree) node, (JCTree.JCCompilationUnit) unit).reverse();
   466     }
   468     abstract class Filter {
   469         void run(Queue<Env<AttrContext>> list, Iterable<? extends TypeElement> classes) {
   470             Set<TypeElement> set = new HashSet<TypeElement>();
   471             for (TypeElement item: classes)
   472                 set.add(item);
   474             ListBuffer<Env<AttrContext>> defer = ListBuffer.<Env<AttrContext>>lb();
   475             while (list.peek() != null) {
   476                 Env<AttrContext> env = list.remove();
   477                 ClassSymbol csym = env.enclClass.sym;
   478                 if (csym != null && set.contains(csym.outermostClass()))
   479                     process(env);
   480                 else
   481                     defer = defer.append(env);
   482             }
   484             list.addAll(defer);
   485         }
   487         abstract void process(Env<AttrContext> env);
   488     }
   490     /**
   491      * For internal use only.  This method will be
   492      * removed without warning.
   493      */
   494     public Type parseType(String expr, TypeElement scope) {
   495         if (expr == null || expr.equals(""))
   496             throw new IllegalArgumentException();
   497         compiler = JavaCompiler.instance(context);
   498         JavaFileObject prev = compiler.log.useSource(null);
   499         ParserFactory parserFactory = ParserFactory.instance(context);
   500         Attr attr = Attr.instance(context);
   501         try {
   502             CharBuffer buf = CharBuffer.wrap((expr+"\u0000").toCharArray(), 0, expr.length());
   503             Parser parser = parserFactory.newParser(buf, false, false, false);
   504             JCTree tree = parser.parseType();
   505             return attr.attribType(tree, (Symbol.TypeSymbol)scope);
   506         } finally {
   507             compiler.log.useSource(prev);
   508         }
   509     }
   511 }

mercurial