/**
   * 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;
  }
  /**
   * Translate the given abstract syntax trees to elements.
   *
   * @param trees a list of abstract syntax trees.
   * @throws java.io.IOException TODO
   * @return a list of elements corresponding to the top level classes in the abstract syntax trees
   */
  public Iterable<? extends TypeElement> enter(Iterable<? extends CompilationUnitTree> trees)
      throws IOException {
    prepareCompiler();

    ListBuffer<JCCompilationUnit> roots = null;

    if (trees == null) {
      // If there are still files which were specified to be compiled
      // (i.e. in fileObjects) but which have not yet been entered,
      // then we make sure they have been parsed and add them to the
      // list to be entered.
      if (notYetEntered.size() > 0) {
        if (!parsed) parse(); // TODO would be nice to specify files needed to be parsed
        for (JavaFileObject file : fileObjects) {
          JCCompilationUnit unit = notYetEntered.remove(file);
          if (unit != null) {
            if (roots == null) roots = new ListBuffer<JCCompilationUnit>();
            roots.append(unit);
          }
        }
        notYetEntered.clear();
      }
    } else {
      for (CompilationUnitTree cu : trees) {
        if (cu instanceof JCCompilationUnit) {
          if (roots == null) roots = new ListBuffer<JCCompilationUnit>();
          roots.append((JCCompilationUnit) cu);
          notYetEntered.remove(cu.getSourceFile());
        } else throw new IllegalArgumentException(cu.toString());
      }
    }

    if (roots == null) return List.nil();

    try {
      List<JCCompilationUnit> units = compiler.enterTrees(roots.toList());

      if (notYetEntered.isEmpty()) compiler = compiler.processAnnotations(units);

      ListBuffer<TypeElement> elements = new ListBuffer<TypeElement>();
      for (JCCompilationUnit unit : units) {
        for (JCTree node : unit.defs) {
          if (node.getTag() == JCTree.CLASSDEF) {
            JCClassDecl cdef = (JCClassDecl) node;
            if (cdef.sym != null) // maybe null if errors in anno processing
            elements.append(cdef.sym);
          }
        }
      }
      return elements.toList();
    } finally {
      compiler.log.flush();
    }
  }
 void cleanup() {
   if (compiler != null) compiler.close();
   compiler = null;
   compilerMain = null;
   args = null;
   classNames = null;
   context = null;
   fileObjects = null;
   notYetEntered = null;
 }
  // 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;
  }
 /**
  * Parse the specified files returning a list of abstract syntax trees.
  *
  * @throws java.io.IOException TODO
  * @return a list of abstract syntax trees
  */
 public Iterable<? extends CompilationUnitTree> parse() throws IOException {
   try {
     prepareCompiler();
     List<JCCompilationUnit> units = compiler.parseFiles(fileObjects);
     for (JCCompilationUnit unit : units) {
       JavaFileObject file = unit.getSourceFile();
       if (notYetEntered.containsKey(file)) notYetEntered.put(file, unit);
     }
     return units;
   } finally {
     parsed = true;
     if (compiler != null && compiler.log != null) compiler.log.flush();
   }
 }
 /** For internal use only. This method will be removed without warning. */
 public Type parseType(String expr, TypeElement scope) {
   if (expr == null || expr.equals("")) throw new IllegalArgumentException();
   compiler = JavaCompiler.instance(context);
   JavaFileObject prev = compiler.log.useSource(null);
   ParserFactory parserFactory = ParserFactory.instance(context);
   Attr attr = Attr.instance(context);
   try {
     CharBuffer buf = CharBuffer.wrap((expr + "\u0000").toCharArray(), 0, expr.length());
     Parser parser = parserFactory.newParser(buf, false, false, false);
     JCTree tree = parser.parseType();
     return attr.attribType(tree, (Symbol.TypeSymbol) scope);
   } finally {
     compiler.log.useSource(prev);
   }
 }
 private void prepareCompiler() throws IOException {
   if (used.getAndSet(true)) {
     if (compiler == null) throw new IllegalStateException();
   } else {
     initContext();
     compilerMain.setOptions(Options.instance(context));
     compilerMain.filenames = new LinkedHashSet<File>();
     Collection<File> filenames = compilerMain.processArgs(CommandLine.parse(args), classNames);
     if (!filenames.isEmpty())
       throw new IllegalArgumentException("Malformed arguments " + toString(filenames, " "));
     compiler = JavaCompiler.instance(context);
     compiler.keepComments = true;
     compiler.genEndPos = true;
     // NOTE: this value will be updated after annotation processing
     compiler.initProcessAnnotations(processors);
     notYetEntered = new HashMap<JavaFileObject, JCCompilationUnit>();
     for (JavaFileObject file : fileObjects) notYetEntered.put(file, null);
     genList = new ListBuffer<Env<AttrContext>>();
     // endContext will be called when all classes have been generated
     // TODO: should handle the case after each phase if errors have occurred
     args = null;
     classNames = null;
   }
 }