You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by su...@apache.org on 2020/06/13 09:47:38 UTC

[groovy] 06/06: GROOVY-9586: add trait to owner list when getting for trait helper class

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

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

commit 9a5aabc016f5ecb4b0d5691da6280c6efea3349b
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Thu Jun 11 14:06:26 2020 -0500

    GROOVY-9586: add trait to owner list when getting for trait helper class
    
    (cherry picked from commit 67d86419e0f6c3a9c8d18fe94b1326e999199586)
---
 .../transform/stc/StaticTypeCheckingVisitor.java   |  46 +++---
 .../groovy/classgen/asm/sc/bugs/Groovy7242.groovy  | 156 +++++++++++++++++++++
 .../classgen/asm/sc/bugs/Groovy7242Bug.groovy      | 101 -------------
 3 files changed, 184 insertions(+), 119 deletions(-)

diff --git a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
index a0b10eb..7945eaf 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -1449,7 +1449,7 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
         boolean foundGetterOrSetter = false;
         String capName = capitalize(propertyName);
         Set<ClassNode> handledNodes = new HashSet<>();
-        List<Receiver<String>> receivers = new LinkedList<>();
+        List<Receiver<String>> receivers = new ArrayList<>();
         addReceivers(receivers, makeOwnerList(objectExpression), pexp.isImplicitThis());
 
         for (Receiver<String> receiver : receivers) {
@@ -3204,9 +3204,8 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
     }
 
     private static void addDelegateReceiver(final List<Receiver<String>> receivers, final ClassNode delegate, final String path) {
-        receivers.add(new Receiver<>(delegate, path));
-        if (Traits.isTrait(delegate.getOuterClass())) {
-            receivers.add(new Receiver<>(delegate.getOuterClass(), path));
+        if (receivers.stream().map(Receiver::getType).noneMatch(delegate::equals)) {
+            receivers.add(new Receiver<>(delegate, path));
         }
     }
 
@@ -3335,9 +3334,9 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
                 //   - the actual receiver as found in the method call expression
                 //   - any of the potential receivers found in the instanceof temporary table
                 // in that order
-                List<Receiver<String>> receivers = new LinkedList<>();
-                List<Receiver<String>> owners = makeOwnerList(objectExpression);
-                addReceivers(receivers, owners, call.isImplicitThis());
+                List<Receiver<String>> receivers = new ArrayList<>();
+                addReceivers(receivers, makeOwnerList(objectExpression), call.isImplicitThis());
+
                 List<MethodNode> mn = null;
                 Receiver<String> chosenReceiver = null;
                 for (Receiver<String> currentReceiver : receivers) {
@@ -3644,19 +3643,23 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
      */
     protected List<Receiver<String>> makeOwnerList(final Expression objectExpression) {
         ClassNode receiver = getType(objectExpression);
-        List<Receiver<String>> owners = new LinkedList<>();
-        owners.add(Receiver.make(receiver));
+        List<Receiver<String>> owners = new ArrayList<>();
         if (isClassClassNodeWrappingConcreteType(receiver)) {
-            GenericsType clazzGT = receiver.getGenericsTypes()[0];
-            owners.add(0, Receiver.make(clazzGT.getType()));
-        }
-        if (receiver.isInterface()) {
-            owners.add(Receiver.make(OBJECT_TYPE));
+            ClassNode staticType = receiver.getGenericsTypes()[0].getType();
+            owners.add(Receiver.make(staticType)); // Type from Class<Type>
+            addTraitType(staticType, owners); // T in Class<T$Trait$Helper>
+            owners.add(Receiver.make(receiver)); // Class<Type>
+        } else {
+            owners.add(Receiver.make(receiver));
+            if (receiver.isInterface()) {
+                owners.add(Receiver.make(OBJECT_TYPE));
+            }
+            addSelfTypes(receiver, owners);
+            addTraitType(receiver, owners);
         }
-        addSelfTypes(receiver, owners);
         if (!typeCheckingContext.temporaryIfBranchTypeInformation.isEmpty()) {
             List<ClassNode> potentialReceiverType = getTemporaryTypesForExpression(objectExpression);
-            if (potentialReceiverType != null) {
+            if (potentialReceiverType != null && !potentialReceiverType.isEmpty()) {
                 for (ClassNode node : potentialReceiverType) {
                     owners.add(Receiver.make(node));
                 }
@@ -3680,12 +3683,19 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
     }
 
     private static void addSelfTypes(final ClassNode receiver, final List<Receiver<String>> owners) {
-        LinkedHashSet<ClassNode> selfTypes = new LinkedHashSet<>();
-        for (ClassNode selfType : Traits.collectSelfTypes(receiver, selfTypes)) {
+        for (ClassNode selfType : Traits.collectSelfTypes(receiver, new LinkedHashSet<>())) {
             owners.add(Receiver.make(selfType));
         }
     }
 
+    private static void addTraitType(final ClassNode receiver, final List<Receiver<String>> owners) {
+        if (Traits.isTrait(receiver.getOuterClass()) && receiver.getName().endsWith("$Helper")) {
+            ClassNode traitType = receiver.getOuterClass();
+            owners.add(Receiver.make(traitType));
+            addSelfTypes(traitType, owners);
+        }
+    }
+
     protected void checkForbiddenSpreadArgument(final ArgumentListExpression argumentList) {
         for (Expression arg : argumentList.getExpressions()) {
             if (arg instanceof SpreadExpression) {
diff --git a/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7242.groovy b/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7242.groovy
new file mode 100644
index 0000000..6884ea6
--- /dev/null
+++ b/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7242.groovy
@@ -0,0 +1,156 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.codehaus.groovy.classgen.asm.sc.bugs
+
+import groovy.transform.stc.StaticTypeCheckingTestCase
+import org.codehaus.groovy.classgen.asm.sc.StaticCompilationTestSupport
+
+final class Groovy7242 extends StaticTypeCheckingTestCase implements StaticCompilationTestSupport {
+
+    void testWriteTraitPropertyFromTraitClosure() {
+        assertScript '''
+            trait T {
+                void p() {
+                    [1].each { x = it }
+                }
+                int x
+            }
+
+            class C implements T {
+            }
+
+            def c = new C()
+            c.p()
+            assert c.x == 1
+        '''
+    }
+
+    void testCallTraitMethodFromTraitClosure() {
+        assertScript '''
+            trait T {
+                def f() {
+                    ['a'].collect { String s -> g(s) }
+                }
+
+                String g(String s) {
+                    s.toUpperCase()
+                }
+            }
+
+            class C implements T {
+            }
+
+            def c = new C()
+            assert c.f() == ['A']
+        '''
+    }
+
+    void testCallTraitMethodFromTraitClosure_ImplicitParameter() {
+        assertScript '''
+            trait T {
+                def f() {
+                    ['a'].collect { g(it) }
+                }
+
+                String g(String s) {
+                    s.toUpperCase()
+                }
+            }
+
+            class C implements T {
+            }
+
+            def c = new C()
+            assert c.f() == ['A']
+        '''
+    }
+
+    // GROOVY-7456
+    void testCallPrivateTraitMethodFromTraitClosure() {
+        assertScript '''
+            trait T {
+                def f() {
+                    ['a'].collect { String s -> g(s) }
+                }
+
+                private String g(String s) {
+                    s.toUpperCase()
+                }
+            }
+
+            class C implements T {
+            }
+
+            def c = new C()
+            assert c.f() == ['A']
+        '''
+    }
+
+    // GROOVY-9586
+    void testDelegateVsOwnerMethodFromTraitClosure1() {
+        assertScript '''
+            class C {
+                def m(@DelegatesTo(strategy=Closure.DELEGATE_ONLY, value=C) Closure<?> block) {
+                    block.setResolveStrategy(Closure.OWNER_ONLY)
+                    block.setDelegate(this)
+                    return block.call()
+                }
+                def x() { 'C' }
+            }
+
+            trait T {
+                def test() {
+                    new C().m { -> x() } // "x" must come from delegate
+                }
+                def x() { 'T' }
+            }
+
+            class U implements T {
+            }
+
+            assert new U().test() == 'C'
+        '''
+    }
+
+    // GROOVY-9586
+    void testDelegateVsOwnerMethodFromTraitClosure2() {
+        assertScript '''
+            class C {
+                def m(@DelegatesTo(strategy=Closure.OWNER_ONLY, type='Void') Closure<?> block) {
+                    block.setResolveStrategy(Closure.OWNER_ONLY)
+                    block.setDelegate(null)
+                    return block.call()
+                }
+                def x() { 'C' }
+            }
+
+            trait T {
+                def test() {
+                    new C().m { -> x() } // "x" must come from owner
+                }
+                def x() { 'T' }
+            }
+
+            class U implements T {
+            }
+
+            assert new U().test() == 'T'
+        '''
+    }
+}
diff --git a/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7242Bug.groovy b/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7242Bug.groovy
deleted file mode 100644
index 17e6d62..0000000
--- a/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7242Bug.groovy
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-
-
-
-
-
-
-
-
-package org.codehaus.groovy.classgen.asm.sc.bugs
-
-import groovy.transform.stc.StaticTypeCheckingTestCase
-import org.codehaus.groovy.classgen.asm.sc.StaticCompilationTestSupport
-
-class Groovy7242Bug extends StaticTypeCheckingTestCase implements StaticCompilationTestSupport {
-    void testCallMethodOfTraitInsideClosure() {
-        assertScript '''
-            trait MyTrait {
-                def f() {
-                    ['a'].collect {String it -> f2(it)}
-                }
-
-                def f2(String s) {
-                    s.toUpperCase()
-                }
-            }
-
-            class A implements MyTrait {}
-            def a = new A()
-            assert a.f() == ['A']
-        '''
-    }
-
-    void testCallMethodOfTraitInsideClosureAndClosureParamTypeInference() {
-        assertScript '''
-            trait MyTrait {
-                def f() {
-                    ['a'].collect {f2(it)}
-                }
-
-                def f2(String s) {
-                    s.toUpperCase()
-                }
-            }
-
-            class A implements MyTrait {}
-            def a = new A()
-            assert a.f() == ['A']
-        '''
-    }
-
-    void testAccessTraitPropertyFromClosureInTrait() {
-        assertScript '''
-            trait MyTrait {
-                int x
-                def f() {
-                    [1].each { x = it }
-                }
-            }
-            class A implements MyTrait {}
-            def a = new A()
-            a.f()
-            assert a.x == 1
-        '''
-    }
-
-    void testCallPrivateMethodOfTraitInsideClosure() {
-        assertScript '''
-            trait MyTrait {
-                def f() {
-                    ['a'].collect {String it -> f2(it)}
-                }
-
-                private f2(String s) {
-                    s.toUpperCase()
-                }
-            }
-
-            class A implements MyTrait {}
-            def a = new A()
-            assert a.f() == ['A']
-        '''
-    }
-}