1 /*
   2  * Copyright 2004-2009 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  */
  25 
  26 package com.sun.tools.apt.main;
  27 
  28 import java.io.*;
  29 import java.util.Map;
  30 
  31 import javax.tools.JavaFileManager;
  32 import javax.tools.JavaFileObject;
  33 
  34 import com.sun.tools.javac.file.JavacFileManager;
  35 import com.sun.tools.javac.util.*;
  36 import com.sun.tools.javac.code.*;
  37 import com.sun.tools.javac.jvm.*;
  38 
  39 import com.sun.tools.javac.code.Symbol.*;
  40 import com.sun.tools.javac.tree.JCTree.*;
  41 
  42 import com.sun.tools.apt.comp.*;
  43 import com.sun.tools.apt.util.Bark;
  44 import com.sun.mirror.apt.AnnotationProcessorFactory;
  45 import com.sun.tools.javac.parser.DocCommentScanner;
  46 
  47 /**
  48  *  <p><b>This is NOT part of any API supported by Sun Microsystems.
  49  *  If you write code that depends on this, you do so at your own
  50  *  risk.  This code and its internal interfaces are subject to change
  51  *  or deletion without notice.</b>
  52  */
  53 @SuppressWarnings("deprecation")
  54 public class JavaCompiler extends com.sun.tools.javac.main.JavaCompiler {
  55     /** The context key for the compiler. */
  56     protected static final Context.Key<JavaCompiler> compilerKey =
  57         new Context.Key<JavaCompiler>();
  58 
  59     /** Get the JavaCompiler instance for this context. */
  60     public static JavaCompiler instance(Context context) {
  61         JavaCompiler instance = context.get(compilerKey);
  62         if (instance == null)
  63             instance = new JavaCompiler(context);
  64         return instance;
  65     }
  66 
  67 
  68     java.util.Set<String> genSourceFileNames;
  69     java.util.Set<String> genClassFileNames;
  70 
  71     public java.util.Set<String> getSourceFileNames() {
  72         return genSourceFileNames;
  73     }
  74 
  75     /** List of names of generated class files.
  76      */
  77     public java.util.Set<String> getClassFileNames() {
  78         return genClassFileNames;
  79     }
  80 
  81     java.util.Set<java.io.File> aggregateGenFiles = java.util.Collections.emptySet();
  82 
  83     public java.util.Set<java.io.File> getAggregateGenFiles() {
  84         return aggregateGenFiles;
  85     }
  86 
  87     /** The bark to be used for error reporting.
  88      */
  89     Bark bark;
  90 
  91     /** The log to be used for error reporting.
  92      */
  93     Log log;
  94 
  95     /** The annotation framework
  96      */
  97     Apt apt;
  98 
  99     private static Context preRegister(Context context) {
 100         Bark.preRegister(context);
 101 
 102         // force the use of the scanner that captures Javadoc comments
 103         DocCommentScanner.Factory.preRegister(context);
 104 
 105         if (context.get(JavaFileManager.class) == null)
 106             JavacFileManager.preRegister(context);
 107 
 108         return context;
 109     }
 110 
 111     /** Construct a new compiler from a shared context.
 112      */
 113     public JavaCompiler(Context context) {
 114         super(preRegister(context));
 115 
 116         context.put(compilerKey, this);
 117         apt = Apt.instance(context);
 118 
 119         ClassReader classReader = ClassReader.instance(context);
 120         classReader.preferSource = true;
 121 
 122         // TEMPORARY NOTE: bark==log, but while refactoring, we maintain their
 123         // original identities, to remember the original intent.
 124         log = Log.instance(context);
 125         bark = Bark.instance(context);
 126 
 127         Options options = Options.instance(context);
 128         classOutput   = options.get("-retrofit")      == null;
 129         nocompile     = options.get("-nocompile")     != null;
 130         print         = options.get("-print")         != null;
 131         classesAsDecls= options.get("-XclassesAsDecls") != null;
 132 
 133         genSourceFileNames = new java.util.LinkedHashSet<String>();
 134         genClassFileNames  = new java.util.LinkedHashSet<String>();
 135 
 136         // this forces a copy of the line map to be kept in the tree,
 137         // for use by com.sun.mirror.util.SourcePosition.
 138         lineDebugInfo = true;
 139     }
 140 
 141     /* Switches:
 142      */
 143 
 144     /** Emit class files. This switch is always set, except for the first
 145      *  phase of retrofitting, where signatures are parsed.
 146      */
 147     public boolean classOutput;
 148 
 149     /** The internal printing annotation processor should be used.
 150      */
 151     public boolean print;
 152 
 153     /** Compilation should not be done after annotation processing.
 154      */
 155     public boolean nocompile;
 156 
 157     /** Are class files being treated as declarations
 158      */
 159     public boolean classesAsDecls;
 160 
 161     /** Try to open input stream with given name.
 162      *  Report an error if this fails.
 163      *  @param filename   The file name of the input stream to be opened.
 164      */
 165     // PROVIDED FOR EXTREME BACKWARDS COMPATIBILITY
 166     // There are some very obscure errors that can arise while translating
 167     // the contents of a file from bytes to characters. In Tiger, these
 168     // diagnostics were ignored. This method provides compatibility with
 169     // that behavior. It would be better to honor those diagnostics, in which
 170     // case, this method can be deleted.
 171     @Override
 172     public CharSequence readSource(JavaFileObject filename) {
 173         try {
 174             inputFiles.add(filename);
 175             boolean prev = bark.setDiagnosticsIgnored(true);
 176             try {
 177                 return filename.getCharContent(false);
 178             }
 179             finally {
 180                 bark.setDiagnosticsIgnored(prev);
 181             }
 182         } catch (IOException e) {
 183             bark.error(Position.NOPOS, "cant.read.file", filename);
 184             return null;
 185         }
 186     }
 187 
 188     /** Parse contents of input stream.
 189      *  @param filename     The name of the file from which input stream comes.
 190      *  @param input        The input stream to be parsed.
 191      */
 192     // PROVIDED FOR BACKWARDS COMPATIBILITY
 193     // In Tiger, diagnostics from the scanner and parser were ignored.
 194     // This method provides compatibility with that behavior.
 195     // It would be better to honor those diagnostics, in which
 196     // case, this method can be deleted.
 197     @Override
 198     protected JCCompilationUnit parse(JavaFileObject filename, CharSequence content) {
 199         boolean prev = bark.setDiagnosticsIgnored(true);
 200         try {
 201             return super.parse(filename, content);
 202         }
 203         finally {
 204             bark.setDiagnosticsIgnored(prev);
 205         }
 206     }
 207 
 208     @Override
 209     protected boolean keepComments() {
 210         return true;  // make doc comments available to mirror API impl.
 211     }
 212 
 213     /** Track when the JavaCompiler has been used to compile something. */
 214     private boolean hasBeenUsed = false;
 215 
 216     /** Main method: compile a list of files, return all compiled classes
 217      *  @param filenames     The names of all files to be compiled.
 218      */
 219     public List<ClassSymbol> compile(List<String> filenames,
 220                                      Map<String, String> origOptions,
 221                                      ClassLoader aptCL,
 222                                      AnnotationProcessorFactory providedFactory,
 223                                      java.util.Set<Class<? extends AnnotationProcessorFactory> > productiveFactories,
 224                                      java.util.Set<java.io.File> aggregateGenFiles)
 225         throws Throwable {
 226         // as a JavaCompiler can only be used once, throw an exception if
 227         // it has been used before.
 228         assert !hasBeenUsed : "attempt to reuse JavaCompiler";
 229         hasBeenUsed = true;
 230 
 231         this.aggregateGenFiles = aggregateGenFiles;
 232 
 233         long msec = System.currentTimeMillis();
 234 
 235         ListBuffer<ClassSymbol> classes = new ListBuffer<ClassSymbol>();
 236         try {
 237             JavacFileManager fm = (JavacFileManager)fileManager;
 238             //parse all files
 239             ListBuffer<JCCompilationUnit> trees = new ListBuffer<JCCompilationUnit>();
 240             for (List<String> l = filenames; l.nonEmpty(); l = l.tail) {
 241                 if (classesAsDecls) {
 242                     if (! l.head.endsWith(".java") ) { // process as class file
 243                         ClassSymbol cs = reader.enterClass(names.fromString(l.head));
 244                         try {
 245                             cs.complete();
 246                         } catch(Symbol.CompletionFailure cf) {
 247                             bark.aptError("CantFindClass", l);
 248                             continue;
 249                         }
 250 
 251                         classes.append(cs); // add to list of classes
 252                         continue;
 253                     }
 254                 }
 255                 JavaFileObject fo = fm.getJavaFileObjectsFromStrings(List.of(l.head)).iterator().next();
 256                 trees.append(parse(fo));
 257             }
 258 
 259             //enter symbols for all files
 260             List<JCCompilationUnit> roots = trees.toList();
 261 
 262             if (errorCount() == 0) {
 263                 boolean prev = bark.setDiagnosticsIgnored(true);
 264                 try {
 265                     enter.main(roots);
 266                 }
 267                 finally {
 268                     bark.setDiagnosticsIgnored(prev);
 269                 }
 270             }
 271 
 272             if (errorCount() == 0) {
 273                 apt.main(roots,
 274                          classes,
 275                          origOptions, aptCL,
 276                          providedFactory,
 277                          productiveFactories);
 278                 genSourceFileNames.addAll(apt.getSourceFileNames());
 279                 genClassFileNames.addAll(apt.getClassFileNames());
 280             }
 281 
 282         } catch (Abort ex) {
 283         }
 284 
 285         if (verbose)
 286             printVerbose("total", Long.toString(System.currentTimeMillis() - msec));
 287 
 288         chk.reportDeferredDiagnostics();
 289 
 290         printCount("error", errorCount());
 291         printCount("warn", warningCount());
 292 
 293         return classes.toList();
 294     }
 295 }