/** Create a new round. */
    private Round(
        Round prev, Set<JavaFileObject> newSourceFiles, Map<String, JavaFileObject> newClassFiles) {
      this(prev.nextContext(), prev.number + 1, prev.nMessagerErrors, prev.compiler.log.nwarnings);
      this.genClassFiles = prev.genClassFiles;

      List<JCCompilationUnit> parsedFiles = compiler.parseFiles(newSourceFiles);
      roots = cleanTrees(prev.roots).appendList(parsedFiles);

      // Check for errors after parsing
      if (unrecoverableError()) return;

      enterClassFiles(genClassFiles);
      List<ClassSymbol> newClasses = enterClassFiles(newClassFiles);
      genClassFiles.putAll(newClassFiles);
      enterTrees(roots);

      if (unrecoverableError()) return;

      topLevelClasses =
          join(getTopLevelClasses(parsedFiles), getTopLevelClassesFromClasses(newClasses));

      packageInfoFiles =
          join(getPackageInfoFiles(parsedFiles), getPackageInfoFilesFromClasses(newClasses));

      findAnnotationsPresent();
    }
  // 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) {

    TaskListener taskListener = context.get(TaskListener.class);
    log = Log.instance(context);

    Set<PackageSymbol> specifiedPackages = new LinkedHashSet<PackageSymbol>();
    for (PackageSymbol psym : pckSymbols) specifiedPackages.add(psym);
    this.specifiedPackages = Collections.unmodifiableSet(specifiedPackages);

    Round round = new Round(context, roots, classSymbols);

    boolean errorStatus;
    boolean moreToDo;
    do {
      // Run processors for round n
      round.run(false, false);

      // Processors for round n have run to completion.
      // Check for errors and whether there is more work to do.
      errorStatus = round.unrecoverableError();
      moreToDo = moreToDo();

      round.showDiagnostics(errorStatus || showResolveErrors);

      // Set up next round.
      // Copy mutable collections returned from filer.
      round =
          round.next(
              new LinkedHashSet<JavaFileObject>(filer.getGeneratedSourceFileObjects()),
              new LinkedHashMap<String, JavaFileObject>(filer.getGeneratedClasses()));

      // Check for errors during setup.
      if (round.unrecoverableError()) errorStatus = true;

    } while (moreToDo && !errorStatus);

    // run last round
    round.run(true, errorStatus);
    round.showDiagnostics(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.
     */
    if (messager.errorRaised() || werror && round.warningCount() > 0 && round.errorCount() > 0)
      errorStatus = true;

    Set<JavaFileObject> newSourceFiles =
        new LinkedHashSet<JavaFileObject>(filer.getGeneratedSourceFileObjects());
    roots = cleanTrees(round.roots);

    JavaCompiler compiler = round.finalCompiler(errorStatus);

    if (newSourceFiles.size() > 0) roots = roots.appendList(compiler.parseFiles(newSourceFiles));

    errorStatus = errorStatus || (compiler.errorCount() > 0);

    // Free resources
    this.close();

    if (taskListener != null)
      taskListener.finished(new TaskEvent(TaskEvent.Kind.ANNOTATION_PROCESSING));

    if (errorStatus) {
      if (compiler.errorCount() == 0) compiler.log.nerrors++;
      return compiler;
    }

    if (procOnly && !foundTypeProcessors) {
      compiler.todo.clear();
    } else {
      if (procOnly && foundTypeProcessors) compiler.shouldStopPolicy = CompileState.FLOW;

      compiler.enterTrees(roots);
    }

    return compiler;
  }