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 2022/02/25 20:36:54 UTC

[groovy] 02/02: GROOVY-10396: StaticImportVisitor: static context skips instance methods

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

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

commit 2871e15cc275d04b43f0a2e45b200c3321bdd4f3
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Tue Nov 30 10:54:18 2021 -0600

    GROOVY-10396: StaticImportVisitor: static context skips instance methods
    
    Conflicts:
    	src/main/java/org/codehaus/groovy/control/StaticImportVisitor.java
    	src/test/groovy/StaticImportTest.groovy
---
 .../groovy/control/StaticImportVisitor.java        |  35 +-
 src/test/groovy/StaticImportTest.groovy            | 487 +++++++++++++++------
 src/test/groovy/bugs/Groovy8389Bug.groovy          | 109 -----
 3 files changed, 375 insertions(+), 256 deletions(-)

diff --git a/src/main/java/org/codehaus/groovy/control/StaticImportVisitor.java b/src/main/java/org/codehaus/groovy/control/StaticImportVisitor.java
index eb74e80..5ac4917 100644
--- a/src/main/java/org/codehaus/groovy/control/StaticImportVisitor.java
+++ b/src/main/java/org/codehaus/groovy/control/StaticImportVisitor.java
@@ -227,14 +227,6 @@ public class StaticImportVisitor extends ClassCodeExpressionTransformer {
         return ve;
     }
 
-    private boolean hasPossibleClassOrOuterMethod(String name, Expression args) {
-        if (currentClass.tryFindPossibleMethod(name, args) != null) return true;
-        for (ClassNode outerClass : currentClass.getOuterClasses()) {
-            if (outerClass.tryFindPossibleMethod(name, args) != null) return true;
-        }
-        return false;
-    }
-
     /**
      * Set the source position of toSet including its property expression if it has one.
      *
@@ -253,24 +245,30 @@ public class StaticImportVisitor extends ClassCodeExpressionTransformer {
         Expression method = transform(mce.getMethod());
         Expression args = transform(mce.getArguments());
 
+        // GROOVY-10396: skip the instance method checks when the context is static with-respect-to current class
+        boolean staticWrtCurrent = inSpecialConstructorCall || currentMethod != null && currentMethod.isStatic();
+
         if (mce.isImplicitThis()) {
             String name = mce.getMethodAsString();
-            if (!hasPossibleClassOrOuterMethod(name, args)) { // GROOVY-5239
+            boolean thisOrSuperMethod = staticWrtCurrent ? hasPossibleStaticMethod(currentClass, name, args, true) : currentClass.tryFindPossibleMethod(name, args) != null;
+            if (!thisOrSuperMethod && !hasPossibleOuterMethod(currentClass, name, args)) { // GROOVY-5239
                 Expression result = findStaticMethodImportFromModule(method, args);
                 if (result != null) {
-                    setSourcePosition(result, mce);
+                    result.setSourcePosition(mce);
                     return result;
                 }
                 if (name != null && !inLeftExpression) { // maybe a closure field
                     result = findStaticFieldOrPropAccessorImportFromModule(name);
                     if (result != null) {
+                        setSourcePosition(result, method);
                         result = new MethodCallExpression(result, "call", args);
+                        ((MethodCallExpression) result).setImplicitThis(false);
                         result.setSourcePosition(mce);
                         return result;
                     }
                 }
             }
-        } else if (currentMethod != null && currentMethod.isStatic() && isSuperExpression(object)) {
+        } else if (staticWrtCurrent && isSuperExpression(object)) {
             Expression result = new MethodCallExpression(new ClassExpression(currentClass.getSuperClass()), method, args);
             result.setSourcePosition(mce);
             return result;
@@ -279,7 +277,7 @@ public class StaticImportVisitor extends ClassCodeExpressionTransformer {
         if (method instanceof ConstantExpression && ((ConstantExpression) method).getValue() instanceof String && (mce.isImplicitThis() || isThisOrSuper(object))) {
             String methodName = (String) ((ConstantExpression) method).getValue();
 
-            boolean foundInstanceMethod = (currentMethod != null && !currentMethod.isStatic() && currentClass.hasPossibleMethod(methodName, args));
+            boolean foundInstanceMethod = !staticWrtCurrent && currentClass.hasPossibleMethod(methodName, args);
 
             if (mce.isImplicitThis()) {
                 if (isInnerClass(currentClass)) {
@@ -353,7 +351,7 @@ public class StaticImportVisitor extends ClassCodeExpressionTransformer {
         if (currentMethod != null && currentMethod.isStatic()
                 && isSuperExpression(pe.getObjectExpression())) {
             PropertyExpression pexp = new PropertyExpression(
-                    new ClassExpression(currentClass.getSuperClass()),
+                    new ClassExpression(currentClass.getUnresolvedSuperClass()),
                     transform(pe.getProperty())
             );
             pexp.setSourcePosition(pe);
@@ -370,7 +368,7 @@ public class StaticImportVisitor extends ClassCodeExpressionTransformer {
         if (foundArgs != null && foundConstant != null
                 && !foundConstant.getText().trim().isEmpty()
                 && objectExpression instanceof MethodCallExpression
-                && ((MethodCallExpression)objectExpression).isImplicitThis()) {
+                && ((MethodCallExpression) objectExpression).isImplicitThis()) {
             Expression result = findStaticMethodImportFromModule(foundConstant, foundArgs);
             if (result != null) {
                 objectExpression = result;
@@ -568,6 +566,15 @@ public class StaticImportVisitor extends ClassCodeExpressionTransformer {
         return false;
     }
 
+    private static boolean hasPossibleOuterMethod(ClassNode type, String name, Expression args) {
+        for (ClassNode outerClass : type.getOuterClasses()) {
+            if (outerClass.tryFindPossibleMethod(name, args) != null) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     private static PropertyExpression newStaticPropertyX(ClassNode type, String name) {
         return new PropertyExpression(new ClassExpression(type.getPlainNodeReference()), name);
     }
diff --git a/src/test/groovy/StaticImportTest.groovy b/src/test/groovy/StaticImportTest.groovy
index 5f12f0b..4f2f35d 100644
--- a/src/test/groovy/StaticImportTest.groovy
+++ b/src/test/groovy/StaticImportTest.groovy
@@ -18,7 +18,6 @@
  */
 package groovy
 
-import gls.CompilableTestSupport
 import static java.lang.Boolean.FALSE as F
 import static java.text.DateFormat.MEDIUM as M
 import static java.util.regex.Pattern.*
@@ -27,24 +26,21 @@ import static junit.framework.Assert.format
 import static junit.framework.Assert.assertEquals
 import static groovy.StaticImportTarget.x
 import static groovy.StaticImportTarget.z // do not remove
-import static groovy.StaticImportTarget.cl
 import static java.lang.Math.*
 import static java.util.Calendar.getInstance as now
 import static groovy.API.*
 import static groovy.StaticImportChild.*
-import static groovy.bugs.Groovy4145.foo4145
 import static groovy.Outer1.*
 import static groovy.Outer2.Inner2
 import static groovy.Outer2.Inner2 as InnerAlias2
 import static java.util.jar.Attributes.*
 import static java.util.jar.Attributes.Name as AttrName
-// TODO GROOVY-4287: reinstate next two imports
-//import static Outer3.*
-//import static Outer4.Inner4
 import static groovy.Container5087.*
+import static Foo4964.*
 import org.codehaus.groovy.runtime.DefaultGroovyMethods as DGM
 
-class StaticImportTest extends CompilableTestSupport {
+final class StaticImportTest extends gls.CompilableTestSupport {
+
     void testFieldWithAliasInExpression() {
         assert !F
     }
@@ -71,15 +67,16 @@ class StaticImportTest extends CompilableTestSupport {
     }
 
     void testFieldAsArgumentList() {
-        assert ("" + PI.toString()).contains('3.14')
+        assert ('' + PI.toString()).contains('3.14')
     }
 
     void testFieldAliasing() {
         assert MEDIUM == M
     }
 
+    // GROOVY-1809
     void testMethodAliasing() {
-        // GROOVY-1809 making this not possible on one line?
+        // making this not possible on one line?
         def now = now().time
         assert now.class == Date
     }
@@ -91,7 +88,7 @@ class StaticImportTest extends CompilableTestSupport {
     private format(a, b, c, ignored) { format(a, b, c) }
 
     void testMethodDefCanUseStaticallyImportedMethodWithSameNameButDiffArgs() {
-        assert format("different", "abc", "aBc", 3) == 'different expected:<abc> but was:<aBc>'
+        assert format('different', 'abc', 'aBc', 3) == 'different expected:<abc> but was:<aBc>'
     }
 
     void testAssertEqualsFromJUnit() {
@@ -103,15 +100,15 @@ class StaticImportTest extends CompilableTestSupport {
     }
 
     void testStaticImportFromGroovy() {
-        def nonstaticval = new StaticImportTarget().y("he", 3)
-        def staticval = x("he", 3)
+        def nonstaticval = new StaticImportTarget().y('he', 3)
+        def staticval = x('he', 3)
         assert nonstaticval == staticval
     }
 
     void testStaticImportWithVarArgs() {
-        assert noArrayMethod("one", 1) == 'noArrayMethod(one, 1)'
-        assert API.arrayMethod("two", 1, 2, 3) == 'arrayMethod(two, 1, 2, 3)'
-        assert arrayMethod("three", 1, 2, 3) == 'arrayMethod(three, 1, 2, 3)'
+        assert noArrayMethod('one', 1) == 'noArrayMethod(one, 1)'
+        assert API.arrayMethod('two', 1, 2, 3) == 'arrayMethod(two, 1, 2, 3)'
+        assert arrayMethod('three', 1, 2, 3) == 'arrayMethod(three, 1, 2, 3)'
     }
 
     void testStaticImportFromParentClass() {
@@ -120,126 +117,284 @@ class StaticImportTest extends CompilableTestSupport {
         assert cfield == 21
         assert pfield == 42
     }
-    
+
     void testStaticImportAndDefaultValue() {
-      assertScript """
-        import static Foo.*
-        import static Bar.*
-        
-        class Bar {
-          static void bar() { 
-            assert foo(10,1000) == 1010 
-            assert foo(10) == 110
-          }
-        }
-        
-        class Foo {
-          static int foo(int x, int y = 100) {x+y}
-        }
-        
-        Bar.bar()
-      """  
+        assertScript '''
+            import static Foo.*
+            import static Bar.*
+
+            class Bar {
+                static void bar() {
+                    assert foo(10,1000) == 1010
+                    assert foo(10) == 110
+                }
+            }
+
+            class Foo {
+                static int foo(int x, int y = 100) {x+y}
+            }
+
+            Bar.bar()
+        '''
     }
 
     void testStaticImportProperty() {
-        def sources = [
-            "class Foo { static x = 'foo'" + " }",
-            "class Foo { static x = 'foo'" + "; static getX() { x + '_get' } }",
-            "class Foo { static x = 'foo'" + ";                               static void setX(newx) { x = newx + '_set' } }",
-            "class Foo { static x = 'foo'" + "; static getX() { x + '_get' }; static void setX(newx) { x = newx + '_set' } }"
-        ]
-        def imports = [
-            "import static Foo.*",
-            "import static Foo.getX; import static Foo.setX"
-        ]
-        def results = [
-            "assert x == 'foo';     x = 'bar'; assert getX() == 'bar';         setX('baz'); assert 'baz'         == x",
-            "assert x == 'foo_get'; x = 'bar'; assert getX() == 'bar_get';     setX('baz'); assert 'baz_get'     == x",
-            "assert x == 'foo';     x = 'bar'; assert getX() == 'bar_set';     setX('baz'); assert 'baz_set'     == x",
-            "assert x == 'foo_get'; x = 'bar'; assert getX() == 'bar_set_get'; setX('baz'); assert 'baz_set_get' == x"
-        ]
-        [0..<sources.size(), 0..<imports.size()].combinations().each { i, j ->
-            assertScript sources[i] + "\n" + imports[j] + "\n" + results[i]
+        for (imports in ['import static Foo.getX; import static Foo.setX', 'import static Foo.*']) {
+            assertScript """$imports
+                class Foo {
+                    static x = 'foo'
+                }
+                assert x == 'foo'
+                x = 'bar'
+                assert getX() == 'bar'
+                setX('baz')
+                assert 'baz' == x
+            """
+            assertScript """$imports
+                class Foo {
+                    static x = 'foo'
+                    static getX() { x + '_get' }
+                }
+                assert x == 'foo_get'
+                x = 'bar'
+                assert getX() == 'bar_get'
+                setX('baz')
+                assert 'baz_get' == x
+            """
+            assertScript """$imports
+                class Foo {
+                    static x = 'foo'
+                    static void setX(newx) { x = newx + '_set' }
+                }
+                assert x == 'foo'
+                x = 'bar'
+                assert getX() == 'bar_set'
+                setX('baz')
+                assert 'baz_set' == x
+            """
+            assertScript """$imports
+                class Foo {
+                    static x = 'foo'
+                    static getX() { x + '_get' }
+                    static void setX(newx) { x = newx + '_set' }
+                }
+                assert x == 'foo_get'
+                x = 'bar'
+                assert getX() == 'bar_set_get'
+                setX('baz')
+                assert 'baz_set_get' == x
+            """
         }
     }
 
     void testStaticImportPropertyBooleanAlternative() {
-        def sources = [
-            "class Foo { static x = null" + "; static boolean isX() { x } }",
-            "class Foo { static x = null" + "; static boolean isX() { x }; static void setX(newx) { x = newx } }"
-        ]
-        def imports = [
-            "import static Foo.*",
-            "import static Foo.x",
-            "import static Foo.isX; import static Foo.setX"
-        ]
-        def results = [
-            "assert !x; x = true ; assert  isX(); setX(false); assert !x",
-            "assert !x; x = false; assert !isX(); setX(true);  assert  x"
-        ]
-        [0..<sources.size(), 0..<imports.size()].combinations().each { i, j ->
-            assertScript sources[i] + "\n" + imports[j] + "\n" + results[i]
+        for (imports in ['import static Foo.isX; import static Foo.setX', 'import static Foo.x', 'import static Foo.*']) {
+            assertScript """$imports
+                class Foo {
+                    static x
+                    static boolean isX() { !!x }
+                }
+                assert !x
+                x = true
+                assert isX()
+                setX(false)
+                assert !x
+            """
+            assertScript """$imports
+                class Foo {
+                    static x
+                    static boolean isX() { !!x }
+                    static void setX(newx) { x = newx }
+                }
+                assert !x
+                x = false
+                assert !isX()
+                setX(true)
+                assert x
+            """
         }
     }
 
     void testStaticImportPropertyWithPublicField() {
-        def sources = [
-            "class Foo { public static x = 'foo'" + " }",
-            "class Foo { public static x = 'foo'" + "; static getX() { x + '_get' } }",
-            "class Foo { public static x = 'foo'" + ";                               static void setX(newx) { x = newx + '_set' } }",
-            "class Foo { public static x = 'foo'" + "; static getX() { x + '_get' }; static void setX(newx) { x = newx + '_set' } }"
-        ]
-        def imports = [
-            "import static Foo.*",
-            "import static Foo.x"
-        ]
-        def results = [
-            "assert x == 'foo';     x = 'bar'; assert      x == 'bar';         x = 'baz'  ; assert 'baz'         == x",
-            "assert x == 'foo_get'; x = 'bar'; assert getX() == 'bar_get';     x = 'baz'  ; assert 'baz_get'     == x",
-            "assert x == 'foo';     x = 'bar'; assert      x == 'bar_set';     setX('baz'); assert 'baz_set'     == x",
-            "assert x == 'foo_get'; x = 'bar'; assert getX() == 'bar_set_get'; setX('baz'); assert 'baz_set_get' == x"
-        ]
-        [0..<sources.size(), 0..<imports.size()].combinations().each { i, j ->
-            assertScript sources[i] + "\n" + imports[j] + "\n" + results[i]
+        for (imports in ['import static Foo.x', 'import static Foo.*']) {
+            assertScript """$imports
+                class Foo {
+                    public static x = 'foo'
+                }
+                assert x == 'foo'
+                x = 'bar'
+                assert x == 'bar'
+                x = 'baz'
+                assert x == 'baz'
+            """
+            assertScript """$imports
+                class Foo {
+                    public static x = 'foo'
+                    static getX() { x + '_get' }
+                }
+                assert x == 'foo_get'
+                x = 'bar'
+                assert getX() == 'bar_get'
+                x = 'baz'
+                assert x == 'baz_get'
+            """
+            assertScript """$imports
+                class Foo {
+                    public static x = 'foo'
+                    static void setX(newx) { x = newx + '_set' }
+                }
+                assert x == 'foo'
+                x = 'bar'
+                assert x == 'bar_set'
+                setX('baz')
+                assert x == 'baz_set'
+            """
+            assertScript """$imports
+                class Foo {
+                    public static x = 'foo'
+                    static getX() { x + '_get' }
+                    static void setX(newx) { x = newx + '_set' }
+                }
+                assert x == 'foo_get'
+                x = 'bar'
+                assert getX() == 'bar_set_get'
+                setX('baz')
+                assert x == 'baz_set_get'
+            """
         }
-        assertScript sources[3] + """
+        assertScript '''
             import static Foo.getX; import static Foo.setX
+            class Foo { public static x = 'foo'; static getX() { x + '_get' }; static void setX(newx) { x = newx + '_set' } }
             assert getX() == 'foo_get'; setX('bar'); assert getX() == 'bar_set_get'; setX('baz'); assert 'baz_set_get' == getX()
-        """
+        '''
     }
 
     void testStaticImportPropertyWithAliases() {
-        def sources = [
-            "class Foo { static x = 'foo'" + " }",
-            "class Foo { static x = 'foo'" + "; static getX() { x + '_get' } }",
-            "class Foo { static x = 'foo'" + ";                               static void setX(newx) { x = newx + '_set' } }",
-            "class Foo { static x = 'foo'" + "; static getX() { x + '_get' }; static void setX(newx) { x = newx + '_set' } }"
-        ]
-        def imports = [
-            "import static Foo.x as z",
-            "import static Foo.getX as getZ; import static Foo.setX as setZ"
-        ]
-        def results = [
-            "assert z == 'foo';     z = 'bar'; assert getZ() == 'bar';         setZ('baz'); assert 'baz'         == z",
-            "assert z == 'foo_get'; z = 'bar'; assert getZ() == 'bar_get';     setZ('baz'); assert 'baz_get'     == z",
-            "assert z == 'foo';     z = 'bar'; assert getZ() == 'bar_set';     setZ('baz'); assert 'baz_set'     == z",
-            "assert z == 'foo_get'; z = 'bar'; assert getZ() == 'bar_set_get'; setZ('baz'); assert 'baz_set_get' == z"
-        ]
-        [0..<sources.size(), 0..<imports.size()].combinations().each { i, j ->
-            assertScript sources[i] + "\n" + imports[j] + "\n" + results[i]
+        for (imports in ['import static Foo.getX as getZ; import static Foo.setX as setZ', 'import static Foo.x as z']) {
+            assertScript """$imports
+                class Foo {
+                    static x = 'foo'
+                }
+                assert z == 'foo'
+                z = 'bar'
+                assert getZ() == 'bar'
+                setZ('baz')
+                assert z == 'baz'
+            """
+            assertScript """$imports
+                class Foo {
+                    static x = 'foo'
+                    static getX() { x + '_get' }
+                }
+                assert z == 'foo_get'
+                z = 'bar'
+                assert getZ() == 'bar_get'
+                setZ('baz')
+                assert z == 'baz_get'
+            """
+            assertScript """$imports
+                class Foo {
+                    static x = 'foo'
+                    static void setX(newx) { x = newx + '_set' }
+                }
+                assert z == 'foo'
+                z = 'bar'
+                assert getZ() == 'bar_set'
+                setZ('baz')
+                assert z == 'baz_set'
+            """
+            assertScript """$imports
+                class Foo {
+                    static x = 'foo'
+                    static getX() { x + '_get' }
+                    static void setX(newx) { x = newx + '_set' }
+                }
+                assert z == 'foo_get'
+                z = 'bar'
+                assert getZ() == 'bar_set_get'
+                setZ('baz')
+                assert z == 'baz_set_get'
+            """
         }
     }
 
+    // GROOVY-8389
+    void testStaticImportMethodVsLocalMethod() {
+        assertScript '''
+            import static Foo.bar
+            class Foo {
+                static bar = 'foo'
+            }
+            def bar() {
+                'bar'
+            }
+            @groovy.transform.CompileStatic
+            def test() {
+                bar()
+            }
+            assert test() == 'bar'
+        '''
+
+        assertScript '''
+            import static Foo.bar
+            class Foo {
+                static bar = 'foo'
+            }
+            static bar() {
+                'bar'
+            }
+            @groovy.transform.CompileStatic
+            def test() {
+                bar()
+            }
+            assert test() == 'bar'
+        '''
+
+        assertScript '''
+            import static Foo.baz
+            import static Foo.bar
+            class Foo {
+                static bar() { 'foobar' }
+                static baz() { 'foobaz' }
+            }
+            def bar() {
+                'bar'
+            }
+            @groovy.transform.CompileStatic
+            def test() {
+                "${bar()}${baz()}"
+            }
+            assert test() == 'barfoobaz'
+        '''
+
+        assertScript '''
+            import static Foo.baz
+            import static Foo.bar
+            class Foo {
+                static bar() { 'foobar' }
+                static baz() { 'foobaz' }
+            }
+            static bar() {
+                'bar'
+            }
+            @groovy.transform.CompileStatic
+            def test() {
+                "${bar()}${baz()}"
+            }
+            assert test() == 'barfoobaz'
+        '''
+    }
+
     void testConstructorArgsAliasing() {
         // not recommended style to use statics in constructors but supported
-        assertScript """
-        class Foo {
-            static x
-        }
-        import static Foo.x as z
-        new Foo(z:'hi')
-        assert z == 'hi'
-        """
+        assertScript '''
+            class Foo {
+                static x
+            }
+            import static Foo.x as z
+            new Foo(z:'hi')
+            assert z == 'hi'
+        '''
     }
 
     void testMethodCallWithThisTargetIsNotResolvedToStaticallyImportedMethod() {
@@ -257,17 +412,33 @@ class StaticImportTest extends CompilableTestSupport {
             fail()
         } catch (MissingMethodException expected) {}
     }
-    
-    void testStaticImportOfAClosureField() { //GROOVY-3945
-        assert cl() == 'StaticImportTarget#static closure called'
+
+    // GROOVY-3945, GROOVY-10329
+    void testStaticImportOfClosureProperty() {
+        for (imports in ['import static groovy.StaticImportTarget.cl', 'import static groovy.StaticImportTarget.*']) {
+            assertScript """$imports
+                String result = cl()
+                assert result == 'StaticImportTarget#static closure called'
+            """
+        }
     }
 
-    void testStaticPropertyImportedImplementedAsGetter() { //GROOVY-4145
-        assert foo4145 == 3
+    // GROOVY-4145
+    void testStaticPropertyImportedImplementedAsGetter() {
+        assertScript '''
+            import static Groovy4145.foo4145
+            class Groovy4145 {
+                static getFoo4145() {
+                    return 3
+                }
+            }
+            assert foo4145 == 3
+        '''
     }
 
-    void testMethodCallExpressionInStaticContextWithInstanceVariableShouldFail() { //GROOVY-4228
-        shouldNotCompile '''
+    // GROOVY-4228
+    void testMethodCallExpressionInStaticContextWithInstanceVariableShouldFail() {
+        def err = shouldFail '''
             class B {
                 def c = new Object()
                 static main(args) {
@@ -275,6 +446,57 @@ class StaticImportTest extends CompilableTestSupport {
                 }
             }
         '''
+        assert err =~ /Apparent variable 'c' was found in a static scope but doesn't refer to a local variable, static field or class/
+    }
+
+    // GROOVY-10396
+    void testStaticImportVersusThisOrSuperMethod1() {
+        assertScript '''
+            import static groovy.Extension10396.*
+
+            static void test() {
+                println 'x'
+            }
+            strings.clear()
+            test()
+
+            assert 'x' in strings
+        '''
+    }
+
+    // GROOVY-10396
+    void testStaticImportVersusThisOrSuperMethod2() {
+        assertScript '''
+            import static groovy.Extension10396.*
+
+            def obj = new Object() { // outer class extends Script
+                String toString() {
+                    println 'AIC::x'
+                    super.toString()
+                }
+            }
+            strings.clear()
+            obj.toString()
+
+            assert !('x' in strings)
+        '''
+    }
+
+    // GROOVY-10396
+    void testStaticImportVersusThisOrSuperMethod3() {
+        assertScript '''
+            import static groovy.Extension10396.*
+
+            static void println(String s) { // static overload
+            }
+            static void test() {
+                println 'x'
+            }
+            strings.clear()
+            test()
+
+            assert !('x' in strings)
+        '''
     }
 
     void testStaticStarImportOfStaticInnerClass() {
@@ -301,15 +523,6 @@ class StaticImportTest extends CompilableTestSupport {
         Bar4964.run()
     }
 
-    // TODO GROOVY-4287: reinstate next two tests
-//    void testStaticStarImportOfStaticInnerClassExternalClass() {
-//        assert Inner3.class.name == 'Outer3$Inner3'
-//    }
-//
-//    void testStaticImportOfStaticInnerClassExternalClass() {
-//        assert Inner4.class.name == 'Outer4$Inner4'
-//    }
-
     void testMapIndexInLeftExpressionOfEquals() {
         holder = 'foo'
         def map = [:]
@@ -337,6 +550,8 @@ class StaticImportTest extends CompilableTestSupport {
     }
 }
 
+//------------------------------------------------------------------------------
+
 class API {
     static noArrayMethod(String s, int value) {
         "noArrayMethod(${s}, ${value})"
@@ -348,13 +563,13 @@ class API {
 }
 
 class StaticImportParent {
-  static pfield = 42
-  static pmethod() { 'hello from parent' }
+    static pfield = 42
+    static pmethod() { 'hello from parent' }
 }
 
 class StaticImportChild extends StaticImportParent {
-  static cfield = 21
-  static cmethod() { 'hello from child' }
+    static cfield = 21
+    static cmethod() { 'hello from child' }
 }
 
 class Outer1 {
@@ -369,7 +584,6 @@ class Foo4964 {
     static doIt() { [k: 'foo'] }
 }
 
-import static Foo4964.*
 class Bar4964 {
     static doIt() { [k: 'bar'] }
 
@@ -405,3 +619,10 @@ class HolderWrapper {
         holder[name] = value
     }
 }
+
+class Extension10396 {
+    static final List<String> strings = []
+    static void println(String s) {
+        strings << s
+    }
+}
diff --git a/src/test/groovy/bugs/Groovy8389Bug.groovy b/src/test/groovy/bugs/Groovy8389Bug.groovy
deleted file mode 100644
index bf56fbd..0000000
--- a/src/test/groovy/bugs/Groovy8389Bug.groovy
+++ /dev/null
@@ -1,109 +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
-
-class Groovy8389Bug extends GroovyTestCase {
-    void testLocalMethodInvoked() {
-        assertScript '''
-            import static A.bar
-            
-            class A {
-              static bar = "A"
-            }
-            
-            def bar() {
-              "bar"
-            }
-            
-            @groovy.transform.CompileStatic
-            def usage() {
-              bar()
-            }
-            
-            assert "bar" == usage() 
-        '''
-    }
-
-    void testLocalMethodInvoked2() {
-        assertScript '''
-            import static A.bar
-            
-            class A {
-              static bar = "A"
-            }
-            
-            static bar() {
-              "bar"
-            }
-            
-            @groovy.transform.CompileStatic
-            def usage() {
-              bar()
-            }
-            
-            assert "bar" == usage() 
-        '''
-    }
-
-    void testLocalMethodInvoked3() {
-        assertScript '''
-            import static A.baz
-            import static A.bar
-            
-            class A {
-              static bar() { "Abar" }
-              static baz() { "Abaz" }
-            }
-            
-            def bar() {
-              "bar"
-            }
-            
-            @groovy.transform.CompileStatic
-            def usage() {
-              "${bar()}${baz()}"
-            }
-            
-            assert usage() == 'barAbaz'
-        '''
-    }
-
-    void testLocalMethodInvoked4() {
-        assertScript '''
-            import static A.baz
-            import static A.bar
-            
-            class A {
-              static bar() { "Abar" }
-              static baz() { "Abaz" }
-            }
-            
-            static bar() {
-              "bar"
-            }
-            
-            @groovy.transform.CompileStatic
-            def usage() {
-              "${bar()}${baz()}"
-            }
-            
-            assert usage() == 'barAbaz'
-        '''
-    }
-}