diff -r f50c012cd1f0 -r f01ebbf5a5f7 langtools/src/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java --- 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 roots; + /** The classes to be compiler that have were generated. */ + Map genClassFiles; /** The set of annotations to be processed this round. */ Set annotationsPresent; @@ -803,10 +810,12 @@ /** The set of package-info files to be processed this round. */ List 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(); topLevelClasses = List.nil(); packageInfoFiles = List.nil(); } + /** Create the first round. */ + Round(Context context, List roots, List classSymbols) { + this(context, 1, 0); + this.roots = roots; + genClassFiles = new HashMap(); + + 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 newSourceFiles, Map newClassFiles) + throws IOException { + this(prev.nextContext(), prev.number+1, prev.compiler.log.nwarnings); + this.genClassFiles = prev.genClassFiles; + + updateProcessingState(); + + List parsedFiles = compiler.parseFiles(newSourceFiles); + roots = cleanTrees(prev.roots).appendList(parsedFiles); + + // Check for errors after parsing + if (unrecoverableError()) + return; + + enterClassFiles(genClassFiles); + List 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 newSourceFiles, Map 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(); 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 parseNewSourceFiles() - throws IOException { - List 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 enterNewClassFiles() { + /** Enter a set of generated class files. */ + List enterClassFiles(Map classFiles) { ClassReader reader = ClassReader.instance(context); Names names = Names.instance(context); List list = List.nil(); - for (Map.Entry entry : filer.getGeneratedClasses().entrySet()) { + for (Map.Entry 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.nil(), Collections.emptySet(), lastRound); filer.setLastRound(true); Set 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 topLevelClasses, - Set annotationsPresent, - boolean lastRound) { + private void printRoundInfo(boolean lastRound) { if (printRounds || verbose) { + List tlc = lastRound ? List.nil() : topLevelClasses; + Set ap = lastRound ? Collections.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 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 specifiedPackages = new LinkedHashSet(); 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 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 newClasses = round.enterNewClassFiles(); - round.enterTrees(roots); + // Set up next round. + // Copy mutable collections returned from filer. + round = round.next( + new LinkedHashSet(filer.getGeneratedSourceFileObjects()), + new LinkedHashMap(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 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 newSourceFiles = + new LinkedHashSet(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); } } }