6966604: JavacFiler not correctly notified of lastRound
authorjjg
Thu, 29 Jul 2010 19:30:35 -0700
changeset 6159 88930a1c409e
parent 6158 d02e088255a0
child 6160 f84f82e24ceb
6966604: JavacFiler not correctly notified of lastRound Reviewed-by: darcy
langtools/src/share/classes/com/sun/tools/javac/processing/JavacFiler.java
langtools/src/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java
langtools/test/tools/javac/diags/examples.not-yet.txt
langtools/test/tools/javac/diags/examples/ProcFileCreateLastRound/ProcFileCreateLastRound.java
langtools/test/tools/javac/diags/examples/ProcFileCreateLastRound/processors/AnnoProc.java
langtools/test/tools/javac/processing/filer/TestLastRound.java
langtools/test/tools/javac/processing/filer/TestLastRound.out
langtools/test/tools/javac/processing/werror/WErrorGen.java
--- a/langtools/src/share/classes/com/sun/tools/javac/processing/JavacFiler.java	Thu Jul 29 19:27:11 2010 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/processing/JavacFiler.java	Thu Jul 29 19:30:35 2010 -0700
@@ -539,11 +539,14 @@
     /**
      * 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);
+        clearRoundState();
+    }
+
+    void setLastRound(boolean lastRound) {
         this.lastRound = lastRound;
-        clearRoundState();
     }
 
     public void close() {
--- a/langtools/src/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java	Thu Jul 29 19:27:11 2010 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java	Thu Jul 29 19:30:35 2010 -0700
@@ -68,7 +68,6 @@
 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;
@@ -759,7 +758,7 @@
         }
 
         @Override
-         public Set<TypeElement> scan(Element e, Set<TypeElement> p) {
+        public Set<TypeElement> scan(Element e, Set<TypeElement> p) {
             for (AnnotationMirror annotationMirror :
                      elements.getAllAnnotationMirrors(e) ) {
                 Element e2 = annotationMirror.getAnnotationType().asElement();
@@ -784,6 +783,237 @@
         }
     }
 
+    /**
+     * Helper object for a single round of annotation processing.
+     */
+    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);
+            return new Round(contextForNextRound(), number + 1);
+        }
+
+        /** 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();
+        }
+
+        /** Return the number of warnings found so far in this round. */
+        int warningCount() {
+            return compiler.warningCount();
+        }
+
+        /** 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);
+        }
+
+        /**
+         * 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() {
+            ClassReader reader = ClassReader.instance(context);
+            Names names = Names.instance(context);
+            List<ClassSymbol> list = List.nil();
+
+            for (Map.Entry<String,JavaFileObject> entry : filer.getGeneratedClasses().entrySet()) {
+                Name name = names.fromString(entry.getKey());
+                JavaFileObject file = entry.getValue();
+                if (file.getKind() != JavaFileObject.Kind.CLASS)
+                    throw new AssertionError(file);
+                ClassSymbol cs;
+                if (isPkgInfo(file, JavaFileObject.Kind.CLASS)) {
+                    Name packageName = Convert.packagePart(name);
+                    PackageSymbol p = reader.enterPackage(packageName);
+                    if (p.package_info == null)
+                        p.package_info = reader.enterClass(Convert.shortName(name), p);
+                    cs = p.package_info;
+                    if (cs.classfile == null)
+                        cs.classfile = file;
+                } else
+                    cs = reader.enterClass(name, file);
+                list = list.prepend(cs);
+            }
+            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
@@ -794,60 +1024,37 @@
         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;
+        Round round = new Round(context, 1);
+        round.compiler.todo.clear(); // free the compiler's resources
 
-        // List<JCAnnotation> annotationsPresentInSource = collector.findAnnotations(roots);
-        List<ClassSymbol> topLevelClasses = getTopLevelClasses(roots);
+        // 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());
 
-        for (ClassSymbol classSym : classSymbols)
-            topLevelClasses = topLevelClasses.prepend(classSym);
-        List<PackageSymbol> packageInfoFiles =
-            getPackageInfoFiles(roots);
+        round.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);
+        round.findAnnotationsPresent(annotationComputer);
 
-        Context currentContext = context;
-
-        int roundNumber = 0;
         boolean errorStatus = false;
 
         runAround:
-        while(true) {
-            if ((fatalErrors && compiler.errorCount() != 0)
-                    || (werror && compiler.warningCount() != 0)) {
+        while (true) {
+            if ((fatalErrors && round.errorCount() != 0)
+                    || (werror && round.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));
-            }
+            round.run(false, false);
 
             /*
              * Processors for round n have run to completion.  Prepare
@@ -858,65 +1065,54 @@
             if (messager.errorRaised()) {
                 errorStatus = true;
                 break runAround;
-            } else {
-                if (moreToDo()) {
-                    // annotationsPresentInSource = List.nil();
-                    annotationsPresent = new LinkedHashSet<TypeElement>();
-                    topLevelClasses  = List.nil();
-                    packageInfoFiles = List.nil();
+            }
 
-                    compiler.close(false);
-                    currentContext = contextForNextRound(currentContext, true);
+            if (!moreToDo())
+                break runAround; // No new files
 
-                    JavaFileManager fileManager = currentContext.get(JavaFileManager.class);
+            round = round.next();
 
-                    compiler = JavaCompiler.instance(currentContext);
-                    List<JCCompilationUnit> parsedFiles = sourcesToParsedFiles(compiler);
-                    roots = cleanTrees(roots).appendList(parsedFiles);
+            List<JCCompilationUnit> parsedFiles = round.parseNewSourceFiles();
+            roots = cleanTrees(roots).appendList(parsedFiles);
 
-                    // Check for errors after parsing
-                    if (log.unrecoverableError) {
-                        errorStatus = true;
-                        break runAround;
-                    } else {
-                        List<ClassSymbol> newClasses = enterNewClassFiles(currentContext);
-                        compiler.enterTrees(roots);
+            // Check for errors after parsing
+            if (round.unrecoverableError()) {
+                errorStatus = true;
+                break runAround;
+            }
+
+            List<ClassSymbol> newClasses = round.enterNewClassFiles();
+            round.enterTrees(roots);
 
-                        // annotationsPresentInSource =
-                        // collector.findAnnotations(parsedFiles);
-                        ListBuffer<ClassSymbol> tlc = new ListBuffer<ClassSymbol>();
-                        tlc.appendList(getTopLevelClasses(parsedFiles));
-                        tlc.appendList(getTopLevelClassesFromClasses(newClasses));
-                        topLevelClasses  = tlc.toList();
+            round.topLevelClasses = join(
+                    getTopLevelClasses(parsedFiles),
+                    getTopLevelClassesFromClasses(newClasses));
 
-                        ListBuffer<PackageSymbol> pif = new ListBuffer<PackageSymbol>();
-                        pif.appendList(getPackageInfoFiles(parsedFiles));
-                        pif.appendList(getPackageInfoFilesFromClasses(newClasses));
-                        packageInfoFiles = pif.toList();
+            round.packageInfoFiles = join(
+                    getPackageInfoFiles(parsedFiles),
+                    getPackageInfoFilesFromClasses(newClasses));
 
-                        annotationsPresent = new LinkedHashSet<TypeElement>();
-                        for (ClassSymbol classSym : topLevelClasses)
-                            annotationComputer.scan(classSym, annotationsPresent);
-                        for (PackageSymbol pkgSym : packageInfoFiles)
-                            annotationComputer.scan(pkgSym, annotationsPresent);
+            round.findAnnotationsPresent(annotationComputer);
+            round.updateProcessingState();
+        }
+
+        // run last round
+        round.run(true, errorStatus);
 
-                        updateProcessingState(currentContext, false);
-                    }
-                } else
-                    break runAround; // No new files
-            }
+        // 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);
         }
-        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))
+        if (round.unrecoverableError() || (werror && round.warningCount() != 0))
             errorStatus = true;
 
-        compiler.close(false);
-        currentContext = contextForNextRound(currentContext, true);
-        compiler = JavaCompiler.instance(currentContext);
+        round = round.next();
 
-        filer.newRound(currentContext, true);
         filer.warnIfUnclosedFiles();
         warnIfUnmatchedOptions();
 
@@ -933,142 +1129,43 @@
         */
         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
-            compiler.close(false);
-            currentContext = contextForNextRound(currentContext, true);
-            this.context = currentContext;
-            updateProcessingState(currentContext, true);
-            compiler = JavaCompiler.instance(currentContext);
+            round = round.next();
+            round.updateProcessingState();
+            compiler = round.compiler;
             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()));
-            }
+            compiler.enterTrees(cleanTrees(roots));
         }
 
         return compiler;
     }
 
-    private List<JCCompilationUnit> sourcesToParsedFiles(JavaCompiler compiler)
-        throws IOException {
-        List<JavaFileObject> fileObjects = List.nil();
-        for (JavaFileObject jfo : filer.getGeneratedSourceFileObjects() ) {
-            fileObjects = fileObjects.prepend(jfo);
-        }
-
-       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);
-        List<ClassSymbol> list = List.nil();
-
-        for (Map.Entry<String,JavaFileObject> entry : filer.getGeneratedClasses().entrySet()) {
-            Name name = names.fromString(entry.getKey());
-            JavaFileObject file = entry.getValue();
-            if (file.getKind() != JavaFileObject.Kind.CLASS)
-                throw new AssertionError(file);
-            ClassSymbol cs;
-            if (isPkgInfo(file, JavaFileObject.Kind.CLASS)) {
-                Name packageName = Convert.packagePart(name);
-                PackageSymbol p = reader.enterPackage(packageName);
-                if (p.package_info == null)
-                    p.package_info = reader.enterClass(Convert.shortName(name), p);
-                cs = p.package_info;
-                if (cs.classfile == null)
-                    cs.classfile = file;
-            } else
-                cs = reader.enterClass(name, file);
-            list = list.prepend(cs);
-        }
-        return list.reverse();
-    }
-
     /**
      * Free resources related to annotation processing.
      */
@@ -1123,6 +1220,11 @@
         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 @@
         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.
--- a/langtools/test/tools/javac/diags/examples.not-yet.txt	Thu Jul 29 19:27:11 2010 -0700
+++ b/langtools/test/tools/javac/diags/examples.not-yet.txt	Thu Jul 29 19:30:35 2010 -0700
@@ -108,7 +108,6 @@
 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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/diags/examples/ProcFileCreateLastRound/ProcFileCreateLastRound.java	Thu Jul 29 19:30:35 2010 -0700
@@ -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 { }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/diags/examples/ProcFileCreateLastRound/processors/AnnoProc.java	Thu Jul 29 19:30:35 2010 -0700
@@ -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();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/processing/filer/TestLastRound.java	Thu Jul 29 19:30:35 2010 -0700
@@ -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();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/processing/filer/TestLastRound.out	Thu Jul 29 19:30:35 2010 -0700
@@ -0,0 +1,3 @@
+- compiler.warn.proc.file.create.last.round: LastRound.java
+- compiler.err.warnings.and.werror
+1 error
--- a/langtools/test/tools/javac/processing/werror/WErrorGen.java	Thu Jul 29 19:27:11 2010 -0700
+++ b/langtools/test/tools/javac/processing/werror/WErrorGen.java	Thu Jul 29 19:30:35 2010 -0700
@@ -42,7 +42,7 @@
     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 SourceVersion getSupportedSourceVersion() {
         return SourceVersion.latest();
     }
+
+    int round = 0;
 }