JDK-6403468 : JSR269: processors raising errors doesn't result in nonzero exit code
Type:Bug
Component:core-libs
Sub-Component:javax.annotation.processing
Affected Version:6
Priority:P2
Status:Closed
Resolution:Fixed
OS:generic
CPU:generic
Submitted:2006-03-24
Updated:2010-04-02
Resolved:2006-05-30
The Version table provides details related to the release that this issue/RFE will be addressed.
Unresolved : Release in which this issue/RFE will be addressed. Resolved: Release in which this issue/RFE has been resolved. Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.
Even when a processor raises an error, a zero exist status can be returned from the javac process. A processor raises an error should always be considered an erroneous exist status.
Comments
SUGGESTED FIX
src/share/classes/com/sun/tools/javac/main>sccs sccsdiff -r1.101 -r1.102 JavaCompiler.java
------- JavaCompiler.java -------
415a416,421
>
> /** Whether or not any parse errors have occurred.
> */
> public boolean parseErrors() {
> return parseErrors;
> }
450a457
> int initialErrorCount = log.nerrors;
453a461
> parseErrors |= (log.nerrors > initialErrorCount);
616a625,627
>
> /** Track whether any errors occurred while parsing source text. */
> private boolean parseErrors = false;
791,793d801
< if (processors != null)
< // FIXME: should be removed when merging with Joe's changes of b83
< System.err.println("Got annotation processors: " + processors);
800c808
< procEnvImpl = new JavacProcessingEnvironment(context);
---
> procEnvImpl = new JavacProcessingEnvironment(context, processors);
808c816
< keepComments = true;
---
> keepComments = true;
810a819,820
>
>
src/share/classes/com/sun/tools/javac/processing>sccs sccsdiff -r1.18 -r1.19 JavacProcessingEnvironment.java
------- JavacProcessingEnvironment.java -------
113c113
< public JavacProcessingEnvironment(Context context) {
---
> public JavacProcessingEnvironment(Context context, Iterable<? extends Processor> processors) {
133c133
< initProcessorIterator(context);
---
> initProcessorIterator(context, processors);
148,149c148
< // TODO: Should accomodate a passed-in Processor object
< private void initProcessorIterator(Context context) {
---
> private void initProcessorIterator(Context context, Iterable<? extends Processor> processors) {
152c151
< Iterator<Processor> processorIterator;
---
> Iterator<? extends Processor> processorIterator;
166a166,167
> } else if (processors != null) {
> processorIterator = processors.iterator();
380,385d380
< /*
< * Compare the ordinal positions of the two kinds of
< * enums; the Source enum's first value is "1.2" so its
< * ordinal is offset by 2 compared to the corresponding
< * SourceVersion enum.
< */
508c503
< Iterator<Processor> processorIterator;
---
> Iterator<? extends Processor> processorIterator;
515c510
< DiscoveredProcessors(Iterator<Processor> processorIterator) {
---
> DiscoveredProcessors(Iterator<? extends Processor> processorIterator) {
521,523c516,518
< public void discovery(Context context,
< java.util.Set<TypeElement> annotationsPresent,
< java.util.List<ClassSymbol> topLevelClasses) {
---
> private void discoverAndRunProcs(Context context,
> java.util.Set<TypeElement> annotationsPresent,
> java.util.List<ClassSymbol> topLevelClasses) {
658a654
>
682c678
< // Use annotation processing to compute set of annotation present
---
> // Use annotation processing to compute the set of annotations present
691d686
< boolean lastRound = false;
699c694
<
---
> runAround:
703,715c698,700
<
< if (printRounds || verbose) {
< xout.format("Round %d:" +
< "%n\tinput files: {%s}" +
< "%n\tannotations: %s" +
< "%n\tlast round: %b%n",
< roundNumber,
< topLevelClasses.toString(", "),
< annotationsPresent,
< lastRound);
< }
<
< if (taskListener != null)
---
> printRoundInfo(xout, roundNumber, topLevelClasses, annotationsPresent, false);
>
> if (taskListener != null)
717c702
<
---
>
719,739c704
< if (!lastRound) {
< discovery(currentContext,
< annotationsPresent,
< topLevelClasses);
< // annotationsPresentInSource = com.sun.tools.javac.util.List.nil();
< annotationsPresent = new LinkedHashSet<TypeElement>();
< topLevelClasses = com.sun.tools.javac.util.List.nil();
<
< // System.out.println("moreToDo? : " + moreToDo());
< // System.out.println("error raised? : " + errorRaised());
<
< lastRound = !moreToDo();
< } else {
< Set<? extends TypeElement> emptyTypeElements = Collections.emptySet();
< RoundEnvironment renv = new JavacRoundEnvironment(true,
< errorStatus,
< emptyTypeElements);
< // System.out.println("Running contributing procs for last round...");
< discoveredProcs.iterator().runContributingProcs(renv);
< break;
< }
---
> discoverAndRunProcs(currentContext, annotationsPresent, topLevelClasses);
741c706
< if (taskListener != null)
---
> if (taskListener != null)
744d708
<
746,748c710,723
< errorStatus = errorRaised();
< compiler.close();
< currentContext = contextForNextRound(currentContext, true);
---
> /*
> * 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;
> } else {
> if (moreToDo()) {
> // annotationsPresentInSource = com.sun.tools.javac.util.List.nil();
> annotationsPresent = new LinkedHashSet<TypeElement>();
> topLevelClasses = com.sun.tools.javac.util.List.nil();
750c725,728
< JavaFileManager fileManager = currentContext.get(JavaFileManager.class);
---
> compiler.close();
> currentContext = contextForNextRound(currentContext, true);
>
> JavaFileManager fileManager = currentContext.get(JavaFileManager.class);
752,757c730,735
< com.sun.tools.javac.util.List<JavaFileObject> fileObjects =
< com.sun.tools.javac.util.List.nil();
< for (JavaFileObject jfo : filer.getGeneratedSourceFileObjects() ) {
< aggregateSourceFileObjects = aggregateSourceFileObjects.prepend(jfo);
< fileObjects = fileObjects.prepend(jfo);
< }
---
> com.sun.tools.javac.util.List<JavaFileObject> fileObjects =
> com.sun.tools.javac.util.List.nil();
> for (JavaFileObject jfo : filer.getGeneratedSourceFileObjects() ) {
> aggregateSourceFileObjects = aggregateSourceFileObjects.prepend(jfo);
> fileObjects = fileObjects.prepend(jfo);
> }
759,763c737,746
<
< compiler = JavaCompiler.instance(currentContext);
< com.sun.tools.javac.util.List<JCCompilationUnit> parsedFiles =
< compiler.parseFiles(fileObjects);
< parsedFiles = compiler.enterTrees(parsedFiles);
---
> compiler = JavaCompiler.instance(currentContext);
> com.sun.tools.javac.util.List<JCCompilationUnit> parsedFiles =
> compiler.parseFiles(fileObjects);
>
> // Check for errors after parsing
> if (compiler.parseErrors()) {
> errorStatus = true;
> break runAround;
> } else {
> parsedFiles = compiler.enterTrees(parsedFiles);
765,767c748,751
< // annotationsPresentInSource =
< // collector.findAnnotations(parsedFiles);
< topLevelClasses = getTopLevelClasses(parsedFiles);
---
> // annotationsPresentInSource =
> // collector.findAnnotations(parsedFiles);
> topLevelClasses = getTopLevelClasses(parsedFiles);
> topLevelClasses = enterNewClassFiles(currentContext, topLevelClasses);
769,777c753,755
< ClassReader reader = ClassReader.instance(currentContext);
< Name.Table names = Name.Table.instance(currentContext);
< for (Map.Entry<String,JavaFileObject> entry : filer.getGeneratedClasses().entrySet()) {
< ClassSymbol cs = reader.enterClass(names.fromString(entry.getKey()));
<
< assert cs.completer != null : cs;
< assert cs.classfile == null : cs.classfile;
< assert cs.sourcefile == null : cs.sourcefile;
< cs.classfile = entry.getValue();
---
> annotationsPresent = new LinkedHashSet<TypeElement>();
> for (ClassSymbol classSym : topLevelClasses)
> annotationComputer.scan(classSym, annotationsPresent);
779c757,760
< topLevelClasses = topLevelClasses.prepend(cs);
---
> updateProcessingState(currentContext, false);
> }
> } else
> break runAround; // No new files
781,791d761
<
< annotationsPresent = new LinkedHashSet<TypeElement>();
< for (ClassSymbol classSym : topLevelClasses)
< annotationComputer.scan(classSym, annotationsPresent);
<
< // System.out.println("\tTop level classes: " + topLevelClasses.toString(", "));
< filer.newRound(currentContext, lastRound);
< messager.newRound(currentContext);
<
< elementUtils.setContext(currentContext);
< typeUtils.setContext(currentContext);
792a763
> runLastRound(xout, roundNumber, errorStatus, taskListener);
797c768
< filer.newRound(currentContext, lastRound);
---
> filer.newRound(currentContext, true);
801c772,783
< errorStatus = 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.
> */
> errorStatus = errorStatus || messager.errorRaised();
802a785
>
806,808c789,791
< if (taskListener != null)
< taskListener.finished(new TaskEvent(TaskEvent.Kind.ANNOTATION_PROCESSING));
<
---
> if (taskListener != null)
> taskListener.finished(new TaskEvent(TaskEvent.Kind.ANNOTATION_PROCESSING));
>
809a793
> compiler.log.nerrors += messager.errorCount();
835a820,853
> // Call the last round of annotation processing
> private void runLastRound(PrintWriter xout,
> int roundNumber,
> boolean errorStatus,
> TaskListener taskListener) throws IOException {
> roundNumber++;
> com.sun.tools.javac.util.List<ClassSymbol> noTopLevelClasses =
> com.sun.tools.javac.util.List.nil();
> Set<TypeElement> noAnnotations = Collections.emptySet();
> printRoundInfo(xout, roundNumber, noTopLevelClasses, noAnnotations, true);
>
> Set<? extends TypeElement> emptyTypeElements = Collections.emptySet();
> RoundEnvironment renv = new JavacRoundEnvironment(true,
> errorStatus,
> emptyTypeElements);
> 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));
> }
> }
>
> private void updateProcessingState(Context currentContext, boolean lastRound) {
> filer.newRound(currentContext, lastRound);
> messager.newRound(currentContext);
>
> elementUtils.setContext(currentContext);
> typeUtils.setContext(currentContext);
> }
>
841a860,894
> private void printRoundInfo(PrintWriter xout,
> int roundNumber,
> com.sun.tools.javac.util.List<ClassSymbol> topLevelClasses,
> Set<TypeElement> annotationsPresent,
> boolean lastRound) {
> if (printRounds || verbose) {
> xout.format("Round %d:" +
> "%n\tinput files: {%s}" +
> "%n\tannotations: %s" +
> "%n\tlast round: %b%n",
> roundNumber,
> topLevelClasses.toString(", "),
> annotationsPresent,
> lastRound);
> }
> }
>
> private com.sun.tools.javac.util.List<ClassSymbol> enterNewClassFiles(Context currentContext,
> com.sun.tools.javac.util.List<ClassSymbol> topLevelClasses) {
> ClassReader reader = ClassReader.instance(currentContext);
> Name.Table names = Name.Table.instance(currentContext);
>
> for (Map.Entry<String,JavaFileObject> entry : filer.getGeneratedClasses().entrySet()) {
> ClassSymbol cs = reader.enterClass(names.fromString(entry.getKey()));
>
> assert cs.completer != null : cs;
> assert cs.classfile == null : cs.classfile;
> assert cs.sourcefile == null : cs.sourcefile;
> cs.classfile = entry.getValue();
>
> topLevelClasses = topLevelClasses.prepend(cs);
> }
> return topLevelClasses;
> }
>
1032,1033c1085,1086
< public boolean moreToDo() {
< return filer.newFiles() && !messager.errorRaised();
---
> private boolean moreToDo() {
> return filer.newFiles();
1036,1040d1088
< // TODO: Should some flavor's of log's error be checked here too?
< public boolean errorRaised() {
< return messager.errorRaised();
< }
<
1206c1254
< for(String s : optionName.split("\\.")) {
---
> for(String s : optionName.split("\\.", -1)) {
src/share/classes/com/sun/tools/javac/processing>sccs sccsdiff -r1.7 -r1.8 JavacMessager.java
------- JavacMessager.java -------
145a146,149
> public int errorCount() {
> return errorCount;
> }
>