public void applyToGeneratedGroovyClasses(GroovyClassOperation body)
      throws CompilationFailedException {
    if (this.phase != Phases.OUTPUT
        && !(this.phase == Phases.CLASS_GENERATION && this.phaseComplete)) {
      throw new GroovyBugError(
          "CompilationUnit not ready for output(). Current phase=" + getPhaseDescription());
    }

    for (GroovyClass gclass : this.generatedClasses) {
      //
      // Get the class and calculate its filesystem name
      //
      try {
        body.call(gclass);

      } catch (CompilationFailedException e) {
        // fall through, getErrorReporter().failIfErrors() will trigger
      } catch (NullPointerException npe) {
        throw npe;
      } catch (GroovyBugError e) {
        changeBugText(e, null);
        throw e;
      } catch (Exception e) {
        throw new GroovyBugError(e);
      }
    }

    getErrorCollector().failIfErrors();
  }
  /**
   * A loop driver for applying operations to all primary ClassNodes in our AST. Automatically skips
   * units that have already been processed through the current phase.
   */
  public void applyToPrimaryClassNodes(PrimaryClassNodeOperation body)
      throws CompilationFailedException {
    // GRECLIPSE: start
    /*old{
    Iterator classNodes = getPrimaryClassNodes(body.needSortedInput()).iterator();
    }*/
    // newcode
    List primaryClassNodes = getPrimaryClassNodes(body.needSortedInput());
    Iterator classNodes = primaryClassNodes.iterator();
    // end
    while (classNodes.hasNext()) {
      SourceUnit context = null;
      try {
        ClassNode classNode = (ClassNode) classNodes.next();
        context = classNode.getModule().getContext();
        // GRECLIPSE get to the bottom of this - why are operations running multiple times that
        // should only run once?
        if (context == null
            || context.phase < phase
            || (context.phase == phase && !context.phaseComplete)) {

          int offset = 1;
          Iterator<InnerClassNode> iterator = classNode.getInnerClasses();
          while (iterator.hasNext()) {
            iterator.next();
            offset++;
          }
          body.call(context, new GeneratorContext(this.ast, offset), classNode);
        }
      } catch (CompilationFailedException e) {
        // fall through, getErrorReporter().failIfErrors() will trigger
      } catch (NullPointerException npe) {
        throw npe;
      } catch (GroovyBugError e) {
        changeBugText(e, context);
        throw e;
      } catch (Exception e) {
        // check the exception for a nested compilation exception
        ErrorCollector nestedCollector = null;
        for (Throwable next = e.getCause(); next != e && next != null; next = next.getCause()) {
          if (!(next instanceof MultipleCompilationErrorsException)) continue;
          MultipleCompilationErrorsException mcee = (MultipleCompilationErrorsException) next;
          nestedCollector = mcee.collector;
          break;
        }

        if (nestedCollector != null) {
          getErrorCollector().addCollectorContents(nestedCollector);
        } else {
          getErrorCollector().addError(new ExceptionMessage(e, configuration.getDebug(), this));
        }
      }
    }

    getErrorCollector().failIfErrors();
  }
  /**
   * A loop driver for applying operations to all SourceUnits. Automatically skips units that have
   * already been processed through the current phase.
   */
  public void applyToSourceUnits(SourceUnitOperation body) throws CompilationFailedException {
    // GRECLIPSE: start
    try {
      iterating = true;
      // end
      for (String name : names) {
        SourceUnit source = sources.get(name);
        if ((source.phase < phase) || (source.phase == phase && !source.phaseComplete)) {
          try {
            body.call(source);
            // GRECLIPSE: start
            if (phase == Phases.CONVERSION
                && getProgressListener() != null
                && body == phaseOperations[phase].getLast()) {
              getProgressListener().parseComplete(phase, name);
            }
            // end
          } catch (CompilationFailedException e) {
            throw e;
          } catch (Exception e) {
            GroovyBugError gbe = new GroovyBugError(e);
            changeBugText(gbe, source);
            throw gbe;
          } catch (GroovyBugError e) {
            changeBugText(e, source);
            throw e;
          }
        }
      }
      // GRECLIPSE: start
    } finally {
      iterating = false;
    }
    // end

    getErrorCollector().failIfErrors();
  }