mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-20 11:04:34 +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.
|
||||
*/
|
||||
public void newRound(Context context, boolean lastRound) {
|
||||
public void newRound(Context context) {
|
||||
this.context = context;
|
||||
this.log = Log.instance(context);
|
||||
this.lastRound = lastRound;
|
||||
clearRoundState();
|
||||
}
|
||||
|
||||
void setLastRound(boolean lastRound) {
|
||||
this.lastRound = lastRound;
|
||||
}
|
||||
|
||||
public void close() {
|
||||
clearRoundState();
|
||||
// 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.Convert;
|
||||
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.JavacMessages;
|
||||
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
|
||||
// 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.
|
||||
/**
|
||||
* Helper object for a single round of annotation processing.
|
||||
*/
|
||||
if (messager.errorRaised()) {
|
||||
errorStatus = true;
|
||||
break runAround;
|
||||
} else {
|
||||
if (moreToDo()) {
|
||||
// annotationsPresentInSource = List.nil();
|
||||
class Round {
|
||||
/** The round number. */
|
||||
final int number;
|
||||
/** The context for the round. */
|
||||
final Context context;
|
||||
/** 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>();
|
||||
topLevelClasses = List.nil();
|
||||
packageInfoFiles = List.nil();
|
||||
}
|
||||
|
||||
/** Create the next round to be used. */
|
||||
Round next() {
|
||||
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);
|
||||
List<JCCompilationUnit> parsedFiles = sourcesToParsedFiles(compiler);
|
||||
roots = cleanTrees(roots).appendList(parsedFiles);
|
||||
/** Return the number of warnings found so far in this round. */
|
||||
int warningCount() {
|
||||
return compiler.warningCount();
|
||||
}
|
||||
|
||||
// Check for errors after parsing
|
||||
if (log.unrecoverableError) {
|
||||
errorStatus = true;
|
||||
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();
|
||||
/** Return whether or not an unrecoverable error has occurred. */
|
||||
boolean unrecoverableError() {
|
||||
return log.unrecoverableError;
|
||||
}
|
||||
|
||||
/** 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>();
|
||||
for (ClassSymbol classSym : topLevelClasses)
|
||||
annotationComputer.scan(classSym, annotationsPresent);
|
||||
for (PackageSymbol pkgSym : packageInfoFiles)
|
||||
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);
|
||||
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.
|
||||
/**
|
||||
* Parse the latest set of generated source files created by the filer.
|
||||
*/
|
||||
errorStatus = errorStatus || messager.errorRaised();
|
||||
|
||||
|
||||
// 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)
|
||||
List<JCCompilationUnit> parseNewSourceFiles()
|
||||
throws IOException {
|
||||
List<JavaFileObject> fileObjects = List.nil();
|
||||
for (JavaFileObject jfo : filer.getGeneratedSourceFileObjects() ) {
|
||||
|
@ -980,72 +866,10 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea
|
|||
return compiler.parseFiles(fileObjects);
|
||||
}
|
||||
|
||||
// Call the last round of annotation processing
|
||||
private List<JCCompilationUnit> runLastRound(int roundNumber,
|
||||
boolean errorStatus,
|
||||
JavaCompiler compiler,
|
||||
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);
|
||||
/** Enter the latest set of generated class files created by the filer. */
|
||||
List<ClassSymbol> enterNewClassFiles() {
|
||||
ClassReader reader = ClassReader.instance(context);
|
||||
Names names = Names.instance(context);
|
||||
List<ClassSymbol> list = List.nil();
|
||||
|
||||
for (Map.Entry<String,JavaFileObject> entry : filer.getGeneratedClasses().entrySet()) {
|
||||
|
@ -1069,6 +893,279 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea
|
|||
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.
|
||||
*/
|
||||
|
@ -1123,6 +1220,11 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea
|
|||
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) {
|
||||
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);
|
||||
}
|
||||
|
||||
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,
|
||||
* after we have failed to create one.
|
||||
|
|
|
@ -108,7 +108,6 @@ compiler.warn.illegal.char.for.encoding
|
|||
compiler.warn.invalid.archive.file
|
||||
compiler.warn.override.bridge
|
||||
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.unchecked.assign # DEAD, replaced by compiler.misc.unchecked.assign
|
||||
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,
|
||||
RoundEnvironment roundEnv) {
|
||||
Filer filer = processingEnv.getFiler();
|
||||
if (roundEnv.processingOver()) {
|
||||
if (++round == 1) {
|
||||
try {
|
||||
JavaFileObject fo = filer.createSourceFile("Gen");
|
||||
Writer out = fo.openWriter();
|
||||
|
@ -58,4 +58,6 @@ public class WErrorGen extends AbstractProcessor {
|
|||
public SourceVersion getSupportedSourceVersion() {
|
||||
return SourceVersion.latest();
|
||||
}
|
||||
|
||||
int round = 0;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue