You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by su...@apache.org on 2019/12/17 03:57:44 UTC

[groovy] branch GROOVY_3_0_X updated (0041f71 -> 19e5949)

This is an automated email from the ASF dual-hosted git repository.

sunlan pushed a change to branch GROOVY_3_0_X
in repository https://gitbox.apache.org/repos/asf/groovy.git.


    from 0041f71  add test cases and other minor edits
     new 8c63690  minor edits
     new 9ca3b4f  handle SourceUnitOperation, GroovyClassOperation, etc. polymorphically
     new 0e74933  normalize addPhaseOperations()
     new 6e60396  add functional interfaces for phase operations to support lambdas
     new 19e5949  minor edits

The 5 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../groovy/tools/ast/TransformTestHelper.groovy    |   8 +-
 src/main/java/groovy/lang/GroovyClassLoader.java   |   2 +-
 src/main/java/groovy/util/GroovyScriptEngine.java  |  17 +-
 .../java/org/codehaus/groovy/ast/ClassHelper.java  |  27 +-
 .../org/codehaus/groovy/ast/VariableScope.java     |   3 +-
 .../groovy/classgen/asm/InvocationWriter.java      |   7 +-
 .../codehaus/groovy/control/CompilationUnit.java   | 983 ++++++++++-----------
 .../groovy/control/CompilerConfiguration.java      |   2 +-
 .../groovy/control/DefaultTransformer.java         |  69 --
 .../groovy/control/ParserPluginFactory.java        |  38 +-
 .../java/org/codehaus/groovy/control/Phases.java   |  57 +-
 .../codehaus/groovy/control/ResolveVisitor.java    |   4 +-
 .../groovy/control/StaticImportVisitor.java        |  22 +-
 .../control/customizers/CompilationCustomizer.java |   4 +-
 .../tools/javac/JavaAwareCompilationUnit.java      |  40 +-
 .../tools/javac/JavaStubCompilationUnit.java       |  26 +-
 .../groovy/transform/ASTTransformationVisitor.java |  37 +-
 .../transform/sc/StaticCompilationVisitor.java     |  14 +-
 .../transform/trait/TraitASTTransformation.java    |  23 +-
 src/test/groovy/lang/GroovyClassLoaderTest.groovy  |   4 +-
 .../ClosureAndInnerClassNodeStructureTest.groovy   |   4 +-
 .../asm/sc/StaticCompilationTestSupport.groovy     |   4 +-
 .../codehaus/groovy/tools/gse/DependencyTest.java  |  41 +-
 .../console/ui/AstNodeToScriptAdapter.groovy       |   3 +-
 .../console/ui/ScriptToTreeNodeAdapter.groovy      |   3 +-
 .../groovysh/util/ScriptVariableAnalyzer.groovy    |   4 +-
 .../codehaus/groovy/jsr223/JSR223SecurityTest.java |   9 +-
 .../groovy/parser/antlr4/util/AstDumper.groovy     |   3 +-
 28 files changed, 640 insertions(+), 818 deletions(-)
 delete mode 100644 src/main/java/org/codehaus/groovy/control/DefaultTransformer.java


[groovy] 02/05: handle SourceUnitOperation, GroovyClassOperation, etc. polymorphically

Posted by su...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

sunlan pushed a commit to branch GROOVY_3_0_X
in repository https://gitbox.apache.org/repos/asf/groovy.git

commit 9ca3b4f54201aa2ba89d1c3cd9279a219928ae33
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Mon Dec 16 11:53:31 2019 -0600

    handle SourceUnitOperation, GroovyClassOperation, etc. polymorphically
    
    (cherry picked from commit 4e26e28abdae275c07431a24704138fac5a50664)
---
 .../codehaus/groovy/control/CompilationUnit.java   | 46 +++++++++++-----------
 1 file changed, 24 insertions(+), 22 deletions(-)

diff --git a/src/main/java/org/codehaus/groovy/control/CompilationUnit.java b/src/main/java/org/codehaus/groovy/control/CompilationUnit.java
index 193a13d..29ca6f3 100644
--- a/src/main/java/org/codehaus/groovy/control/CompilationUnit.java
+++ b/src/main/java/org/codehaus/groovy/control/CompilationUnit.java
@@ -92,8 +92,8 @@ public class CompilationUnit extends ProcessingUnit {
     /** The classes generated during classgen. */
     private List<GroovyClass> generatedClasses = new ArrayList<>();
 
-    private Deque[] phaseOperations;
-    private Deque[] newPhaseOperations;
+    private Deque<PhaseOperation>[] phaseOperations;
+    private Deque<PhaseOperation>[] newPhaseOperations;
     {
         final int n = Phases.ALL + 1;
         phaseOperations = new Deque[n];
@@ -565,7 +565,7 @@ public class CompilationUnit extends ProcessingUnit {
         while (throughPhase >= phase && phase <= Phases.ALL) {
 
             if (phase == Phases.SEMANTIC_ANALYSIS) {
-                doPhaseOperation(resolve);
+                resolve.doPhaseOperation(this);
                 if (dequeued()) continue;
             }
 
@@ -590,19 +590,19 @@ public class CompilationUnit extends ProcessingUnit {
     }
 
     private void processPhaseOperations(final int phase) {
-        for (Object op : phaseOperations[phase]) {
-            doPhaseOperation(op);
+        for (PhaseOperation op : phaseOperations[phase]) {
+            op.doPhaseOperation(this);
         }
     }
 
     private void processNewPhaseOperations(final int phase) {
         recordPhaseOpsInAllOtherPhases(phase);
-        LinkedList currentPhaseNewOps = newPhaseOperations[phase];
+        Deque<PhaseOperation> currentPhaseNewOps = newPhaseOperations[phase];
         while (!currentPhaseNewOps.isEmpty()) {
-            Object operation = currentPhaseNewOps.removeFirst();
-            // push this operation to master list and then process it.
+            PhaseOperation operation = currentPhaseNewOps.removeFirst();
+            // push this operation to master list and then process it
             phaseOperations[phase].add(operation);
-            doPhaseOperation(operation);
+            operation.doPhaseOperation(this);
             // if this operation has brought in more phase ops for ast transforms, keep recording them
             // in master list of other phases and keep processing them for this phase
             recordPhaseOpsInAllOtherPhases(phase);
@@ -610,16 +610,6 @@ public class CompilationUnit extends ProcessingUnit {
         }
     }
 
-    private void doPhaseOperation(final Object operation) {
-        if (operation instanceof PrimaryClassNodeOperation) {
-            applyToPrimaryClassNodes((PrimaryClassNodeOperation) operation);
-        } else if (operation instanceof SourceUnitOperation) {
-            applyToSourceUnits((SourceUnitOperation) operation);
-        } else {
-            applyToGeneratedGroovyClasses((GroovyClassOperation) operation);
-        }
-    }
-
     private void recordPhaseOpsInAllOtherPhases(final int phase) {
         // apart from current phase, push new operations for every other phase in the master phase ops list
         for (int ph = Phases.INITIALIZATION; ph <= Phases.ALL; ph += 1) {
@@ -917,11 +907,23 @@ public class CompilationUnit extends ProcessingUnit {
     //---------------------------------------------------------------------------
     // LOOP SIMPLIFICATION FOR SourceUnit OPERATIONS
 
+    private interface PhaseOperation {
+        default void doPhaseOperation(final CompilationUnit unit) {
+            if (this instanceof SourceUnitOperation) {
+                unit.applyToSourceUnits((SourceUnitOperation) this);
+            } else if (this instanceof PrimaryClassNodeOperation) {
+                unit.applyToPrimaryClassNodes((PrimaryClassNodeOperation) this);
+            } else {
+                unit.applyToGeneratedGroovyClasses((GroovyClassOperation) this);
+            }
+        }
+    }
+
     /**
      * A callback interface for use in the applyToSourceUnits loop driver.
      */
     // TODO: convert to functional interface
-    public abstract static class SourceUnitOperation {
+    public abstract static class SourceUnitOperation implements PhaseOperation {
         public abstract void call(SourceUnit source) throws CompilationFailedException;
     }
 
@@ -958,7 +960,7 @@ public class CompilationUnit extends ProcessingUnit {
      * An callback interface for use in the applyToPrimaryClassNodes loop driver.
      */
     // TODO: convert to functional interface
-    public abstract static class PrimaryClassNodeOperation {
+    public abstract static class PrimaryClassNodeOperation implements PhaseOperation {
         public abstract void call(SourceUnit source, GeneratorContext context, ClassNode classNode) throws CompilationFailedException;
 
         public boolean needSortedInput() {
@@ -967,7 +969,7 @@ public class CompilationUnit extends ProcessingUnit {
     }
 
     // TODO: convert to functional interface
-    public abstract static class GroovyClassOperation {
+    public abstract static class GroovyClassOperation implements PhaseOperation {
         public abstract void call(GroovyClass groovyClass) throws CompilationFailedException;
     }
 


[groovy] 05/05: minor edits

Posted by su...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

sunlan pushed a commit to branch GROOVY_3_0_X
in repository https://gitbox.apache.org/repos/asf/groovy.git

commit 19e5949e2d60c3d8e33172ea1d8044897b829602
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Tue Dec 17 10:22:50 2019 +0800

    minor edits
    
    (cherry picked from commit 8fe41a2feff9960a6b9bcd62a1077b32ccde839b)
---
 .../java/org/codehaus/groovy/ast/ClassHelper.java  | 27 +++++++--------
 .../org/codehaus/groovy/ast/VariableScope.java     |  3 +-
 .../groovy/classgen/asm/InvocationWriter.java      |  7 ++--
 .../groovy/control/ParserPluginFactory.java        | 38 ++++------------------
 .../codehaus/groovy/control/ResolveVisitor.java    |  3 +-
 .../groovy/transform/ASTTransformationVisitor.java |  4 +--
 6 files changed, 27 insertions(+), 55 deletions(-)

diff --git a/src/main/java/org/codehaus/groovy/ast/ClassHelper.java b/src/main/java/org/codehaus/groovy/ast/ClassHelper.java
index 0a659d2..17bcc8d 100644
--- a/src/main/java/org/codehaus/groovy/ast/ClassHelper.java
+++ b/src/main/java/org/codehaus/groovy/ast/ClassHelper.java
@@ -68,7 +68,6 @@ import java.math.BigInteger;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
-import java.util.Objects;
 import java.util.regex.Pattern;
 
 /**
@@ -408,38 +407,36 @@ public class ClassHelper {
         return false;
     }
 
-    /**
-     * Check if the type is a generated function, i.e. closure/lambda
-     * @param type the type to check
-     * @return the check result
-     * @since 3.0.0
-     */
-    public static boolean isGeneratedFunction(ClassNode type) {
-        Objects.requireNonNull(type, "type should not be null");
-        return type.implementsAnyInterfaces(GENERATED_CLOSURE_Type, GENERATED_LAMBDA_TYPE);
-    }
-
     static class ClassHelperCache {
         static ManagedConcurrentMap<Class, SoftReference<ClassNode>> classCache = new ManagedConcurrentMap<Class, SoftReference<ClassNode>>(ReferenceBundle.getWeakBundle());
     }
 
-    public static boolean isSAMType(ClassNode type) {
+    public static boolean isSAMType(final ClassNode type) {
         return findSAM(type) != null;
     }
 
-    public static boolean isFunctionalInterface(ClassNode type) {
+    public static boolean isFunctionalInterface(final ClassNode type) {
         // Functional interface must be an interface at first, or the following exception will occur:
         // java.lang.invoke.LambdaConversionException: Functional interface SamCallable is not an interface
         return type.isInterface() && isSAMType(type);
     }
 
     /**
+     * Checks if the type is a generated function, i.e. closure or lambda.
+     *
+     * @since 3.0.0
+     */
+    public static boolean isGeneratedFunction(final ClassNode type) {
+        return type.implementsAnyInterfaces(GENERATED_CLOSURE_Type, GENERATED_LAMBDA_TYPE);
+    }
+
+    /**
      * Returns the single abstract method of a class node, if it is a SAM type, or null otherwise.
      *
      * @param type a type for which to search for a single abstract method
      * @return the method node if type is a SAM type, null otherwise
      */
-    public static MethodNode findSAM(ClassNode type) {
+    public static MethodNode findSAM(final ClassNode type) {
         if (!Modifier.isAbstract(type.getModifiers())) return null;
         if (type.isInterface()) {
             List<MethodNode> methods;
diff --git a/src/main/java/org/codehaus/groovy/ast/VariableScope.java b/src/main/java/org/codehaus/groovy/ast/VariableScope.java
index 4b0fbfc..942cfd5 100644
--- a/src/main/java/org/codehaus/groovy/ast/VariableScope.java
+++ b/src/main/java/org/codehaus/groovy/ast/VariableScope.java
@@ -27,7 +27,7 @@ import java.util.Map;
  * Records declared and referenced variabes for a given scope.  Helps determine
  * variable sharing across closure and method boundaries.
  */
-public class VariableScope implements Cloneable {
+public class VariableScope {
 
     private VariableScope parent;
     private ClassNode classScope;
@@ -186,7 +186,6 @@ public class VariableScope implements Cloneable {
 
     //
 
-    // TODO: implement Cloneable and override Object.clone()
     public VariableScope copy() {
         VariableScope that = new VariableScope(parent);
         that.classScope = this.classScope;
diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/InvocationWriter.java b/src/main/java/org/codehaus/groovy/classgen/asm/InvocationWriter.java
index 221361b..6848dab 100644
--- a/src/main/java/org/codehaus/groovy/classgen/asm/InvocationWriter.java
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/InvocationWriter.java
@@ -51,6 +51,7 @@ import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.Objects;
 import java.util.TreeMap;
 
 import static org.objectweb.asm.Opcodes.AALOAD;
@@ -187,10 +188,8 @@ public class InvocationWriter {
                     mv.visitTypeInsn(CHECKCAST, owner);
                 }
             } else if (target.isPublic()
-                    && (!Modifier.isPublic(declaringClass.getModifiers())
-                    && !receiverType.equals(declaringClass))
-                    && receiverType.isDerivedFrom(declaringClass)
-                    && !receiverType.getPackageName().equals(classNode.getPackageName())) {
+                    && (!receiverType.equals(declaringClass) && !Modifier.isPublic(declaringClass.getModifiers()))
+                    && receiverType.isDerivedFrom(declaringClass) && !Objects.equals(receiverType.getPackageName(), classNode.getPackageName())) {
                 // GROOVY-6962: package private class, public method
                 owner = BytecodeHelper.getClassInternalName(receiverType);
             }
diff --git a/src/main/java/org/codehaus/groovy/control/ParserPluginFactory.java b/src/main/java/org/codehaus/groovy/control/ParserPluginFactory.java
index f2bb160..ee09105 100644
--- a/src/main/java/org/codehaus/groovy/control/ParserPluginFactory.java
+++ b/src/main/java/org/codehaus/groovy/control/ParserPluginFactory.java
@@ -19,15 +19,14 @@
 package org.codehaus.groovy.control;
 
 import org.apache.groovy.parser.antlr4.Antlr4PluginFactory;
-import org.codehaus.groovy.antlr.AntlrParserPluginFactory;
 
 /**
- * A factory of parser plugin instances
- *
+ * A factory of parser plugin instances.
  */
 public abstract class ParserPluginFactory {
     /**
-     * creates the ANTLR 4 parser
+     * Creates the ANTLR 4 parser.
+     *
      * @return the factory for the parser
      */
     public static ParserPluginFactory antlr4(CompilerConfiguration compilerConfiguration) {
@@ -35,36 +34,13 @@ public abstract class ParserPluginFactory {
     }
 
     /**
-     * creates the ANTLR 2.7 parser
-     * @return the factory for the parser
-     */
-    @Deprecated
-    public static ParserPluginFactory antlr2() {
-        return new AntlrParserPluginFactory();
-    }
-
-    /**
-     * creates the ANTLR 2.7 parser. This method was used to switch between the pre JSR
-     * parser and the new ANTLR 2.7 based parser, but even before Groovy 1.0 this
-     * method was changed to always return the ANTLR 2.7 parser.
-     * @param useNewParser - ignored
-     * @return the ANTLR 2.7 based parser
-     */
-    @Deprecated
-    public static ParserPluginFactory newInstance(boolean useNewParser) {
-        return newInstance();
-    }
-
-    /**
-     * creates the ANTLR 2.7 parser. This method was used to switch between the pre JSR
-     * parser and the new ANTLR 2.7 based parser, but even before Groovy 1.0 this
-     * method was changed to always return the ANTLR 2.7 parser.
+     * Creates the ANTLR 2 parser.
      *
-     * @return the new parser factory.
+     * @throws UnsupportedOperationException always
      */
     @Deprecated
-    public static ParserPluginFactory newInstance() {
-        return antlr2();
+    public static ParserPluginFactory antlr2() {
+        throw new UnsupportedOperationException("The Antlr2-based parser is no longer supported");
     }
 
     public abstract ParserPlugin createParserPlugin();
diff --git a/src/main/java/org/codehaus/groovy/control/ResolveVisitor.java b/src/main/java/org/codehaus/groovy/control/ResolveVisitor.java
index 30b3476..07c3c88 100644
--- a/src/main/java/org/codehaus/groovy/control/ResolveVisitor.java
+++ b/src/main/java/org/codehaus/groovy/control/ResolveVisitor.java
@@ -321,7 +321,7 @@ public class ResolveVisitor extends ClassCodeExpressionTransformer {
         genericParameterNames = oldPNames;
     }
 
-    private boolean resolveToInner(final ClassNode type) {
+    protected boolean resolveToInner(final ClassNode type) {
         // we do not do our name mangling to find an inner class
         // if the type is a ConstructedClassWithPackage, because in this case we
         // are resolving the name at a different place already
@@ -355,6 +355,7 @@ public class ResolveVisitor extends ClassCodeExpressionTransformer {
     // when resolving the outer class later, we set the resolved type of ConstructedOuterNestedClass instance to the actual inner class node(SEE GROOVY-7812(#2))
     private boolean resolveToOuterNested(final ClassNode type) {
         CompileUnit compileUnit = currentClass.getCompileUnit();
+        if (compileUnit == null) return false;
         String typeName = type.getName();
 
         BiConsumer<ConstructedOuterNestedClassNode, ClassNode> setRedirectListener = (s, c) -> type.setRedirect(s);
diff --git a/src/main/java/org/codehaus/groovy/transform/ASTTransformationVisitor.java b/src/main/java/org/codehaus/groovy/transform/ASTTransformationVisitor.java
index ea950a6..b8348c6 100644
--- a/src/main/java/org/codehaus/groovy/transform/ASTTransformationVisitor.java
+++ b/src/main/java/org/codehaus/groovy/transform/ASTTransformationVisitor.java
@@ -332,10 +332,10 @@ public final class ASTTransformationVisitor extends ClassCodeVisitorSupport {
                 if (ASTTransformation.class.isAssignableFrom(gTransClass)) {
                     ASTTransformation instance = (ASTTransformation) gTransClass.getDeclaredConstructor().newInstance();
                     if (instance instanceof CompilationUnitAware) {
-                        ((CompilationUnitAware)instance).setCompilationUnit(compilationUnit);
+                        ((CompilationUnitAware) instance).setCompilationUnit(compilationUnit);
                     }
                     CompilationUnit.ISourceUnitOperation suOp = source -> {
-                        instance.visit(new ASTNode[] {source.getAST()}, source);
+                        instance.visit(new ASTNode[]{source.getAST()}, source);
                     };
                     if (isFirstScan) {
                         compilationUnit.addPhaseOperation(suOp, transformAnnotation.phase().getPhaseNumber());


[groovy] 04/05: add functional interfaces for phase operations to support lambdas

Posted by su...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

sunlan pushed a commit to branch GROOVY_3_0_X
in repository https://gitbox.apache.org/repos/asf/groovy.git

commit 6e60396c789e5b6a39a897174ad9dc07d5232f85
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Mon Dec 16 16:12:03 2019 -0600

    add functional interfaces for phase operations to support lambdas
    
    - retain abstract classes and method overloads for binary compatibility
    
    (cherry picked from commit 33bbc38e7a443929e3be380741a7186a1244437f)
---
 .../groovy/tools/ast/TransformTestHelper.groovy    |   8 +-
 src/main/java/groovy/lang/GroovyClassLoader.java   |   2 +-
 src/main/java/groovy/util/GroovyScriptEngine.java  |  17 +-
 .../codehaus/groovy/control/CompilationUnit.java   | 667 ++++++++++-----------
 .../groovy/control/CompilerConfiguration.java      |   2 +-
 .../groovy/control/StaticImportVisitor.java        |  22 +-
 .../control/customizers/CompilationCustomizer.java |   4 +-
 .../tools/javac/JavaAwareCompilationUnit.java      |  40 +-
 .../tools/javac/JavaStubCompilationUnit.java       |  26 +-
 .../groovy/transform/ASTTransformationVisitor.java |  35 +-
 .../transform/sc/StaticCompilationVisitor.java     |  14 +-
 .../transform/trait/TraitASTTransformation.java    |  23 +-
 src/test/groovy/lang/GroovyClassLoaderTest.groovy  |   4 +-
 .../ClosureAndInnerClassNodeStructureTest.groovy   |   4 +-
 .../codehaus/groovy/tools/gse/DependencyTest.java  |  41 +-
 .../console/ui/AstNodeToScriptAdapter.groovy       |   3 +-
 .../console/ui/ScriptToTreeNodeAdapter.groovy      |   3 +-
 .../groovysh/util/ScriptVariableAnalyzer.groovy    |   4 +-
 .../codehaus/groovy/jsr223/JSR223SecurityTest.java |   9 +-
 .../groovy/parser/antlr4/util/AstDumper.groovy     |   3 +-
 20 files changed, 430 insertions(+), 501 deletions(-)

diff --git a/src/main/groovy/org/codehaus/groovy/tools/ast/TransformTestHelper.groovy b/src/main/groovy/org/codehaus/groovy/tools/ast/TransformTestHelper.groovy
index d4005e6..8a073bf 100644
--- a/src/main/groovy/org/codehaus/groovy/tools/ast/TransformTestHelper.groovy
+++ b/src/main/groovy/org/codehaus/groovy/tools/ast/TransformTestHelper.groovy
@@ -22,7 +22,6 @@ import groovy.transform.PackageScope
 import org.codehaus.groovy.ast.ClassNode
 import org.codehaus.groovy.classgen.GeneratorContext
 import org.codehaus.groovy.control.CompilationUnit
-import org.codehaus.groovy.control.CompilationUnit.PrimaryClassNodeOperation
 import org.codehaus.groovy.control.CompilePhase
 import org.codehaus.groovy.control.CompilerConfiguration
 import org.codehaus.groovy.control.SourceUnit
@@ -104,15 +103,16 @@ class TestHarnessClassLoader extends GroovyClassLoader {
  * Operation exists so that an AstTransformation can be run against the SourceUnit.
  */
 @PackageScope
-class TestHarnessOperation extends PrimaryClassNodeOperation {
+class TestHarnessOperation implements CompilationUnit.IPrimaryClassNodeOperation {
 
     private final ASTTransformation transform
 
-    TestHarnessOperation(transform) {
+    TestHarnessOperation(ASTTransformation transform) {
         this.transform = transform
     }
 
+    @Override
     void call(SourceUnit source, GeneratorContext ignoredContext, ClassNode ignoredNode) {
-        transform.visit(null, source)
+        this.transform.visit(null, source)
     }
 }
diff --git a/src/main/java/groovy/lang/GroovyClassLoader.java b/src/main/java/groovy/lang/GroovyClassLoader.java
index abc6da0..cda6ad7 100644
--- a/src/main/java/groovy/lang/GroovyClassLoader.java
+++ b/src/main/java/groovy/lang/GroovyClassLoader.java
@@ -1185,7 +1185,7 @@ public class GroovyClassLoader extends URLClassLoader {
         clearCache();
     }
 
-    private static class TimestampAdder extends CompilationUnit.PrimaryClassNodeOperation implements Opcodes {
+    private static class TimestampAdder implements CompilationUnit.IPrimaryClassNodeOperation, Opcodes {
         private static final TimestampAdder INSTANCE = new TimestampAdder();
 
         private TimestampAdder() {}
diff --git a/src/main/java/groovy/util/GroovyScriptEngine.java b/src/main/java/groovy/util/GroovyScriptEngine.java
index fa813a6..7afd183 100644
--- a/src/main/java/groovy/util/GroovyScriptEngine.java
+++ b/src/main/java/groovy/util/GroovyScriptEngine.java
@@ -25,7 +25,6 @@ import groovy.lang.GroovyResourceLoader;
 import groovy.lang.Script;
 import org.codehaus.groovy.GroovyBugError;
 import org.codehaus.groovy.ast.ClassNode;
-import org.codehaus.groovy.ast.InnerClassNode;
 import org.codehaus.groovy.classgen.GeneratorContext;
 import org.codehaus.groovy.control.ClassNodeResolver;
 import org.codehaus.groovy.control.CompilationFailedException;
@@ -166,16 +165,12 @@ public class GroovyScriptEngine implements ResourceConnector {
             // remove all old entries including the "." entry
             cache.clear();
 
-            cu.addPhaseOperation(new CompilationUnit.PrimaryClassNodeOperation() {
-                @Override
-                public void call(final SourceUnit source, GeneratorContext context, ClassNode classNode)
-                        throws CompilationFailedException {
-                    // GROOVY-4013: If it is an inner class, tracking its dependencies doesn't really
-                    // serve any purpose and also interferes with the caching done to track dependencies
-                    if (classNode instanceof InnerClassNode) return;
-                    DependencyTracker dt = new DependencyTracker(source, cache, precompiledEntries);
-                    dt.visitClass(classNode);
-                }
+            cu.addPhaseOperation((final SourceUnit sourceUnit, final GeneratorContext context, final ClassNode classNode) -> {
+               // GROOVY-4013: If it is an inner class, tracking its dependencies doesn't really
+               // serve any purpose and also interferes with the caching done to track dependencies
+               if (classNode.getOuterClass() != null) return;
+               DependencyTracker dt = new DependencyTracker(sourceUnit, cache, precompiledEntries);
+               dt.visitClass(classNode);
             }, Phases.CLASS_GENERATION);
 
             cu.setClassNodeResolver(new ClassNodeResolver() {
diff --git a/src/main/java/org/codehaus/groovy/control/CompilationUnit.java b/src/main/java/org/codehaus/groovy/control/CompilationUnit.java
index 210ec3f..5b81391 100644
--- a/src/main/java/org/codehaus/groovy/control/CompilationUnit.java
+++ b/src/main/java/org/codehaus/groovy/control/CompilationUnit.java
@@ -72,8 +72,8 @@ import java.util.Map;
 import java.util.Optional;
 import java.util.Queue;
 import java.util.Set;
-import java.util.stream.Collectors;
 
+import static java.util.stream.Collectors.toList;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.classX;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.propX;
 import static org.codehaus.groovy.transform.sc.StaticCompilationMetadataKeys.DYNAMIC_OUTER_NODE_CALLBACK;
@@ -123,8 +123,6 @@ public class CompilationUnit extends ProcessingUnit {
 
     protected ClassNodeResolver classNodeResolver = new ClassNodeResolver();
     protected ResolveVisitor resolveVisitor = new ResolveVisitor(this);
-    protected OptimizerVisitor optimizer = new OptimizerVisitor(this);
-    protected Verifier verifier = new Verifier();
 
     /** The AST transformations state data. */
     protected ASTTransformationsContext astTransformationsContext;
@@ -164,9 +162,10 @@ public class CompilationUnit extends ProcessingUnit {
      * Initializes the CompilationUnit with a CodeSource for controlling
      * security stuff, a class loader for loading classes, and a class
      * loader for loading AST transformations.
-     * <b>Note</b> The transform loader must be
-     * able to load compiler classes. That means CompilationUnit.class.classLoader
-     * must be at last a parent to transformLoader. The other loader has no such constraint.
+     * <p>
+     * <b>Note</b>: The transform loader must be able to load compiler classes.
+     * That means {@link #classLoader} must be at last a parent to {@code transformLoader}.
+     * The other loader has no such constraint.
      *
      * @param transformLoader - the loader for transforms
      * @param loader          - loader used to resolve classes against during compilation
@@ -178,188 +177,165 @@ public class CompilationUnit extends ProcessingUnit {
         super(configuration, loader, null);
 
         this.astTransformationsContext = new ASTTransformationsContext(this, transformLoader);
-        this.ast = new CompileUnit(this.classLoader, codeSource, this.configuration);
+        this.ast = new CompileUnit(getClassLoader(), codeSource, getConfiguration());
 
         addPhaseOperations();
         applyCompilationCustomizers();
     }
 
     private void addPhaseOperations() {
-        addPhaseOperation(new SourceUnitOperation() {
-            @Override
-            public void call(final SourceUnit source) throws CompilationFailedException {
-                source.parse();
-            }
-        }, Phases.PARSING);
-
-        addPhaseOperation(new SourceUnitOperation() {
-            @Override
-            public void call(final SourceUnit source) throws CompilationFailedException {
-                source.convert();
-                // add module to compile unit
-                getAST().addModule(source.getAST());
-
-                if (progressCallback != null) {
-                    progressCallback.call(source, phase);
-                }
-            }
+        addPhaseOperation(SourceUnit::parse, Phases.PARSING);
+
+        addPhaseOperation(source -> {
+            source.convert();
+            // add module to compile unit
+            getAST().addModule(source.getAST());
+            Optional.ofNullable(getProgressCallback())
+                .ifPresent(callback -> callback.call(source, getPhase()));
         }, Phases.CONVERSION);
-        addPhaseOperation(new PrimaryClassNodeOperation() {
-            @Override
-            public void call(final SourceUnit source, final GeneratorContext context, final ClassNode classNode) throws CompilationFailedException {
-                GroovyClassVisitor visitor = new EnumVisitor(CompilationUnit.this, source);
-                visitor.visitClass(classNode);
-            }
+
+        addPhaseOperation((final SourceUnit source, final GeneratorContext context, final ClassNode classNode) -> {
+            GroovyClassVisitor visitor = new EnumVisitor(this, source);
+            visitor.visitClass(classNode);
         }, Phases.CONVERSION);
 
         addPhaseOperation(resolve, Phases.SEMANTIC_ANALYSIS);
-        addPhaseOperation(new PrimaryClassNodeOperation() {
-            @Override
-            public void call(final SourceUnit source, final GeneratorContext context, final ClassNode classNode) throws CompilationFailedException {
-                StaticImportVisitor visitor = new StaticImportVisitor();
-                visitor.visitClass(classNode, source);
-            }
+
+        addPhaseOperation((final SourceUnit source, final GeneratorContext context, final ClassNode classNode) -> {
+            GroovyClassVisitor visitor = new StaticImportVisitor(classNode, source);
+            visitor.visitClass(classNode);
         }, Phases.SEMANTIC_ANALYSIS);
-        addPhaseOperation(new PrimaryClassNodeOperation() {
-            @Override
-            public void call(final SourceUnit source, final GeneratorContext context, final ClassNode classNode) throws CompilationFailedException {
-                GroovyClassVisitor visitor = new InnerClassVisitor(CompilationUnit.this, source);
-                visitor.visitClass(classNode);
-            }
+
+        addPhaseOperation((final SourceUnit source, final GeneratorContext context, final ClassNode classNode) -> {
+            GroovyClassVisitor visitor = new InnerClassVisitor(this, source);
+            visitor.visitClass(classNode);
         }, Phases.SEMANTIC_ANALYSIS);
-        addPhaseOperation(new PrimaryClassNodeOperation() {
-            @Override
-            public void call(final SourceUnit source, final GeneratorContext context, final ClassNode classNode) throws CompilationFailedException {
-                if (!classNode.isSynthetic()) {
-                    GroovyClassVisitor visitor = new GenericsVisitor(source);
-                    visitor.visitClass(classNode);
-                }
+
+        addPhaseOperation((final SourceUnit source, final GeneratorContext context, final ClassNode classNode) -> {
+            if (!classNode.isSynthetic()) {
+                GroovyClassVisitor visitor = new GenericsVisitor(source);
+                visitor.visitClass(classNode);
             }
         }, Phases.SEMANTIC_ANALYSIS);
 
-        addPhaseOperation(new PrimaryClassNodeOperation() {
-            @Override
-            public void call(final SourceUnit source, final GeneratorContext context, final ClassNode classNode) throws CompilationFailedException {
-                TraitComposer.doExtendTraits(classNode, source, CompilationUnit.this);
-            }
+        addPhaseOperation((final SourceUnit source, final GeneratorContext context, final ClassNode classNode) -> {
+            TraitComposer.doExtendTraits(classNode, source, this);
         }, Phases.CANONICALIZATION);
-        addPhaseOperation(new SourceUnitOperation() {
-            @Override
-            public void call(final SourceUnit source) throws CompilationFailedException {
-                List<ClassNode> classes = source.ast.getClasses();
-                for (ClassNode node : classes) {
-                    CompileUnit cu = node.getCompileUnit();
-                    for (Iterator<String> it = cu.iterateClassNodeToCompile(); it.hasNext(); ) {
-                        String name = it.next();
-                        StringBuilder message = new StringBuilder();
-                        message
-                                .append("Compilation incomplete: expected to find the class ")
-                                .append(name)
-                                .append(" in ")
-                                .append(source.getName());
-                        if (classes.isEmpty()) {
-                            message.append(", but the file seems not to contain any classes");
-                        } else {
-                            message.append(", but the file contains the classes: ");
-                            boolean first = true;
-                            for (ClassNode cn : classes) {
-                                if (!first) {
-                                    message.append(", ");
-                                } else {
-                                    first = false;
-                                }
-                                message.append(cn.getName());
+
+        addPhaseOperation(source -> {
+            List<ClassNode> classes = source.getAST().getClasses();
+            for (ClassNode node : classes) {
+                CompileUnit cu = node.getCompileUnit();
+                for (Iterator<String> it = cu.iterateClassNodeToCompile(); it.hasNext(); ) {
+                    String name = it.next();
+                    StringBuilder message = new StringBuilder();
+                    message
+                            .append("Compilation incomplete: expected to find the class ")
+                            .append(name)
+                            .append(" in ")
+                            .append(source.getName());
+                    if (classes.isEmpty()) {
+                        message.append(", but the file seems not to contain any classes");
+                    } else {
+                        message.append(", but the file contains the classes: ");
+                        boolean first = true;
+                        for (ClassNode cn : classes) {
+                            if (first) {
+                                first = false;
+                            } else {
+                                message.append(", ");
                             }
+                            message.append(cn.getName());
                         }
-
-                        getErrorCollector().addErrorAndContinue(
-                                new SimpleMessage(message.toString(), CompilationUnit.this)
-                        );
-                        it.remove();
                     }
+
+                    getErrorCollector().addErrorAndContinue(
+                            new SimpleMessage(message.toString(), this)
+                    );
+                    it.remove();
                 }
             }
         }, Phases.CANONICALIZATION);
 
         addPhaseOperation(classgen, Phases.CLASS_GENERATION);
 
-        addPhaseOperation(output);
+        addPhaseOperation(groovyClass -> {
+            String name = groovyClass.getName().replace('.', File.separatorChar) + ".class";
+            File path = new File(getConfiguration().getTargetDirectory(), name);
 
-        addPhaseOperation(new PrimaryClassNodeOperation() {
-            @Override
-            public void call(final SourceUnit source, final GeneratorContext context, final ClassNode classNode) throws CompilationFailedException {
-                AnnotationCollectorTransform.ClassChanger xformer = new AnnotationCollectorTransform.ClassChanger();
-                xformer.transformClass(classNode);
+            // ensure the path is ready for the file
+            File directory = path.getParentFile();
+            if (directory != null && !directory.exists()) {
+                directory.mkdirs();
             }
+
+            // create the file and write out the data
+            try (FileOutputStream stream = new FileOutputStream(path)) {
+                byte[] bytes = groovyClass.getBytes();
+                stream.write(bytes, 0, bytes.length);
+            } catch (IOException e) {
+                getErrorCollector().addError(Message.create(e.getMessage(), this));
+            }
+        });
+
+        addPhaseOperation((final SourceUnit source, final GeneratorContext context, final ClassNode classNode) -> {
+            AnnotationCollectorTransform.ClassChanger xformer = new AnnotationCollectorTransform.ClassChanger();
+            xformer.transformClass(classNode);
         }, Phases.SEMANTIC_ANALYSIS);
         ASTTransformationVisitor.addPhaseOperations(this);
 
         // post-transform operations:
 
-        addPhaseOperation(new PrimaryClassNodeOperation() {
-            @Override
-            public void call(final SourceUnit source, final GeneratorContext context, final ClassNode classNode) throws CompilationFailedException {
-                StaticVerifier verifier = new StaticVerifier();
-                verifier.visitClass(classNode, source);
-            }
+        addPhaseOperation((final SourceUnit source, final GeneratorContext context, final ClassNode classNode) -> {
+            StaticVerifier verifier = new StaticVerifier();
+            verifier.visitClass(classNode, source);
         }, Phases.SEMANTIC_ANALYSIS);
 
-        addPhaseOperation(new PrimaryClassNodeOperation() {
-            @Override
-            public void call(final SourceUnit source, final GeneratorContext context, final ClassNode classNode) throws CompilationFailedException {
-                GroovyClassVisitor visitor = new InnerClassCompletionVisitor(CompilationUnit.this, source);
-                visitor.visitClass(classNode);
-            }
-        }, Phases.CANONICALIZATION);
-        addPhaseOperation(new PrimaryClassNodeOperation() {
-            @Override
-            public void call(final SourceUnit source, final GeneratorContext context, final ClassNode classNode) throws CompilationFailedException {
-                GroovyClassVisitor visitor = new EnumCompletionVisitor(CompilationUnit.this, source);
-                visitor.visitClass(classNode);
-            }
+        addPhaseOperation((final SourceUnit source, final GeneratorContext context, final ClassNode classNode) -> {
+            GroovyClassVisitor visitor = new InnerClassCompletionVisitor(this, source);
+            visitor.visitClass(classNode);
+
+            visitor = new EnumCompletionVisitor(this, source);
+            visitor.visitClass(classNode);
         }, Phases.CANONICALIZATION);
 
-        addPhaseOperation(new PrimaryClassNodeOperation() {
-            @Override
-            public void call(final SourceUnit source, final GeneratorContext context, final ClassNode classNode) throws CompilationFailedException {
-                Object callback = classNode.getNodeMetaData(DYNAMIC_OUTER_NODE_CALLBACK);
-                if (callback instanceof PrimaryClassNodeOperation) {
-                    ((PrimaryClassNodeOperation) callback).call(source, context, classNode);
-                    classNode.removeNodeMetaData(DYNAMIC_OUTER_NODE_CALLBACK);
-                }
+        addPhaseOperation((final SourceUnit source, final GeneratorContext context, final ClassNode classNode) -> {
+            Object callback = classNode.getNodeMetaData(DYNAMIC_OUTER_NODE_CALLBACK);
+            if (callback instanceof IPrimaryClassNodeOperation) {
+                ((IPrimaryClassNodeOperation) callback).call(source, context, classNode);
+                classNode.removeNodeMetaData(DYNAMIC_OUTER_NODE_CALLBACK);
             }
         }, Phases.INSTRUCTION_SELECTION);
-        addPhaseOperation(new PrimaryClassNodeOperation() {
-            @Override
-            public void call(final SourceUnit source, final GeneratorContext context, final ClassNode classNode) throws CompilationFailedException {
-                // TODO: Could this be moved into org.codehaus.groovy.transform.sc.transformers.VariableExpressionTransformer?
-                new ClassCodeExpressionTransformer() {
-                    @Override
-                    protected SourceUnit getSourceUnit() {
-                        return source;
-                    }
 
-                    @Override
-                    public Expression transform(final Expression expression) {
-                        if (expression instanceof VariableExpression) {
-                            // check for "switch(enumType) { case CONST: ... }"
-                            ClassNode enumType = expression.getNodeMetaData(SWITCH_CONDITION_EXPRESSION_TYPE);
-                            if (enumType != null) {
-                                // replace "CONST" variable expression with "EnumType.CONST" property expression
-                                Expression propertyExpression = propX(classX(enumType), expression.getText());
-                                setSourcePosition(propertyExpression, expression);
-                                return propertyExpression;
-                            }
+        addPhaseOperation((final SourceUnit source, final GeneratorContext context, final ClassNode classNode) -> {
+            // TODO: Can this be moved into org.codehaus.groovy.transform.sc.transformers.VariableExpressionTransformer?
+            GroovyClassVisitor visitor = new ClassCodeExpressionTransformer() {
+                @Override
+                protected SourceUnit getSourceUnit() {
+                    return source;
+                }
+
+                @Override
+                public Expression transform(final Expression expression) {
+                    if (expression instanceof VariableExpression) {
+                        // check for "switch(enumType) { case CONST: ... }"
+                        ClassNode enumType = expression.getNodeMetaData(SWITCH_CONDITION_EXPRESSION_TYPE);
+                        if (enumType != null) {
+                            // replace "CONST" variable expression with "EnumType.CONST" property expression
+                            Expression propertyExpression = propX(classX(enumType), expression.getText());
+                            setSourcePosition(propertyExpression, expression);
+                            return propertyExpression;
                         }
-                        return expression;
                     }
-                }.visitClass(classNode);
-            }
+                    return expression;
+                }
+            };
+            visitor.visitClass(classNode);
         }, Phases.INSTRUCTION_SELECTION);
     }
 
     private void applyCompilationCustomizers() {
-        for (CompilationCustomizer customizer : configuration.getCompilationCustomizers()) {
+        for (CompilationCustomizer customizer : getConfiguration().getCompilationCustomizers()) {
             if (customizer instanceof CompilationUnitAware) {
                 ((CompilationUnitAware) customizer).setCompilationUnit(this);
             }
@@ -367,26 +343,26 @@ public class CompilationUnit extends ProcessingUnit {
         }
     }
 
-    public void addPhaseOperation(final GroovyClassOperation op) {
+    public void addPhaseOperation(final IGroovyClassOperation op) {
         phaseOperations[Phases.OUTPUT].addFirst(op);
     }
 
-    public void addPhaseOperation(final SourceUnitOperation op, final int phase) {
+    public void addPhaseOperation(final ISourceUnitOperation op, final int phase) {
         validatePhase(phase);
         phaseOperations[phase].add(op);
     }
 
-    public void addPhaseOperation(final PrimaryClassNodeOperation op, final int phase) {
+    public void addPhaseOperation(final IPrimaryClassNodeOperation op, final int phase) {
         validatePhase(phase);
         phaseOperations[phase].add(op);
     }
 
-    public void addFirstPhaseOperation(final PrimaryClassNodeOperation op, final int phase) {
+    public void addFirstPhaseOperation(final IPrimaryClassNodeOperation op, final int phase) {
         validatePhase(phase);
         phaseOperations[phase].addFirst(op);
     }
 
-    public void addNewPhaseOperation(final SourceUnitOperation op, final int phase) {
+    public void addNewPhaseOperation(final ISourceUnitOperation op, final int phase) {
         validatePhase(phase);
         newPhaseOperations[phase].add(op);
     }
@@ -404,7 +380,7 @@ public class CompilationUnit extends ProcessingUnit {
     @Override
     public void configure(final CompilerConfiguration configuration) {
         super.configure(configuration);
-        this.debug = this.configuration.getDebug();
+        this.debug = getConfiguration().getDebug();
         this.configured = true;
     }
 
@@ -435,16 +411,13 @@ public class CompilationUnit extends ProcessingUnit {
      */
     public ClassNode getClassNode(final String name) {
         ClassNode[] result = new ClassNode[1];
-        PrimaryClassNodeOperation handler = new PrimaryClassNodeOperation() {
-            @Override
-            public void call(SourceUnit source, GeneratorContext context, ClassNode classNode) {
-                if (classNode.getName().equals(name)) {
-                    result[0] = classNode;
-                }
+        IPrimaryClassNodeOperation handler = (source, context, classNode) -> {
+            if (classNode.getName().equals(name)) {
+                result[0] = classNode;
             }
         };
         try {
-            applyToPrimaryClassNodes(handler);
+            handler.doPhaseOperation(this);
         } catch (CompilationFailedException e) {
             if (debug) e.printStackTrace();
         }
@@ -506,26 +479,26 @@ public class CompilationUnit extends ProcessingUnit {
      * Adds a source file to the unit.
      */
     public SourceUnit addSource(final File file) {
-        return addSource(new SourceUnit(file, configuration, classLoader, getErrorCollector()));
+        return addSource(new SourceUnit(file, getConfiguration(), getClassLoader(), getErrorCollector()));
     }
 
     /**
      * Adds a source file to the unit.
      */
     public SourceUnit addSource(final URL url) {
-        return addSource(new SourceUnit(url, configuration, classLoader, getErrorCollector()));
+        return addSource(new SourceUnit(url, getConfiguration(), getClassLoader(), getErrorCollector()));
     }
 
     /**
      * Adds a InputStream source to the unit.
      */
     public SourceUnit addSource(final String name, final InputStream stream) {
-        ReaderSource source = new InputStreamReaderSource(stream, configuration);
-        return addSource(new SourceUnit(name, source, configuration, classLoader, getErrorCollector()));
+        ReaderSource source = new InputStreamReaderSource(stream, getConfiguration());
+        return addSource(new SourceUnit(name, source, getConfiguration(), getClassLoader(), getErrorCollector()));
     }
 
     public SourceUnit addSource(final String name, final String scriptText) {
-        return addSource(new SourceUnit(name, scriptText, configuration, classLoader, getErrorCollector()));
+        return addSource(new SourceUnit(name, scriptText, getConfiguration(), getClassLoader(), getErrorCollector()));
     }
 
     /**
@@ -533,7 +506,7 @@ public class CompilationUnit extends ProcessingUnit {
      */
     public SourceUnit addSource(final SourceUnit source) {
         String name = source.getName();
-        source.setClassLoader(this.classLoader);
+        source.setClassLoader(getClassLoader());
         for (SourceUnit su : queuedSources) {
             if (name.equals(su.getName())) return su;
         }
@@ -589,6 +562,10 @@ public class CompilationUnit extends ProcessingUnit {
         void call(ClassVisitor writer, ClassNode node) throws CompilationFailedException;
     }
 
+    public ClassgenCallback getClassgenCallback() {
+        return classgenCallback;
+    }
+
     /**
      * Sets a ClassgenCallback.  You can have only one, and setting
      * it to {@code null} removes any existing setting.
@@ -597,10 +574,6 @@ public class CompilationUnit extends ProcessingUnit {
         this.classgenCallback = visitor;
     }
 
-    public ClassgenCallback getClassgenCallback() {
-        return classgenCallback;
-    }
-
     /**
      * A callback interface you can use to get a callback after every
      * unit of the compile process.  You will be called-back with a
@@ -612,6 +585,10 @@ public class CompilationUnit extends ProcessingUnit {
         void call(ProcessingUnit context, int phase) throws CompilationFailedException;
     }
 
+    public ProgressCallback getProgressCallback() {
+        return progressCallback;
+    }
+
     /**
      * Sets a ProgressCallback.  You can have only one, and setting
      * it to {@code null} removes any existing setting.
@@ -620,15 +597,11 @@ public class CompilationUnit extends ProcessingUnit {
         this.progressCallback = callback;
     }
 
-    public ProgressCallback getProgressCallback() {
-        return progressCallback;
-    }
-
     //---------------------------------------------------------------------------
     // ACTIONS
 
     /**
-     * Synonym for compile(Phases.ALL).
+     * Synonym for {@code compile(Phases.ALL)}.
      */
     public void compile() throws CompilationFailedException {
         compile(Phases.ALL);
@@ -656,9 +629,10 @@ public class CompilationUnit extends ProcessingUnit {
             // Grab processing may have brought in new AST transforms into various phases, process them as well
             processNewPhaseOperations(phase);
 
-            if (progressCallback != null) progressCallback.call(this, phase);
+            Optional.ofNullable(getProgressCallback())
+                .ifPresent(callback -> callback.call(this, phase));
             completePhase();
-            applyToSourceUnits(mark);
+            mark();
 
             if (dequeued()) continue;
 
@@ -669,7 +643,7 @@ public class CompilationUnit extends ProcessingUnit {
             }
         }
 
-        errorCollector.failIfErrors();
+        getErrorCollector().failIfErrors();
     }
 
     private void processPhaseOperations(final int phase) {
@@ -735,56 +709,28 @@ public class CompilationUnit extends ProcessingUnit {
     /**
      * Resolves all types.
      */
-    private final SourceUnitOperation resolve = new SourceUnitOperation() {
-        @Override
-        public void call(final SourceUnit source) throws CompilationFailedException {
-            List<ClassNode> classes = source.ast.getClasses();
-            for (ClassNode node : classes) {
-                VariableScopeVisitor scopeVisitor = new VariableScopeVisitor(source);
-                scopeVisitor.visitClass(node);
-
-                resolveVisitor.setClassNodeResolver(classNodeResolver);
-                resolveVisitor.startResolving(node, source);
-            }
-
-        }
-    };
-
-    private final GroovyClassOperation output = new GroovyClassOperation() {
-        @Override
-        public void call(final GroovyClass groovyClass) throws CompilationFailedException {
-            String name = groovyClass.getName().replace('.', File.separatorChar) + ".class";
-            File path = new File(configuration.getTargetDirectory(), name);
-
-            // ensure the path is ready for the file
-            File directory = path.getParentFile();
-            if (directory != null && !directory.exists()) {
-                directory.mkdirs();
-            }
-
-            // create the file and write out the data
-            byte[] bytes = groovyClass.getBytes();
+    private final ISourceUnitOperation resolve = (final SourceUnit source) -> {
+        for (ClassNode classNode : source.getAST().getClasses()) {
+            GroovyClassVisitor visitor = new VariableScopeVisitor(source);
+            visitor.visitClass(classNode);
 
-            try (FileOutputStream stream = new FileOutputStream(path)) {
-                stream.write(bytes, 0, bytes.length);
-            } catch (IOException e) {
-                getErrorCollector().addError(Message.create(e.getMessage(), CompilationUnit.this));
-            }
+            resolveVisitor.setClassNodeResolver(classNodeResolver);
+            resolveVisitor.startResolving(classNode, source);
         }
     };
 
     /**
-     * Runs classgen() on a single ClassNode.
+     * Runs {@link #classgen()} on a single {@code ClassNode}.
      */
-    private final PrimaryClassNodeOperation classgen = new PrimaryClassNodeOperation() {
+    private final IPrimaryClassNodeOperation classgen = new IPrimaryClassNodeOperation() {
         @Override
         public void call(final SourceUnit source, final GeneratorContext context, final ClassNode classNode) throws CompilationFailedException {
-            optimizer.visitClass(classNode, source); // GROOVY-4272: repositioned it here from static import visitor
+            new OptimizerVisitor(CompilationUnit.this).visitClass(classNode, source); // GROOVY-4272: repositioned from static import visitor
 
             //
             // Run the Verifier on the outer class
             //
-            GroovyClassVisitor visitor = verifier;
+            GroovyClassVisitor visitor = new Verifier();
             try {
                 visitor.visitClass(classNode);
             } catch (RuntimeParserException rpe) {
@@ -808,8 +754,6 @@ public class CompilationUnit extends ProcessingUnit {
             visitor = new ExtendedVerifier(source);
             visitor.visitClass(classNode);
 
-            visitor = null;
-
             // because the class may be generated even if a error was found
             // and that class may have an invalid format we fail here if needed
             getErrorCollector().failIfErrors();
@@ -822,33 +766,34 @@ public class CompilationUnit extends ProcessingUnit {
             String sourceName = (source == null ? classNode.getModule().getDescription() : source.getName());
             // only show the file name and its extension like javac does in its stacktraces rather than the full path
             // also takes care of both \ and / depending on the host compiling environment
-            if (sourceName != null)
+            if (sourceName != null) {
                 sourceName = sourceName.substring(Math.max(sourceName.lastIndexOf('\\'), sourceName.lastIndexOf('/')) + 1);
-            AsmClassGenerator generator = new AsmClassGenerator(source, context, classVisitor, sourceName);
+            }
 
             //
             // Run the generation and create the class (if required)
             //
-            generator.visitClass(classNode);
+            visitor = new AsmClassGenerator(source, context, classVisitor, sourceName);
+            visitor.visitClass(classNode);
 
             byte[] bytes = ((ClassWriter) classVisitor).toByteArray();
-            generatedClasses.add(new GroovyClass(classNode.getName(), bytes));
+            getClasses().add(new GroovyClass(classNode.getName(), bytes));
 
             //
             // Handle any callback that's been set
             //
-            if (CompilationUnit.this.classgenCallback != null) {
-                classgenCallback.call(classVisitor, classNode);
-            }
+            Optional.ofNullable(getClassgenCallback())
+                .ifPresent(callback -> callback.call(classVisitor, classNode));
 
             //
             // Recurse for inner classes
             //
-            LinkedList<ClassNode> innerClasses = generator.getInnerClasses();
+            LinkedList<ClassNode> innerClasses = ((AsmClassGenerator) visitor).getInnerClasses();
             while (!innerClasses.isEmpty()) {
                 classgen.call(source, context, innerClasses.removeFirst());
             }
         }
+
         @Override
         public boolean needSortedInput() {
             return true;
@@ -866,10 +811,10 @@ public class CompilationUnit extends ProcessingUnit {
                 // try classes under compilation
                 CompileUnit cu = getAST();
                 ClassNode cn = cu.getClass(name);
-                if (cn!=null) return cn;
+                if (cn != null) return cn;
                 // try inner classes
                 cn = cu.getGeneratedInnerClass(name);
-                if (cn!=null) return cn;
+                if (cn != null) return cn;
                 ClassNodeResolver.LookupResult lookupResult = getClassNodeResolver().resolveName(name, CompilationUnit.this);
                 return lookupResult == null ? null : lookupResult.getClassNode();
             }
@@ -880,8 +825,8 @@ public class CompilationUnit extends ProcessingUnit {
                 if (c.isInterface() || d.isInterface()) return ClassHelper.OBJECT_TYPE;
                 do {
                     c = c.getSuperClass();
-                } while (c!=null && !d.isDerivedFrom(c));
-                if (c==null) return ClassHelper.OBJECT_TYPE;
+                } while (c != null && !d.isDerivedFrom(c));
+                if (c == null) return ClassHelper.OBJECT_TYPE;
                 return c;
             }
             @Override
@@ -900,115 +845,153 @@ public class CompilationUnit extends ProcessingUnit {
      * Updates the phase marker on all sources.
      */
     protected void mark() throws CompilationFailedException {
-        applyToSourceUnits(mark);
-    }
-
-    /**
-     * Marks a single SourceUnit with the current phase,
-     * if it isn't already there yet.
-     */
-    private final SourceUnitOperation mark = new SourceUnitOperation() {
-        @Override
-        public void call(final SourceUnit source) throws CompilationFailedException {
+        ISourceUnitOperation mark = (final SourceUnit source) -> {
             if (source.phase < phase) {
                 source.gotoPhase(phase);
             }
             if (source.phase == phase && phaseComplete && !source.phaseComplete) {
                 source.completePhase();
             }
-        }
-    };
+        };
+        mark.doPhaseOperation(this);
+    }
 
     //---------------------------------------------------------------------------
     // LOOP SIMPLIFICATION FOR SourceUnit OPERATIONS
 
     private interface PhaseOperation {
-        default void doPhaseOperation(final CompilationUnit unit) {
-            if (this instanceof SourceUnitOperation) {
-                unit.applyToSourceUnits((SourceUnitOperation) this);
-            } else if (this instanceof PrimaryClassNodeOperation) {
-                unit.applyToPrimaryClassNodes((PrimaryClassNodeOperation) this);
-            } else {
-                unit.applyToGeneratedGroovyClasses((GroovyClassOperation) this);
+        void doPhaseOperation(CompilationUnit unit);
+    }
+
+    @FunctionalInterface
+    public interface ISourceUnitOperation extends PhaseOperation {
+        void call(SourceUnit source) throws CompilationFailedException;
+
+        /**
+         * A loop driver for applying operations to all SourceUnits.
+         * Automatically skips units that have already been processed
+         * through the current phase.
+         */
+        @Override
+        default void doPhaseOperation(final CompilationUnit unit) throws CompilationFailedException {
+            for (String name : unit.sources.keySet()) {
+                SourceUnit source = unit.sources.get(name);
+                if (source.phase < unit.phase || (source.phase == unit.phase && !source.phaseComplete)) {
+                    try {
+                        this.call(source);
+                    } catch (CompilationFailedException e) {
+                        throw e;
+                    } catch (Exception e) {
+                        GroovyBugError gbe = new GroovyBugError(e);
+                        unit.changeBugText(gbe, source);
+                        throw gbe;
+                    } catch (GroovyBugError e) {
+                        unit.changeBugText(e, source);
+                        throw e;
+                    }
+                }
             }
+            unit.getErrorCollector().failIfErrors();
         }
     }
 
-    /**
-     * A callback interface for use in the applyToSourceUnits loop driver.
-     */
-    // TODO: convert to functional interface
-    public abstract static class SourceUnitOperation implements PhaseOperation {
-        public abstract void call(SourceUnit source) throws CompilationFailedException;
-    }
+    //---------------------------------------------------------------------------
+    // LOOP SIMPLIFICATION FOR PRIMARY ClassNode OPERATIONS
 
-    /**
-     * A loop driver for applying operations to all SourceUnits.
-     * Automatically skips units that have already been processed
-     * through the current phase.
-     */
-    public void applyToSourceUnits(final SourceUnitOperation body) throws CompilationFailedException {
-        for (String name : sources.keySet()) {
-            SourceUnit source = sources.get(name);
-            if ((source.phase < phase) || (source.phase == phase && !source.phaseComplete)) {
+    @FunctionalInterface
+    public interface IPrimaryClassNodeOperation extends PhaseOperation {
+        void call(SourceUnit source, GeneratorContext context, ClassNode classNode) throws CompilationFailedException;
+
+        /**
+         * 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.
+         */
+        @Override
+        default void doPhaseOperation(final CompilationUnit unit) throws CompilationFailedException {
+            for (ClassNode classNode : unit.getPrimaryClassNodes(this.needSortedInput())) {
+                SourceUnit context = null;
                 try {
-                    body.call(source);
+                    context = classNode.getModule().getContext();
+                    if (context == null || context.phase < unit.phase || (context.phase == unit.phase && !context.phaseComplete)) {
+                        int offset = 1;
+                        for (Iterator<InnerClassNode> it = classNode.getInnerClasses(); it.hasNext(); ) {
+                            it.next();
+                            offset += 1;
+                        }
+                        this.call(context, new GeneratorContext(unit.getAST(), offset), classNode);
+                    }
                 } catch (CompilationFailedException e) {
-                    throw e;
-                } catch (Exception e) {
-                    GroovyBugError gbe = new GroovyBugError(e);
-                    changeBugText(gbe, source);
+                    // fall through
+                } catch (NullPointerException npe) {
+                    GroovyBugError gbe = new GroovyBugError("unexpected NullPointerException", npe);
+                    unit.changeBugText(gbe, context);
                     throw gbe;
                 } catch (GroovyBugError e) {
-                    changeBugText(e, source);
+                    unit.changeBugText(e, context);
                     throw e;
+                } catch (NoClassDefFoundError | Exception e) {
+                    // effort to get more logging in case a dependency of a class is loaded
+                    // although it shouldn't have
+                    unit.convertUncaughtExceptionToCompilationError(e);
                 }
             }
+            unit.getErrorCollector().failIfErrors();
         }
-        getErrorCollector().failIfErrors();
-    }
 
-    //---------------------------------------------------------------------------
-    // LOOP SIMPLIFICATION FOR PRIMARY ClassNode OPERATIONS
-
-    /**
-     * An callback interface for use in the applyToPrimaryClassNodes loop driver.
-     */
-    // TODO: convert to functional interface
-    public abstract static class PrimaryClassNodeOperation implements PhaseOperation {
-        public abstract void call(SourceUnit source, GeneratorContext context, ClassNode classNode) throws CompilationFailedException;
-
-        public boolean needSortedInput() {
+        default boolean needSortedInput() {
             return false;
         }
     }
 
-    // TODO: convert to functional interface
-    public abstract static class GroovyClassOperation implements PhaseOperation {
-        public abstract void call(GroovyClass groovyClass) throws CompilationFailedException;
+    @FunctionalInterface
+    public interface IGroovyClassOperation extends PhaseOperation {
+        void call(GroovyClass groovyClass) throws CompilationFailedException;
+
+        @Override
+        default void doPhaseOperation(final CompilationUnit unit) throws CompilationFailedException {
+            if (unit.phase != Phases.OUTPUT && !(unit.phase == Phases.CLASS_GENERATION && unit.phaseComplete)) {
+                throw new GroovyBugError("CompilationUnit not ready for output(). Current phase=" + unit.getPhaseDescription());
+            }
+
+            for (GroovyClass groovyClass : unit.getClasses()) {
+                try {
+                    this.call(groovyClass);
+                } catch (CompilationFailedException e) {
+                    // fall through
+                } catch (NullPointerException npe) {
+                    throw npe;
+                } catch (GroovyBugError e) {
+                    unit.changeBugText(e, null);
+                    throw e;
+                } catch (Exception e) {
+                    throw new GroovyBugError(e);
+                }
+            }
+            unit.getErrorCollector().failIfErrors();
+        }
     }
 
-    private static int getSuperClassCount(ClassNode element) {
+    private static int getSuperClassCount(ClassNode classNode) {
         int count = 0;
-        while (element != null) {
+        while (classNode != null) {
             count += 1;
-            element = element.getSuperClass();
+            classNode = classNode.getSuperClass();
         }
         return count;
     }
 
-    private int getSuperInterfaceCount(final ClassNode element) {
+    private static int getSuperInterfaceCount(final ClassNode classNode) {
         int count = 1;
-        ClassNode[] interfaces = element.getInterfaces();
-        for (ClassNode anInterface : interfaces) {
-            count = Math.max(count, getSuperInterfaceCount(anInterface) + 1);
+        for (ClassNode face : classNode.getInterfaces()) {
+            count = Math.max(count, getSuperInterfaceCount(face) + 1);
         }
         return count;
     }
 
     private List<ClassNode> getPrimaryClassNodes(final boolean sort) {
         List<ClassNode> unsorted = getAST().getModules().stream()
-            .flatMap(module -> module.getClasses().stream()).collect(Collectors.toList());
+            .flatMap(module -> module.getClasses().stream()).collect(toList());
 
         if (!sort) return unsorted;
 
@@ -1052,46 +1035,9 @@ public class CompilationUnit extends ProcessingUnit {
         return sorted;
     }
 
-    /**
-     * 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(final PrimaryClassNodeOperation body) throws CompilationFailedException {
-        for (ClassNode classNode : getPrimaryClassNodes(body.needSortedInput())) {
-            SourceUnit context = null;
-            try {
-                context = classNode.getModule().getContext();
-                if (context == null || context.phase < phase || (context.phase == phase && !context.phaseComplete)) {
-                    int offset = 1;
-                    for (Iterator<InnerClassNode> it = classNode.getInnerClasses(); it.hasNext(); ) {
-                        it.next();
-                        offset += 1;
-                    }
-                    body.call(context, new GeneratorContext(getAST(), 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 | Exception e) {
-                // effort to get more logging in case a dependency of a class is loaded
-                // although it shouldn't have
-                convertUncaughtExceptionToCompilationError(e);
-            }
-        }
-
-        getErrorCollector().failIfErrors();
-    }
-
     private void convertUncaughtExceptionToCompilationError(final Throwable e) {
-        // check the exception for a nested compilation exception
         ErrorCollector nestedCollector = null;
+        // check the exception for a nested compilation exception
         for (Throwable next = e.getCause(); next != e && next != null; next = next.getCause()) {
             if (!(next instanceof MultipleCompilationErrorsException)) continue;
             MultipleCompilationErrorsException mcee = (MultipleCompilationErrorsException) next;
@@ -1103,37 +1049,50 @@ public class CompilationUnit extends ProcessingUnit {
             getErrorCollector().addCollectorContents(nestedCollector);
         } else {
             Exception err = e instanceof Exception?((Exception)e):new RuntimeException(e);
-            getErrorCollector().addError(new ExceptionMessage(err, configuration.getDebug(), this));
+            getErrorCollector().addError(new ExceptionMessage(err, debug, this));
         }
     }
 
-    public void applyToGeneratedGroovyClasses(final 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());
-        }
+    private void changeBugText(final GroovyBugError e, final SourceUnit context) {
+        e.setBugText("exception in phase '" + getPhaseDescription() + "' in source unit '" + (context != null ? context.getName() : "?") + "' " + e.getBugText());
+    }
 
-        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();
+    @Deprecated
+    public void addPhaseOperation(final GroovyClassOperation op) {
+        addPhaseOperation((IGroovyClassOperation) op);
     }
 
-    private void changeBugText(final GroovyBugError e, final SourceUnit context) {
-        e.setBugText("exception in phase '" + getPhaseDescription() + "' in source unit '" + (context != null ? context.getName() : "?") + "' " + e.getBugText());
+    @Deprecated
+    public void addPhaseOperation(final SourceUnitOperation op, final int phase) {
+        addPhaseOperation((ISourceUnitOperation) op, phase);
+    }
+
+    @Deprecated
+    public void addPhaseOperation(final PrimaryClassNodeOperation op, final int phase) {
+        addPhaseOperation((IPrimaryClassNodeOperation) op, phase);
+    }
+
+    @Deprecated
+    public void addFirstPhaseOperation(final PrimaryClassNodeOperation op, final int phase) {
+        addFirstPhaseOperation((IPrimaryClassNodeOperation) op, phase);
+    }
+
+    @Deprecated
+    public void addNewPhaseOperation(final SourceUnitOperation op, final int phase) {
+        addNewPhaseOperation((ISourceUnitOperation) op, phase);
+    }
+
+    @Deprecated
+    public abstract static class SourceUnitOperation implements ISourceUnitOperation {
+    }
+
+    @Deprecated
+    public abstract static class GroovyClassOperation implements IGroovyClassOperation {
+    }
+
+    @Deprecated
+    public abstract static class PrimaryClassNodeOperation implements IPrimaryClassNodeOperation {
     }
 }
diff --git a/src/main/java/org/codehaus/groovy/control/CompilerConfiguration.java b/src/main/java/org/codehaus/groovy/control/CompilerConfiguration.java
index 1530ada..88733bd 100644
--- a/src/main/java/org/codehaus/groovy/control/CompilerConfiguration.java
+++ b/src/main/java/org/codehaus/groovy/control/CompilerConfiguration.java
@@ -1067,7 +1067,7 @@ public class CompilerConfiguration {
      * META-INF/services/org.codehaus.groovy.transform.ASTTransformation file.
      * If you explicitly add a global AST transformation in your compilation process,
      * for example using the {@link org.codehaus.groovy.control.customizers.ASTTransformationCustomizer} or
-     * using a {@link org.codehaus.groovy.control.CompilationUnit.PrimaryClassNodeOperation},
+     * using a {@link org.codehaus.groovy.control.CompilationUnit.IPrimaryClassNodeOperation},
      * then nothing will prevent the transformation from being loaded.
      *
      * @param disabledGlobalASTTransformations a set of fully qualified class names of global AST transformations
diff --git a/src/main/java/org/codehaus/groovy/control/StaticImportVisitor.java b/src/main/java/org/codehaus/groovy/control/StaticImportVisitor.java
index 1dea516..e1dd084 100644
--- a/src/main/java/org/codehaus/groovy/control/StaticImportVisitor.java
+++ b/src/main/java/org/codehaus/groovy/control/StaticImportVisitor.java
@@ -68,7 +68,7 @@ import static org.codehaus.groovy.ast.tools.ClosureUtils.getParametersSafe;
 public class StaticImportVisitor extends ClassCodeExpressionTransformer {
     private ClassNode currentClass;
     private MethodNode currentMethod;
-    private SourceUnit source;
+    private SourceUnit sourceUnit;
     private boolean inSpecialConstructorCall;
     private boolean inClosure;
     private boolean inPropertyExpression;
@@ -77,10 +77,19 @@ public class StaticImportVisitor extends ClassCodeExpressionTransformer {
     private boolean inAnnotation;
     private boolean inLeftExpression;
 
-    public void visitClass(ClassNode node, SourceUnit source) {
-        this.currentClass = node;
-        this.source = source;
-        super.visitClass(node);
+    public StaticImportVisitor(final ClassNode classNode, final SourceUnit sourceUnit) {
+        this.currentClass = classNode;
+        this.sourceUnit = sourceUnit;
+    }
+
+    /**
+     * Call {@link #StaticImportVisitor(ClassNode,SourceUnit)} then {@link #visitClass(ClassNode)}.
+     */
+    @Deprecated
+    public void visitClass(final ClassNode classNode, final SourceUnit sourceUnit) {
+        this.currentClass = classNode;
+        this.sourceUnit = sourceUnit;
+        visitClass(classNode);
     }
 
     @Override
@@ -565,7 +574,8 @@ public class StaticImportVisitor extends ClassCodeExpressionTransformer {
         return new StaticMethodCallExpression(type.getPlainNodeReference(), name, args);
     }
 
+    @Override
     protected SourceUnit getSourceUnit() {
-        return source;
+        return sourceUnit;
     }
 }
diff --git a/src/main/java/org/codehaus/groovy/control/customizers/CompilationCustomizer.java b/src/main/java/org/codehaus/groovy/control/customizers/CompilationCustomizer.java
index 9d0b565..63583c5 100644
--- a/src/main/java/org/codehaus/groovy/control/customizers/CompilationCustomizer.java
+++ b/src/main/java/org/codehaus/groovy/control/customizers/CompilationCustomizer.java
@@ -29,10 +29,10 @@ import org.codehaus.groovy.control.CompilePhase;
  *
  * @since 1.8.0
  */
-public abstract class CompilationCustomizer extends CompilationUnit.PrimaryClassNodeOperation {
+public abstract class CompilationCustomizer implements CompilationUnit.IPrimaryClassNodeOperation {
     private final CompilePhase phase;
 
-    public CompilationCustomizer(CompilePhase phase) {
+    public CompilationCustomizer(final CompilePhase phase) {
         this.phase = phase;
     }
 
diff --git a/src/main/java/org/codehaus/groovy/tools/javac/JavaAwareCompilationUnit.java b/src/main/java/org/codehaus/groovy/tools/javac/JavaAwareCompilationUnit.java
index de646aa..f43141b 100644
--- a/src/main/java/org/codehaus/groovy/tools/javac/JavaAwareCompilationUnit.java
+++ b/src/main/java/org/codehaus/groovy/tools/javac/JavaAwareCompilationUnit.java
@@ -20,6 +20,7 @@ package org.codehaus.groovy.tools.javac;
 
 import groovy.lang.GroovyClassLoader;
 import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.GroovyClassVisitor;
 import org.codehaus.groovy.ast.ModuleNode;
 import org.codehaus.groovy.classgen.GeneratorContext;
 import org.codehaus.groovy.classgen.VariableScopeVisitor;
@@ -75,35 +76,24 @@ public class JavaAwareCompilationUnit extends CompilationUnit {
         this.stubGenerator = new JavaStubGenerator(generationGoal, false, useJava5, encoding);
         this.keepStubs = Boolean.TRUE.equals(options.get("keepStubs"));
 
-        addPhaseOperation(new PrimaryClassNodeOperation() {
-            @Override
-            public void call(SourceUnit source, GeneratorContext context, ClassNode node) throws CompilationFailedException {
-                if (!javaSources.isEmpty()) {
-                    VariableScopeVisitor scopeVisitor = new VariableScopeVisitor(source);
-                    scopeVisitor.visitClass(node);
-                    new JavaAwareResolveVisitor(JavaAwareCompilationUnit.this).startResolving(node, source);
-                    AnnotationConstantsVisitor acv = new AnnotationConstantsVisitor();
-                    acv.visitClass(node, source);
-                }
+        addPhaseOperation((final SourceUnit source, final GeneratorContext context, final ClassNode classNode) -> {
+            if (!javaSources.isEmpty()) {
+                new VariableScopeVisitor(source).visitClass(classNode);
+                new JavaAwareResolveVisitor(this).startResolving(classNode, source);
+                new AnnotationConstantsVisitor().visitClass(classNode, source);
             }
         }, Phases.CONVERSION);
-        addPhaseOperation(new CompilationUnit.PrimaryClassNodeOperation() {
-            @Override
-            public void call(SourceUnit source, GeneratorContext context, ClassNode classNode) throws CompilationFailedException {
-                ASTTransformationCollectorCodeVisitor collector =
-                        new ASTTransformationCollectorCodeVisitor(source, JavaAwareCompilationUnit.this.getTransformLoader());
-                collector.visitClass(classNode);
-            }
+
+        addPhaseOperation((final SourceUnit source, final GeneratorContext context, final ClassNode classNode) -> {
+            GroovyClassVisitor visitor = new ASTTransformationCollectorCodeVisitor(source, getTransformLoader());
+            visitor.visitClass(classNode);
         }, Phases.CONVERSION);
 
-        addPhaseOperation(new PrimaryClassNodeOperation() {
-            @Override
-            public void call(SourceUnit source, GeneratorContext context, ClassNode classNode) throws CompilationFailedException {
-                try {
-                    if (!javaSources.isEmpty()) stubGenerator.generateClass(classNode);
-                } catch (FileNotFoundException fnfe) {
-                    source.addException(fnfe);
-                }
+        addPhaseOperation((final SourceUnit source, final GeneratorContext context, final ClassNode classNode) -> {
+            try {
+                if (!javaSources.isEmpty()) stubGenerator.generateClass(classNode);
+            } catch (FileNotFoundException fnfe) {
+                source.addException(fnfe);
             }
         }, Phases.CONVERSION);
     }
diff --git a/src/main/java/org/codehaus/groovy/tools/javac/JavaStubCompilationUnit.java b/src/main/java/org/codehaus/groovy/tools/javac/JavaStubCompilationUnit.java
index e5aefae..46e1d42 100644
--- a/src/main/java/org/codehaus/groovy/tools/javac/JavaStubCompilationUnit.java
+++ b/src/main/java/org/codehaus/groovy/tools/javac/JavaStubCompilationUnit.java
@@ -53,23 +53,17 @@ public class JavaStubCompilationUnit extends CompilationUnit {
         String encoding = configuration.getSourceEncoding();
         stubGenerator = new JavaStubGenerator(destDir, false, useJava5, encoding);
 
-        addPhaseOperation(new PrimaryClassNodeOperation() {
-            @Override
-            public void call(SourceUnit source, GeneratorContext context, ClassNode node) throws CompilationFailedException {
-                VariableScopeVisitor scopeVisitor = new VariableScopeVisitor(source);
-                scopeVisitor.visitClass(node);
-                new JavaAwareResolveVisitor(JavaStubCompilationUnit.this).startResolving(node, source);
-            }
+        addPhaseOperation((final SourceUnit source, final GeneratorContext context, final ClassNode classNode) -> {
+            new VariableScopeVisitor(source).visitClass(classNode);
+            new JavaAwareResolveVisitor(this).startResolving(classNode, source);
         }, Phases.CONVERSION);
-        addPhaseOperation(new PrimaryClassNodeOperation() {
-            @Override
-            public void call(final SourceUnit source, final GeneratorContext context, final ClassNode node) throws CompilationFailedException {
-                try {
-                    stubGenerator.generateClass(node);
-                    stubCount++;
-                } catch (FileNotFoundException e) {
-                    source.addException(e);
-                }
+
+        addPhaseOperation((final SourceUnit source, final GeneratorContext context, final ClassNode classNode) -> {
+            try {
+                stubGenerator.generateClass(classNode);
+                stubCount += 1;
+            } catch (FileNotFoundException e) {
+                source.addException(e);
             }
         }, Phases.CONVERSION);
     }
diff --git a/src/main/java/org/codehaus/groovy/transform/ASTTransformationVisitor.java b/src/main/java/org/codehaus/groovy/transform/ASTTransformationVisitor.java
index c2c508f..ea950a6 100644
--- a/src/main/java/org/codehaus/groovy/transform/ASTTransformationVisitor.java
+++ b/src/main/java/org/codehaus/groovy/transform/ASTTransformationVisitor.java
@@ -27,10 +27,10 @@ import org.codehaus.groovy.ast.AnnotatedNode;
 import org.codehaus.groovy.ast.AnnotationNode;
 import org.codehaus.groovy.ast.ClassCodeVisitorSupport;
 import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.GroovyClassVisitor;
 import org.codehaus.groovy.ast.expr.Expression;
 import org.codehaus.groovy.classgen.GeneratorContext;
 import org.codehaus.groovy.control.ASTTransformationsContext;
-import org.codehaus.groovy.control.CompilationFailedException;
 import org.codehaus.groovy.control.CompilationUnit;
 import org.codehaus.groovy.control.CompilePhase;
 import org.codehaus.groovy.control.Phases;
@@ -197,18 +197,14 @@ public final class ASTTransformationVisitor extends ClassCodeVisitorSupport {
 
 
     public static void addPhaseOperations(final CompilationUnit compilationUnit) {
-        final ASTTransformationsContext context = compilationUnit.getASTTransformationsContext();
+        ASTTransformationsContext context = compilationUnit.getASTTransformationsContext();
         addGlobalTransforms(context);
 
-        compilationUnit.addPhaseOperation(new CompilationUnit.PrimaryClassNodeOperation() {
-            public void call(SourceUnit source, GeneratorContext context, ClassNode classNode) throws CompilationFailedException {
-                ASTTransformationCollectorCodeVisitor collector =
-                    new ASTTransformationCollectorCodeVisitor(source, compilationUnit.getTransformLoader());
-                collector.visitClass(classNode);
-            }
+        compilationUnit.addPhaseOperation((final SourceUnit source, final GeneratorContext ignore, final ClassNode classNode) -> {
+            GroovyClassVisitor visitor = new ASTTransformationCollectorCodeVisitor(source, compilationUnit.getTransformLoader());
+            visitor.visitClass(classNode);
         }, Phases.SEMANTIC_ANALYSIS);
         for (CompilePhase phase : CompilePhase.values()) {
-            final ASTTransformationVisitor visitor = new ASTTransformationVisitor(phase, context);
             switch (phase) {
                 case INITIALIZATION:
                 case PARSING:
@@ -217,11 +213,10 @@ public final class ASTTransformationVisitor extends ClassCodeVisitorSupport {
                     break;
 
                 default:
-                    compilationUnit.addPhaseOperation(new CompilationUnit.PrimaryClassNodeOperation() {
-                        public void call(SourceUnit source, GeneratorContext context, ClassNode classNode) throws CompilationFailedException {
-                            visitor.source = source;
-                            visitor.visitClass(classNode);
-                        }
+                    compilationUnit.addPhaseOperation((final SourceUnit source, final GeneratorContext ignore, final ClassNode classNode) -> {
+                        ASTTransformationVisitor visitor = new ASTTransformationVisitor(phase, context);
+                        visitor.source = source;
+                        visitor.visitClass(classNode);
                     }, phase.getPhaseNumber());
                     break;
 
@@ -322,8 +317,8 @@ public final class ASTTransformationVisitor extends ClassCodeVisitorSupport {
         GroovyClassLoader transformLoader = compilationUnit.getTransformLoader();
         for (Map.Entry<String, URL> entry : transformNames.entrySet()) {
             try {
-                Class gTransClass = transformLoader.loadClass(entry.getKey(), false, true, false);
-                GroovyASTTransformation transformAnnotation = (GroovyASTTransformation) gTransClass.getAnnotation(GroovyASTTransformation.class);
+                Class<?> gTransClass = transformLoader.loadClass(entry.getKey(), false, true, false);
+                GroovyASTTransformation transformAnnotation = gTransClass.getAnnotation(GroovyASTTransformation.class);
                 if (transformAnnotation == null) {
                     compilationUnit.getErrorCollector().addWarning(new WarningMessage(
                         WarningMessage.POSSIBLE_ERRORS,
@@ -335,14 +330,12 @@ public final class ASTTransformationVisitor extends ClassCodeVisitorSupport {
                     continue;
                 }
                 if (ASTTransformation.class.isAssignableFrom(gTransClass)) {
-                    final ASTTransformation instance = (ASTTransformation)gTransClass.getDeclaredConstructor().newInstance();
+                    ASTTransformation instance = (ASTTransformation) gTransClass.getDeclaredConstructor().newInstance();
                     if (instance instanceof CompilationUnitAware) {
                         ((CompilationUnitAware)instance).setCompilationUnit(compilationUnit);
                     }
-                    CompilationUnit.SourceUnitOperation suOp = new CompilationUnit.SourceUnitOperation() {
-                        public void call(SourceUnit source) throws CompilationFailedException {
-                            instance.visit(new ASTNode[] {source.getAST()}, source);
-                        }
+                    CompilationUnit.ISourceUnitOperation suOp = source -> {
+                        instance.visit(new ASTNode[] {source.getAST()}, source);
                     };
                     if (isFirstScan) {
                         compilationUnit.addPhaseOperation(suOp, transformAnnotation.phase().getPhaseNumber());
diff --git a/src/main/java/org/codehaus/groovy/transform/sc/StaticCompilationVisitor.java b/src/main/java/org/codehaus/groovy/transform/sc/StaticCompilationVisitor.java
index 99b72c1..3dec6b8 100644
--- a/src/main/java/org/codehaus/groovy/transform/sc/StaticCompilationVisitor.java
+++ b/src/main/java/org/codehaus/groovy/transform/sc/StaticCompilationVisitor.java
@@ -49,14 +49,13 @@ import org.codehaus.groovy.ast.stmt.ExpressionStatement;
 import org.codehaus.groovy.ast.stmt.ForStatement;
 import org.codehaus.groovy.ast.stmt.Statement;
 import org.codehaus.groovy.ast.tools.GeneralUtils;
-import org.codehaus.groovy.classgen.GeneratorContext;
 import org.codehaus.groovy.classgen.asm.InvocationWriter;
 import org.codehaus.groovy.classgen.asm.MopWriter;
 import org.codehaus.groovy.classgen.asm.TypeChooser;
 import org.codehaus.groovy.classgen.asm.WriterControllerFactory;
 import org.codehaus.groovy.classgen.asm.sc.StaticCompilationMopWriter;
 import org.codehaus.groovy.classgen.asm.sc.StaticTypesTypeChooser;
-import org.codehaus.groovy.control.CompilationUnit;
+import org.codehaus.groovy.control.CompilationUnit.IPrimaryClassNodeOperation;
 import org.codehaus.groovy.control.SourceUnit;
 import org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport;
 import org.codehaus.groovy.transform.stc.StaticTypeCheckingVisitor;
@@ -155,13 +154,10 @@ public class StaticCompilationVisitor extends StaticTypeCheckingVisitor {
     private void addDynamicOuterClassAccessorsCallback(final ClassNode outer) {
         if (outer != null) {
             if (!isStaticallyCompiled(outer) && outer.getNodeMetaData(DYNAMIC_OUTER_NODE_CALLBACK) == null) {
-                outer.putNodeMetaData(DYNAMIC_OUTER_NODE_CALLBACK, new CompilationUnit.PrimaryClassNodeOperation() {
-                    @Override
-                    public void call(final SourceUnit source, final GeneratorContext context, final ClassNode classNode) {
-                        if (classNode == outer) {
-                            addPrivateBridgeMethods(classNode);
-                            addPrivateFieldsAccessors(classNode);
-                        }
+                outer.putNodeMetaData(DYNAMIC_OUTER_NODE_CALLBACK, (IPrimaryClassNodeOperation) (source, context, classNode) -> {
+                    if (classNode == outer) {
+                        addPrivateBridgeMethods(classNode);
+                        addPrivateFieldsAccessors(classNode);
                     }
                 });
             }
diff --git a/src/main/java/org/codehaus/groovy/transform/trait/TraitASTTransformation.java b/src/main/java/org/codehaus/groovy/transform/trait/TraitASTTransformation.java
index a12584c..70952bf 100644
--- a/src/main/java/org/codehaus/groovy/transform/trait/TraitASTTransformation.java
+++ b/src/main/java/org/codehaus/groovy/transform/trait/TraitASTTransformation.java
@@ -27,6 +27,7 @@ import org.codehaus.groovy.ast.ClassHelper;
 import org.codehaus.groovy.ast.ClassNode;
 import org.codehaus.groovy.ast.FieldNode;
 import org.codehaus.groovy.ast.GenericsType;
+import org.codehaus.groovy.ast.GroovyClassVisitor;
 import org.codehaus.groovy.ast.InnerClassNode;
 import org.codehaus.groovy.ast.MethodNode;
 import org.codehaus.groovy.ast.Parameter;
@@ -47,7 +48,6 @@ import org.codehaus.groovy.ast.tools.GeneralUtils;
 import org.codehaus.groovy.classgen.GeneratorContext;
 import org.codehaus.groovy.classgen.VariableScopeVisitor;
 import org.codehaus.groovy.classgen.Verifier;
-import org.codehaus.groovy.control.CompilationFailedException;
 import org.codehaus.groovy.control.CompilationUnit;
 import org.codehaus.groovy.control.CompilePhase;
 import org.codehaus.groovy.control.SourceUnit;
@@ -340,19 +340,16 @@ public class TraitASTTransformation extends AbstractASTTransformation implements
     }
 
     private void registerASTTransformations(final ClassNode helper) {
-        ASTTransformationCollectorCodeVisitor collector = new ASTTransformationCollectorCodeVisitor(
-                unit, compilationUnit.getTransformLoader()
-        );
-        collector.visitClass(helper);
+        {
+            GroovyClassVisitor visitor = new ASTTransformationCollectorCodeVisitor(unit, compilationUnit.getTransformLoader());
+            visitor.visitClass(helper);
+        }
         // Perform an additional phase which has to be done *after* type checking
-        compilationUnit.addPhaseOperation(new CompilationUnit.PrimaryClassNodeOperation() {
-            @Override
-            public void call(final SourceUnit source, final GeneratorContext context, final ClassNode classNode) throws CompilationFailedException {
-                if (classNode==helper) {
-                    PostTypeCheckingExpressionReplacer replacer = new PostTypeCheckingExpressionReplacer(source);
-                    replacer.visitClass(helper);
-                }
-            }
+        compilationUnit.addPhaseOperation((final SourceUnit source, final GeneratorContext context, final ClassNode classNode) -> {
+            if (classNode != helper) return;
+
+            GroovyClassVisitor visitor = new PostTypeCheckingExpressionReplacer(source);
+            visitor.visitClass(helper);
         }, CompilePhase.INSTRUCTION_SELECTION.getPhaseNumber());
     }
 
diff --git a/src/test/groovy/lang/GroovyClassLoaderTest.groovy b/src/test/groovy/lang/GroovyClassLoaderTest.groovy
index 9466beb..41a41e3 100644
--- a/src/test/groovy/lang/GroovyClassLoaderTest.groovy
+++ b/src/test/groovy/lang/GroovyClassLoaderTest.groovy
@@ -270,13 +270,15 @@ class GroovyClassLoaderTestCustomGCL extends GroovyClassLoader {
     }
 }
 
-class GroovyClassLoaderTestPropertyAdder extends CompilationUnit.PrimaryClassNodeOperation {
+class GroovyClassLoaderTestPropertyAdder implements CompilationUnit.IPrimaryClassNodeOperation {
+    @Override
     void call(SourceUnit source, GeneratorContext context, ClassNode classNode) {
         classNode.addProperty("id", ClassNode.ACC_PUBLIC, ClassHelper.long_TYPE, null, null, null)
     }
 }
 
 class GroovyClassLoaderTestCustomPhaseOperation extends GroovyClassLoader {
+    @Override
     CompilationUnit createCompilationUnit(CompilerConfiguration config, CodeSource source) {
         def cu = super.createCompilationUnit(config, source)
         cu.addPhaseOperation(new GroovyClassLoaderTestPropertyAdder(), Phases.CONVERSION)
diff --git a/src/test/org/codehaus/groovy/ClosureAndInnerClassNodeStructureTest.groovy b/src/test/org/codehaus/groovy/ClosureAndInnerClassNodeStructureTest.groovy
index 9fc89b0..75d3196 100644
--- a/src/test/org/codehaus/groovy/ClosureAndInnerClassNodeStructureTest.groovy
+++ b/src/test/org/codehaus/groovy/ClosureAndInnerClassNodeStructureTest.groovy
@@ -20,7 +20,6 @@ package org.codehaus.groovy
 
 import groovy.test.GroovyTestCase
 import org.codehaus.groovy.control.CompilationUnit
-import org.codehaus.groovy.control.CompilationUnit.PrimaryClassNodeOperation
 import org.codehaus.groovy.classgen.GeneratorContext
 import org.codehaus.groovy.control.SourceUnit
 import org.codehaus.groovy.control.Phases
@@ -53,7 +52,8 @@ class ClosureAndInnerClassNodeStructureTest extends GroovyTestCase {
 
         def classNodes = [:]
 
-        cu.addPhaseOperation(new PrimaryClassNodeOperation() {
+        cu.addPhaseOperation(new CompilationUnit.IPrimaryClassNodeOperation() {
+            @Override
             void call(SourceUnit source, GeneratorContext context, ClassNode cn) {
                 def recurse = { ClassNode node ->
                     classNodes[node.name] = node
diff --git a/src/test/org/codehaus/groovy/tools/gse/DependencyTest.java b/src/test/org/codehaus/groovy/tools/gse/DependencyTest.java
index e903298..5788b39 100644
--- a/src/test/org/codehaus/groovy/tools/gse/DependencyTest.java
+++ b/src/test/org/codehaus/groovy/tools/gse/DependencyTest.java
@@ -18,39 +18,32 @@
  */
 package org.codehaus.groovy.tools.gse;
 
-import java.io.StringBufferInputStream;
-import java.util.Set;
-
+import groovy.test.GroovyTestCase;
 import org.codehaus.groovy.ast.ClassNode;
 import org.codehaus.groovy.classgen.GeneratorContext;
-import org.codehaus.groovy.control.CompilationFailedException;
 import org.codehaus.groovy.control.CompilationUnit;
 import org.codehaus.groovy.control.Phases;
 import org.codehaus.groovy.control.SourceUnit;
 
-import groovy.test.GroovyTestCase;
+import java.io.StringBufferInputStream;
+import java.util.Set;
 
 @SuppressWarnings("deprecation")
 public class DependencyTest extends GroovyTestCase {
     private CompilationUnit cu;
     StringSetMap cache;
-    
+
     @Override
     protected void setUp() throws Exception {
         super.setUp();
-        cu = new CompilationUnit();
         cache = new StringSetMap();
-        cu.addPhaseOperation(new CompilationUnit.PrimaryClassNodeOperation() {
-            @Override
-            public void call(final SourceUnit source, GeneratorContext context, ClassNode classNode) 
-                throws CompilationFailedException 
-            {   
-                DependencyTracker dt = new DependencyTracker(source,cache);
-                dt.visitClass(classNode);
-            }
+        cu = new CompilationUnit();
+        cu.addPhaseOperation((final SourceUnit source, final GeneratorContext context, final ClassNode classNode) -> {
+            DependencyTracker dt = new DependencyTracker(source, cache);
+            dt.visitClass(classNode);
         }, Phases.CLASS_GENERATION);
     }
-    
+
     public void testDep(){
         cu.addSource("testDep.gtest", new StringBufferInputStream(
                 "class C1 {}\n" +
@@ -64,22 +57,22 @@ public class DependencyTest extends GroovyTestCase {
         assertEquals(cache.get("C1").size(),1);
         assertEquals(cache.get("C2").size(),1);
         assertEquals(cache.get("C3").size(),1);
-        
+
         Set<String> dep = cache.get("A1");
         assertEquals(dep.size(),2);
         assertTrue(dep.contains("C1"));
-        
+
         dep = cache.get("A2");
         assertEquals(dep.size(),2);
         assertTrue(dep.contains("C2"));
-        
+
         dep = cache.get("A3");
         assertEquals(dep.size(),4);
         assertTrue(dep.contains("C1"));
         assertTrue(dep.contains("C2"));
         assertTrue(dep.contains("C3"));
     }
-    
+
     public void testTransitiveDep(){
         cu.addSource("testTransitiveDep.gtest", new StringBufferInputStream(
                 "class A1 {}\n" +
@@ -88,19 +81,19 @@ public class DependencyTest extends GroovyTestCase {
         ));
         cu.compile(Phases.CLASS_GENERATION);
         cache.makeTransitiveHull();
-         
+
         Set<String> dep = cache.get("A1");
         assertEquals(dep.size(),1);
-        
+
         dep = cache.get("A2");
         assertEquals(dep.size(),2);
         assertTrue(dep.contains("A1"));
-        
+
         dep = cache.get("A3");
         assertEquals(dep.size(),3);
         assertTrue(dep.contains("A1"));
         assertTrue(dep.contains("A2"));
     }
-    
+
 
 }
diff --git a/subprojects/groovy-console/src/main/groovy/groovy/console/ui/AstNodeToScriptAdapter.groovy b/subprojects/groovy-console/src/main/groovy/groovy/console/ui/AstNodeToScriptAdapter.groovy
index 292a8ae..1edda5f 100644
--- a/subprojects/groovy-console/src/main/groovy/groovy/console/ui/AstNodeToScriptAdapter.groovy
+++ b/subprojects/groovy-console/src/main/groovy/groovy/console/ui/AstNodeToScriptAdapter.groovy
@@ -95,7 +95,6 @@ import org.codehaus.groovy.classgen.GeneratorContext
 import org.codehaus.groovy.classgen.Verifier
 import org.codehaus.groovy.control.CompilationFailedException
 import org.codehaus.groovy.control.CompilationUnit
-import org.codehaus.groovy.control.CompilationUnit.PrimaryClassNodeOperation
 import org.codehaus.groovy.control.CompilePhase
 import org.codehaus.groovy.control.CompilerConfiguration
 import org.codehaus.groovy.control.SourceUnit
@@ -189,7 +188,7 @@ and [compilephase] is a valid Integer based org.codehaus.groovy.control.CompileP
  * An adapter from ASTNode tree to source code.
  */
 @CompileStatic
-class AstNodeToScriptVisitor extends PrimaryClassNodeOperation implements GroovyCodeVisitor, GroovyClassVisitor {
+class AstNodeToScriptVisitor implements CompilationUnit.IPrimaryClassNodeOperation, GroovyClassVisitor, GroovyCodeVisitor {
 
     private final Writer _out
     Stack<String> classNameStack = new Stack<String>()
diff --git a/subprojects/groovy-console/src/main/groovy/groovy/console/ui/ScriptToTreeNodeAdapter.groovy b/subprojects/groovy-console/src/main/groovy/groovy/console/ui/ScriptToTreeNodeAdapter.groovy
index d42f3ba..c9e78f4 100644
--- a/subprojects/groovy-console/src/main/groovy/groovy/console/ui/ScriptToTreeNodeAdapter.groovy
+++ b/subprojects/groovy-console/src/main/groovy/groovy/console/ui/ScriptToTreeNodeAdapter.groovy
@@ -98,7 +98,6 @@ import org.codehaus.groovy.classgen.GeneratorContext
 import org.codehaus.groovy.classgen.asm.BytecodeHelper
 import org.codehaus.groovy.control.CompilationFailedException
 import org.codehaus.groovy.control.CompilationUnit
-import org.codehaus.groovy.control.CompilationUnit.PrimaryClassNodeOperation
 import org.codehaus.groovy.control.CompilerConfiguration
 import org.codehaus.groovy.control.SourceUnit
 
@@ -275,7 +274,7 @@ class ScriptToTreeNodeAdapter {
 /**
  * This Node Operation builds up a root tree node for the viewer.
  */
-class TreeNodeBuildingNodeOperation extends PrimaryClassNodeOperation {
+class TreeNodeBuildingNodeOperation implements CompilationUnit.IPrimaryClassNodeOperation {
 
     final root
     final sourceCollected = new AtomicBoolean(false)
diff --git a/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/util/ScriptVariableAnalyzer.groovy b/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/util/ScriptVariableAnalyzer.groovy
index 47e7990..281a31c 100644
--- a/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/util/ScriptVariableAnalyzer.groovy
+++ b/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/util/ScriptVariableAnalyzer.groovy
@@ -69,10 +69,10 @@ class ScriptVariableAnalyzer {
     }
 
     /**
-     * custom PrimaryClassNodeOperation
+     * custom IPrimaryClassNodeOperation
      * to be able to hook our code visitor
      */
-    static class VisitorSourceOperation extends CompilationUnit.PrimaryClassNodeOperation {
+    static class VisitorSourceOperation implements CompilationUnit.IPrimaryClassNodeOperation {
 
         final GroovyClassVisitor visitor
 
diff --git a/subprojects/groovy-jsr223/src/test/java/org/codehaus/groovy/jsr223/JSR223SecurityTest.java b/subprojects/groovy-jsr223/src/test/java/org/codehaus/groovy/jsr223/JSR223SecurityTest.java
index 52b98a3..561beb2 100644
--- a/subprojects/groovy-jsr223/src/test/java/org/codehaus/groovy/jsr223/JSR223SecurityTest.java
+++ b/subprojects/groovy-jsr223/src/test/java/org/codehaus/groovy/jsr223/JSR223SecurityTest.java
@@ -25,7 +25,6 @@ import org.codehaus.groovy.ast.expr.MethodCallExpression;
 import org.codehaus.groovy.ast.stmt.ExpressionStatement;
 import org.codehaus.groovy.classgen.GeneratorContext;
 import org.codehaus.groovy.control.CompilationUnit;
-import org.codehaus.groovy.control.CompilationUnit.PrimaryClassNodeOperation;
 import org.codehaus.groovy.control.CompilerConfiguration;
 import org.codehaus.groovy.control.Phases;
 import org.codehaus.groovy.control.SourceUnit;
@@ -35,6 +34,7 @@ import org.junit.Test;
 import javax.script.ScriptEngine;
 import javax.script.ScriptEngineManager;
 import javax.script.ScriptException;
+
 import java.lang.reflect.Field;
 import java.security.CodeSource;
 import java.util.HashSet;
@@ -161,11 +161,12 @@ class CustomGroovyClassLoader extends GroovyClassLoader {
     }
 }
 
-class CustomPrimaryClassNodeOperation extends PrimaryClassNodeOperation {
-
+class CustomPrimaryClassNodeOperation implements CompilationUnit.IPrimaryClassNodeOperation {
+    @Override
     public void call(SourceUnit source, GeneratorContext context, ClassNode classNode) {
-        for (Object statement : source.getAST().getStatementBlock().getStatements())
+        for (Object statement : source.getAST().getStatementBlock().getStatements()) {
             ((ExpressionStatement) statement).visit(new CustomCodeVisitorSupport());
+        }
     }
 }
 
diff --git a/subprojects/parser-antlr4/src/test/groovy/org/apache/groovy/parser/antlr4/util/AstDumper.groovy b/subprojects/parser-antlr4/src/test/groovy/org/apache/groovy/parser/antlr4/util/AstDumper.groovy
index a4a5616..8d3b8d4 100644
--- a/subprojects/parser-antlr4/src/test/groovy/org/apache/groovy/parser/antlr4/util/AstDumper.groovy
+++ b/subprojects/parser-antlr4/src/test/groovy/org/apache/groovy/parser/antlr4/util/AstDumper.groovy
@@ -147,7 +147,7 @@ class AstDumper {
  * An adapter from ASTNode tree to source code.
  */
 @CompileStatic
-class AstNodeToScriptVisitor extends CompilationUnit.PrimaryClassNodeOperation implements GroovyCodeVisitor, GroovyClassVisitor {
+class AstNodeToScriptVisitor implements CompilationUnit.IPrimaryClassNodeOperation, GroovyClassVisitor, GroovyCodeVisitor {
 
     private final Writer _out
     Stack<String> classNameStack = new Stack<String>()
@@ -164,6 +164,7 @@ class AstNodeToScriptVisitor extends CompilationUnit.PrimaryClassNodeOperation i
         this.scriptHasBeenVisited = false
     }
 
+    @Override
     void call(SourceUnit source, GeneratorContext context, ClassNode classNode) {
 
         visitPackage(source?.getAST()?.getPackage())


[groovy] 01/05: minor edits

Posted by su...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

sunlan pushed a commit to branch GROOVY_3_0_X
in repository https://gitbox.apache.org/repos/asf/groovy.git

commit 8c63690719b14d3dd1ad972d3085f1e71f3b9797
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Mon Dec 16 10:55:47 2019 -0600

    minor edits
    
    (cherry picked from commit d3a67f009dc24fc884a410c79fa9819a343141da)
---
 .../codehaus/groovy/control/CompilationUnit.java   | 379 ++++++++++-----------
 .../java/org/codehaus/groovy/control/Phases.java   |  57 ++--
 .../codehaus/groovy/control/ResolveVisitor.java    |   1 +
 .../asm/sc/StaticCompilationTestSupport.groovy     |   4 +-
 4 files changed, 207 insertions(+), 234 deletions(-)

diff --git a/src/main/java/org/codehaus/groovy/control/CompilationUnit.java b/src/main/java/org/codehaus/groovy/control/CompilationUnit.java
index 51763cf..193a13d 100644
--- a/src/main/java/org/codehaus/groovy/control/CompilationUnit.java
+++ b/src/main/java/org/codehaus/groovy/control/CompilationUnit.java
@@ -53,7 +53,6 @@ import org.codehaus.groovy.transform.trait.TraitComposer;
 import org.objectweb.asm.ClassVisitor;
 import org.objectweb.asm.ClassWriter;
 
-import javax.tools.JavaFileObject;
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
@@ -61,14 +60,17 @@ import java.io.InputStream;
 import java.net.URL;
 import java.security.CodeSource;
 import java.util.ArrayList;
-import java.util.HashMap;
+import java.util.Deque;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.LinkedHashMap;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
+import java.util.Optional;
+import java.util.Queue;
 import java.util.Set;
+import java.util.stream.Collectors;
 
 /**
  * The CompilationUnit collects all compilation data as it is generated by the compiler system.
@@ -80,37 +82,49 @@ import java.util.Set;
  */
 public class CompilationUnit extends ProcessingUnit {
 
-    //---------------------------------------------------------------------------
-    // CONSTRUCTION AND SUCH
+    /** The overall AST for this CompilationUnit. */
+    protected CompileUnit ast; // TODO: Switch to private and access through getAST().
 
-    protected ASTTransformationsContext astTransformationsContext; // AST transformations state data
+    /** The source units from which this unit is built. */
+    protected Map<String, SourceUnit> sources = new LinkedHashMap<>();
+    protected Queue<SourceUnit> queuedSources = new LinkedList<>();
 
-    protected Map<String, SourceUnit> sources;    // The SourceUnits from which this unit is built
-    protected Map summariesBySourceName;      // Summary of each SourceUnit
-    protected Map summariesByPublicClassName;       // Summary of each SourceUnit
-    protected Map classSourcesByPublicClassName;    // Summary of each Class
-    protected LinkedList<SourceUnit> queuedSources;
+    /** The classes generated during classgen. */
+    private List<GroovyClass> generatedClasses = new ArrayList<>();
 
-    protected CompileUnit ast;        // The overall AST for this CompilationUnit.
-    protected List<GroovyClass> generatedClasses;  // The classes generated during classgen.
+    private Deque[] phaseOperations;
+    private Deque[] newPhaseOperations;
+    {
+        final int n = Phases.ALL + 1;
+        phaseOperations = new Deque[n];
+        newPhaseOperations = new Deque[n];
+        for (int i = 0; i < n; i += 1) {
+            phaseOperations[i] = new LinkedList<>();
+            newPhaseOperations[i] = new LinkedList<>();
+        }
+    }
 
-    protected Verifier verifier;   // For use by verify().
+    /** Controls behavior of {@link #classgen()} and other routines. */
+    protected boolean debug;
+    /** True after the first {@link #configure()} operation. */
+    protected boolean configured;
 
-    protected boolean debug;      // Controls behavior of classgen() and other routines.
-    protected boolean configured; // Set true after the first configure() operation
+    /** A callback for use during {@link #classgen()} */
+    protected ClassgenCallback classgenCallback;
+    /** A callback for use during {@link #compile()} */
+    protected ProgressCallback progressCallback;
 
-    protected ClassgenCallback classgenCallback;  // A callback for use during classgen()
-    protected ProgressCallback progressCallback;  // A callback for use during compile()
-    protected ResolveVisitor resolveVisitor;
-    protected StaticImportVisitor staticImportVisitor;
-    protected DefaultTransformer defaultTransformer;
-    protected OptimizerVisitor optimizer;
-    protected ClassNodeResolver classNodeResolver;
+    protected StaticImportVisitor staticImportVisitor = new StaticImportVisitor();
+    protected DefaultTransformer defaultTransformer = new DefaultTransformer();
+    protected ClassNodeResolver classNodeResolver = new ClassNodeResolver();
+    protected ResolveVisitor resolveVisitor = new ResolveVisitor(this);
+    protected OptimizerVisitor optimizer = new OptimizerVisitor(this);
+    protected Verifier verifier = new Verifier();
 
-    LinkedList[] phaseOperations;
-    LinkedList[] newPhaseOperations;
+    /** The AST transformations state data. */
+    protected ASTTransformationsContext astTransformationsContext;
 
-    private Set<JavaFileObject> javaCompilationUnitSet = new HashSet<>();
+    private Set<javax.tools.JavaFileObject> javaCompilationUnitSet = new HashSet<>();
 
     /**
      * Initializes the CompilationUnit with defaults.
@@ -122,14 +136,14 @@ public class CompilationUnit extends ProcessingUnit {
     /**
      * Initializes the CompilationUnit with defaults except for class loader.
      */
-    public CompilationUnit(GroovyClassLoader loader) {
+    public CompilationUnit(final GroovyClassLoader loader) {
         this(null, null, loader);
     }
 
     /**
      * Initializes the CompilationUnit with no security considerations.
      */
-    public CompilationUnit(CompilerConfiguration configuration) {
+    public CompilationUnit(final CompilerConfiguration configuration) {
         this(configuration, null, null);
     }
 
@@ -137,8 +151,8 @@ public class CompilationUnit extends ProcessingUnit {
      * Initializes the CompilationUnit with a CodeSource for controlling
      * security stuff and a class loader for loading classes.
      */
-    public CompilationUnit(CompilerConfiguration configuration, CodeSource security, GroovyClassLoader loader) {
-        this(configuration, security, loader, null);
+    public CompilationUnit(final CompilerConfiguration configuration, final CodeSource codeSource, final GroovyClassLoader loader) {
+        this(configuration, codeSource, loader, null);
     }
 
     /**
@@ -151,46 +165,18 @@ public class CompilationUnit extends ProcessingUnit {
      *
      * @param transformLoader - the loader for transforms
      * @param loader          - loader used to resolve classes against during compilation
-     * @param security        - security setting for the compilation
+     * @param codeSource      - security setting for the compilation
      * @param configuration   - compilation configuration
      */
-    public CompilationUnit(CompilerConfiguration configuration, CodeSource security,
-                           GroovyClassLoader loader, GroovyClassLoader transformLoader) {
+    public CompilationUnit(final CompilerConfiguration configuration, final CodeSource codeSource,
+                           final GroovyClassLoader loader, final GroovyClassLoader transformLoader) {
         super(configuration, loader, null);
 
         this.astTransformationsContext = new ASTTransformationsContext(this, transformLoader);
-        this.queuedSources = new LinkedList<>();
-        this.sources = new LinkedHashMap<>();
-        this.summariesBySourceName = new HashMap<>();
-        this.summariesByPublicClassName = new HashMap<>();
-        this.classSourcesByPublicClassName = new HashMap<>();
-
-        this.ast = new CompileUnit(this.classLoader, security, this.configuration);
-        this.generatedClasses = new ArrayList<>();
-
-        this.verifier = new Verifier();
-        this.resolveVisitor = new ResolveVisitor(this);
-        this.staticImportVisitor = new StaticImportVisitor();
-        this.defaultTransformer = new DefaultTransformer();
-        this.optimizer = new OptimizerVisitor(this);
-
-        initPhaseOperations();
-        addPhaseOperations();
+        this.ast = new CompileUnit(this.classLoader, codeSource, this.configuration);
 
+        addPhaseOperations();
         applyCompilationCustomizers();
-
-        this.classgenCallback = null;
-        this.classNodeResolver = new ClassNodeResolver();
-    }
-
-    private void initPhaseOperations() {
-        int cnt = Phases.ALL + 1;
-        phaseOperations = new LinkedList[cnt];
-        newPhaseOperations = new LinkedList[cnt];
-        for (int i = 0; i < phaseOperations.length; i++) {
-            phaseOperations[i] = new LinkedList<>();
-            newPhaseOperations[i] = new LinkedList<>();
-        }
     }
 
     private void addPhaseOperations() {
@@ -298,48 +284,42 @@ public class CompilationUnit extends ProcessingUnit {
         }
     }
 
-    /**
-     * Returns the class loader for loading AST transformations.
-     * @return - the transform class loader
-     */
-    public GroovyClassLoader getTransformLoader() {
-        return astTransformationsContext.getTransformLoader() == null ? getClassLoader() : astTransformationsContext.getTransformLoader();
+    public void addPhaseOperation(final GroovyClassOperation op) {
+        phaseOperations[Phases.OUTPUT].addFirst(op);
     }
 
-    public void addPhaseOperation(SourceUnitOperation op, int phase) {
+    public void addPhaseOperation(final SourceUnitOperation op, final int phase) {
         validatePhase(phase);
         phaseOperations[phase].add(op);
     }
 
-    public void addPhaseOperation(PrimaryClassNodeOperation op, int phase) {
+    public void addPhaseOperation(final PrimaryClassNodeOperation op, final int phase) {
         validatePhase(phase);
         phaseOperations[phase].add(op);
     }
 
-    private static void validatePhase(int phase) {
-        if (phase < 0 || phase > Phases.ALL) throw new IllegalArgumentException("phase " + phase + " is unknown");
-    }
-
-    public void addFirstPhaseOperation(PrimaryClassNodeOperation op, int phase) {
+    public void addFirstPhaseOperation(final PrimaryClassNodeOperation op, final int phase) {
         validatePhase(phase);
-        phaseOperations[phase].add(0, op);
-    }
-
-    public void addPhaseOperation(GroovyClassOperation op) {
-        phaseOperations[Phases.OUTPUT].addFirst(op);
+        phaseOperations[phase].addFirst(op);
     }
 
-    public void addNewPhaseOperation(SourceUnitOperation op, int phase) {
+    public void addNewPhaseOperation(final SourceUnitOperation op, final int phase) {
         validatePhase(phase);
         newPhaseOperations[phase].add(op);
     }
 
+    private static void validatePhase(final int phase) {
+        if (phase < 1 || phase > Phases.ALL) {
+            throw new IllegalArgumentException("phase " + phase + " is unknown");
+        }
+    }
+
     /**
      * Configures its debugging mode and classloader classpath from a given compiler configuration.
      * This cannot be done more than once due to limitations in {@link java.net.URLClassLoader URLClassLoader}.
      */
     @Override
-    public void configure(CompilerConfiguration configuration) {
+    public void configure(final CompilerConfiguration configuration) {
         super.configure(configuration);
         this.debug = this.configuration.getDebug();
         this.configured = true;
@@ -353,25 +333,6 @@ public class CompilationUnit extends ProcessingUnit {
     }
 
     /**
-     * Get the source summaries
-     */
-    public Map getSummariesBySourceName() {
-        return summariesBySourceName;
-    }
-
-    public Map getSummariesByPublicClassName() {
-        return summariesByPublicClassName;
-    }
-
-    public Map getClassSourcesByPublicClassName() {
-        return classSourcesByPublicClassName;
-    }
-
-    public boolean isPublicClass(String className) {
-        return summariesByPublicClassName.containsKey(className);
-    }
-
-    /**
      * Get the GroovyClasses generated by compile().
      */
     public List<GroovyClass> getClasses() {
@@ -383,14 +344,14 @@ public class CompilationUnit extends ProcessingUnit {
      * when you are sure there is only one.
      */
     public ClassNode getFirstClassNode() {
-        return this.ast.getModules().get(0).getClasses().get(0);
+        return getAST().getModules().get(0).getClasses().get(0);
     }
 
     /**
      * Convenience routine to get the named ClassNode.
      */
     public ClassNode getClassNode(final String name) {
-        final ClassNode[] result = new ClassNode[1];
+        ClassNode[] result = new ClassNode[1];
         PrimaryClassNodeOperation handler = new PrimaryClassNodeOperation() {
             @Override
             public void call(SourceUnit source, GeneratorContext context, ClassNode classNode) {
@@ -399,7 +360,6 @@ public class CompilationUnit extends ProcessingUnit {
                 }
             }
         };
-
         try {
             applyToPrimaryClassNodes(handler);
         } catch (CompilationFailedException e) {
@@ -415,13 +375,36 @@ public class CompilationUnit extends ProcessingUnit {
         return astTransformationsContext;
     }
 
+    public ClassNodeResolver getClassNodeResolver() {
+        return classNodeResolver;
+    }
+
+    public void setClassNodeResolver(final ClassNodeResolver classNodeResolver) {
+        this.classNodeResolver = classNodeResolver;
+    }
+
+    public Set<javax.tools.JavaFileObject> getJavaCompilationUnitSet() {
+        return javaCompilationUnitSet;
+    }
+
+    public void addJavaCompilationUnits(final Set<javax.tools.JavaFileObject> javaCompilationUnitSet) {
+        this.javaCompilationUnitSet.addAll(javaCompilationUnitSet);
+    }
+
+    /**
+     * @return the class loader for loading AST transformations
+     */
+    public GroovyClassLoader getTransformLoader() {
+        return Optional.ofNullable(getASTTransformationsContext().getTransformLoader()).orElseGet(this::getClassLoader);
+    }
+
     //---------------------------------------------------------------------------
     // SOURCE CREATION
 
     /**
      * Adds a set of file paths to the unit.
      */
-    public void addSources(String[] paths) {
+    public void addSources(final String[] paths) {
         for (String path : paths) {
             addSource(new File(path));
         }
@@ -430,7 +413,7 @@ public class CompilationUnit extends ProcessingUnit {
     /**
      * Adds a set of source files to the unit.
      */
-    public void addSources(File[] files) {
+    public void addSources(final File[] files) {
         for (File file : files) {
             addSource(file);
         }
@@ -439,33 +422,33 @@ public class CompilationUnit extends ProcessingUnit {
     /**
      * Adds a source file to the unit.
      */
-    public SourceUnit addSource(File file) {
+    public SourceUnit addSource(final File file) {
         return addSource(new SourceUnit(file, configuration, classLoader, getErrorCollector()));
     }
 
     /**
      * Adds a source file to the unit.
      */
-    public SourceUnit addSource(URL url) {
+    public SourceUnit addSource(final URL url) {
         return addSource(new SourceUnit(url, configuration, classLoader, getErrorCollector()));
     }
 
     /**
      * Adds a InputStream source to the unit.
      */
-    public SourceUnit addSource(String name, InputStream stream) {
+    public SourceUnit addSource(final String name, final InputStream stream) {
         ReaderSource source = new InputStreamReaderSource(stream, configuration);
         return addSource(new SourceUnit(name, source, configuration, classLoader, getErrorCollector()));
     }
 
-    public SourceUnit addSource(String name, String scriptText) {
+    public SourceUnit addSource(final String name, final String scriptText) {
         return addSource(new SourceUnit(name, scriptText, configuration, classLoader, getErrorCollector()));
     }
 
     /**
      * Adds a SourceUnit to the unit.
      */
-    public SourceUnit addSource(SourceUnit source) {
+    public SourceUnit addSource(final SourceUnit source) {
         String name = source.getName();
         source.setClassLoader(this.classLoader);
         for (SourceUnit su : queuedSources) {
@@ -480,7 +463,7 @@ public class CompilationUnit extends ProcessingUnit {
      */
     public Iterator<SourceUnit> iterator() {
         return new Iterator<SourceUnit>() {
-            Iterator<String> nameIterator = sources.keySet().iterator();
+            private Iterator<String> nameIterator = sources.keySet().iterator();
             @Override
             public boolean hasNext() {
                 return nameIterator.hasNext();
@@ -503,9 +486,9 @@ public class CompilationUnit extends ProcessingUnit {
      * this method without setting a SourceUnit will cause
      * NullPinterExceptions
      */
-    public void addClassNode(ClassNode node) {
-        ModuleNode module = new ModuleNode(this.ast);
-        this.ast.addModule(module);
+    public void addClassNode(final ClassNode node) {
+        ModuleNode module = new ModuleNode(getAST());
+        getAST().addModule(module);
         module.addClass(node);
     }
 
@@ -527,7 +510,7 @@ public class CompilationUnit extends ProcessingUnit {
      * Sets a ClassgenCallback.  You can have only one, and setting
      * it to {@code null} removes any existing setting.
      */
-    public void setClassgenCallback(ClassgenCallback visitor) {
+    public void setClassgenCallback(final ClassgenCallback visitor) {
         this.classgenCallback = visitor;
     }
 
@@ -550,7 +533,7 @@ public class CompilationUnit extends ProcessingUnit {
      * Sets a ProgressCallback.  You can have only one, and setting
      * it to {@code null} removes any existing setting.
      */
-    public void setProgressCallback(ProgressCallback callback) {
+    public void setProgressCallback(final ProgressCallback callback) {
         this.progressCallback = callback;
     }
 
@@ -606,29 +589,28 @@ public class CompilationUnit extends ProcessingUnit {
         errorCollector.failIfErrors();
     }
 
-    private void processPhaseOperations(int ph) {
-        LinkedList ops = phaseOperations[ph];
-        for (Object next : ops) {
-            doPhaseOperation(next);
+    private void processPhaseOperations(final int phase) {
+        for (Object op : phaseOperations[phase]) {
+            doPhaseOperation(op);
         }
     }
 
-    private void processNewPhaseOperations(int currPhase) {
-        recordPhaseOpsInAllOtherPhases(currPhase);
-        LinkedList currentPhaseNewOps = newPhaseOperations[currPhase];
+    private void processNewPhaseOperations(final int phase) {
+        recordPhaseOpsInAllOtherPhases(phase);
+        LinkedList currentPhaseNewOps = newPhaseOperations[phase];
         while (!currentPhaseNewOps.isEmpty()) {
             Object operation = currentPhaseNewOps.removeFirst();
             // push this operation to master list and then process it.
-            phaseOperations[currPhase].add(operation);
+            phaseOperations[phase].add(operation);
             doPhaseOperation(operation);
             // if this operation has brought in more phase ops for ast transforms, keep recording them
-            // in master list of other phases and keep processing them for this phase.
-            recordPhaseOpsInAllOtherPhases(currPhase);
-            currentPhaseNewOps = newPhaseOperations[currPhase];
+            // in master list of other phases and keep processing them for this phase
+            recordPhaseOpsInAllOtherPhases(phase);
+            currentPhaseNewOps = newPhaseOperations[phase];
         }
     }
 
-    private void doPhaseOperation(Object operation) {
+    private void doPhaseOperation(final Object operation) {
         if (operation instanceof PrimaryClassNodeOperation) {
             applyToPrimaryClassNodes((PrimaryClassNodeOperation) operation);
         } else if (operation instanceof SourceUnitOperation) {
@@ -638,10 +620,10 @@ public class CompilationUnit extends ProcessingUnit {
         }
     }
 
-    private void recordPhaseOpsInAllOtherPhases(int currPhase) {
+    private void recordPhaseOpsInAllOtherPhases(final int phase) {
         // apart from current phase, push new operations for every other phase in the master phase ops list
-        for (int ph = Phases.INITIALIZATION; ph <= Phases.ALL; ph++) {
-            if (ph != currPhase && !newPhaseOperations[ph].isEmpty()) {
+        for (int ph = Phases.INITIALIZATION; ph <= Phases.ALL; ph += 1) {
+            if (ph != phase && !newPhaseOperations[ph].isEmpty()) {
                 phaseOperations[ph].addAll(newPhaseOperations[ph]);
                 newPhaseOperations[ph].clear();
             }
@@ -649,7 +631,7 @@ public class CompilationUnit extends ProcessingUnit {
     }
 
     private void sortClasses() throws CompilationFailedException {
-        for (ModuleNode module : this.ast.getModules()) {
+        for (ModuleNode module : getAST().getModules()) {
             module.sortClasses();
         }
     }
@@ -667,9 +649,9 @@ public class CompilationUnit extends ProcessingUnit {
     protected boolean dequeued() throws CompilationFailedException {
         boolean dequeue = !queuedSources.isEmpty();
         while (!queuedSources.isEmpty()) {
-            SourceUnit su = queuedSources.removeFirst();
-            String name = su.getName();
-            sources.put(name, su);
+            SourceUnit unit = queuedSources.remove();
+            String name = unit.getName();
+            sources.put(name, unit);
         }
         if (dequeue) {
             gotoPhase(Phases.INITIALIZATION);
@@ -678,10 +660,11 @@ public class CompilationUnit extends ProcessingUnit {
     }
 
     /**
-     * Resolves all types
+     * Resolves all types.
      */
     private final SourceUnitOperation resolve = new SourceUnitOperation() {
-        public void call(SourceUnit source) throws CompilationFailedException {
+        @Override
+        public void call(final SourceUnit source) throws CompilationFailedException {
             List<ClassNode> classes = source.ast.getClasses();
             for (ClassNode node : classes) {
                 VariableScopeVisitor scopeVisitor = new VariableScopeVisitor(source);
@@ -695,13 +678,15 @@ public class CompilationUnit extends ProcessingUnit {
     };
 
     private final PrimaryClassNodeOperation staticImport = new PrimaryClassNodeOperation() {
-        public void call(SourceUnit source, GeneratorContext context, ClassNode classNode) throws CompilationFailedException {
+        @Override
+        public void call(final SourceUnit source, final GeneratorContext context, final ClassNode classNode) throws CompilationFailedException {
             staticImportVisitor.visitClass(classNode, source);
         }
     };
 
     private PrimaryClassNodeOperation defaultTransform = new PrimaryClassNodeOperation() {
-        public void call(SourceUnit source, GeneratorContext context, ClassNode classNode) throws CompilationFailedException {
+        @Override
+        public void call(final SourceUnit source, final GeneratorContext context, final ClassNode classNode) throws CompilationFailedException {
             defaultTransformer.visitClass(classNode, source);
         }
     };
@@ -710,34 +695,30 @@ public class CompilationUnit extends ProcessingUnit {
      * Runs convert() on a single SourceUnit.
      */
     private final SourceUnitOperation convert = new SourceUnitOperation() {
-        public void call(SourceUnit source) throws CompilationFailedException {
+        @Override
+        public void call(final SourceUnit source) throws CompilationFailedException {
             source.convert();
-            CompilationUnit.this.ast.addModule(source.getAST());
-
-
-            if (CompilationUnit.this.progressCallback != null) {
-                CompilationUnit.this.progressCallback.call(source, CompilationUnit.this.phase);
+            getAST().addModule(source.getAST());
+            if (progressCallback != null) {
+                progressCallback.call(source, phase);
             }
         }
     };
 
     private final GroovyClassOperation output = new GroovyClassOperation() {
-        public void call(GroovyClass gclass) throws CompilationFailedException {
-            String name = gclass.getName().replace('.', File.separatorChar) + ".class";
+        @Override
+        public void call(final GroovyClass groovyClass) throws CompilationFailedException {
+            String name = groovyClass.getName().replace('.', File.separatorChar) + ".class";
             File path = new File(configuration.getTargetDirectory(), name);
 
-            //
-            // Ensure the path is ready for the file
-            //
+            // ensure the path is ready for the file
             File directory = path.getParentFile();
             if (directory != null && !directory.exists()) {
                 directory.mkdirs();
             }
 
-            //
-            // Create the file and write out the data
-            //
-            byte[] bytes = gclass.getBytes();
+            // create the file and write out the data
+            byte[] bytes = groovyClass.getBytes();
 
             try (FileOutputStream stream = new FileOutputStream(path)) {
                 stream.write(bytes, 0, bytes.length);
@@ -792,12 +773,8 @@ public class CompilationUnit extends ProcessingUnit {
      */
     private final PrimaryClassNodeOperation classgen = new PrimaryClassNodeOperation() {
         @Override
-        public boolean needSortedInput() {
-            return true;
-        }
-        @Override
-        public void call(SourceUnit source, GeneratorContext context, ClassNode classNode) throws CompilationFailedException {
-            optimizer.visitClass(classNode, source); // GROOVY-4272: repositioned it here from staticImport
+        public void call(final SourceUnit source, final GeneratorContext context, final ClassNode classNode) throws CompilationFailedException {
+            optimizer.visitClass(classNode, source); // GROOVY-4272: repositioned it here from static import visitor
 
             //
             // Run the Verifier on the outer class
@@ -867,6 +844,10 @@ public class CompilationUnit extends ProcessingUnit {
                 classgen.call(source, context, innerClasses.removeFirst());
             }
         }
+        @Override
+        public boolean needSortedInput() {
+            return true;
+        }
     };
 
     protected ClassVisitor createClassVisitor() {
@@ -922,11 +903,11 @@ public class CompilationUnit extends ProcessingUnit {
      * if it isn't already there yet.
      */
     private final SourceUnitOperation mark = new SourceUnitOperation() {
-        public void call(SourceUnit source) throws CompilationFailedException {
+        @Override
+        public void call(final SourceUnit source) throws CompilationFailedException {
             if (source.phase < phase) {
                 source.gotoPhase(phase);
             }
-
             if (source.phase == phase && phaseComplete && !source.phaseComplete) {
                 source.completePhase();
             }
@@ -937,8 +918,9 @@ public class CompilationUnit extends ProcessingUnit {
     // LOOP SIMPLIFICATION FOR SourceUnit OPERATIONS
 
     /**
-     * An callback interface for use in the applyToSourceUnits loop driver.
+     * A callback interface for use in the applyToSourceUnits loop driver.
      */
+    // TODO: convert to functional interface
     public abstract static class SourceUnitOperation {
         public abstract void call(SourceUnit source) throws CompilationFailedException;
     }
@@ -948,7 +930,7 @@ public class CompilationUnit extends ProcessingUnit {
      * Automatically skips units that have already been processed
      * through the current phase.
      */
-    public void applyToSourceUnits(SourceUnitOperation body) throws CompilationFailedException {
+    public void applyToSourceUnits(final SourceUnitOperation body) throws CompilationFailedException {
         for (String name : sources.keySet()) {
             SourceUnit source = sources.get(name);
             if ((source.phase < phase) || (source.phase == phase && !source.phaseComplete)) {
@@ -966,7 +948,6 @@ public class CompilationUnit extends ProcessingUnit {
                 }
             }
         }
-
         getErrorCollector().failIfErrors();
     }
 
@@ -976,6 +957,7 @@ public class CompilationUnit extends ProcessingUnit {
     /**
      * An callback interface for use in the applyToPrimaryClassNodes loop driver.
      */
+    // TODO: convert to functional interface
     public abstract static class PrimaryClassNodeOperation {
         public abstract void call(SourceUnit source, GeneratorContext context, ClassNode classNode) throws CompilationFailedException;
 
@@ -984,20 +966,21 @@ public class CompilationUnit extends ProcessingUnit {
         }
     }
 
+    // TODO: convert to functional interface
     public abstract static class GroovyClassOperation {
-        public abstract void call(GroovyClass gclass) throws CompilationFailedException;
+        public abstract void call(GroovyClass groovyClass) throws CompilationFailedException;
     }
 
     private static int getSuperClassCount(ClassNode element) {
         int count = 0;
         while (element != null) {
-            count++;
+            count += 1;
             element = element.getSuperClass();
         }
         return count;
     }
 
-    private int getSuperInterfaceCount(ClassNode element) {
+    private int getSuperInterfaceCount(final ClassNode element) {
         int count = 1;
         ClassNode[] interfaces = element.getInterfaces();
         for (ClassNode anInterface : interfaces) {
@@ -1006,21 +989,18 @@ public class CompilationUnit extends ProcessingUnit {
         return count;
     }
 
-    private List<ClassNode> getPrimaryClassNodes(boolean sort) {
-        List<ClassNode> unsorted = new ArrayList<ClassNode>();
-        for (ModuleNode module : this.ast.getModules()) {
-            unsorted.addAll(module.getClasses());
-        }
+    private List<ClassNode> getPrimaryClassNodes(final boolean sort) {
+        List<ClassNode> unsorted = getAST().getModules().stream()
+            .flatMap(module -> module.getClasses().stream()).collect(Collectors.toList());
 
         if (!sort) return unsorted;
 
-        int unsortedSize = unsorted.size();
-        int[] indexClass = new int[unsortedSize];
-        int[] indexInterface = new int[unsortedSize];
+        int n = unsorted.size();
+        int[] indexClass = new int[n];
+        int[] indexInterface = new int[n];
         {
             int i = 0;
-            for (Iterator<ClassNode> iter = unsorted.iterator(); iter.hasNext(); i++) {
-                ClassNode element = iter.next();
+            for (ClassNode element : unsorted) {
                 if (element.isInterface()) {
                     indexInterface[i] = getSuperInterfaceCount(element);
                     indexClass[i] = -1;
@@ -1028,6 +1008,7 @@ public class CompilationUnit extends ProcessingUnit {
                     indexClass[i] = getSuperClassCount(element);
                     indexInterface[i] = -1;
                 }
+                i += 1;
             }
         }
 
@@ -1036,12 +1017,12 @@ public class CompilationUnit extends ProcessingUnit {
         return sorted;
     }
 
-    private static List<ClassNode> getSorted(int[] index, List<ClassNode> unsorted) {
+    private static List<ClassNode> getSorted(final int[] index, final List<ClassNode> unsorted) {
         int unsortedSize = unsorted.size();
-        List<ClassNode> sorted = new ArrayList<ClassNode>(unsortedSize);
-        for (int i = 0; i < unsortedSize; i++) {
+        List<ClassNode> sorted = new ArrayList<>(unsortedSize);
+        for (int i = 0; i < unsortedSize; i += 1) {
             int min = -1;
-            for (int j = 0; j < unsortedSize; j++) {
+            for (int j = 0; j < unsortedSize; j += 1) {
                 if (index[j] == -1) continue;
                 if (min == -1 || index[j] < index[min]) {
                     min = j;
@@ -1059,18 +1040,18 @@ public class CompilationUnit extends ProcessingUnit {
      * our AST.  Automatically skips units that have already been processed
      * through the current phase.
      */
-    public void applyToPrimaryClassNodes(PrimaryClassNodeOperation body) throws CompilationFailedException {
+    public void applyToPrimaryClassNodes(final PrimaryClassNodeOperation body) throws CompilationFailedException {
         for (ClassNode classNode : getPrimaryClassNodes(body.needSortedInput())) {
             SourceUnit context = null;
             try {
                 context = classNode.getModule().getContext();
                 if (context == null || context.phase < phase || (context.phase == phase && !context.phaseComplete)) {
                     int offset = 1;
-                    for (Iterator<InnerClassNode> iterator = classNode.getInnerClasses(); iterator.hasNext(); ) {
-                        iterator.next();
-                        offset++;
+                    for (Iterator<InnerClassNode> it = classNode.getInnerClasses(); it.hasNext(); ) {
+                        it.next();
+                        offset += 1;
                     }
-                    body.call(context, new GeneratorContext(this.ast, offset), classNode);
+                    body.call(context, new GeneratorContext(getAST(), offset), classNode);
                 }
             } catch (CompilationFailedException e) {
                 // fall through, getErrorReporter().failIfErrors() will trigger
@@ -1109,7 +1090,7 @@ public class CompilationUnit extends ProcessingUnit {
         }
     }
 
-    public void applyToGeneratedGroovyClasses(GroovyClassOperation body) throws CompilationFailedException {
+    public void applyToGeneratedGroovyClasses(final 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());
         }
@@ -1135,23 +1116,7 @@ public class CompilationUnit extends ProcessingUnit {
         getErrorCollector().failIfErrors();
     }
 
-    private void changeBugText(GroovyBugError e, SourceUnit context) {
-        e.setBugText("exception in phase '" + getPhaseDescription() + "' in source unit '" + ((context != null) ? context.getName() : "?") + "' " + e.getBugText());
-    }
-
-    public ClassNodeResolver getClassNodeResolver() {
-        return classNodeResolver;
-    }
-
-    public void setClassNodeResolver(ClassNodeResolver classNodeResolver) {
-        this.classNodeResolver = classNodeResolver;
-    }
-
-    public Set<JavaFileObject> getJavaCompilationUnitSet() {
-        return javaCompilationUnitSet;
-    }
-
-    public void addJavaCompilationUnits(Set<JavaFileObject> javaCompilationUnitSet) {
-        this.javaCompilationUnitSet.addAll(javaCompilationUnitSet);
+    private void changeBugText(final GroovyBugError e, final SourceUnit context) {
+        e.setBugText("exception in phase '" + getPhaseDescription() + "' in source unit '" + (context != null ? context.getName() : "?") + "' " + e.getBugText());
     }
 }
diff --git a/src/main/java/org/codehaus/groovy/control/Phases.java b/src/main/java/org/codehaus/groovy/control/Phases.java
index eecba8d..2d962ae 100644
--- a/src/main/java/org/codehaus/groovy/control/Phases.java
+++ b/src/main/java/org/codehaus/groovy/control/Phases.java
@@ -22,37 +22,46 @@ package org.codehaus.groovy.control;
  * Compilation phase identifiers.
  */
 public class Phases {
-    public static final int INITIALIZATION = 1;   // Opening of files and such
-    public static final int PARSING = 2;   // Lexing, parsing, and AST building
-    public static final int CONVERSION = 3;   // CST to AST conversion
-    public static final int SEMANTIC_ANALYSIS = 4;   // AST semantic analysis and elucidation
-    public static final int CANONICALIZATION = 5;   // AST completion
-    public static final int INSTRUCTION_SELECTION = 6;   // Class generation, phase 1
-    public static final int CLASS_GENERATION = 7;   // Class generation, phase 2
-    public static final int OUTPUT = 8;   // Output of class to disk
-    public static final int FINALIZATION = 9;   // Cleanup
-    public static final int ALL = 9;   // Synonym for full compilation
+    /** Opening of files and such */
+    public static final int INITIALIZATION = 1;
+    /** Lexing, parsing, and AST building */
+    public static final int PARSING = 2;
+    /** CST to AST conversion */
+    public static final int CONVERSION = 3;
+    /** AST semantic analysis and elucidation */
+    public static final int SEMANTIC_ANALYSIS = 4;
+    /** AST completion */
+    public static final int CANONICALIZATION = 5;
+    /** Class generation (pt.1) */
+    public static final int INSTRUCTION_SELECTION = 6;
+    /** Class generation (pt.2) */
+    public static final int CLASS_GENERATION = 7;   //
+    /** Output of class to disk */
+    public static final int OUTPUT = 8;
+    /** Cleanup */
+    public static final int FINALIZATION = 9;
 
+    /** Synonym for full compilation */
+    public static final int ALL = FINALIZATION;
+
+    // TODO: If no reference is made to array, convert to switch in getDescription(int).
     public static final String[] descriptions = {
-            "startup"
-            , "initialization"
-            , "parsing"
-            , "conversion"
-            , "semantic analysis"
-            , "canonicalization"
-            , "instruction selection"
-            , "class generation"
-            , "output"
-            , "cleanup"
+        "startup",
+        "initialization",
+        "parsing",
+        "conversion",
+        "semantic analysis",
+        "canonicalization",
+        "instruction selection",
+        "class generation",
+        "output",
+        "cleanup",
     };
 
-
     /**
      * Returns a description of the specified phase.
      */
-
-    public static String getDescription(int phase) {
+    public static String getDescription(final int phase) {
         return descriptions[phase];
     }
-
 }
diff --git a/src/main/java/org/codehaus/groovy/control/ResolveVisitor.java b/src/main/java/org/codehaus/groovy/control/ResolveVisitor.java
index 06e9df1..30b3476 100644
--- a/src/main/java/org/codehaus/groovy/control/ResolveVisitor.java
+++ b/src/main/java/org/codehaus/groovy/control/ResolveVisitor.java
@@ -248,6 +248,7 @@ public class ResolveVisitor extends ClassCodeExpressionTransformer {
 
     public ResolveVisitor(final CompilationUnit compilationUnit) {
         this.compilationUnit = compilationUnit;
+        // TODO: CompilationUnit.ClassNodeResolver?
         setClassNodeResolver(new ClassNodeResolver());
     }
 
diff --git a/src/test/org/codehaus/groovy/classgen/asm/sc/StaticCompilationTestSupport.groovy b/src/test/org/codehaus/groovy/classgen/asm/sc/StaticCompilationTestSupport.groovy
index bcfc58f..9e9c67b 100644
--- a/src/test/org/codehaus/groovy/classgen/asm/sc/StaticCompilationTestSupport.groovy
+++ b/src/test/org/codehaus/groovy/classgen/asm/sc/StaticCompilationTestSupport.groovy
@@ -121,8 +121,7 @@ trait StaticCompilationTestSupport {
         void call(final SourceUnit source, final GeneratorContext context, final ClassNode classNode) {
             def unit = testCase.compilationUnit
             if (!unit) return
-            List<GroovyClass> classes = unit.generatedClasses
-            classes.each { GroovyClass groovyClass ->
+            unit.classes.each { GroovyClass groovyClass ->
                 StringWriter stringWriter = new StringWriter()
                 try {
                     ClassReader cr = new ClassReader(groovyClass.bytes)
@@ -135,5 +134,4 @@ trait StaticCompilationTestSupport {
             }
         }
     }
-
 }


[groovy] 03/05: normalize addPhaseOperations()

Posted by su...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

sunlan pushed a commit to branch GROOVY_3_0_X
in repository https://gitbox.apache.org/repos/asf/groovy.git

commit 0e7493353d1da16179020b1308822b6a8b32e530
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Mon Dec 16 12:31:23 2019 -0600

    normalize addPhaseOperations()
    
    (cherry picked from commit 85c1891df466c10fe4aa450dfd90c45fcc6a3124)
---
 .../codehaus/groovy/control/CompilationUnit.java   | 235 +++++++++++----------
 .../groovy/control/DefaultTransformer.java         |  69 ------
 2 files changed, 125 insertions(+), 179 deletions(-)

diff --git a/src/main/java/org/codehaus/groovy/control/CompilationUnit.java b/src/main/java/org/codehaus/groovy/control/CompilationUnit.java
index 29ca6f3..210ec3f 100644
--- a/src/main/java/org/codehaus/groovy/control/CompilationUnit.java
+++ b/src/main/java/org/codehaus/groovy/control/CompilationUnit.java
@@ -21,12 +21,15 @@ package org.codehaus.groovy.control;
 import groovy.lang.GroovyClassLoader;
 import groovy.transform.CompilationUnitAware;
 import org.codehaus.groovy.GroovyBugError;
+import org.codehaus.groovy.ast.ClassCodeExpressionTransformer;
 import org.codehaus.groovy.ast.ClassHelper;
 import org.codehaus.groovy.ast.ClassNode;
 import org.codehaus.groovy.ast.CompileUnit;
 import org.codehaus.groovy.ast.GroovyClassVisitor;
 import org.codehaus.groovy.ast.InnerClassNode;
 import org.codehaus.groovy.ast.ModuleNode;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.expr.VariableExpression;
 import org.codehaus.groovy.classgen.AsmClassGenerator;
 import org.codehaus.groovy.classgen.ClassCompletionVerifier;
 import org.codehaus.groovy.classgen.EnumCompletionVisitor;
@@ -48,7 +51,6 @@ import org.codehaus.groovy.syntax.SyntaxException;
 import org.codehaus.groovy.tools.GroovyClass;
 import org.codehaus.groovy.transform.ASTTransformationVisitor;
 import org.codehaus.groovy.transform.AnnotationCollectorTransform;
-import org.codehaus.groovy.transform.sc.StaticCompilationMetadataKeys;
 import org.codehaus.groovy.transform.trait.TraitComposer;
 import org.objectweb.asm.ClassVisitor;
 import org.objectweb.asm.ClassWriter;
@@ -72,6 +74,11 @@ import java.util.Queue;
 import java.util.Set;
 import java.util.stream.Collectors;
 
+import static org.codehaus.groovy.ast.tools.GeneralUtils.classX;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.propX;
+import static org.codehaus.groovy.transform.sc.StaticCompilationMetadataKeys.DYNAMIC_OUTER_NODE_CALLBACK;
+import static org.codehaus.groovy.transform.stc.StaticTypesMarker.SWITCH_CONDITION_EXPRESSION_TYPE;
+
 /**
  * The CompilationUnit collects all compilation data as it is generated by the compiler system.
  * You can use this object to add additional source units to the compilation, or force the
@@ -114,8 +121,6 @@ public class CompilationUnit extends ProcessingUnit {
     /** A callback for use during {@link #compile()} */
     protected ProgressCallback progressCallback;
 
-    protected StaticImportVisitor staticImportVisitor = new StaticImportVisitor();
-    protected DefaultTransformer defaultTransformer = new DefaultTransformer();
     protected ClassNodeResolver classNodeResolver = new ClassNodeResolver();
     protected ResolveVisitor resolveVisitor = new ResolveVisitor(this);
     protected OptimizerVisitor optimizer = new OptimizerVisitor(this);
@@ -182,97 +187,175 @@ public class CompilationUnit extends ProcessingUnit {
     private void addPhaseOperations() {
         addPhaseOperation(new SourceUnitOperation() {
             @Override
-            public void call(SourceUnit source) throws CompilationFailedException {
+            public void call(final SourceUnit source) throws CompilationFailedException {
                 source.parse();
             }
         }, Phases.PARSING);
-        addPhaseOperation(convert, Phases.CONVERSION);
+
+        addPhaseOperation(new SourceUnitOperation() {
+            @Override
+            public void call(final SourceUnit source) throws CompilationFailedException {
+                source.convert();
+                // add module to compile unit
+                getAST().addModule(source.getAST());
+
+                if (progressCallback != null) {
+                    progressCallback.call(source, phase);
+                }
+            }
+        }, Phases.CONVERSION);
         addPhaseOperation(new PrimaryClassNodeOperation() {
             @Override
-            public void call(SourceUnit source, GeneratorContext context,
-                             ClassNode classNode) throws CompilationFailedException {
-                EnumVisitor ev = new EnumVisitor(CompilationUnit.this, source);
-                ev.visitClass(classNode);
+            public void call(final SourceUnit source, final GeneratorContext context, final ClassNode classNode) throws CompilationFailedException {
+                GroovyClassVisitor visitor = new EnumVisitor(CompilationUnit.this, source);
+                visitor.visitClass(classNode);
             }
         }, Phases.CONVERSION);
+
         addPhaseOperation(resolve, Phases.SEMANTIC_ANALYSIS);
-        addPhaseOperation(staticImport, Phases.SEMANTIC_ANALYSIS);
         addPhaseOperation(new PrimaryClassNodeOperation() {
             @Override
-            public void call(SourceUnit source, GeneratorContext context,
-                             ClassNode classNode) throws CompilationFailedException {
-                InnerClassVisitor iv = new InnerClassVisitor(CompilationUnit.this, source);
-                iv.visitClass(classNode);
+            public void call(final SourceUnit source, final GeneratorContext context, final ClassNode classNode) throws CompilationFailedException {
+                StaticImportVisitor visitor = new StaticImportVisitor();
+                visitor.visitClass(classNode, source);
             }
         }, Phases.SEMANTIC_ANALYSIS);
         addPhaseOperation(new PrimaryClassNodeOperation() {
             @Override
-            public void call(SourceUnit source, GeneratorContext context,
-                             ClassNode classNode) throws CompilationFailedException {
+            public void call(final SourceUnit source, final GeneratorContext context, final ClassNode classNode) throws CompilationFailedException {
+                GroovyClassVisitor visitor = new InnerClassVisitor(CompilationUnit.this, source);
+                visitor.visitClass(classNode);
+            }
+        }, Phases.SEMANTIC_ANALYSIS);
+        addPhaseOperation(new PrimaryClassNodeOperation() {
+            @Override
+            public void call(final SourceUnit source, final GeneratorContext context, final ClassNode classNode) throws CompilationFailedException {
                 if (!classNode.isSynthetic()) {
-                    GenericsVisitor genericsVisitor = new GenericsVisitor(source);
-                    genericsVisitor.visitClass(classNode);
+                    GroovyClassVisitor visitor = new GenericsVisitor(source);
+                    visitor.visitClass(classNode);
                 }
             }
         }, Phases.SEMANTIC_ANALYSIS);
+
         addPhaseOperation(new PrimaryClassNodeOperation() {
             @Override
-            public void call(SourceUnit source, GeneratorContext context,
-                             ClassNode classNode) throws CompilationFailedException {
+            public void call(final SourceUnit source, final GeneratorContext context, final ClassNode classNode) throws CompilationFailedException {
                 TraitComposer.doExtendTraits(classNode, source, CompilationUnit.this);
             }
         }, Phases.CANONICALIZATION);
-        addPhaseOperation(compileCompleteCheck, Phases.CANONICALIZATION);
+        addPhaseOperation(new SourceUnitOperation() {
+            @Override
+            public void call(final SourceUnit source) throws CompilationFailedException {
+                List<ClassNode> classes = source.ast.getClasses();
+                for (ClassNode node : classes) {
+                    CompileUnit cu = node.getCompileUnit();
+                    for (Iterator<String> it = cu.iterateClassNodeToCompile(); it.hasNext(); ) {
+                        String name = it.next();
+                        StringBuilder message = new StringBuilder();
+                        message
+                                .append("Compilation incomplete: expected to find the class ")
+                                .append(name)
+                                .append(" in ")
+                                .append(source.getName());
+                        if (classes.isEmpty()) {
+                            message.append(", but the file seems not to contain any classes");
+                        } else {
+                            message.append(", but the file contains the classes: ");
+                            boolean first = true;
+                            for (ClassNode cn : classes) {
+                                if (!first) {
+                                    message.append(", ");
+                                } else {
+                                    first = false;
+                                }
+                                message.append(cn.getName());
+                            }
+                        }
+
+                        getErrorCollector().addErrorAndContinue(
+                                new SimpleMessage(message.toString(), CompilationUnit.this)
+                        );
+                        it.remove();
+                    }
+                }
+            }
+        }, Phases.CANONICALIZATION);
+
         addPhaseOperation(classgen, Phases.CLASS_GENERATION);
 
         addPhaseOperation(output);
 
         addPhaseOperation(new PrimaryClassNodeOperation() {
             @Override
-            public void call(SourceUnit source, GeneratorContext context,
-                             ClassNode classNode) throws CompilationFailedException {
-                AnnotationCollectorTransform.ClassChanger actt = new AnnotationCollectorTransform.ClassChanger();
-                actt.transformClass(classNode);
+            public void call(final SourceUnit source, final GeneratorContext context, final ClassNode classNode) throws CompilationFailedException {
+                AnnotationCollectorTransform.ClassChanger xformer = new AnnotationCollectorTransform.ClassChanger();
+                xformer.transformClass(classNode);
             }
         }, Phases.SEMANTIC_ANALYSIS);
         ASTTransformationVisitor.addPhaseOperations(this);
+
+        // post-transform operations:
+
         addPhaseOperation(new PrimaryClassNodeOperation() {
             @Override
-            public void call(SourceUnit source, GeneratorContext context,
-                             ClassNode classNode) throws CompilationFailedException {
-                StaticVerifier sv = new StaticVerifier();
-                sv.visitClass(classNode, source);
+            public void call(final SourceUnit source, final GeneratorContext context, final ClassNode classNode) throws CompilationFailedException {
+                StaticVerifier verifier = new StaticVerifier();
+                verifier.visitClass(classNode, source);
             }
         }, Phases.SEMANTIC_ANALYSIS);
+
         addPhaseOperation(new PrimaryClassNodeOperation() {
             @Override
-            public void call(SourceUnit source, GeneratorContext context,
-                             ClassNode classNode) throws CompilationFailedException {
-                InnerClassCompletionVisitor iv = new InnerClassCompletionVisitor(CompilationUnit.this, source);
-                iv.visitClass(classNode);
+            public void call(final SourceUnit source, final GeneratorContext context, final ClassNode classNode) throws CompilationFailedException {
+                GroovyClassVisitor visitor = new InnerClassCompletionVisitor(CompilationUnit.this, source);
+                visitor.visitClass(classNode);
             }
         }, Phases.CANONICALIZATION);
         addPhaseOperation(new PrimaryClassNodeOperation() {
             @Override
-            public void call(SourceUnit source, GeneratorContext context,
-                             ClassNode classNode) throws CompilationFailedException {
-                EnumCompletionVisitor ecv = new EnumCompletionVisitor(CompilationUnit.this, source);
-                ecv.visitClass(classNode);
+            public void call(final SourceUnit source, final GeneratorContext context, final ClassNode classNode) throws CompilationFailedException {
+                GroovyClassVisitor visitor = new EnumCompletionVisitor(CompilationUnit.this, source);
+                visitor.visitClass(classNode);
             }
         }, Phases.CANONICALIZATION);
+
         addPhaseOperation(new PrimaryClassNodeOperation() {
             @Override
-            public void call(SourceUnit source, GeneratorContext context,
-                             ClassNode classNode) throws CompilationFailedException {
-                Object callback = classNode.getNodeMetaData(StaticCompilationMetadataKeys.DYNAMIC_OUTER_NODE_CALLBACK);
+            public void call(final SourceUnit source, final GeneratorContext context, final ClassNode classNode) throws CompilationFailedException {
+                Object callback = classNode.getNodeMetaData(DYNAMIC_OUTER_NODE_CALLBACK);
                 if (callback instanceof PrimaryClassNodeOperation) {
                     ((PrimaryClassNodeOperation) callback).call(source, context, classNode);
-                    classNode.removeNodeMetaData(StaticCompilationMetadataKeys.DYNAMIC_OUTER_NODE_CALLBACK);
+                    classNode.removeNodeMetaData(DYNAMIC_OUTER_NODE_CALLBACK);
                 }
             }
         }, Phases.INSTRUCTION_SELECTION);
+        addPhaseOperation(new PrimaryClassNodeOperation() {
+            @Override
+            public void call(final SourceUnit source, final GeneratorContext context, final ClassNode classNode) throws CompilationFailedException {
+                // TODO: Could this be moved into org.codehaus.groovy.transform.sc.transformers.VariableExpressionTransformer?
+                new ClassCodeExpressionTransformer() {
+                    @Override
+                    protected SourceUnit getSourceUnit() {
+                        return source;
+                    }
 
-        addPhaseOperation(defaultTransform, Phases.INSTRUCTION_SELECTION);
+                    @Override
+                    public Expression transform(final Expression expression) {
+                        if (expression instanceof VariableExpression) {
+                            // check for "switch(enumType) { case CONST: ... }"
+                            ClassNode enumType = expression.getNodeMetaData(SWITCH_CONDITION_EXPRESSION_TYPE);
+                            if (enumType != null) {
+                                // replace "CONST" variable expression with "EnumType.CONST" property expression
+                                Expression propertyExpression = propX(classX(enumType), expression.getText());
+                                setSourcePosition(propertyExpression, expression);
+                                return propertyExpression;
+                            }
+                        }
+                        return expression;
+                    }
+                }.visitClass(classNode);
+            }
+        }, Phases.INSTRUCTION_SELECTION);
     }
 
     private void applyCompilationCustomizers() {
@@ -667,34 +750,6 @@ public class CompilationUnit extends ProcessingUnit {
         }
     };
 
-    private final PrimaryClassNodeOperation staticImport = new PrimaryClassNodeOperation() {
-        @Override
-        public void call(final SourceUnit source, final GeneratorContext context, final ClassNode classNode) throws CompilationFailedException {
-            staticImportVisitor.visitClass(classNode, source);
-        }
-    };
-
-    private PrimaryClassNodeOperation defaultTransform = new PrimaryClassNodeOperation() {
-        @Override
-        public void call(final SourceUnit source, final GeneratorContext context, final ClassNode classNode) throws CompilationFailedException {
-            defaultTransformer.visitClass(classNode, source);
-        }
-    };
-
-    /**
-     * Runs convert() on a single SourceUnit.
-     */
-    private final SourceUnitOperation convert = new SourceUnitOperation() {
-        @Override
-        public void call(final SourceUnit source) throws CompilationFailedException {
-            source.convert();
-            getAST().addModule(source.getAST());
-            if (progressCallback != null) {
-                progressCallback.call(source, phase);
-            }
-        }
-    };
-
     private final GroovyClassOperation output = new GroovyClassOperation() {
         @Override
         public void call(final GroovyClass groovyClass) throws CompilationFailedException {
@@ -718,46 +773,6 @@ public class CompilationUnit extends ProcessingUnit {
         }
     };
 
-    /* checks if all needed classes are compiled before generating the bytecode */
-    private final SourceUnitOperation compileCompleteCheck = new SourceUnitOperation() {
-        public void call(SourceUnit source) throws CompilationFailedException {
-            List<ClassNode> classes = source.ast.getClasses();
-            for (ClassNode node : classes) {
-                CompileUnit cu = node.getCompileUnit();
-                for (Iterator<String> iter = cu.iterateClassNodeToCompile(); iter.hasNext();) {
-                    String name = iter.next();
-                    SourceUnit su = ast.getScriptSourceLocation(name);
-                    List<ClassNode> classesInSourceUnit = su.ast.getClasses();
-                    StringBuilder message = new StringBuilder();
-                    message
-                            .append("Compilation incomplete: expected to find the class ")
-                            .append(name)
-                            .append(" in ")
-                            .append(su.getName());
-                    if (classesInSourceUnit.isEmpty()) {
-                        message.append(", but the file seems not to contain any classes");
-                    } else {
-                        message.append(", but the file contains the classes: ");
-                        boolean first = true;
-                        for (ClassNode cn : classesInSourceUnit) {
-                            if (!first) {
-                                message.append(", ");
-                            } else {
-                                first = false;
-                            }
-                            message.append(cn.getName());
-                        }
-                    }
-
-                    getErrorCollector().addErrorAndContinue(
-                            new SimpleMessage(message.toString(), CompilationUnit.this)
-                    );
-                    iter.remove();
-                }
-            }
-        }
-    };
-
     /**
      * Runs classgen() on a single ClassNode.
      */
diff --git a/src/main/java/org/codehaus/groovy/control/DefaultTransformer.java b/src/main/java/org/codehaus/groovy/control/DefaultTransformer.java
deleted file mode 100644
index 6daa511..0000000
--- a/src/main/java/org/codehaus/groovy/control/DefaultTransformer.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-package org.codehaus.groovy.control;
-
-import org.codehaus.groovy.ast.ClassCodeExpressionTransformer;
-import org.codehaus.groovy.ast.ClassNode;
-import org.codehaus.groovy.ast.expr.ClassExpression;
-import org.codehaus.groovy.ast.expr.Expression;
-import org.codehaus.groovy.ast.expr.PropertyExpression;
-import org.codehaus.groovy.ast.expr.VariableExpression;
-
-import static org.codehaus.groovy.transform.stc.StaticTypesMarker.SWITCH_CONDITION_EXPRESSION_TYPE;
-
-/**
- * The default transformer a.k.a. the last transformer to transform expressions, it can use type info if STC is enabled
- *
- * @since 3.0.0
- */
-public class DefaultTransformer extends ClassCodeExpressionTransformer {
-    private ClassNode currentClass;
-    private SourceUnit source;
-
-    public void visitClass(ClassNode node, SourceUnit source) {
-        this.currentClass = node;
-        this.source = source;
-        super.visitClass(node);
-    }
-
-    public Expression transform(Expression exp) {
-        if (null == exp) return null;
-
-        if (exp.getClass() == VariableExpression.class) {
-            return transformVariableExpression((VariableExpression) exp);
-        }
-        return exp;
-    }
-
-    private Expression transformVariableExpression(VariableExpression ve) {
-        ClassNode enumClassNode = ve.getNodeMetaData(SWITCH_CONDITION_EXPRESSION_TYPE);
-        if (null != enumClassNode) {
-            Expression result = new PropertyExpression(new ClassExpression(enumClassNode), ve.getName());
-            setSourcePosition(result, ve);
-
-            return result;
-        }
-        return ve;
-    }
-
-    @Override
-    protected SourceUnit getSourceUnit() {
-        return source;
-    }
-}