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 }