--- a/langtools/src/share/classes/com/sun/tools/javac/main/JavaCompiler.java Mon Aug 23 17:00:07 2010 +0100
+++ b/langtools/src/share/classes/com/sun/tools/javac/main/JavaCompiler.java Mon Aug 23 11:56:53 2010 -0700
@@ -529,7 +529,7 @@
log.error("warnings.and.werror");
}
}
- return log.nerrors;
+ return log.nerrors;
}
protected final <T> Queue<T> stopIfError(CompileState cs, Queue<T> queue) {
@@ -868,7 +868,7 @@
/**
* Parses a list of files.
*/
- public List<JCCompilationUnit> parseFiles(List<JavaFileObject> fileObjects) throws IOException {
+ public List<JCCompilationUnit> parseFiles(Iterable<JavaFileObject> fileObjects) throws IOException {
if (shouldStop(CompileState.PARSE))
return List.nil();
@@ -981,14 +981,13 @@
*/
public JavaCompiler processAnnotations(List<JCCompilationUnit> roots,
List<String> classnames)
- throws IOException { // TODO: see TEMP note in JavacProcessingEnvironment
+ throws IOException { // TODO: see TEMP note in JavacProcessingEnvironment
if (shouldStop(CompileState.PROCESS)) {
- // Errors were encountered. If todo is empty, then the
- // encountered errors were parse errors. Otherwise, the
- // errors were found during the enter phase which should
- // be ignored when processing annotations.
-
- if (todo.isEmpty())
+ // Errors were encountered.
+ // If log.unrecoverableError is set, the errors were parse errors
+ // or other errors during enter which cannot be fixed by running
+ // any annotation processors.
+ if (log.unrecoverableError)
return this;
}
--- a/langtools/src/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java Mon Aug 23 17:00:07 2010 +0100
+++ b/langtools/src/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java Mon Aug 23 11:56:53 2010 -0700
@@ -795,6 +795,13 @@
final JavaCompiler compiler;
/** The log for the round. */
final Log log;
+ /** The number of warnings in the previous round. */
+ final int priorWarnings;
+
+ /** The ASTs to be compiled. */
+ List<JCCompilationUnit> roots;
+ /** The classes to be compiler that have were generated. */
+ Map<String, JavaFileObject> genClassFiles;
/** The set of annotations to be processed this round. */
Set<TypeElement> annotationsPresent;
@@ -803,10 +810,12 @@
/** The set of package-info files to be processed this round. */
List<PackageSymbol> packageInfoFiles;
- /** Create a round. */
- Round(Context context, int number) {
+ /** Create a round (common code). */
+ private Round(Context context, int number, int priorWarnings) {
this.context = context;
this.number = number;
+ this.priorWarnings = priorWarnings;
+
compiler = JavaCompiler.instance(context);
log = Log.instance(context);
@@ -814,15 +823,86 @@
JavacProcessingEnvironment.this.context = context;
// the following will be populated as needed
- annotationsPresent = new LinkedHashSet<TypeElement>();
topLevelClasses = List.nil();
packageInfoFiles = List.nil();
}
+ /** Create the first round. */
+ Round(Context context, List<JCCompilationUnit> roots, List<ClassSymbol> classSymbols) {
+ this(context, 1, 0);
+ this.roots = roots;
+ genClassFiles = new HashMap<String,JavaFileObject>();
+
+ compiler.todo.clear(); // free the compiler's resources
+
+ // The reverse() in the following line is to maintain behavioural
+ // compatibility with the previous revision of the code. Strictly speaking,
+ // it should not be necessary, but a javah golden file test fails without it.
+ topLevelClasses =
+ getTopLevelClasses(roots).prependList(classSymbols.reverse());
+
+ packageInfoFiles = getPackageInfoFiles(roots);
+
+ findAnnotationsPresent();
+ }
+
+ /** Create a new round. */
+ private Round(Round prev,
+ Set<JavaFileObject> newSourceFiles, Map<String,JavaFileObject> newClassFiles)
+ throws IOException {
+ this(prev.nextContext(), prev.number+1, prev.compiler.log.nwarnings);
+ this.genClassFiles = prev.genClassFiles;
+
+ updateProcessingState();
+
+ List<JCCompilationUnit> parsedFiles = compiler.parseFiles(newSourceFiles);
+ roots = cleanTrees(prev.roots).appendList(parsedFiles);
+
+ // Check for errors after parsing
+ if (unrecoverableError())
+ return;
+
+ enterClassFiles(genClassFiles);
+ List<ClassSymbol> newClasses = enterClassFiles(newClassFiles);
+ genClassFiles.putAll(newClassFiles);
+ enterTrees(roots);
+
+ if (unrecoverableError())
+ return;
+
+ topLevelClasses = join(
+ getTopLevelClasses(parsedFiles),
+ getTopLevelClassesFromClasses(newClasses));
+
+ packageInfoFiles = join(
+ getPackageInfoFiles(parsedFiles),
+ getPackageInfoFilesFromClasses(newClasses));
+
+ findAnnotationsPresent();
+ }
+
/** Create the next round to be used. */
- Round next() {
- compiler.close(false);
- return new Round(contextForNextRound(), number + 1);
+ Round next(Set<JavaFileObject> newSourceFiles, Map<String, JavaFileObject> newClassFiles)
+ throws IOException {
+ try {
+ return new Round(this, newSourceFiles, newClassFiles);
+ } finally {
+ compiler.close(false);
+ }
+ }
+
+ /** Create the compiler to be used for the final compilation. */
+ JavaCompiler finalCompiler(boolean errorStatus) {
+ try {
+ JavaCompiler c = JavaCompiler.instance(nextContext());
+ if (errorStatus) {
+ c.log.nwarnings += priorWarnings + compiler.log.nwarnings;
+ c.log.nerrors += compiler.log.nerrors;
+ }
+ return c;
+ } finally {
+ compiler.close(false);
+ }
}
/** Return the number of errors found so far in this round.
@@ -839,12 +919,16 @@
/** Return whether or not an unrecoverable error has occurred. */
boolean unrecoverableError() {
- return log.unrecoverableError;
+ return log.unrecoverableError
+ || messager.errorRaised()
+ || (werror && log.nwarnings > 0)
+ || (fatalErrors && log.nerrors > 0);
}
/** Find the set of annotations present in the set of top level
- * classes and package info files to be processed this round. */
- void findAnnotationsPresent(ComputeAnnotationSet annotationComputer) {
+ * classes and package info files to be processed this round. */
+ void findAnnotationsPresent() {
+ ComputeAnnotationSet annotationComputer = new ComputeAnnotationSet(elementUtils);
// Use annotation processing to compute the set of annotations present
annotationsPresent = new LinkedHashSet<TypeElement>();
for (ClassSymbol classSym : topLevelClasses)
@@ -853,26 +937,13 @@
annotationComputer.scan(pkgSym, annotationsPresent);
}
- /**
- * Parse the latest set of generated source files created by the filer.
- */
- List<JCCompilationUnit> parseNewSourceFiles()
- throws IOException {
- List<JavaFileObject> fileObjects = List.nil();
- for (JavaFileObject jfo : filer.getGeneratedSourceFileObjects() ) {
- fileObjects = fileObjects.prepend(jfo);
- }
-
- return compiler.parseFiles(fileObjects);
- }
-
- /** Enter the latest set of generated class files created by the filer. */
- List<ClassSymbol> enterNewClassFiles() {
+ /** Enter a set of generated class files. */
+ List<ClassSymbol> enterClassFiles(Map<String, JavaFileObject> classFiles) {
ClassReader reader = ClassReader.instance(context);
Names names = Names.instance(context);
List<ClassSymbol> list = List.nil();
- for (Map.Entry<String,JavaFileObject> entry : filer.getGeneratedClasses().entrySet()) {
+ for (Map.Entry<String,JavaFileObject> entry : classFiles.entrySet()) {
Name name = names.fromString(entry.getKey());
JavaFileObject file = entry.getValue();
if (file.getKind() != JavaFileObject.Kind.CLASS)
@@ -900,11 +971,7 @@
/** Run a processing round. */
void run(boolean lastRound, boolean errorStatus) {
-// assert lastRound
-// ? (topLevelClasses.size() == 0 && annotationsPresent.size() == 0)
-// : (errorStatus == false);
-//
-// printRoundInfo(topLevelClasses, annotationsPresent, lastRound);
+ printRoundInfo(lastRound);
TaskListener taskListener = context.get(TaskListener.class);
if (taskListener != null)
@@ -912,7 +979,6 @@
try {
if (lastRound) {
- printRoundInfo(List.<ClassSymbol>nil(), Collections.<TypeElement>emptySet(), lastRound);
filer.setLastRound(true);
Set<Element> emptyRootElements = Collections.emptySet(); // immutable
RoundEnvironment renv = new JavacRoundEnvironment(true,
@@ -921,7 +987,6 @@
JavacProcessingEnvironment.this);
discoveredProcs.iterator().runContributingProcs(renv);
} else {
- printRoundInfo(topLevelClasses, annotationsPresent, lastRound);
discoverAndRunProcs(context, annotationsPresent, topLevelClasses, packageInfoFiles);
}
} finally {
@@ -931,11 +996,7 @@
}
/** Update the processing state for the current context. */
- // Question: should this not be part of next()?
- // Note: Calling it from next() breaks some tests. There is an issue
- // whether the annotationComputer is using elementUtils with the
- // correct context.
- void updateProcessingState() {
+ private void updateProcessingState() {
filer.newRound(context);
messager.newRound(context);
@@ -944,14 +1005,14 @@
}
/** Print info about this round. */
- private void printRoundInfo(List<ClassSymbol> topLevelClasses,
- Set<TypeElement> annotationsPresent,
- boolean lastRound) {
+ private void printRoundInfo(boolean lastRound) {
if (printRounds || verbose) {
+ List<ClassSymbol> tlc = lastRound ? List.<ClassSymbol>nil() : topLevelClasses;
+ Set<TypeElement> ap = lastRound ? Collections.<TypeElement>emptySet() : annotationsPresent;
log.printNoteLines("x.print.rounds",
- (!lastRound ? number : number + 1),
- "{" + topLevelClasses.toString(", ") + "}",
- annotationsPresent,
+ number,
+ "{" + tlc.toString(", ") + "}",
+ ap,
lastRound);
}
}
@@ -960,7 +1021,7 @@
* Important values are propogated from round to round;
* other values are implicitly reset.
*/
- private Context contextForNextRound() {
+ private Context nextContext() {
Context next = new Context();
Options options = Options.instance(context);
@@ -1025,138 +1086,90 @@
Iterable<? extends PackageSymbol> pckSymbols)
throws IOException {
+ TaskListener taskListener = context.get(TaskListener.class);
log = Log.instance(context);
- Round round = new Round(context, 1);
- round.compiler.todo.clear(); // free the compiler's resources
-
- // The reverse() in the following line is to maintain behavioural
- // compatibility with the previous revision of the code. Strictly speaking,
- // it should not be necessary, but a javah golden file test fails without it.
- round.topLevelClasses =
- getTopLevelClasses(roots).prependList(classSymbols.reverse());
-
- round.packageInfoFiles = getPackageInfoFiles(roots);
-
Set<PackageSymbol> specifiedPackages = new LinkedHashSet<PackageSymbol>();
for (PackageSymbol psym : pckSymbols)
specifiedPackages.add(psym);
this.specifiedPackages = Collections.unmodifiableSet(specifiedPackages);
- ComputeAnnotationSet annotationComputer = new ComputeAnnotationSet(elementUtils);
- round.findAnnotationsPresent(annotationComputer);
-
- boolean errorStatus = false;
+ Round round = new Round(context, roots, classSymbols);
- runAround:
- while (true) {
- if ((fatalErrors && round.errorCount() != 0)
- || (werror && round.warningCount() != 0)) {
- errorStatus = true;
- break runAround;
- }
-
+ boolean errorStatus;
+ boolean moreToDo;
+ do {
+ // Run processors for round n
round.run(false, false);
- /*
- * Processors for round n have run to completion. Prepare
- * for round (n+1) by checked for errors raised by
- * annotation processors and then checking for syntax
- * errors on any generated source files.
- */
- if (messager.errorRaised()) {
- errorStatus = true;
- break runAround;
- }
-
- if (!moreToDo())
- break runAround; // No new files
-
- round = round.next();
-
- List<JCCompilationUnit> parsedFiles = round.parseNewSourceFiles();
- roots = cleanTrees(roots).appendList(parsedFiles);
+ // Processors for round n have run to completion.
+ // Check for errors and whether there is more work to do.
+ errorStatus = round.unrecoverableError();
+ moreToDo = moreToDo();
- // Check for errors after parsing
- if (round.unrecoverableError()) {
- errorStatus = true;
- break runAround;
- }
-
- List<ClassSymbol> newClasses = round.enterNewClassFiles();
- round.enterTrees(roots);
+ // Set up next round.
+ // Copy mutable collections returned from filer.
+ round = round.next(
+ new LinkedHashSet<JavaFileObject>(filer.getGeneratedSourceFileObjects()),
+ new LinkedHashMap<String,JavaFileObject>(filer.getGeneratedClasses()));
- round.topLevelClasses = join(
- getTopLevelClasses(parsedFiles),
- getTopLevelClassesFromClasses(newClasses));
+ // Check for errors during setup.
+ if (round.unrecoverableError())
+ errorStatus = true;
- round.packageInfoFiles = join(
- getPackageInfoFiles(parsedFiles),
- getPackageInfoFilesFromClasses(newClasses));
-
- round.findAnnotationsPresent(annotationComputer);
- round.updateProcessingState();
- }
+ } while (moreToDo && !errorStatus);
// run last round
round.run(true, errorStatus);
- // Add any sources generated during the last round to the set
- // of files to be compiled.
- if (moreToDo()) {
- List<JCCompilationUnit> parsedFiles = round.parseNewSourceFiles();
- roots = cleanTrees(roots).appendList(parsedFiles);
- }
-
- // Set error status for any files compiled and generated in
- // the last round
- if (round.unrecoverableError() || (werror && round.warningCount() != 0))
- errorStatus = true;
-
- round = round.next();
-
filer.warnIfUnclosedFiles();
warnIfUnmatchedOptions();
- /*
- * If an annotation processor raises an error in a round,
- * that round runs to completion and one last round occurs.
- * The last round may also occur because no more source or
- * class files have been generated. Therefore, if an error
- * was raised on either of the last *two* rounds, the compile
- * should exit with a nonzero exit code. The current value of
- * errorStatus holds whether or not an error was raised on the
- * second to last round; errorRaised() gives the error status
- * of the last round.
- */
- errorStatus = errorStatus || messager.errorRaised();
+ /*
+ * If an annotation processor raises an error in a round,
+ * that round runs to completion and one last round occurs.
+ * The last round may also occur because no more source or
+ * class files have been generated. Therefore, if an error
+ * was raised on either of the last *two* rounds, the compile
+ * should exit with a nonzero exit code. The current value of
+ * errorStatus holds whether or not an error was raised on the
+ * second to last round; errorRaised() gives the error status
+ * of the last round.
+ */
+ if (messager.errorRaised()
+ || werror && round.warningCount() > 0 && round.errorCount() > 0)
+ errorStatus = true;
+
+ Set<JavaFileObject> newSourceFiles =
+ new LinkedHashSet<JavaFileObject>(filer.getGeneratedSourceFileObjects());
+ roots = cleanTrees(round.roots);
+
+ JavaCompiler compiler = round.finalCompiler(errorStatus);
+
+ if (newSourceFiles.size() > 0)
+ roots = roots.appendList(compiler.parseFiles(newSourceFiles));
+
+ errorStatus = errorStatus || (compiler.errorCount() > 0);
// Free resources
this.close();
- TaskListener taskListener = this.context.get(TaskListener.class);
if (taskListener != null)
taskListener.finished(new TaskEvent(TaskEvent.Kind.ANNOTATION_PROCESSING));
- JavaCompiler compiler;
-
if (errorStatus) {
- compiler = round.compiler;
- compiler.log.nwarnings += messager.warningCount();
- compiler.log.nerrors += messager.errorCount();
if (compiler.errorCount() == 0)
compiler.log.nerrors++;
- } else if (procOnly && !foundTypeProcessors) {
- compiler = round.compiler;
+ return compiler;
+ }
+
+ if (procOnly && !foundTypeProcessors) {
compiler.todo.clear();
- } else { // Final compilation
- round = round.next();
- round.updateProcessingState();
- compiler = round.compiler;
+ } else {
if (procOnly && foundTypeProcessors)
compiler.shouldStopPolicy = CompileState.FLOW;
- compiler.enterTrees(cleanTrees(roots));
+ compiler.enterTrees(roots);
}
return compiler;
@@ -1185,7 +1198,9 @@
for (JCCompilationUnit unit : units) {
for (JCTree node : unit.defs) {
if (node.getTag() == JCTree.CLASSDEF) {
- classes = classes.prepend(((JCClassDecl) node).sym);
+ ClassSymbol sym = ((JCClassDecl) node).sym;
+ assert sym != null;
+ classes = classes.prepend(sym);
}
}
}
--- a/langtools/test/tools/javac/T6358024.java Mon Aug 23 17:00:07 2010 +0100
+++ b/langtools/test/tools/javac/T6358024.java Mon Aug 23 11:56:53 2010 -0700
@@ -60,7 +60,7 @@
new Option[] { new XOption("-XprintRounds"),
new Option("-processorpath", "."),
new Option("-processor", self) },
- 11);
+ 12);
}
static void test(JavacFileManager fm, JavaFileObject f, Option[] opts, int expect) throws Throwable {
--- a/langtools/test/tools/javac/T6403466.out Mon Aug 23 17:00:07 2010 +0100
+++ b/langtools/test/tools/javac/T6403466.out Mon Aug 23 11:56:53 2010 -0700
@@ -13,6 +13,10 @@
Finished TaskEvent[ENTER,T6403466Wrapper.java,null]
Started TaskEvent[ANNOTATION_PROCESSING_ROUND,null,null]
Finished TaskEvent[ANNOTATION_PROCESSING_ROUND,null,null]
+Started TaskEvent[ENTER,T6403466.java,null]
+Started TaskEvent[ENTER,T6403466Wrapper.java,null]
+Finished TaskEvent[ENTER,T6403466.java,null]
+Finished TaskEvent[ENTER,T6403466Wrapper.java,null]
Started TaskEvent[ANNOTATION_PROCESSING_ROUND,null,null]
Finished TaskEvent[ANNOTATION_PROCESSING_ROUND,null,null]
Finished TaskEvent[ANNOTATION_PROCESSING,null,null]
--- a/langtools/test/tools/javac/processing/filer/TestLastRound.out Mon Aug 23 17:00:07 2010 +0100
+++ b/langtools/test/tools/javac/processing/filer/TestLastRound.out Mon Aug 23 11:56:53 2010 -0700
@@ -1,3 +1,4 @@
- compiler.warn.proc.file.create.last.round: LastRound.java
- compiler.err.warnings.and.werror
1 error
+1 warning