/**
   * Generate code corresponding to the given classes. The classes must have previously been
   * returned from {@link #enter}. If there are classes outstanding to be analyzed, that will be
   * done before any classes are generated. If null is specified, code will be generated for all
   * outstanding classes.
   *
   * @param classes a list of class elements
   */
  public Iterable<? extends JavaFileObject> generate(Iterable<? extends TypeElement> classes)
      throws IOException {
    final ListBuffer<JavaFileObject> results = new ListBuffer<JavaFileObject>();
    try {
      analyze(null); // ensure all classes have been parsed, entered, and analyzed

      if (classes == null) {
        compiler.generate(compiler.desugar(genList), results);
        genList.clear();
      } else {
        Filter f =
            new Filter() {
              public void process(Env<AttrContext> env) {
                compiler.generate(compiler.desugar(ListBuffer.of(env)), results);
              }
            };
        f.run(genList, classes);
      }
      if (genList.isEmpty()) {
        compiler.reportDeferredDiagnostics();
        cleanup();
      }
    } finally {
      if (compiler != null) compiler.log.flush();
    }
    return results;
  }
  // This implementation requires that we open up privileges on JavaCompiler.
  // An alternative implementation would be to move this code to JavaCompiler and
  // wrap it here
  public Iterable<? extends Element> analyze(Iterable<? extends TypeElement> classes)
      throws IOException {
    enter(null); // ensure all classes have been entered

    final ListBuffer<Element> results = new ListBuffer<Element>();
    try {
      if (classes == null) {
        handleFlowResults(compiler.flow(compiler.attribute(compiler.todo)), results);
      } else {
        Filter f =
            new Filter() {
              public void process(Env<AttrContext> env) {
                handleFlowResults(compiler.flow(compiler.attribute(env)), results);
              }
            };
        f.run(compiler.todo, classes);
      }
    } finally {
      compiler.log.flush();
    }
    return results;
  }