001 /* 002 * Copyright 2004-2008 Sun Microsystems, Inc. All Rights Reserved. 003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 004 * 005 * This code is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU General Public License version 2 only, as 007 * published by the Free Software Foundation. Sun designates this 008 * particular file as subject to the "Classpath" exception as provided 009 * by Sun in the LICENSE file that accompanied this code. 010 * 011 * This code is distributed in the hope that it will be useful, but WITHOUT 012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 014 * version 2 for more details (a copy is included in the LICENSE file that 015 * accompanied this code). 016 * 017 * You should have received a copy of the GNU General Public License version 018 * 2 along with this work; if not, write to the Free Software Foundation, 019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 020 * 021 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, 022 * CA 95054 USA or visit www.sun.com if you need additional information or 023 * have any questions. 024 */ 025 026 package com.sun.tools.apt.main; 027 028 import java.io.*; 029 import java.util.Map; 030 031 import javax.tools.JavaFileManager; 032 import javax.tools.JavaFileObject; 033 034 import com.sun.tools.javac.file.JavacFileManager; 035 import com.sun.tools.javac.util.*; 036 import com.sun.tools.javac.code.*; 037 import com.sun.tools.javac.jvm.*; 038 039 import com.sun.tools.javac.code.Symbol.*; 040 import com.sun.tools.javac.tree.JCTree.*; 041 042 import com.sun.tools.apt.comp.*; 043 import com.sun.tools.apt.util.Bark; 044 import com.sun.mirror.apt.AnnotationProcessorFactory; 045 import com.sun.tools.javac.parser.DocCommentScanner; 046 047 /** 048 * <p><b>This is NOT part of any API supported by Sun Microsystems. 049 * If you write code that depends on this, you do so at your own 050 * risk. This code and its internal interfaces are subject to change 051 * or deletion without notice.</b> 052 */ 053 public class JavaCompiler extends com.sun.tools.javac.main.JavaCompiler { 054 /** The context key for the compiler. */ 055 protected static final Context.Key<JavaCompiler> compilerKey = 056 new Context.Key<JavaCompiler>(); 057 058 /** Get the JavaCompiler instance for this context. */ 059 public static JavaCompiler instance(Context context) { 060 JavaCompiler instance = context.get(compilerKey); 061 if (instance == null) 062 instance = new JavaCompiler(context); 063 return instance; 064 } 065 066 067 java.util.Set<String> genSourceFileNames; 068 java.util.Set<String> genClassFileNames; 069 070 public java.util.Set<String> getSourceFileNames() { 071 return genSourceFileNames; 072 } 073 074 /** List of names of generated class files. 075 */ 076 public java.util.Set<String> getClassFileNames() { 077 return genClassFileNames; 078 } 079 080 java.util.Set<java.io.File> aggregateGenFiles = java.util.Collections.emptySet(); 081 082 public java.util.Set<java.io.File> getAggregateGenFiles() { 083 return aggregateGenFiles; 084 } 085 086 /** The bark to be used for error reporting. 087 */ 088 Bark bark; 089 090 /** The log to be used for error reporting. 091 */ 092 Log log; 093 094 /** The annotation framework 095 */ 096 Apt apt; 097 098 private static Context preRegister(Context context) { 099 Bark.preRegister(context); 100 101 // force the use of the scanner that captures Javadoc comments 102 DocCommentScanner.Factory.preRegister(context); 103 104 if (context.get(JavaFileManager.class) == null) 105 JavacFileManager.preRegister(context); 106 107 return context; 108 } 109 110 /** Construct a new compiler from a shared context. 111 */ 112 public JavaCompiler(Context context) { 113 super(preRegister(context)); 114 115 context.put(compilerKey, this); 116 apt = Apt.instance(context); 117 118 ClassReader classReader = ClassReader.instance(context); 119 classReader.preferSource = true; 120 121 // TEMPORARY NOTE: bark==log, but while refactoring, we maintain their 122 // original identities, to remember the original intent. 123 log = Log.instance(context); 124 bark = Bark.instance(context); 125 126 Options options = Options.instance(context); 127 classOutput = options.get("-retrofit") == null; 128 nocompile = options.get("-nocompile") != null; 129 print = options.get("-print") != null; 130 classesAsDecls= options.get("-XclassesAsDecls") != null; 131 132 genSourceFileNames = new java.util.LinkedHashSet<String>(); 133 genClassFileNames = new java.util.LinkedHashSet<String>(); 134 135 // this forces a copy of the line map to be kept in the tree, 136 // for use by com.sun.mirror.util.SourcePosition. 137 lineDebugInfo = true; 138 } 139 140 /* Switches: 141 */ 142 143 /** Emit class files. This switch is always set, except for the first 144 * phase of retrofitting, where signatures are parsed. 145 */ 146 public boolean classOutput; 147 148 /** The internal printing annotation processor should be used. 149 */ 150 public boolean print; 151 152 /** Compilation should not be done after annotation processing. 153 */ 154 public boolean nocompile; 155 156 /** Are class files being treated as declarations 157 */ 158 public boolean classesAsDecls; 159 160 /** Try to open input stream with given name. 161 * Report an error if this fails. 162 * @param filename The file name of the input stream to be opened. 163 */ 164 // PROVIDED FOR EXTREME BACKWARDS COMPATIBILITY 165 // There are some very obscure errors that can arise while translating 166 // the contents of a file from bytes to characters. In Tiger, these 167 // diagnostics were ignored. This method provides compatibility with 168 // that behavior. It would be better to honor those diagnostics, in which 169 // case, this method can be deleted. 170 @Override 171 public CharSequence readSource(JavaFileObject filename) { 172 try { 173 inputFiles.add(filename); 174 boolean prev = bark.setDiagnosticsIgnored(true); 175 try { 176 return filename.getCharContent(false); 177 } 178 finally { 179 bark.setDiagnosticsIgnored(prev); 180 } 181 } catch (IOException e) { 182 bark.error(Position.NOPOS, "cant.read.file", filename); 183 return null; 184 } 185 } 186 187 /** Parse contents of input stream. 188 * @param filename The name of the file from which input stream comes. 189 * @param input The input stream to be parsed. 190 */ 191 // PROVIDED FOR BACKWARDS COMPATIBILITY 192 // In Tiger, diagnostics from the scanner and parser were ignored. 193 // This method provides compatibility with that behavior. 194 // It would be better to honor those diagnostics, in which 195 // case, this method can be deleted. 196 @Override 197 protected JCCompilationUnit parse(JavaFileObject filename, CharSequence content) { 198 boolean prev = bark.setDiagnosticsIgnored(true); 199 try { 200 return super.parse(filename, content); 201 } 202 finally { 203 bark.setDiagnosticsIgnored(prev); 204 } 205 } 206 207 @Override 208 protected boolean keepComments() { 209 return true; // make doc comments available to mirror API impl. 210 } 211 212 /** Track when the JavaCompiler has been used to compile something. */ 213 private boolean hasBeenUsed = false; 214 215 /** Main method: compile a list of files, return all compiled classes 216 * @param filenames The names of all files to be compiled. 217 */ 218 public List<ClassSymbol> compile(List<String> filenames, 219 Map<String, String> origOptions, 220 ClassLoader aptCL, 221 AnnotationProcessorFactory providedFactory, 222 java.util.Set<Class<? extends AnnotationProcessorFactory> > productiveFactories, 223 java.util.Set<java.io.File> aggregateGenFiles) 224 throws Throwable { 225 // as a JavaCompiler can only be used once, throw an exception if 226 // it has been used before. 227 assert !hasBeenUsed : "attempt to reuse JavaCompiler"; 228 hasBeenUsed = true; 229 230 this.aggregateGenFiles = aggregateGenFiles; 231 232 long msec = System.currentTimeMillis(); 233 234 ListBuffer<ClassSymbol> classes = new ListBuffer<ClassSymbol>(); 235 try { 236 JavacFileManager fm = (JavacFileManager)fileManager; 237 //parse all files 238 ListBuffer<JCCompilationUnit> trees = new ListBuffer<JCCompilationUnit>(); 239 for (List<String> l = filenames; l.nonEmpty(); l = l.tail) { 240 if (classesAsDecls) { 241 if (! l.head.endsWith(".java") ) { // process as class file 242 ClassSymbol cs = reader.enterClass(names.fromString(l.head)); 243 try { 244 cs.complete(); 245 } catch(Symbol.CompletionFailure cf) { 246 bark.aptError("CantFindClass", l); 247 continue; 248 } 249 250 classes.append(cs); // add to list of classes 251 continue; 252 } 253 } 254 JavaFileObject fo = fm.getJavaFileObjectsFromStrings(List.of(l.head)).iterator().next(); 255 trees.append(parse(fo)); 256 } 257 258 //enter symbols for all files 259 List<JCCompilationUnit> roots = trees.toList(); 260 261 if (errorCount() == 0) { 262 boolean prev = bark.setDiagnosticsIgnored(true); 263 try { 264 enter.main(roots); 265 } 266 finally { 267 bark.setDiagnosticsIgnored(prev); 268 } 269 } 270 271 if (errorCount() == 0) { 272 apt.main(roots, 273 classes, 274 origOptions, aptCL, 275 providedFactory, 276 productiveFactories); 277 genSourceFileNames.addAll(apt.getSourceFileNames()); 278 genClassFileNames.addAll(apt.getClassFileNames()); 279 } 280 281 } catch (Abort ex) { 282 } 283 284 if (verbose) 285 printVerbose("total", Long.toString(System.currentTimeMillis() - msec)); 286 287 chk.reportDeferredDiagnostics(); 288 289 printCount("error", errorCount()); 290 printCount("warn", warningCount()); 291 292 return classes.toList(); 293 } 294 }