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 }