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

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


The following commit(s) were added to refs/heads/master by this push:
     new 56fd1b0  GROOVY-8389: StaticImportVisitor: import static closure 
property/field
56fd1b0 is described below

commit 56fd1b05eaf9ee7d53ce743ded0afa4677d1810b
Author: Eric Milles <[email protected]>
AuthorDate: Sun Oct 24 17:30:42 2021 -0500

    GROOVY-8389: StaticImportVisitor: import static closure property/field
---
 .../groovy/control/StaticImportVisitor.java        | 100 +++++++----
 src/test/groovy/StaticImportTest.groovy            | 196 +++++++++++++++++----
 src/test/groovy/bugs/Groovy8389Bug.groovy          | 111 ------------
 3 files changed, 224 insertions(+), 183 deletions(-)

diff --git a/src/main/java/org/codehaus/groovy/control/StaticImportVisitor.java 
b/src/main/java/org/codehaus/groovy/control/StaticImportVisitor.java
index 5a31bc1..8ef0b70 100644
--- a/src/main/java/org/codehaus/groovy/control/StaticImportVisitor.java
+++ b/src/main/java/org/codehaus/groovy/control/StaticImportVisitor.java
@@ -204,6 +204,7 @@ public class StaticImportVisitor extends 
ClassCodeExpressionTransformer {
             if (left instanceof StaticMethodCallExpression) {
                 StaticMethodCallExpression smce = (StaticMethodCallExpression) 
left;
                 StaticMethodCallExpression result = new 
StaticMethodCallExpression(smce.getOwnerType(), smce.getMethod(), right);
+                result.copyNodeMetaData(smce);
                 setSourcePosition(result, be);
                 return result;
             }
@@ -428,59 +429,80 @@ public class StaticImportVisitor extends 
ClassCodeExpressionTransformer {
     }
 
     private Expression findStaticMethodImportFromModule(Expression method, 
Expression args) {
-        ModuleNode module = currentClass.getModule();
-        if (module == null || !(method instanceof ConstantExpression)) return 
null;
-        Map<String, ImportNode> importNodes = module.getStaticImports();
-        ConstantExpression ce = (ConstantExpression) method;
+        if (currentClass.getModule() == null) return null;
+        if (!(method instanceof ConstantExpression)) return null;
+        if (!(((ConstantExpression) method).getValue() instanceof String)) 
return null;
+
         Expression expression;
-        Object value = ce.getValue();
-        // skip non-Strings, e.g. Integer
-        if (!(value instanceof String)) return null;
-        final String name = (String) value;
+        String name = method.getText();
+        Map<String, ImportNode> staticImports = 
currentClass.getModule().getStaticImports();
         // look for one of these:
-        //   import static SomeClass.method [as otherName]
-        // when resolving methodCall() or getProp() or setProp()
-        if (importNodes.containsKey(name)) {
-            ImportNode importNode = importNodes.get(name);
+        //   import static MyClass.field [as alias]
+        //   import static MyClass.method [as alias]
+        //   import static MyClass.property [as alias]
+        // when resolving implicit-this call name(args)
+        if (staticImports.containsKey(name)) {
+            ImportNode importNode = staticImports.get(name);
             expression = findStaticMethod(importNode.getType(), 
importNode.getFieldName(), args);
-            if (expression != null) return expression;
-            expression = 
findStaticPropertyAccessorGivenArgs(importNode.getType(), 
getPropNameForAccessor(importNode.getFieldName()), args);
             if (expression != null) {
-                return newStaticMethodCallX(importNode.getType(), 
importNode.getFieldName(), args);
+                return expression;
+            }
+            if (!inClosure) {
+                expression = findStaticPropertyOrField(importNode.getType(), 
importNode.getFieldName());
+                if (expression != null) { // assume name refers to a callable 
static field or property
+                    MethodCallExpression call = new 
MethodCallExpression(expression, "call", args);
+                    call.setImplicitThis(false);
+                    return call;
+                }
             }
         }
         // look for one of these:
-        //   import static SomeClass.someProp [as otherName]
-        // when resolving getProp() or setProp()
-        if (isValidAccessorName(name)) {
-            String propName = getPropNameForAccessor(name);
-            if (importNodes.containsKey(propName)) {
-                ImportNode importNode = importNodes.get(propName);
-                ClassNode importClass = importNode.getType();
+        //   import static MyClass.property [as alias]
+        //   import static MyClass.isProperty [as alias]
+        //   import static MyClass.getProperty [as alias]
+        //   import static MyClass.setProperty [as alias]
+        // when resolving isName(), getName() or setName(args)
+        boolean accessor = isValidAccessorName(name);
+        if (accessor) {
+            ImportNode importNode = staticImports.get(name);
+            if (importNode != null) {
+                String propName = 
getPropNameForAccessor(importNode.getFieldName());
+                expression = 
findStaticPropertyAccessorGivenArgs(importNode.getType(), propName, args);
+                if (expression != null) { // expression may refer to getter or 
setter, so make new call
+                    return newStaticMethodCallX(importNode.getType(), 
importNode.getFieldName(), args);
+                }
+            }
+            importNode = staticImports.get(getPropNameForAccessor(name));
+            if (importNode != null) {
+                ClassNode importType = importNode.getType();
                 String importMember = importNode.getFieldName();
-                expression = findStaticMethod(importClass, prefix(name) + 
capitalize(importMember), args);
+                expression = findStaticMethod(importType, prefix(name) + 
capitalize(importMember), args);
                 if (expression != null) return expression;
-                expression = findStaticPropertyAccessorGivenArgs(importClass, 
importMember, args);
+                expression = findStaticPropertyAccessorGivenArgs(importType, 
importMember, args);
                 if (expression != null) {
-                    return newStaticMethodCallX(importClass, prefix(name) + 
capitalize(importMember), args);
+                    return newStaticMethodCallX(importType, prefix(name) + 
capitalize(importMember), args);
                 }
             }
         }
-        Map<String, ImportNode> starImports = module.getStaticStarImports();
-        ClassNode starImportType;
-        if (currentClass.isEnum() && 
starImports.containsKey(currentClass.getName())) {
-            ImportNode importNode = starImports.get(currentClass.getName());
-            starImportType = importNode == null ? null : importNode.getType();
-            expression = findStaticMethod(starImportType, name, args);
+
+        Map<String, ImportNode> staticStarImports = 
currentClass.getModule().getStaticStarImports();
+        if (currentClass.isEnum() && 
staticStarImports.containsKey(currentClass.getName())) {
+            ImportNode importNode = 
staticStarImports.get(currentClass.getName());
+            expression = findStaticMethod(importNode.getType(), name, args);
             return expression;
-        } else {
-            for (ImportNode importNode : starImports.values()) {
-                starImportType = importNode == null ? null : 
importNode.getType();
-                expression = findStaticMethod(starImportType, name, args);
-                if (expression != null) return expression;
-                expression = 
findStaticPropertyAccessorGivenArgs(starImportType, 
getPropNameForAccessor(name), args);
-                if (expression != null) {
-                    return newStaticMethodCallX(starImportType, name, args);
+        }
+        // look for one of these:
+        //   import static MyClass.*
+        // when resolving name(args), getName(), etc.
+        for (ImportNode importNode : staticStarImports.values()) {
+            ClassNode importType = importNode.getType();
+            expression = findStaticMethod(importType, name, args);
+            if (expression != null) return expression;
+            if (accessor) {
+                String propName = getPropNameForAccessor(name);
+                expression = findStaticPropertyAccessorGivenArgs(importType, 
propName, args);
+                if (expression != null) { // expression may refer to getter or 
setter, so ...
+                    return newStaticMethodCallX(importType, name, args);
                 }
             }
         }
diff --git a/src/test/groovy/StaticImportTest.groovy 
b/src/test/groovy/StaticImportTest.groovy
index 1ccfca2..445f86d 100644
--- a/src/test/groovy/StaticImportTest.groovy
+++ b/src/test/groovy/StaticImportTest.groovy
@@ -142,43 +142,85 @@ final class StaticImportTest extends 
groovy.test.GroovyTestCase {
     }
 
     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.*', 'import static Foo.getX; 
import static Foo.setX']) {
+            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.*', 'import static Foo.x', 'import 
static Foo.isX; import static Foo.setX']) {
+            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
+            """
         }
     }
 
@@ -259,6 +301,94 @@ final class StaticImportTest extends 
groovy.test.GroovyTestCase {
         assert err =~ /No such property: y for class/
     }
 
+    // GROOVY-8389
+    void testStaticImportPropertyWithClosure() {
+        assertScript '''
+            import static Foo.bar
+            import static Foo.baz
+            class Foo {
+                static Closure<String> bar = { -> 'property' }
+                static Closure<String> baz = { -> 'property' }
+            }
+            String bar() {
+                'method'
+            }
+            @groovy.transform.CompileStatic
+            def test() {
+                bar() + ':' + baz()
+            }
+            String result = test()
+            assert result == 'method:property'
+        '''
+    }
+
+    // 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 '''
diff --git a/src/test/groovy/bugs/Groovy8389Bug.groovy 
b/src/test/groovy/bugs/Groovy8389Bug.groovy
deleted file mode 100644
index 749234d..0000000
--- a/src/test/groovy/bugs/Groovy8389Bug.groovy
+++ /dev/null
@@ -1,111 +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
-
-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'
-        '''
-    }
-}

Reply via email to