6975005: improve JavacProcessingEnvironment.Round abstraction
Reviewed-by: darcy
This commit is contained in:
parent
92de62f50b
commit
c72513c86b
@ -529,7 +529,7 @@ public class JavaCompiler implements ClassReader.SourceCompleter {
|
||||
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 @@ public class JavaCompiler implements ClassReader.SourceCompleter {
|
||||
/**
|
||||
* 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 class JavaCompiler implements ClassReader.SourceCompleter {
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -795,6 +795,13 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea
|
||||
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 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea
|
||||
/** 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 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea
|
||||
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 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea
|
||||
|
||||
/** 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 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea
|
||||
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 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea
|
||||
|
||||
/** 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 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea
|
||||
|
||||
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 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea
|
||||
JavacProcessingEnvironment.this);
|
||||
discoveredProcs.iterator().runContributingProcs(renv);
|
||||
} else {
|
||||
printRoundInfo(topLevelClasses, annotationsPresent, lastRound);
|
||||
discoverAndRunProcs(context, annotationsPresent, topLevelClasses, packageInfoFiles);
|
||||
}
|
||||
} finally {
|
||||
@ -931,11 +996,7 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea
|
||||
}
|
||||
|
||||
/** 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 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea
|
||||
}
|
||||
|
||||
/** 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 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea
|
||||
* 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 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea
|
||||
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;
|
||||
|
||||
runAround:
|
||||
while (true) {
|
||||
if ((fatalErrors && round.errorCount() != 0)
|
||||
|| (werror && round.warningCount() != 0)) {
|
||||
errorStatus = true;
|
||||
break runAround;
|
||||
}
|
||||
Round round = new Round(context, roots, classSymbols);
|
||||
|
||||
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()) {
|
||||
// Processors for round n have run to completion.
|
||||
// Check for errors and whether there is more work to do.
|
||||
errorStatus = round.unrecoverableError();
|
||||
moreToDo = moreToDo();
|
||||
|
||||
// Set up next round.
|
||||
// Copy mutable collections returned from filer.
|
||||
round = round.next(
|
||||
new LinkedHashSet<JavaFileObject>(filer.getGeneratedSourceFileObjects()),
|
||||
new LinkedHashMap<String,JavaFileObject>(filer.getGeneratedClasses()));
|
||||
|
||||
// Check for errors during setup.
|
||||
if (round.unrecoverableError())
|
||||
errorStatus = true;
|
||||
break runAround;
|
||||
}
|
||||
|
||||
if (!moreToDo())
|
||||
break runAround; // No new files
|
||||
|
||||
round = round.next();
|
||||
|
||||
List<JCCompilationUnit> parsedFiles = round.parseNewSourceFiles();
|
||||
roots = cleanTrees(roots).appendList(parsedFiles);
|
||||
|
||||
// Check for errors after parsing
|
||||
if (round.unrecoverableError()) {
|
||||
errorStatus = true;
|
||||
break runAround;
|
||||
}
|
||||
|
||||
List<ClassSymbol> newClasses = round.enterNewClassFiles();
|
||||
round.enterTrees(roots);
|
||||
|
||||
round.topLevelClasses = join(
|
||||
getTopLevelClasses(parsedFiles),
|
||||
getTopLevelClassesFromClasses(newClasses));
|
||||
|
||||
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 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -60,7 +60,7 @@ public class T6358024 extends AbstractProcessor {
|
||||
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 {
|
||||
|
@ -13,6 +13,10 @@ 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]
|
||||
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]
|
||||
|
@ -1,3 +1,4 @@
|
||||
- compiler.warn.proc.file.create.last.round: LastRound.java
|
||||
- compiler.err.warnings.and.werror
|
||||
1 error
|
||||
1 warning
|
||||
|
Loading…
x
Reference in New Issue
Block a user