/** Run a processing round. */
    void run(boolean lastRound, boolean errorStatus) {
      printRoundInfo(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));
      }

      nMessagerErrors = messager.errorCount();
    }
 public static void add(ProcessingEnvironment env, Runnable r) {
   try {
     JavacTask task = JavacTask.instance(env);
     TaskListener l = ((BasicJavacTask) task).getTaskListeners().iterator().next();
     // The TaskListener is an instanceof TestClose, but when using the
     // default class loaders. the taskListener uses a different
     // instance of Class<TestClose> than the anno processor.
     // If you try to evaluate
     //      TestClose tc = (TestClose) (l).
     // you get the following somewhat confusing error:
     //   java.lang.ClassCastException: TestClose cannot be cast to TestClose
     // The workaround is to access the fields of TestClose with reflection.
     Field f = l.getClass().getField("runnables");
     @SuppressWarnings("unchecked")
     List<Runnable> runnables = (List<Runnable>) f.get(l);
     runnables.add(r);
   } catch (Throwable t) {
     t.printStackTrace();
   }
 }
  // 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;
  }