code: public void applyToPrimaryClassNodes(PrimaryClassNodeOperation body) throws CompilationFailedException {
          Iterator classNodes = getPrimaryClassNodes(body.needSortedInput()).iterator();
          while (classNodes.hasNext()) {
              SourceUnit context = null;
              try {
                  ClassNode classNode = (ClassNode) classNodes.next();
                  context = classNode.getModule().getContext();
                  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) {
                  GroovyBugError gbe = new GroovyBugError("unexpected NullpointerException", npe);
                  changeBugText(gbe, context);
                  throw gbe;
              } catch (GroovyBugError e) {
                  changeBugText(e, context);
                  throw e;
              } catch (NoClassDefFoundError e) {
                  // effort to get more logging in case a dependency of a class is loaded
                  // although it shouldn't have
                  convertUncaughtExceptionToCompilationError(e);
              } catch (Exception e) {
                  convertUncaughtExceptionToCompilationError(e);
              }
          }
  
          getErrorCollector().failIfErrors();
      }
docs: 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.