mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-20 19:14:38 +02:00
6966604: JavacFiler not correctly notified of lastRound
Reviewed-by: darcy
This commit is contained in:
parent
75b1007388
commit
eff5854b96
8 changed files with 450 additions and 258 deletions
|
@ -539,13 +539,16 @@ public class JavacFiler implements Filer, Closeable {
|
||||||
/**
|
/**
|
||||||
* Update internal state for a new round.
|
* Update internal state for a new round.
|
||||||
*/
|
*/
|
||||||
public void newRound(Context context, boolean lastRound) {
|
public void newRound(Context context) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.log = Log.instance(context);
|
this.log = Log.instance(context);
|
||||||
this.lastRound = lastRound;
|
|
||||||
clearRoundState();
|
clearRoundState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setLastRound(boolean lastRound) {
|
||||||
|
this.lastRound = lastRound;
|
||||||
|
}
|
||||||
|
|
||||||
public void close() {
|
public void close() {
|
||||||
clearRoundState();
|
clearRoundState();
|
||||||
// Cross-round state
|
// Cross-round state
|
||||||
|
|
|
@ -68,7 +68,6 @@ import com.sun.tools.javac.util.Abort;
|
||||||
import com.sun.tools.javac.util.Context;
|
import com.sun.tools.javac.util.Context;
|
||||||
import com.sun.tools.javac.util.Convert;
|
import com.sun.tools.javac.util.Convert;
|
||||||
import com.sun.tools.javac.util.List;
|
import com.sun.tools.javac.util.List;
|
||||||
import com.sun.tools.javac.util.ListBuffer;
|
|
||||||
import com.sun.tools.javac.util.Log;
|
import com.sun.tools.javac.util.Log;
|
||||||
import com.sun.tools.javac.util.JavacMessages;
|
import com.sun.tools.javac.util.JavacMessages;
|
||||||
import com.sun.tools.javac.util.Name;
|
import com.sun.tools.javac.util.Name;
|
||||||
|
@ -784,193 +783,80 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
// TODO: internal catch clauses?; catch and rethrow an annotation
|
* Helper object for a single round of annotation processing.
|
||||||
// processing error
|
|
||||||
public JavaCompiler doProcessing(Context context,
|
|
||||||
List<JCCompilationUnit> roots,
|
|
||||||
List<ClassSymbol> classSymbols,
|
|
||||||
Iterable<? extends PackageSymbol> pckSymbols)
|
|
||||||
throws IOException {
|
|
||||||
|
|
||||||
log = Log.instance(context);
|
|
||||||
TaskListener taskListener = context.get(TaskListener.class);
|
|
||||||
|
|
||||||
JavaCompiler compiler = JavaCompiler.instance(context);
|
|
||||||
compiler.todo.clear(); // free the compiler's resources
|
|
||||||
|
|
||||||
int round = 0;
|
|
||||||
|
|
||||||
// List<JCAnnotation> annotationsPresentInSource = collector.findAnnotations(roots);
|
|
||||||
List<ClassSymbol> topLevelClasses = getTopLevelClasses(roots);
|
|
||||||
|
|
||||||
for (ClassSymbol classSym : classSymbols)
|
|
||||||
topLevelClasses = topLevelClasses.prepend(classSym);
|
|
||||||
List<PackageSymbol> packageInfoFiles =
|
|
||||||
getPackageInfoFiles(roots);
|
|
||||||
|
|
||||||
Set<PackageSymbol> specifiedPackages = new LinkedHashSet<PackageSymbol>();
|
|
||||||
for (PackageSymbol psym : pckSymbols)
|
|
||||||
specifiedPackages.add(psym);
|
|
||||||
this.specifiedPackages = Collections.unmodifiableSet(specifiedPackages);
|
|
||||||
|
|
||||||
// Use annotation processing to compute the set of annotations present
|
|
||||||
Set<TypeElement> annotationsPresent = new LinkedHashSet<TypeElement>();
|
|
||||||
ComputeAnnotationSet annotationComputer = new ComputeAnnotationSet(elementUtils);
|
|
||||||
for (ClassSymbol classSym : topLevelClasses)
|
|
||||||
annotationComputer.scan(classSym, annotationsPresent);
|
|
||||||
for (PackageSymbol pkgSym : packageInfoFiles)
|
|
||||||
annotationComputer.scan(pkgSym, annotationsPresent);
|
|
||||||
|
|
||||||
Context currentContext = context;
|
|
||||||
|
|
||||||
int roundNumber = 0;
|
|
||||||
boolean errorStatus = false;
|
|
||||||
|
|
||||||
runAround:
|
|
||||||
while(true) {
|
|
||||||
if ((fatalErrors && compiler.errorCount() != 0)
|
|
||||||
|| (werror && compiler.warningCount() != 0)) {
|
|
||||||
errorStatus = true;
|
|
||||||
break runAround;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.context = currentContext;
|
|
||||||
roundNumber++;
|
|
||||||
printRoundInfo(roundNumber, topLevelClasses, annotationsPresent, false);
|
|
||||||
|
|
||||||
if (taskListener != null)
|
|
||||||
taskListener.started(new TaskEvent(TaskEvent.Kind.ANNOTATION_PROCESSING_ROUND));
|
|
||||||
|
|
||||||
try {
|
|
||||||
discoverAndRunProcs(currentContext, annotationsPresent, topLevelClasses, packageInfoFiles);
|
|
||||||
} finally {
|
|
||||||
if (taskListener != null)
|
|
||||||
taskListener.finished(new TaskEvent(TaskEvent.Kind.ANNOTATION_PROCESSING_ROUND));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 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()) {
|
class Round {
|
||||||
errorStatus = true;
|
/** The round number. */
|
||||||
break runAround;
|
final int number;
|
||||||
} else {
|
/** The context for the round. */
|
||||||
if (moreToDo()) {
|
final Context context;
|
||||||
// annotationsPresentInSource = List.nil();
|
/** The compiler for the round. */
|
||||||
|
final JavaCompiler compiler;
|
||||||
|
/** The log for the round. */
|
||||||
|
final Log log;
|
||||||
|
|
||||||
|
/** The set of annotations to be processed this round. */
|
||||||
|
Set<TypeElement> annotationsPresent;
|
||||||
|
/** The set of top level classes to be processed this round. */
|
||||||
|
List<ClassSymbol> topLevelClasses;
|
||||||
|
/** The set of package-info files to be processed this round. */
|
||||||
|
List<PackageSymbol> packageInfoFiles;
|
||||||
|
|
||||||
|
/** Create a round. */
|
||||||
|
Round(Context context, int number) {
|
||||||
|
this.context = context;
|
||||||
|
this.number = number;
|
||||||
|
compiler = JavaCompiler.instance(context);
|
||||||
|
log = Log.instance(context);
|
||||||
|
|
||||||
|
// the following is for the benefit of JavacProcessingEnvironment.getContext()
|
||||||
|
JavacProcessingEnvironment.this.context = context;
|
||||||
|
|
||||||
|
// the following will be populated as needed
|
||||||
annotationsPresent = new LinkedHashSet<TypeElement>();
|
annotationsPresent = new LinkedHashSet<TypeElement>();
|
||||||
topLevelClasses = List.nil();
|
topLevelClasses = List.nil();
|
||||||
packageInfoFiles = List.nil();
|
packageInfoFiles = List.nil();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Create the next round to be used. */
|
||||||
|
Round next() {
|
||||||
compiler.close(false);
|
compiler.close(false);
|
||||||
currentContext = contextForNextRound(currentContext, true);
|
return new Round(contextForNextRound(), number + 1);
|
||||||
|
}
|
||||||
|
|
||||||
JavaFileManager fileManager = currentContext.get(JavaFileManager.class);
|
/** Return the number of errors found so far in this round.
|
||||||
|
* This may include uncoverable errors, such as parse errors,
|
||||||
|
* and transient errors, such as missing symbols. */
|
||||||
|
int errorCount() {
|
||||||
|
return compiler.errorCount();
|
||||||
|
}
|
||||||
|
|
||||||
compiler = JavaCompiler.instance(currentContext);
|
/** Return the number of warnings found so far in this round. */
|
||||||
List<JCCompilationUnit> parsedFiles = sourcesToParsedFiles(compiler);
|
int warningCount() {
|
||||||
roots = cleanTrees(roots).appendList(parsedFiles);
|
return compiler.warningCount();
|
||||||
|
}
|
||||||
|
|
||||||
// Check for errors after parsing
|
/** Return whether or not an unrecoverable error has occurred. */
|
||||||
if (log.unrecoverableError) {
|
boolean unrecoverableError() {
|
||||||
errorStatus = true;
|
return log.unrecoverableError;
|
||||||
break runAround;
|
}
|
||||||
} else {
|
|
||||||
List<ClassSymbol> newClasses = enterNewClassFiles(currentContext);
|
|
||||||
compiler.enterTrees(roots);
|
|
||||||
|
|
||||||
// annotationsPresentInSource =
|
|
||||||
// collector.findAnnotations(parsedFiles);
|
|
||||||
ListBuffer<ClassSymbol> tlc = new ListBuffer<ClassSymbol>();
|
|
||||||
tlc.appendList(getTopLevelClasses(parsedFiles));
|
|
||||||
tlc.appendList(getTopLevelClassesFromClasses(newClasses));
|
|
||||||
topLevelClasses = tlc.toList();
|
|
||||||
|
|
||||||
ListBuffer<PackageSymbol> pif = new ListBuffer<PackageSymbol>();
|
|
||||||
pif.appendList(getPackageInfoFiles(parsedFiles));
|
|
||||||
pif.appendList(getPackageInfoFilesFromClasses(newClasses));
|
|
||||||
packageInfoFiles = pif.toList();
|
|
||||||
|
|
||||||
|
/** 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) {
|
||||||
|
// Use annotation processing to compute the set of annotations present
|
||||||
annotationsPresent = new LinkedHashSet<TypeElement>();
|
annotationsPresent = new LinkedHashSet<TypeElement>();
|
||||||
for (ClassSymbol classSym : topLevelClasses)
|
for (ClassSymbol classSym : topLevelClasses)
|
||||||
annotationComputer.scan(classSym, annotationsPresent);
|
annotationComputer.scan(classSym, annotationsPresent);
|
||||||
for (PackageSymbol pkgSym : packageInfoFiles)
|
for (PackageSymbol pkgSym : packageInfoFiles)
|
||||||
annotationComputer.scan(pkgSym, annotationsPresent);
|
annotationComputer.scan(pkgSym, annotationsPresent);
|
||||||
|
|
||||||
updateProcessingState(currentContext, false);
|
|
||||||
}
|
}
|
||||||
} else
|
|
||||||
break runAround; // No new files
|
|
||||||
}
|
|
||||||
}
|
|
||||||
roots = runLastRound(roundNumber, errorStatus, compiler, roots, taskListener);
|
|
||||||
// Set error status for any files compiled and generated in
|
|
||||||
// the last round
|
|
||||||
if (log.unrecoverableError || (werror && compiler.warningCount() != 0))
|
|
||||||
errorStatus = true;
|
|
||||||
|
|
||||||
compiler.close(false);
|
/**
|
||||||
currentContext = contextForNextRound(currentContext, true);
|
* Parse the latest set of generated source files created by the filer.
|
||||||
compiler = JavaCompiler.instance(currentContext);
|
|
||||||
|
|
||||||
filer.newRound(currentContext, true);
|
|
||||||
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();
|
List<JCCompilationUnit> parseNewSourceFiles()
|
||||||
|
|
||||||
|
|
||||||
// Free resources
|
|
||||||
this.close();
|
|
||||||
|
|
||||||
if (taskListener != null)
|
|
||||||
taskListener.finished(new TaskEvent(TaskEvent.Kind.ANNOTATION_PROCESSING));
|
|
||||||
|
|
||||||
if (errorStatus) {
|
|
||||||
compiler.log.nwarnings += messager.warningCount();
|
|
||||||
compiler.log.nerrors += messager.errorCount();
|
|
||||||
if (compiler.errorCount() == 0)
|
|
||||||
compiler.log.nerrors++;
|
|
||||||
} else if (procOnly && !foundTypeProcessors) {
|
|
||||||
compiler.todo.clear();
|
|
||||||
} else { // Final compilation
|
|
||||||
compiler.close(false);
|
|
||||||
currentContext = contextForNextRound(currentContext, true);
|
|
||||||
this.context = currentContext;
|
|
||||||
updateProcessingState(currentContext, true);
|
|
||||||
compiler = JavaCompiler.instance(currentContext);
|
|
||||||
if (procOnly && foundTypeProcessors)
|
|
||||||
compiler.shouldStopPolicy = CompileState.FLOW;
|
|
||||||
|
|
||||||
if (true) {
|
|
||||||
compiler.enterTrees(cleanTrees(roots));
|
|
||||||
} else {
|
|
||||||
List<JavaFileObject> fileObjects = List.nil();
|
|
||||||
for (JCCompilationUnit unit : roots)
|
|
||||||
fileObjects = fileObjects.prepend(unit.getSourceFile());
|
|
||||||
roots = null;
|
|
||||||
compiler.enterTrees(compiler.parseFiles(fileObjects.reverse()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return compiler;
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<JCCompilationUnit> sourcesToParsedFiles(JavaCompiler compiler)
|
|
||||||
throws IOException {
|
throws IOException {
|
||||||
List<JavaFileObject> fileObjects = List.nil();
|
List<JavaFileObject> fileObjects = List.nil();
|
||||||
for (JavaFileObject jfo : filer.getGeneratedSourceFileObjects() ) {
|
for (JavaFileObject jfo : filer.getGeneratedSourceFileObjects() ) {
|
||||||
|
@ -980,72 +866,10 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea
|
||||||
return compiler.parseFiles(fileObjects);
|
return compiler.parseFiles(fileObjects);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call the last round of annotation processing
|
/** Enter the latest set of generated class files created by the filer. */
|
||||||
private List<JCCompilationUnit> runLastRound(int roundNumber,
|
List<ClassSymbol> enterNewClassFiles() {
|
||||||
boolean errorStatus,
|
ClassReader reader = ClassReader.instance(context);
|
||||||
JavaCompiler compiler,
|
Names names = Names.instance(context);
|
||||||
List<JCCompilationUnit> roots,
|
|
||||||
TaskListener taskListener) throws IOException {
|
|
||||||
roundNumber++;
|
|
||||||
List<ClassSymbol> noTopLevelClasses = List.nil();
|
|
||||||
Set<TypeElement> noAnnotations = Collections.emptySet();
|
|
||||||
printRoundInfo(roundNumber, noTopLevelClasses, noAnnotations, true);
|
|
||||||
|
|
||||||
Set<Element> emptyRootElements = Collections.emptySet(); // immutable
|
|
||||||
RoundEnvironment renv = new JavacRoundEnvironment(true,
|
|
||||||
errorStatus,
|
|
||||||
emptyRootElements,
|
|
||||||
JavacProcessingEnvironment.this);
|
|
||||||
if (taskListener != null)
|
|
||||||
taskListener.started(new TaskEvent(TaskEvent.Kind.ANNOTATION_PROCESSING_ROUND));
|
|
||||||
|
|
||||||
try {
|
|
||||||
discoveredProcs.iterator().runContributingProcs(renv);
|
|
||||||
} finally {
|
|
||||||
if (taskListener != null)
|
|
||||||
taskListener.finished(new TaskEvent(TaskEvent.Kind.ANNOTATION_PROCESSING_ROUND));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add any sources generated during the last round to the set
|
|
||||||
// of files to be compiled.
|
|
||||||
if (moreToDo()) {
|
|
||||||
List<JCCompilationUnit> parsedFiles = sourcesToParsedFiles(compiler);
|
|
||||||
roots = cleanTrees(roots).appendList(parsedFiles);
|
|
||||||
}
|
|
||||||
|
|
||||||
return roots;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateProcessingState(Context currentContext, boolean lastRound) {
|
|
||||||
filer.newRound(currentContext, lastRound);
|
|
||||||
messager.newRound(currentContext);
|
|
||||||
|
|
||||||
elementUtils.setContext(currentContext);
|
|
||||||
typeUtils.setContext(currentContext);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void warnIfUnmatchedOptions() {
|
|
||||||
if (!unmatchedProcessorOptions.isEmpty()) {
|
|
||||||
log.warning("proc.unmatched.processor.options", unmatchedProcessorOptions.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void printRoundInfo(int roundNumber,
|
|
||||||
List<ClassSymbol> topLevelClasses,
|
|
||||||
Set<TypeElement> annotationsPresent,
|
|
||||||
boolean lastRound) {
|
|
||||||
if (printRounds || verbose) {
|
|
||||||
log.printNoteLines("x.print.rounds",
|
|
||||||
roundNumber,
|
|
||||||
"{" + topLevelClasses.toString(", ") + "}",
|
|
||||||
annotationsPresent,
|
|
||||||
lastRound);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<ClassSymbol> enterNewClassFiles(Context currentContext) {
|
|
||||||
ClassReader reader = ClassReader.instance(currentContext);
|
|
||||||
Names names = Names.instance(currentContext);
|
|
||||||
List<ClassSymbol> list = List.nil();
|
List<ClassSymbol> list = List.nil();
|
||||||
|
|
||||||
for (Map.Entry<String,JavaFileObject> entry : filer.getGeneratedClasses().entrySet()) {
|
for (Map.Entry<String,JavaFileObject> entry : filer.getGeneratedClasses().entrySet()) {
|
||||||
|
@ -1069,6 +893,279 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea
|
||||||
return list.reverse();
|
return list.reverse();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Enter a set of syntax trees. */
|
||||||
|
void enterTrees(List<JCCompilationUnit> roots) {
|
||||||
|
compiler.enterTrees(roots);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Run a processing round. */
|
||||||
|
void run(boolean lastRound, boolean errorStatus) {
|
||||||
|
assert lastRound
|
||||||
|
? (topLevelClasses.size() == 0 && annotationsPresent.size() == 0)
|
||||||
|
: (errorStatus == false);
|
||||||
|
|
||||||
|
printRoundInfo(topLevelClasses, annotationsPresent, lastRound);
|
||||||
|
|
||||||
|
TaskListener taskListener = context.get(TaskListener.class);
|
||||||
|
if (taskListener != null)
|
||||||
|
taskListener.started(new TaskEvent(TaskEvent.Kind.ANNOTATION_PROCESSING_ROUND));
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (lastRound) {
|
||||||
|
filer.setLastRound(true);
|
||||||
|
Set<Element> emptyRootElements = Collections.emptySet(); // immutable
|
||||||
|
RoundEnvironment renv = new JavacRoundEnvironment(true,
|
||||||
|
errorStatus,
|
||||||
|
emptyRootElements,
|
||||||
|
JavacProcessingEnvironment.this);
|
||||||
|
discoveredProcs.iterator().runContributingProcs(renv);
|
||||||
|
} else {
|
||||||
|
discoverAndRunProcs(context, annotationsPresent, topLevelClasses, packageInfoFiles);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
if (taskListener != null)
|
||||||
|
taskListener.finished(new TaskEvent(TaskEvent.Kind.ANNOTATION_PROCESSING_ROUND));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 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() {
|
||||||
|
filer.newRound(context);
|
||||||
|
messager.newRound(context);
|
||||||
|
|
||||||
|
elementUtils.setContext(context);
|
||||||
|
typeUtils.setContext(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Print info about this round. */
|
||||||
|
private void printRoundInfo(List<ClassSymbol> topLevelClasses,
|
||||||
|
Set<TypeElement> annotationsPresent,
|
||||||
|
boolean lastRound) {
|
||||||
|
if (printRounds || verbose) {
|
||||||
|
log.printNoteLines("x.print.rounds",
|
||||||
|
number,
|
||||||
|
"{" + topLevelClasses.toString(", ") + "}",
|
||||||
|
annotationsPresent,
|
||||||
|
lastRound);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Get the context for the next round of processing.
|
||||||
|
* Important values are propogated from round to round;
|
||||||
|
* other values are implicitly reset.
|
||||||
|
*/
|
||||||
|
private Context contextForNextRound() {
|
||||||
|
Context next = new Context();
|
||||||
|
|
||||||
|
Options options = Options.instance(context);
|
||||||
|
assert options != null;
|
||||||
|
next.put(Options.optionsKey, options);
|
||||||
|
|
||||||
|
PrintWriter out = context.get(Log.outKey);
|
||||||
|
assert out != null;
|
||||||
|
next.put(Log.outKey, out);
|
||||||
|
|
||||||
|
final boolean shareNames = true;
|
||||||
|
if (shareNames) {
|
||||||
|
Names names = Names.instance(context);
|
||||||
|
assert names != null;
|
||||||
|
next.put(Names.namesKey, names);
|
||||||
|
}
|
||||||
|
|
||||||
|
DiagnosticListener<?> dl = context.get(DiagnosticListener.class);
|
||||||
|
if (dl != null)
|
||||||
|
next.put(DiagnosticListener.class, dl);
|
||||||
|
|
||||||
|
TaskListener tl = context.get(TaskListener.class);
|
||||||
|
if (tl != null)
|
||||||
|
next.put(TaskListener.class, tl);
|
||||||
|
|
||||||
|
JavaFileManager jfm = context.get(JavaFileManager.class);
|
||||||
|
assert jfm != null;
|
||||||
|
next.put(JavaFileManager.class, jfm);
|
||||||
|
if (jfm instanceof JavacFileManager) {
|
||||||
|
((JavacFileManager)jfm).setContext(next);
|
||||||
|
}
|
||||||
|
|
||||||
|
Names names = Names.instance(context);
|
||||||
|
assert names != null;
|
||||||
|
next.put(Names.namesKey, names);
|
||||||
|
|
||||||
|
Keywords keywords = Keywords.instance(context);
|
||||||
|
assert(keywords != null);
|
||||||
|
next.put(Keywords.keywordsKey, keywords);
|
||||||
|
|
||||||
|
JavaCompiler oldCompiler = JavaCompiler.instance(context);
|
||||||
|
JavaCompiler nextCompiler = JavaCompiler.instance(next);
|
||||||
|
nextCompiler.initRound(oldCompiler);
|
||||||
|
|
||||||
|
JavacTaskImpl task = context.get(JavacTaskImpl.class);
|
||||||
|
if (task != null) {
|
||||||
|
next.put(JavacTaskImpl.class, task);
|
||||||
|
task.updateContext(next);
|
||||||
|
}
|
||||||
|
|
||||||
|
context.clear();
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// TODO: internal catch clauses?; catch and rethrow an annotation
|
||||||
|
// processing error
|
||||||
|
public JavaCompiler doProcessing(Context context,
|
||||||
|
List<JCCompilationUnit> roots,
|
||||||
|
List<ClassSymbol> classSymbols,
|
||||||
|
Iterable<? extends PackageSymbol> pckSymbols)
|
||||||
|
throws IOException {
|
||||||
|
|
||||||
|
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.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);
|
||||||
|
|
||||||
|
// 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();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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();
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
compiler.todo.clear();
|
||||||
|
} else { // Final compilation
|
||||||
|
round = round.next();
|
||||||
|
round.updateProcessingState();
|
||||||
|
compiler = round.compiler;
|
||||||
|
if (procOnly && foundTypeProcessors)
|
||||||
|
compiler.shouldStopPolicy = CompileState.FLOW;
|
||||||
|
|
||||||
|
compiler.enterTrees(cleanTrees(roots));
|
||||||
|
}
|
||||||
|
|
||||||
|
return compiler;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void warnIfUnmatchedOptions() {
|
||||||
|
if (!unmatchedProcessorOptions.isEmpty()) {
|
||||||
|
log.warning("proc.unmatched.processor.options", unmatchedProcessorOptions.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Free resources related to annotation processing.
|
* Free resources related to annotation processing.
|
||||||
*/
|
*/
|
||||||
|
@ -1123,6 +1220,11 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea
|
||||||
return packages.reverse();
|
return packages.reverse();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// avoid unchecked warning from use of varargs
|
||||||
|
private static <T> List<T> join(List<T> list1, List<T> list2) {
|
||||||
|
return list1.appendList(list2);
|
||||||
|
}
|
||||||
|
|
||||||
private boolean isPkgInfo(JavaFileObject fo, JavaFileObject.Kind kind) {
|
private boolean isPkgInfo(JavaFileObject fo, JavaFileObject.Kind kind) {
|
||||||
return fo.isNameCompatible("package-info", kind);
|
return fo.isNameCompatible("package-info", kind);
|
||||||
}
|
}
|
||||||
|
@ -1131,62 +1233,6 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea
|
||||||
return isPkgInfo(sym.classfile, JavaFileObject.Kind.CLASS) && (sym.packge().package_info == sym);
|
return isPkgInfo(sym.classfile, JavaFileObject.Kind.CLASS) && (sym.packge().package_info == sym);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Context contextForNextRound(Context context, boolean shareNames)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
Context next = new Context();
|
|
||||||
|
|
||||||
Options options = Options.instance(context);
|
|
||||||
assert options != null;
|
|
||||||
next.put(Options.optionsKey, options);
|
|
||||||
|
|
||||||
PrintWriter out = context.get(Log.outKey);
|
|
||||||
assert out != null;
|
|
||||||
next.put(Log.outKey, out);
|
|
||||||
|
|
||||||
if (shareNames) {
|
|
||||||
Names names = Names.instance(context);
|
|
||||||
assert names != null;
|
|
||||||
next.put(Names.namesKey, names);
|
|
||||||
}
|
|
||||||
|
|
||||||
DiagnosticListener<?> dl = context.get(DiagnosticListener.class);
|
|
||||||
if (dl != null)
|
|
||||||
next.put(DiagnosticListener.class, dl);
|
|
||||||
|
|
||||||
TaskListener tl = context.get(TaskListener.class);
|
|
||||||
if (tl != null)
|
|
||||||
next.put(TaskListener.class, tl);
|
|
||||||
|
|
||||||
JavaFileManager jfm = context.get(JavaFileManager.class);
|
|
||||||
assert jfm != null;
|
|
||||||
next.put(JavaFileManager.class, jfm);
|
|
||||||
if (jfm instanceof JavacFileManager) {
|
|
||||||
((JavacFileManager)jfm).setContext(next);
|
|
||||||
}
|
|
||||||
|
|
||||||
Names names = Names.instance(context);
|
|
||||||
assert names != null;
|
|
||||||
next.put(Names.namesKey, names);
|
|
||||||
|
|
||||||
Keywords keywords = Keywords.instance(context);
|
|
||||||
assert(keywords != null);
|
|
||||||
next.put(Keywords.keywordsKey, keywords);
|
|
||||||
|
|
||||||
JavaCompiler oldCompiler = JavaCompiler.instance(context);
|
|
||||||
JavaCompiler nextCompiler = JavaCompiler.instance(next);
|
|
||||||
nextCompiler.initRound(oldCompiler);
|
|
||||||
|
|
||||||
JavacTaskImpl task = context.get(JavacTaskImpl.class);
|
|
||||||
if (task != null) {
|
|
||||||
next.put(JavacTaskImpl.class, task);
|
|
||||||
task.updateContext(next);
|
|
||||||
}
|
|
||||||
|
|
||||||
context.clear();
|
|
||||||
return next;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Called retroactively to determine if a class loader was required,
|
* Called retroactively to determine if a class loader was required,
|
||||||
* after we have failed to create one.
|
* after we have failed to create one.
|
||||||
|
|
|
@ -108,7 +108,6 @@ compiler.warn.illegal.char.for.encoding
|
||||||
compiler.warn.invalid.archive.file
|
compiler.warn.invalid.archive.file
|
||||||
compiler.warn.override.bridge
|
compiler.warn.override.bridge
|
||||||
compiler.warn.position.overflow # CRTable: caused by files with long lines >= 1024 chars
|
compiler.warn.position.overflow # CRTable: caused by files with long lines >= 1024 chars
|
||||||
compiler.warn.proc.file.create.last.round # See CR 6966604
|
|
||||||
compiler.warn.proc.type.already.exists # JavacFiler: just mentioned in TODO
|
compiler.warn.proc.type.already.exists # JavacFiler: just mentioned in TODO
|
||||||
compiler.warn.unchecked.assign # DEAD, replaced by compiler.misc.unchecked.assign
|
compiler.warn.unchecked.assign # DEAD, replaced by compiler.misc.unchecked.assign
|
||||||
compiler.warn.unchecked.cast.to.type # DEAD, replaced by compiler.misc.unchecked.cast.to.type
|
compiler.warn.unchecked.cast.to.type # DEAD, replaced by compiler.misc.unchecked.cast.to.type
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// key: compiler.warn.proc.file.create.last.round
|
||||||
|
// options: -Xlint:processing -processor AnnoProc
|
||||||
|
|
||||||
|
class ProcFileCreateLastRound { }
|
|
@ -0,0 +1,52 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.util.*;
|
||||||
|
import javax.annotation.processing.*;
|
||||||
|
import javax.lang.model.*;
|
||||||
|
import javax.lang.model.element.*;
|
||||||
|
import javax.tools.*;
|
||||||
|
|
||||||
|
@SupportedAnnotationTypes("*")
|
||||||
|
public class AnnoProc extends AbstractProcessor {
|
||||||
|
public boolean process(Set<? extends TypeElement> elems, RoundEnvironment renv) {
|
||||||
|
if (renv.processingOver()) {
|
||||||
|
Filer filer = processingEnv.getFiler();
|
||||||
|
Messager messager = processingEnv.getMessager();
|
||||||
|
try {
|
||||||
|
JavaFileObject fo = filer.createSourceFile("Gen");
|
||||||
|
Writer out = fo.openWriter();
|
||||||
|
out.write("class Gen { }");
|
||||||
|
out.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
messager.printMessage(Diagnostic.Kind.ERROR, e.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SourceVersion getSupportedSourceVersion() {
|
||||||
|
return SourceVersion.latest();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,60 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @test 6966604
|
||||||
|
* @summary JavacFiler not correctly notified of lastRound
|
||||||
|
* @compile TestLastRound.java
|
||||||
|
* @compile/fail/ref=TestLastRound.out -XDrawDiagnostics -Werror -proc:only -processor TestLastRound TestLastRound.java
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.util.*;
|
||||||
|
import javax.annotation.processing.*;
|
||||||
|
import javax.lang.model.*;
|
||||||
|
import javax.lang.model.element.*;
|
||||||
|
import javax.tools.*;
|
||||||
|
|
||||||
|
@SupportedAnnotationTypes("*")
|
||||||
|
public class TestLastRound extends AbstractProcessor {
|
||||||
|
@Override
|
||||||
|
public boolean process(Set<? extends TypeElement> annotations,
|
||||||
|
RoundEnvironment roundEnv) {
|
||||||
|
Filer filer = processingEnv.getFiler();
|
||||||
|
if (roundEnv.processingOver()) {
|
||||||
|
try {
|
||||||
|
JavaFileObject fo = filer.createSourceFile("LastRound.java");
|
||||||
|
Writer out = fo.openWriter();
|
||||||
|
out.write("class LastRound { }");
|
||||||
|
out.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SourceVersion getSupportedSourceVersion() {
|
||||||
|
return SourceVersion.latest();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
- compiler.warn.proc.file.create.last.round: LastRound.java
|
||||||
|
- compiler.err.warnings.and.werror
|
||||||
|
1 error
|
|
@ -42,7 +42,7 @@ public class WErrorGen extends AbstractProcessor {
|
||||||
public boolean process(Set<? extends TypeElement> annotations,
|
public boolean process(Set<? extends TypeElement> annotations,
|
||||||
RoundEnvironment roundEnv) {
|
RoundEnvironment roundEnv) {
|
||||||
Filer filer = processingEnv.getFiler();
|
Filer filer = processingEnv.getFiler();
|
||||||
if (roundEnv.processingOver()) {
|
if (++round == 1) {
|
||||||
try {
|
try {
|
||||||
JavaFileObject fo = filer.createSourceFile("Gen");
|
JavaFileObject fo = filer.createSourceFile("Gen");
|
||||||
Writer out = fo.openWriter();
|
Writer out = fo.openWriter();
|
||||||
|
@ -58,4 +58,6 @@ public class WErrorGen extends AbstractProcessor {
|
||||||
public SourceVersion getSupportedSourceVersion() {
|
public SourceVersion getSupportedSourceVersion() {
|
||||||
return SourceVersion.latest();
|
return SourceVersion.latest();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int round = 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue