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/03/29 14:26:00 UTC

[groovy] 03/03: GROOVY-9967: makeGroovyObjectGetPropertySite: leverage property owner

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 42798a8bc60fa71d926ed2bf75e40f97ff9fcdf4
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Mon Mar 29 09:25:43 2021 -0500

    GROOVY-9967: makeGroovyObjectGetPropertySite: leverage property owner
    
    Conflicts:
    	src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesCallSiteWriter.java
    	src/test/groovy/transform/stc/TypeInferenceSTCTest.groovy
---
 .../classgen/asm/sc/StaticTypesCallSiteWriter.java | 14 ++---
 .../transform/stc/TypeInferenceSTCTest.groovy      | 52 +++++++++++++++-
 .../classgen/asm/sc/bugs/Groovy6276Bug.groovy      | 70 ++++++++++------------
 3 files changed, 87 insertions(+), 49 deletions(-)

diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesCallSiteWriter.java b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesCallSiteWriter.java
index 33329c6..da059f7 100644
--- a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesCallSiteWriter.java
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesCallSiteWriter.java
@@ -416,21 +416,17 @@ public class StaticTypesCallSiteWriter extends CallSiteWriter implements Opcodes
     }
 
     @Override
-    public void makeGroovyObjectGetPropertySite(final Expression receiver, final String methodName, final boolean safe, final boolean implicitThis) {
-        TypeChooser typeChooser = controller.getTypeChooser();
-        ClassNode classNode = controller.getClassNode();
-        ClassNode receiverType = typeChooser.resolveType(receiver, classNode);
-        if (receiver instanceof VariableExpression && ((VariableExpression) receiver).isThisExpression() && !controller.isInClosure()) {
-            receiverType = classNode;
+    public void makeGroovyObjectGetPropertySite(final Expression receiver, final String propertyName, final boolean safe, final boolean implicitThis) {
+        ClassNode receiverType = controller.getClassNode();
+        if (!AsmClassGenerator.isThisExpression(receiver) || controller.isInClosure()) {
+            receiverType = getPropertyOwnerType(receiver); // GROOVY-9967, et al.
         }
 
-        String propertyName = methodName;
         if (implicitThis) {
             if (controller.getInvocationWriter() instanceof StaticInvocationWriter) {
                 MethodCallExpression currentCall = ((StaticInvocationWriter) controller.getInvocationWriter()).getCurrentCall();
                 if (currentCall != null && currentCall.getNodeMetaData(StaticTypesMarker.IMPLICIT_RECEIVER) != null) {
-                    propertyName = currentCall.getNodeMetaData(StaticTypesMarker.IMPLICIT_RECEIVER);
-                    String[] props = propertyName.split("\\.");
+                    String[] props = currentCall.<String>getNodeMetaData(StaticTypesMarker.IMPLICIT_RECEIVER).split("\\.");
                     BytecodeExpression thisLoader = new BytecodeExpression() {
                         @Override
                         public void visit(final MethodVisitor mv) {
diff --git a/src/test/groovy/transform/stc/TypeInferenceSTCTest.groovy b/src/test/groovy/transform/stc/TypeInferenceSTCTest.groovy
index 2ae9b95..cabdcc0 100644
--- a/src/test/groovy/transform/stc/TypeInferenceSTCTest.groovy
+++ b/src/test/groovy/transform/stc/TypeInferenceSTCTest.groovy
@@ -252,7 +252,7 @@ class TypeInferenceSTCTest extends StaticTypeCheckingTestCase {
         '''
     }
 
-    void testInstanceOfInferenceWithField() {
+    void testInstanceOfInferenceWithProperty1() {
         assertScript '''
             class A {
                 int x
@@ -264,7 +264,7 @@ class TypeInferenceSTCTest extends StaticTypeCheckingTestCase {
         '''
     }
 
-    void testInstanceOfInferenceWithFieldAndAssignment() {
+    void testInstanceOfInferenceWithProperty2() {
         shouldFailWithMessages '''
             class A {
                 int x
@@ -276,7 +276,7 @@ class TypeInferenceSTCTest extends StaticTypeCheckingTestCase {
         ''', 'Cannot assign value of type java.lang.String to variable of type int'
     }
 
-    void testInstanceOfInferenceWithMissingField() {
+    void testInstanceOfInferenceWithMissingProperty() {
         shouldFailWithMessages '''
             class A {
                 int x
@@ -288,6 +288,52 @@ class TypeInferenceSTCTest extends StaticTypeCheckingTestCase {
         ''', 'No such property: y for class: A'
     }
 
+    // GROOVY-9967
+    void testInstanceOfInferenceWithSubclassProperty() {
+        assertScript '''
+            class A {
+                int i
+            }
+            class B extends A {
+                String s = 'foo'
+            }
+
+            String scenario1(x) {
+                (x instanceof String) ? x.toLowerCase() : 'bar'
+            }
+            String scenario2(B x) {
+                x.s
+            }
+            String scenario2a(B x) {
+                x.getS()
+            }
+            String scenario3(B x) {
+                (x instanceof B) ? x.s : 'bar'
+            }
+            String scenario3a(B x) {
+                (x instanceof B) ? x.getS() : 'bar'
+            }
+            String scenario4(A x) {
+                (x instanceof B) ? x.s : 'bar' // Access to A#s is forbidden
+            }
+            String scenario4a(A x) {
+                (x instanceof B) ? x.getS() : 'bar'
+            }
+
+            assert scenario1(null) == 'bar'
+            assert scenario1('Foo') == 'foo'
+            assert scenario2(new B()) == 'foo'
+            assert scenario2a(new B()) == 'foo'
+            assert scenario3(new B()) == 'foo'
+            assert scenario3a(new B()) == 'foo'
+
+            assert scenario4(new A()) == 'bar'
+            assert scenario4(new B()) == 'foo'
+            assert scenario4a(new A()) == 'bar'
+            assert scenario4a(new B()) == 'foo'
+        '''
+    }
+
     void testShouldNotFailWithWith() {
         assertScript '''
             class A {
diff --git a/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy6276Bug.groovy b/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy6276Bug.groovy
index 51fa3ce..171d006 100644
--- a/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy6276Bug.groovy
+++ b/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy6276Bug.groovy
@@ -16,56 +16,52 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-
-
-
-
-
-
 package org.codehaus.groovy.classgen.asm.sc.bugs
 
 import groovy.transform.stc.StaticTypeCheckingTestCase
 import org.codehaus.groovy.classgen.asm.sc.StaticCompilationTestSupport
 
-class Groovy6276Bug extends StaticTypeCheckingTestCase implements StaticCompilationTestSupport {
+final class Groovy6276Bug extends StaticTypeCheckingTestCase implements StaticCompilationTestSupport {
+
     void testOuterClassMethodCall() {
-        assertScript '''class Outer {
-    private int outerField = 1
+        assertScript '''
+            class Outer {
+                private int outerField = 1
 
-    private int outerMethod() { 2 }
-    int outerProperty = 3
-    class Inner {
-        void assertions() {
-            assert outerField == 1            // #1
-            assert outerMethod() == 2         // #2
-            assert outerProperty == 3         // #3
-            assert getOuterProperty() == 3    // #4
-        }
-    }
+                private int outerMethod() { 2 }
+                int outerProperty = 3
+                class Inner {
+                    void assertions() {
+                        assert outerField == 1            // #1
+                        assert outerMethod() == 2         // #2
+                        assert outerProperty == 3         // #3
+                        assert getOuterProperty() == 3    // #4
+                    }
+                }
 
-    void test() {
-        new Inner().assertions()
-    }
-}
+                void test() {
+                    new Inner().assertions()
+                }
+            }
 
-new Outer().test()
-    '''
+            new Outer().test()
+        '''
     }
 
     void testAccessPrivateMethodFromClosure() {
         assertScript '''
-    class Outer {
-        private int foo(int x) {
-            2*x
-        }
+            class Outer {
+                private int foo(int x) {
+                    2*x
+                }
 
-        public int bar() {
-            (Integer) [1,2,3].collect {
-                foo(it)
-            }.sum()
-        }
-    }
-    new Outer().bar()
-'''
+                int bar() {
+                    (Integer) [1,2,3].collect {
+                        foo(it)
+                    }.sum()
+                }
+            }
+            new Outer().bar()
+        '''
     }
 }