You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by em...@apache.org on 2021/10/07 18:06:22 UTC

[groovy] 01/02: GROOVY-4287, GROOVY-4386, GROOVY-7812, GROOVY-9243: runtime resolve test

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

emilles pushed a commit to branch GROOVY-10248
in repository https://gitbox.apache.org/repos/asf/groovy.git

commit a8f38a4e58e35e180056f10baea157f339e8961c
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Thu Oct 7 11:42:25 2021 -0500

    GROOVY-4287, GROOVY-4386, GROOVY-7812, GROOVY-9243: runtime resolve test
---
 .../java/org/codehaus/groovy/ast/CompileUnit.java  | 227 ++++++++-------------
 .../codehaus/groovy/control/CompilationUnit.java   |   8 +-
 .../codehaus/groovy/control/ResolveVisitor.java    | 143 +------------
 .../groovy/bugs/groovy4386/Constants.groovy}       |  17 +-
 .../groovy/bugs/groovy4386/StaticField.groovy}     |  18 +-
 .../groovy/bugs/groovy4386/StaticProperty.groovy}  |  17 +-
 .../bugs/groovy4386/StaticStarImport.groovy}       |  18 +-
 src/test/groovy/bugs/Groovy4386_Bug.groovy         |  90 --------
 src/test/groovy/bugs/Groovy7812Bug.groovy          |  48 -----
 src/test/groovy/bugs/Groovy9236.groovy             | 125 ++++++++++++
 .../groovy/bugs/groovy9236/Groovy9236Bug.groovy    | 115 -----------
 src/test/groovy/script/RuntimeResolveTests.groovy  |  77 +++++++
 12 files changed, 321 insertions(+), 582 deletions(-)

diff --git a/src/main/java/org/codehaus/groovy/ast/CompileUnit.java b/src/main/java/org/codehaus/groovy/ast/CompileUnit.java
index 082252c..ed856c6 100644
--- a/src/main/java/org/codehaus/groovy/ast/CompileUnit.java
+++ b/src/main/java/org/codehaus/groovy/ast/CompileUnit.java
@@ -19,10 +19,8 @@
 package org.codehaus.groovy.ast;
 
 import groovy.lang.GroovyClassLoader;
-import groovy.transform.Internal;
 import org.codehaus.groovy.control.CompilerConfiguration;
 import org.codehaus.groovy.control.SourceUnit;
-import org.codehaus.groovy.control.messages.SyntaxErrorMessage;
 import org.codehaus.groovy.syntax.SyntaxException;
 
 import java.security.CodeSource;
@@ -32,94 +30,132 @@ import java.util.Iterator;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.function.BiConsumer;
-
-import static org.objectweb.asm.Opcodes.ACC_PUBLIC;
 
 /**
- * Represents the entire contents of a compilation step which consists of one or more
- * {@link ModuleNode} instances. There's one instance of this that's shared by all modules and
- * classes compiled during a single invocation of the compiler.
+ * Represents the entire contents of a compilation step which consists of one or
+ * more {@link ModuleNode} instances. There's one instance of this that's shared
+ * by all modules and classes compiled during a single invocation of the compiler.
  * <p>
- * It's attached to MethodNodes and ClassNodes and is used to find fully qualified names of classes,
- * resolve imports, and that sort of thing.
+ * It's attached to MethodNodes and ClassNodes and is used to find fully qualified
+ * names of classes, resolve imports, and that sort of thing.
  */
 public class CompileUnit implements NodeMetaDataHandler {
 
-    private final List<ModuleNode> modules = new ArrayList<>();
-    private final Map<String, ClassNode> classes = new LinkedHashMap<>();
     private final CompilerConfiguration config;
-    private final GroovyClassLoader classLoader;
+    private final GroovyClassLoader loader;
     private final CodeSource codeSource;
+    private Map<?, ?> metaDataMap;
+
+    private final List<ModuleNode> modules = new ArrayList<>();
+    private final Map<String, ClassNode> classes = new LinkedHashMap<>();
     private final Map<String, ClassNode> classesToCompile = new LinkedHashMap<>();
     private final Map<String, SourceUnit> classNameToSource = new LinkedHashMap<>();
     private final Map<String, InnerClassNode> generatedInnerClasses = new LinkedHashMap<>();
-    private final Map<String, ConstructedOuterNestedClassNode> classesToResolve = new LinkedHashMap<>();
-    private Map metaDataMap;
 
-    public CompileUnit(GroovyClassLoader classLoader, CompilerConfiguration config) {
+    public CompileUnit(final GroovyClassLoader classLoader, final CompilerConfiguration config) {
         this(classLoader, null, config);
     }
 
-    public CompileUnit(GroovyClassLoader classLoader, CodeSource codeSource, CompilerConfiguration config) {
-        this.classLoader = classLoader;
-        this.config = config;
+    public CompileUnit(final GroovyClassLoader classLoader, final CodeSource codeSource, final CompilerConfiguration config) {
+        this.loader = classLoader;
         this.codeSource = codeSource;
+        this.config = config;
     }
 
-    public List<ModuleNode> getModules() {
-        return modules;
+    public CompilerConfiguration getConfig() {
+        return config;
     }
 
-    public void addModule(ModuleNode node) {
-        // node==null means a compilation error prevented
-        // groovy from building an ast
-        if (node == null) return;
-        modules.add(node);
-        node.setUnit(this);
-        addClasses(node.getClasses());
+    public GroovyClassLoader getClassLoader() {
+        return loader;
     }
 
-    /**
-     * @return the ClassNode for the given qualified name or returns null if
-     *         the name does not exist in the current compilation unit
-     *         (ignoring the .class files on the classpath)
-     */
-    public ClassNode getClass(String name) {
-        ClassNode cn = classes.get(name);
-        if (cn != null) return cn;
-        return classesToCompile.get(name);
+    public CodeSource getCodeSource() {
+        return codeSource;
+    }
+
+    @Override
+    public Map<?, ?> getMetaDataMap() {
+        return metaDataMap;
+    }
+
+    @Override
+    public void setMetaDataMap(final Map<?, ?> metaDataMap) {
+        this.metaDataMap = metaDataMap;
+    }
+
+    public List<ModuleNode> getModules() {
+        return modules;
     }
 
     /**
      * @return a list of all the classes in each module in the compilation unit
      */
     public List<ClassNode> getClasses() {
-        List<ClassNode> answer = new ArrayList<ClassNode>();
+        List<ClassNode> answer = new ArrayList<>();
         for (ModuleNode module : modules) {
             answer.addAll(module.getClasses());
         }
         return answer;
     }
 
-    public CompilerConfiguration getConfig() {
-        return config;
+    /**
+     * @return the ClassNode for the given qualified name or returns null if
+     *         the name does not exist in the current compilation unit
+     *         (ignoring the .class files on the classpath)
+     */
+    public ClassNode getClass(final String name) {
+        ClassNode cn = classes.get(name);
+        if (cn == null)
+            cn = classesToCompile.get(name);
+        return cn;
     }
 
-    public GroovyClassLoader getClassLoader() {
-        return classLoader;
+    public Map<String, ClassNode> getClassesToCompile() {
+        return classesToCompile;
     }
 
-    public CodeSource getCodeSource() {
-        return codeSource;
+    public SourceUnit getScriptSourceLocation(final String className) {
+        return classNameToSource.get(className);
+    }
+
+    public Map<String, InnerClassNode> getGeneratedInnerClasses() {
+        return Collections.unmodifiableMap(generatedInnerClasses);
+    }
+
+    public InnerClassNode getGeneratedInnerClass(final String name) {
+        return generatedInnerClasses.get(name);
+    }
+
+    //--------------------------------------------------------------------------
+
+    @Deprecated
+    public boolean hasClassNodeToCompile() {
+        return !classesToCompile.isEmpty();
+    }
+
+    @Deprecated
+    public Iterator<String> iterateClassNodeToCompile() {
+        return classesToCompile.keySet().iterator();
+    }
+
+    //--------------------------------------------------------------------------
+
+    public void addModule(final ModuleNode node) {
+        // null means a compilation error prevented groovy from building an AST
+        if (node != null) {
+            modules.add(node);
+            node.setUnit(this);
+            addClasses(node.getClasses());
+        }
     }
 
     /**
-     * Appends all of the fully qualified class names in this
-     * module into the given map
+     * Appends all of the fully-qualified class names in this
+     * module into the given map.
      */
-    void addClasses(List<ClassNode> classList) {
-        for (ClassNode node : classList) {
+    public void addClasses(final List<ClassNode> list) {
+        for (ClassNode node : list) {
             addClass(node);
         }
     }
@@ -148,17 +184,12 @@ public class CompileUnit implements NodeMetaDataHandler {
             } else {
                 txt += "The sources " + nodeSource.getName() + " and " + storedSource.getName() + " each contain a class with the name " + node.getName() + ".\n";
             }
-            nodeSource.getErrorCollector().addErrorAndContinue(
-                    new SyntaxErrorMessage(new SyntaxException(txt, node.getLineNumber(), node.getColumnNumber(), node.getLastLineNumber(), node.getLastColumnNumber()), nodeSource)
-            );
+            nodeSource.addErrorAndContinue(new SyntaxException(txt, node));
         }
         classes.put(name, node);
 
-        ClassNode cn = classesToCompile.get(name);
-        if (null != cn) {
-            cn.setRedirect(node);
-            classesToCompile.remove(name);
-        }
+        ClassNode cn = classesToCompile.remove(name);
+        if (cn != null) cn.setRedirect(node);
     }
 
     /**
@@ -166,93 +197,13 @@ public class CompileUnit implements NodeMetaDataHandler {
      * a marker that this type has to be compiled by the CompilationUnit
      * at the end of a parse step no node should be be left.
      */
-    public void addClassNodeToCompile(ClassNode node, SourceUnit location) {
+    public void addClassNodeToCompile(final ClassNode node, final SourceUnit location) {
         String nodeName = node.getName();
         classesToCompile.put(nodeName, node);
         classNameToSource.put(nodeName, location);
     }
 
-    public SourceUnit getScriptSourceLocation(String className) {
-        return classNameToSource.get(className);
-    }
-
-    public boolean hasClassNodeToCompile() {
-        return !classesToCompile.isEmpty();
-    }
-
-    public Iterator<String> iterateClassNodeToCompile() {
-        return classesToCompile.keySet().iterator();
-    }
-
-    public InnerClassNode getGeneratedInnerClass(String name) {
-        return generatedInnerClasses.get(name);
-    }
-
-    public void addGeneratedInnerClass(InnerClassNode icn) {
+    public void addGeneratedInnerClass(final InnerClassNode icn) {
         generatedInnerClasses.put(icn.getName(), icn);
     }
-
-    public Map<String, InnerClassNode> getGeneratedInnerClasses() {
-        return Collections.unmodifiableMap(generatedInnerClasses);
-    }
-
-    public Map<String, ClassNode> getClassesToCompile() {
-        return classesToCompile;
-    }
-
-    public Map<String, ConstructedOuterNestedClassNode> getClassesToResolve() {
-        return classesToResolve;
-    }
-
-    /**
-     * Add a constructed class node as a placeholder to resolve outer nested class further.
-     *
-     * @param cn the constructed class node
-     */
-    public void addClassNodeToResolve(ConstructedOuterNestedClassNode cn) {
-        classesToResolve.put(cn.getUnresolvedName(), cn);
-    }
-
-    @Override
-    public Map<?, ?> getMetaDataMap() {
-        return metaDataMap;
-    }
-
-    @Override
-    public void setMetaDataMap(Map<?, ?> metaDataMap) {
-        this.metaDataMap = metaDataMap;
-    }
-
-    /**
-     * Represents a resolved type as a placeholder.
-     *
-     * @see <a href="https://issues.apache.org/jira/browse/GROOVY-7812">GROOVY-7812</a>
-     */
-    @Internal
-    public static class ConstructedOuterNestedClassNode extends ClassNode {
-        private final ClassNode enclosingClassNode;
-        private final List<BiConsumer<ConstructedOuterNestedClassNode, ClassNode>> setRedirectListenerList = new ArrayList<>();
-
-        public ConstructedOuterNestedClassNode(ClassNode outer, String innerClassName) {
-            super(innerClassName, ACC_PUBLIC, ClassHelper.OBJECT_TYPE);
-            this.enclosingClassNode = outer;
-            this.isPrimaryNode = false;
-        }
-
-        public ClassNode getEnclosingClassNode() {
-            return enclosingClassNode;
-        }
-
-        @Override
-        public void setRedirect(ClassNode cn) {
-            for (BiConsumer<ConstructedOuterNestedClassNode, ClassNode> setRedirectListener : setRedirectListenerList) {
-                setRedirectListener.accept(this, cn);
-            }
-            super.setRedirect(cn);
-        }
-
-        public void addSetRedirectListener(BiConsumer<ConstructedOuterNestedClassNode, ClassNode> setRedirectListener) {
-            setRedirectListenerList.add(setRedirectListener);
-        }
-    }
 }
diff --git a/src/main/java/org/codehaus/groovy/control/CompilationUnit.java b/src/main/java/org/codehaus/groovy/control/CompilationUnit.java
index af48d23..4de5ae8 100644
--- a/src/main/java/org/codehaus/groovy/control/CompilationUnit.java
+++ b/src/main/java/org/codehaus/groovy/control/CompilationUnit.java
@@ -46,7 +46,6 @@ import org.codehaus.groovy.control.io.InputStreamReaderSource;
 import org.codehaus.groovy.control.io.ReaderSource;
 import org.codehaus.groovy.control.messages.ExceptionMessage;
 import org.codehaus.groovy.control.messages.Message;
-import org.codehaus.groovy.control.messages.SimpleMessage;
 import org.codehaus.groovy.syntax.RuntimeParserException;
 import org.codehaus.groovy.syntax.SyntaxException;
 import org.codehaus.groovy.tools.GroovyClass;
@@ -227,7 +226,7 @@ public class CompilationUnit extends ProcessingUnit {
             List<ClassNode> classes = source.getAST().getClasses();
             for (ClassNode node : classes) {
                 CompileUnit cu = node.getCompileUnit();
-                for (Iterator<String> it = cu.iterateClassNodeToCompile(); it.hasNext(); ) {
+                for (Iterator<String> it = cu.getClassesToCompile().keySet().iterator(); it.hasNext(); ) {
                     String name = it.next();
                     StringBuilder message = new StringBuilder();
                     message
@@ -250,9 +249,8 @@ public class CompilationUnit extends ProcessingUnit {
                         }
                     }
 
-                    getErrorCollector().addErrorAndContinue(
-                            new SimpleMessage(message.toString(), this)
-                    );
+                    getErrorCollector().addErrorAndContinue(Message.create(message.toString(), this));
+
                     it.remove();
                 }
             }
diff --git a/src/main/java/org/codehaus/groovy/control/ResolveVisitor.java b/src/main/java/org/codehaus/groovy/control/ResolveVisitor.java
index d4ce72e..9b17df7 100644
--- a/src/main/java/org/codehaus/groovy/control/ResolveVisitor.java
+++ b/src/main/java/org/codehaus/groovy/control/ResolveVisitor.java
@@ -27,7 +27,6 @@ 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.CompileUnit.ConstructedOuterNestedClassNode;
 import org.codehaus.groovy.ast.DynamicVariable;
 import org.codehaus.groovy.ast.FieldNode;
 import org.codehaus.groovy.ast.GenericsType;
@@ -60,7 +59,6 @@ import org.codehaus.groovy.ast.stmt.BlockStatement;
 import org.codehaus.groovy.ast.stmt.CatchStatement;
 import org.codehaus.groovy.ast.stmt.ForStatement;
 import org.codehaus.groovy.ast.stmt.Statement;
-import org.codehaus.groovy.control.ClassNodeResolver.LookupResult;
 import org.codehaus.groovy.runtime.memoize.UnlimitedConcurrentCache;
 import org.codehaus.groovy.syntax.Types;
 import org.codehaus.groovy.transform.trait.Traits;
@@ -77,7 +75,6 @@ import java.util.ListIterator;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
-import java.util.function.BiConsumer;
 import java.util.function.Predicate;
 
 import static groovy.lang.Tuple.tuple;
@@ -340,7 +337,6 @@ public class ResolveVisitor extends ClassCodeExpressionTransformer {
         }
         if (resolve(type)) return;
         if (resolveToInner(type)) return;
-        if (resolveToOuterNested(type)) return;
 
         addError("unable to resolve class " + type.toString(false) + msg, node);
     }
@@ -370,107 +366,6 @@ public class ResolveVisitor extends ClassCodeExpressionTransformer {
         return false;
     }
 
-    // GROOVY-7812(#1): Static inner classes cannot be accessed from other files
-    // when running by 'groovy' command if the type to resolve is an inner class
-    // and it is in an outer class which is not resolved, we set resolved type to
-    // a placeholder class node, i.e. a ConstructedOuterNestedClass instance 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);
-
-        ModuleNode module = currentClass.getModule();
-        for (ImportNode importNode : module.getStaticImports().values()) {
-            String importFieldName = importNode.getFieldName();
-            String importAlias = importNode.getAlias();
-
-            if (!typeName.equals(importAlias)) continue;
-
-            ConstructedOuterNestedClassNode constructedOuterNestedClassNode =
-                    tryToConstructOuterNestedClassNodeViaStaticImport(compileUnit, importNode, importFieldName, setRedirectListener);
-            if (constructedOuterNestedClassNode != null) {
-                compileUnit.addClassNodeToResolve(constructedOuterNestedClassNode);
-                return true;
-            }
-        }
-
-        for (ClassNode outerClassNode : compileUnit.getClassesToCompile().values()) {
-            ConstructedOuterNestedClassNode constructedOuterNestedClassNode =
-                    tryToConstructOuterNestedClassNode(type, outerClassNode, setRedirectListener);
-            if (constructedOuterNestedClassNode != null) {
-                compileUnit.addClassNodeToResolve(constructedOuterNestedClassNode);
-                return true;
-            }
-        }
-
-        boolean toResolveFurther = false;
-        for (ImportNode importNode : module.getStaticStarImports().values()) {
-            ConstructedOuterNestedClassNode constructedOuterNestedClassNode =
-                    tryToConstructOuterNestedClassNodeViaStaticImport(compileUnit, importNode, typeName, setRedirectListener);
-            if (constructedOuterNestedClassNode != null) {
-                compileUnit.addClassNodeToResolve(constructedOuterNestedClassNode);
-                toResolveFurther = true; // try all static star imports because we do not know which outer class the class is declared in
-            }
-        }
-        if (toResolveFurther) return true;
-
-        // GROOVY-9243
-        toResolveFurther = false;
-        if (typeName.indexOf('.') == -1) {
-            for (ClassNode cn = currentClass; cn != null && !isObjectType(cn); cn = cn.getSuperClass()) {
-                ConstructedOuterNestedClassNode constructedOuterNestedClassNode =
-                        tryToConstructOuterNestedClassNodeForBaseType(compileUnit, typeName, cn, setRedirectListener);
-                if (constructedOuterNestedClassNode != null) {
-                    compileUnit.addClassNodeToResolve(constructedOuterNestedClassNode);
-                    toResolveFurther = true;
-                }
-            }
-        }
-
-        return toResolveFurther;
-    }
-
-    private ConstructedOuterNestedClassNode tryToConstructOuterNestedClassNodeViaStaticImport(final CompileUnit compileUnit, final ImportNode importNode, final String typeName, final BiConsumer<ConstructedOuterNestedClassNode, ClassNode> setRedirectListener) {
-        String importClassName = importNode.getClassName();
-        ClassNode outerClassNode = compileUnit.getClass(importClassName);
-
-        if (null == outerClassNode) return null;
-
-        String outerNestedClassName = importClassName + "$" + typeName.replace('.', '$');
-        ConstructedOuterNestedClassNode constructedOuterNestedClassNode = new ConstructedOuterNestedClassNode(outerClassNode, outerNestedClassName);
-        constructedOuterNestedClassNode.addSetRedirectListener(setRedirectListener);
-        return constructedOuterNestedClassNode;
-    }
-
-    private ConstructedOuterNestedClassNode tryToConstructOuterNestedClassNode(final ClassNode type, final ClassNode outerClassNode, final BiConsumer<ConstructedOuterNestedClassNode, ClassNode> setRedirectListener) {
-        String outerClassName = outerClassNode.getName();
-
-        for (String typeName = type.getName(), ident = typeName; ident.indexOf('.') != -1; ) {
-            ident = ident.substring(0, ident.lastIndexOf('.'));
-            if (outerClassName.endsWith(ident)) {
-                String outerNestedClassName = outerClassName + typeName.substring(ident.length()).replace('.', '$');
-                ConstructedOuterNestedClassNode constructedOuterNestedClassNode = new ConstructedOuterNestedClassNode(outerClassNode, outerNestedClassName);
-                constructedOuterNestedClassNode.addSetRedirectListener(setRedirectListener);
-                return constructedOuterNestedClassNode;
-            }
-        }
-
-        return null;
-    }
-
-    private ConstructedOuterNestedClassNode tryToConstructOuterNestedClassNodeForBaseType(final CompileUnit compileUnit, final String typeName, final ClassNode cn, final BiConsumer<ConstructedOuterNestedClassNode, ClassNode> setRedirectListener) {
-        if (!compileUnit.getClassesToCompile().containsValue(cn)) return null;
-
-        String outerNestedClassName = cn.getName() + "$" + typeName;
-        ConstructedOuterNestedClassNode constructedOuterNestedClassNode = new ConstructedOuterNestedClassNode(cn, outerNestedClassName);
-        constructedOuterNestedClassNode.addSetRedirectListener(setRedirectListener);
-        return constructedOuterNestedClassNode;
-    }
-
     protected boolean resolve(final ClassNode type) {
         return resolve(type, true, true, true);
     }
@@ -867,11 +762,10 @@ public class ResolveVisitor extends ClassCodeExpressionTransformer {
 
         if (currentClass.getModule().hasPackageName() && name.indexOf('.') == -1) return false;
 
-        LookupResult lr = classNodeResolver.resolveName(name, compilationUnit);
+        ClassNodeResolver.LookupResult lr = classNodeResolver.resolveName(name, compilationUnit);
         if (lr != null) {
             if (lr.isSourceUnit()) {
-                SourceUnit su = lr.getSourceUnit();
-                currentClass.getCompileUnit().addClassNodeToCompile(type, su);
+                currentClass.getCompileUnit().addClassNodeToCompile(type, lr.getSourceUnit());
             } else {
                 type.setRedirect(lr.getClassNode());
             }
@@ -1456,8 +1350,6 @@ public class ResolveVisitor extends ClassCodeExpressionTransformer {
 
         super.visitClass(node);
 
-        resolveOuterNestedClassFurther(node);
-
         currentClass = oldNode;
     }
 
@@ -1488,37 +1380,6 @@ public class ResolveVisitor extends ClassCodeExpressionTransformer {
         }
     }
 
-    // GROOVY-7812(#2): Static inner classes cannot be accessed from other files when running by 'groovy' command
-    private void resolveOuterNestedClassFurther(final ClassNode node) {
-        CompileUnit compileUnit = currentClass.getCompileUnit();
-
-        if (null == compileUnit) return;
-
-        Map<String, ConstructedOuterNestedClassNode> classesToResolve = compileUnit.getClassesToResolve();
-        List<String> resolvedInnerClassNameList = new LinkedList<>();
-
-        for (Map.Entry<String, ConstructedOuterNestedClassNode> entry : classesToResolve.entrySet()) {
-            String innerClassName = entry.getKey();
-            ConstructedOuterNestedClassNode constructedOuterNestedClass = entry.getValue();
-
-            // When the outer class is resolved, all inner classes are resolved too
-            if (node.getName().equals(constructedOuterNestedClass.getEnclosingClassNode().getName())) {
-                ClassNode innerClassNode = compileUnit.getClass(innerClassName); // find the resolved inner class
-
-                if (null == innerClassNode) {
-                    return; // "unable to resolve class" error can be thrown already, no need to `addError`, so just return
-                }
-
-                constructedOuterNestedClass.setRedirect(innerClassNode);
-                resolvedInnerClassNameList.add(innerClassName);
-            }
-        }
-
-        for (String innerClassName : resolvedInnerClassNameList) {
-            classesToResolve.remove(innerClassName);
-        }
-    }
-
     @Override
     public void visitCatchStatement(final CatchStatement cs) {
         resolveOrFail(cs.getExceptionType(), cs);
diff --git a/src/test/groovy/bugs/Groovy9243.groovy b/src/test-resources/groovy/bugs/groovy4386/Constants.groovy
similarity index 71%
copy from src/test/groovy/bugs/Groovy9243.groovy
copy to src/test-resources/groovy/bugs/groovy4386/Constants.groovy
index 51014ee..2d7ac2f 100644
--- a/src/test/groovy/bugs/Groovy9243.groovy
+++ b/src/test-resources/groovy/bugs/groovy4386/Constants.groovy
@@ -16,18 +16,9 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package groovy.bugs
+package groovy.bugs.groovy4386
 
-
-import groovy.transform.CompileStatic
-import org.apache.groovy.util.ScriptRunner
-import org.junit.Ignore
-import org.junit.Test
-
-@CompileStatic
-final class Groovy9243 {
-    @Ignore @Test
-    void testResolveNestedClassFromBaseType() {
-        ScriptRunner.runScript('/groovy/bugs/groovy9243/Main.groovy')
-    }
+class Constants {
+    public static final PI = 3.14
+    static final TWOPI = 6.28
 }
diff --git a/src/test/groovy/bugs/Groovy9243.groovy b/src/test-resources/groovy/bugs/groovy4386/StaticField.groovy
similarity index 72%
rename from src/test/groovy/bugs/Groovy9243.groovy
rename to src/test-resources/groovy/bugs/groovy4386/StaticField.groovy
index 51014ee..b2c2966 100644
--- a/src/test/groovy/bugs/Groovy9243.groovy
+++ b/src/test-resources/groovy/bugs/groovy4386/StaticField.groovy
@@ -16,18 +16,14 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package groovy.bugs
+package groovy.bugs.groovy4386
 
+import static groovy.bugs.groovy4386.Constants.PI
 
-import groovy.transform.CompileStatic
-import org.apache.groovy.util.ScriptRunner
-import org.junit.Ignore
-import org.junit.Test
-
-@CompileStatic
-final class Groovy9243 {
-    @Ignore @Test
-    void testResolveNestedClassFromBaseType() {
-        ScriptRunner.runScript('/groovy/bugs/groovy9243/Main.groovy')
+class Test {
+    static test() {
+        assert PI == 3.14
     }
 }
+
+Test.test()
diff --git a/src/test/groovy/bugs/Groovy4287Bug.groovy b/src/test-resources/groovy/bugs/groovy4386/StaticProperty.groovy
similarity index 68%
rename from src/test/groovy/bugs/Groovy4287Bug.groovy
rename to src/test-resources/groovy/bugs/groovy4386/StaticProperty.groovy
index e881e19..856aaea 100644
--- a/src/test/groovy/bugs/Groovy4287Bug.groovy
+++ b/src/test-resources/groovy/bugs/groovy4386/StaticProperty.groovy
@@ -16,17 +16,14 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package groovy.bugs
+package groovy.bugs.groovy4386
 
-import groovy.test.GroovyTestCase
-import org.apache.groovy.util.ScriptRunner
+import static groovy.bugs.groovy4386.Constants.TWOPI
 
-class Groovy4287Bug extends GroovyTestCase {
-    void testResolvingOuterStaticNestedClass() {
-        ScriptRunner.runScript('/groovy/bugs/groovy4287/Main.groovy')
-    }
-
-    void testResolvingOuterStaticNestedClassAlias() {
-        ScriptRunner.runScript('/groovy/bugs/groovy4287/Main2.groovy')
+class Test {
+    static test() {
+        assert TWOPI == 6.28
     }
 }
+
+Test.test()
diff --git a/src/test/groovy/bugs/groovy9236/Groovy9236ClassLoader.java b/src/test-resources/groovy/bugs/groovy4386/StaticStarImport.groovy
similarity index 67%
rename from src/test/groovy/bugs/groovy9236/Groovy9236ClassLoader.java
rename to src/test-resources/groovy/bugs/groovy4386/StaticStarImport.groovy
index 8a430b1..14c361a 100644
--- a/src/test/groovy/bugs/groovy9236/Groovy9236ClassLoader.java
+++ b/src/test-resources/groovy/bugs/groovy4386/StaticStarImport.groovy
@@ -16,18 +16,14 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package bugs.groovy9236;
+package groovy.bugs.groovy4386
 
-import groovy.lang.GroovyClassLoader;
+import static groovy.bugs.groovy4386.Constants.*
 
-import java.util.ArrayList;
-import java.util.List;
-
-public class Groovy9236ClassLoader extends GroovyClassLoader {
-    final List<String> guessedClassNameList = new ArrayList<>();
-
-    protected Class<?> findClass(final String name) throws ClassNotFoundException {
-        guessedClassNameList.add(name);
-        return super.findClass(name);
+class Test {
+    static test() {
+        assert TWOPI == PI + PI
     }
 }
+
+Test.test()
diff --git a/src/test/groovy/bugs/Groovy4386_Bug.groovy b/src/test/groovy/bugs/Groovy4386_Bug.groovy
deleted file mode 100644
index ffe084d..0000000
--- a/src/test/groovy/bugs/Groovy4386_Bug.groovy
+++ /dev/null
@@ -1,90 +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 groovy.bugs
-
-import groovy.test.GroovyTestCase
-import org.codehaus.groovy.control.CompilerConfiguration
-import org.codehaus.groovy.runtime.ResourceGroovyMethods
-
-/**
- * Test for GROOVY-4386: Using static imports to a script on the classpath.
- */
-class Groovy4386_Bug extends GroovyTestCase {
-    private static final scriptSource = """
-        package foo
-        class Constants {
-            public static final PI = 3.14
-            static final TWOPI = 6.28
-        }
-    """
-    File tmpDir
-
-    @Override protected void setUp() {
-        tmpDir = File.createTempDir()
-        File dir = new File(tmpDir, 'foo')
-        dir.mkdir()
-        File file = new File(dir, "Constants.groovy")
-        ResourceGroovyMethods.setText(file, scriptSource);
-    }
-
-    @Override protected void tearDown() {
-        tmpDir.deleteDir()
-    }
-
-    void testAccessPublicStaticField() {
-        assertScript """
-            import static foo.Constants.PI
-            class Test {
-                static test() {
-                    assert PI == 3.14
-                }
-            }
-            Test.test()
-        """
-    }
-
-    void testAccessStaticProperty() {
-        assertScript """
-            import static foo.Constants.TWOPI
-            class Test {
-                static test() {
-                    assert TWOPI == 6.28
-                }
-            }
-            Test.test()
-        """
-    }
-
-    void testStarImport() {
-        assertScript """
-            import static foo.Constants.*
-            class Test {
-                static test() {
-                    assert TWOPI == PI + PI
-                }
-            }
-            Test.test()
-        """
-    }
-
-    void assertScript(String script) {
-        GroovyShell shell = new GroovyShell(new CompilerConfiguration(classpath: tmpDir.path))
-        shell.evaluate(script, getTestClassName())
-    }
-}
diff --git a/src/test/groovy/bugs/Groovy7812Bug.groovy b/src/test/groovy/bugs/Groovy7812Bug.groovy
deleted file mode 100644
index 6055402..0000000
--- a/src/test/groovy/bugs/Groovy7812Bug.groovy
+++ /dev/null
@@ -1,48 +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 groovy.bugs
-
-import groovy.test.GroovyTestCase
-import org.apache.groovy.util.ScriptRunner
-
-class Groovy7812Bug extends GroovyTestCase {
-    void testResolvingOuterNestedClass() {
-        ScriptRunner.runScript('/groovy/bugs/groovy7812/Main.groovy')
-    }
-
-//   Even if try to catch `Throwable`, the expected error is thrown all the same..., as a result, the test fails due to the weired problem...
-//
-//    org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
-//D:\_APPS\git_apps\groovy\out\test\resources\groovy\bugs\groovy7812\MainWithErrors.groovy: 22: unable to resolve class Outer.Inner123
-// @ line 22, column 8.
-//   assert new Outer.Inner123()
-//          ^
-//
-//1 error
-//
-//    void testUnexistingInnerClass() {
-//        try {
-//            def mainScriptPath = new File(this.getClass().getResource('/groovy/bugs/groovy7812/MainWithErrors.groovy').toURI()).absolutePath
-//            runScript(mainScriptPath)
-//        } catch (Throwable t) {
-//            assert t.getMessage().contains('unable to resolve class Outer.Inner123')
-//        }
-//    }
-
-}
diff --git a/src/test/groovy/bugs/Groovy9236.groovy b/src/test/groovy/bugs/Groovy9236.groovy
new file mode 100644
index 0000000..8493952
--- /dev/null
+++ b/src/test/groovy/bugs/Groovy9236.groovy
@@ -0,0 +1,125 @@
+/*
+ *  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 groovy.bugs
+
+import org.junit.Test
+
+final class Groovy9236 {
+
+    /**
+     * groovy-3.0.0-beta-3 will try to guess and load the following classes:
+     * <pre>
+     * Script1$_p_lambda1BeanInfo
+     * Script1$_p_lambda1Customizer
+     * Script1BeanInfo
+     * Script1Customizer
+     * groovy$transform$CompileStatic
+     * groovy.lang.GroovyObject$Collectors
+     * groovy.lang.GroovyObject$CompileStatic
+     * groovy.lang.GroovyObject$groovy$transform$CompileStatic
+     * groovy.lang.GroovyObject$java$util$stream$Collectors
+     * groovy.lang.GroovyObject$java$util$stream$Stream
+     * groovy.lang.groovy$transform$CompileStatic
+     * groovy.lang.java$util$stream$Collectors
+     * groovy.lang.java$util$stream$Stream
+     * groovy.transform$CompileStatic
+     * groovy.util.groovy$transform$CompileStatic
+     * groovy.util.java$util$stream$Collectors
+     * groovy.util.java$util$stream$Stream
+     * java$util$stream$Collectors
+     * java$util$stream$Stream
+     * java.io.groovy$transform$CompileStatic
+     * java.io.java$util$stream$Collectors
+     * java.io.java$util$stream$Stream
+     * java.lang.groovy$transform$CompileStatic
+     * java.lang.java$util$stream$Collectors
+     * java.lang.java$util$stream$Stream
+     * java.net.groovy$transform$CompileStatic
+     * java.net.java$util$stream$Collectors
+     * java.net.java$util$stream$Stream
+     * java.util$stream$Collectors
+     * java.util$stream$Stream
+     * java.util.groovy$transform$CompileStatic
+     * java.util.java$util$stream$Collectors
+     * java.util.java$util$stream$Stream
+     * java.util.stream$Collectors
+     * java.util.stream$Stream
+     * </pre>
+     */
+    @Test
+    void testAvoidUnnecessaryResolving() {
+        def guessedClassNameList = []
+
+        def loader = new GroovyClassLoader() {
+            @Override
+            protected Class<?> findClass(String name) throws ClassNotFoundException {
+                guessedClassNameList.add(name)
+                return super.findClass(name)
+            }
+        }
+
+        new GroovyShell(loader).evaluate('''
+            import groovy.transform.CompileStatic
+            import java.util.stream.Collectors
+            import java.util.stream.Stream
+
+            @CompileStatic
+            void p() {
+                assert [2, 3, 4] == [1, 2, 3].stream().map(e -> e.plus(1)).collect(Collectors.toList())
+            }
+
+            p()
+        ''')
+
+        Set<String> classNamesShouldAvoidToGuess = [
+            'java.lang.java$util$stream$Collectors',
+            'java.util.java$util$stream$Collectors',
+            'java.io.java$util$stream$Collectors',
+            'java.net.java$util$stream$Collectors',
+            'groovy.lang.java$util$stream$Collectors',
+            'groovy.util.java$util$stream$Collectors',
+            'java$util$stream$Collectors',
+            'java.util$stream$Collectors',
+            'java.util.stream$Collectors',
+            'java.lang.groovy$transform$CompileStatic',
+            'java.util.groovy$transform$CompileStatic',
+            'java.io.groovy$transform$CompileStatic',
+            'java.net.groovy$transform$CompileStatic',
+            'groovy.lang.groovy$transform$CompileStatic',
+            'groovy.util.groovy$transform$CompileStatic',
+            'groovy$transform$CompileStatic',
+            'groovy.transform$CompileStatic',
+            'java.lang.java$util$stream$Stream',
+            'java.util.java$util$stream$Stream',
+            'java.io.java$util$stream$Stream',
+            'java.net.java$util$stream$Stream',
+            'groovy.lang.java$util$stream$Stream',
+            'groovy.util.java$util$stream$Stream',
+            'java$util$stream$Stream',
+            'java.util$stream$Stream',
+            'java.util.stream$Stream',
+            'groovy.lang.GroovyObject$java$util$stream$Collectors',
+            'groovy.lang.GroovyObject$groovy$transform$CompileStatic',
+            'groovy.lang.GroovyObject$java$util$stream$Stream'
+        ]
+
+        assert !guessedClassNameList.isEmpty()
+        assert guessedClassNameList.every(n -> !classNamesShouldAvoidToGuess.contains(n))
+    }
+}
diff --git a/src/test/groovy/bugs/groovy9236/Groovy9236Bug.groovy b/src/test/groovy/bugs/groovy9236/Groovy9236Bug.groovy
deleted file mode 100644
index 093eed4..0000000
--- a/src/test/groovy/bugs/groovy9236/Groovy9236Bug.groovy
+++ /dev/null
@@ -1,115 +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 bugs.groovy9236
-
-import groovy.test.GroovyTestCase
-import org.apache.groovy.util.ScriptRunner
-
-class Groovy9236Bug extends GroovyTestCase {
-    /* groovy-3.0.0-beta-3 will try to guess and load the following classes:
-Script1$_p_lambda1BeanInfo
-Script1$_p_lambda1Customizer
-Script1BeanInfo
-Script1Customizer
-groovy$transform$CompileStatic
-groovy.lang.GroovyObject$Collectors
-groovy.lang.GroovyObject$CompileStatic
-groovy.lang.GroovyObject$groovy$transform$CompileStatic
-groovy.lang.GroovyObject$java$util$stream$Collectors
-groovy.lang.GroovyObject$java$util$stream$Stream
-groovy.lang.groovy$transform$CompileStatic
-groovy.lang.java$util$stream$Collectors
-groovy.lang.java$util$stream$Stream
-groovy.transform$CompileStatic
-groovy.util.groovy$transform$CompileStatic
-groovy.util.java$util$stream$Collectors
-groovy.util.java$util$stream$Stream
-java$util$stream$Collectors
-java$util$stream$Stream
-java.io.groovy$transform$CompileStatic
-java.io.java$util$stream$Collectors
-java.io.java$util$stream$Stream
-java.lang.groovy$transform$CompileStatic
-java.lang.java$util$stream$Collectors
-java.lang.java$util$stream$Stream
-java.net.groovy$transform$CompileStatic
-java.net.java$util$stream$Collectors
-java.net.java$util$stream$Stream
-java.util$stream$Collectors
-java.util$stream$Stream
-java.util.groovy$transform$CompileStatic
-java.util.java$util$stream$Collectors
-java.util.java$util$stream$Stream
-java.util.stream$Collectors
-java.util.stream$Stream
-     */
-    void testAvoidUnnecessaryResolving() {
-        def cl = new Groovy9236ClassLoader()
-        def gs = new GroovyShell(cl)
-        gs.evaluate('''
-                import groovy.transform.CompileStatic
-                import java.util.stream.Collectors
-                import java.util.stream.Stream
-
-                @CompileStatic
-                void p() {
-                    assert [2, 3, 4] == [1, 2, 3].stream().map(e -> e.plus(1)).collect(Collectors.toList())
-                }
-
-                p()
-        ''')
-
-        final classNamesShouldAvoidToGuess = ['java.lang.java$util$stream$Collectors',
-                                              'java.util.java$util$stream$Collectors',
-                                              'java.io.java$util$stream$Collectors',
-                                              'java.net.java$util$stream$Collectors',
-                                              'groovy.lang.java$util$stream$Collectors',
-                                              'groovy.util.java$util$stream$Collectors',
-                                              'java$util$stream$Collectors',
-                                              'java.util$stream$Collectors',
-                                              'java.util.stream$Collectors',
-                                              'java.lang.groovy$transform$CompileStatic',
-                                              'java.util.groovy$transform$CompileStatic',
-                                              'java.io.groovy$transform$CompileStatic',
-                                              'java.net.groovy$transform$CompileStatic',
-                                              'groovy.lang.groovy$transform$CompileStatic',
-                                              'groovy.util.groovy$transform$CompileStatic',
-                                              'groovy$transform$CompileStatic',
-                                              'groovy.transform$CompileStatic',
-                                              'java.lang.java$util$stream$Stream',
-                                              'java.util.java$util$stream$Stream',
-                                              'java.io.java$util$stream$Stream',
-                                              'java.net.java$util$stream$Stream',
-                                              'groovy.lang.java$util$stream$Stream',
-                                              'groovy.util.java$util$stream$Stream',
-                                              'java$util$stream$Stream',
-                                              'java.util$stream$Stream',
-                                              'java.util.stream$Stream',
-                                              'groovy.lang.GroovyObject$java$util$stream$Collectors',
-                                              'groovy.lang.GroovyObject$groovy$transform$CompileStatic',
-                                              'groovy.lang.GroovyObject$java$util$stream$Stream']
-
-        assert !cl.guessedClassNameList.isEmpty()
-        assert cl.guessedClassNameList.every(n -> !classNamesShouldAvoidToGuess.contains(n))
-    }
-
-    void testResolvingPrecedence() {
-        ScriptRunner.runScript('/groovy/bugs/groovy9236/Main.groovy')
-    }
-}
diff --git a/src/test/groovy/script/RuntimeResolveTests.groovy b/src/test/groovy/script/RuntimeResolveTests.groovy
new file mode 100644
index 0000000..922bdbf
--- /dev/null
+++ b/src/test/groovy/script/RuntimeResolveTests.groovy
@@ -0,0 +1,77 @@
+/*
+ *  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 groovy.script
+
+import org.junit.Ignore
+import org.junit.Test
+
+import static org.apache.groovy.util.ScriptRunner.runScript
+
+@Ignore('disabled pending rework')
+final class RuntimeResolveTests {
+
+    @Test
+    void testResolveOuterStaticNestedClass() {
+        runScript('/groovy/bugs/groovy4287/Main.groovy')
+    }
+
+    @Test
+    void testResolveOuterStaticNestedClassAlias() {
+        runScript('/groovy/bugs/groovy4287/Main2.groovy')
+    }
+
+    @Test
+    void testResolvePublicStaticField() {
+        runScript('/groovy/bugs/groovy4386/StaticField.groovy')
+    }
+
+    @Test
+    void testResolveStaticProperty() {
+        runScript('/groovy/bugs/groovy4386/StaticProperty.groovy')
+    }
+
+    @Test
+    void testResolveStaticMembers() {
+        runScript('/groovy/bugs/groovy4386/StaticStarImport.groovy')
+    }
+
+    @Test
+    void testResolveOuterNestedClass() {
+        runScript('/groovy/bugs/groovy7812/Main.groovy')
+    }
+
+    @Test @Ignore('exception in script causes problem for build')
+    void testUnexistingInnerClass() {
+        try {
+            runScript('/groovy/bugs/groovy7812/MainWithErrors.groovy')
+        } catch (Throwable t) {
+            assert t.getMessage().contains('unable to resolve class Outer.Inner123')
+        }
+    }
+
+    @Test
+    void testResolvePrecedence() {
+        runScript('/groovy/bugs/groovy9236/Main.groovy')
+    }
+
+    @Test
+    void testResolveNestedClassFromBaseType() {
+        runScript('/groovy/bugs/groovy9243/Main.groovy')
+    }
+}