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    }