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']
- '''
- }
-}