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/05/07 20:34:15 UTC
[groovy] branch master updated: GROOVY-10075: STC: always re-check
extension method receiver/argument(s)
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 308287c GROOVY-10075: STC: always re-check extension method receiver/argument(s)
308287c is described below
commit 308287cbc3ef8f0d1a32c0ebec8c63e92e838ada
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Fri May 7 15:22:53 2021 -0500
GROOVY-10075: STC: always re-check extension method receiver/argument(s)
---
.../transform/stc/StaticTypeCheckingSupport.java | 26 +++----
.../transform/stc/StaticTypeCheckingVisitor.java | 7 +-
.../stc/DefaultGroovyMethodsSTCTest.groovy | 80 +++++++++++++++-------
.../groovy/runtime/m12n/TestStringExtension.java | 12 +++-
4 files changed, 84 insertions(+), 41 deletions(-)
diff --git a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
index fa24e5a..de4b243 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
@@ -1399,25 +1399,21 @@ public abstract class StaticTypeCheckingSupport {
}
protected static boolean typeCheckMethodsWithGenerics(final ClassNode receiver, final ClassNode[] argumentTypes, final MethodNode candidateMethod) {
- boolean isExtensionMethod = candidateMethod instanceof ExtensionMethodNode;
- if (!isExtensionMethod
- && receiver.isUsingGenerics()
+ if (candidateMethod instanceof ExtensionMethodNode) {
+ ClassNode[] realTypes = new ClassNode[argumentTypes.length + 1];
+ realTypes[0] = receiver; // object expression is implicit argument
+ System.arraycopy(argumentTypes, 0, realTypes, 1, argumentTypes.length);
+ MethodNode realMethod = ((ExtensionMethodNode) candidateMethod).getExtensionMethodNode();
+ return typeCheckMethodsWithGenerics(realMethod.getDeclaringClass(), realTypes, realMethod, true);
+ }
+
+ if (receiver.isUsingGenerics()
&& receiver.equals(CLASS_Type)
&& !candidateMethod.getDeclaringClass().equals(CLASS_Type)) {
return typeCheckMethodsWithGenerics(receiver.getGenericsTypes()[0].getType(), argumentTypes, candidateMethod);
}
- // both candidate method and receiver have generic information so a check is possible
- GenericsType[] genericsTypes = candidateMethod.getGenericsTypes();
- boolean methodUsesGenerics = (genericsTypes != null && genericsTypes.length > 0);
- if (isExtensionMethod && methodUsesGenerics) {
- ClassNode[] dgmArgs = new ClassNode[argumentTypes.length + 1];
- dgmArgs[0] = receiver;
- System.arraycopy(argumentTypes, 0, dgmArgs, 1, argumentTypes.length);
- MethodNode extensionMethodNode = ((ExtensionMethodNode) candidateMethod).getExtensionMethodNode();
- return typeCheckMethodsWithGenerics(extensionMethodNode.getDeclaringClass(), dgmArgs, extensionMethodNode, true);
- } else {
- return typeCheckMethodsWithGenerics(receiver, argumentTypes, candidateMethod, false);
- }
+
+ return typeCheckMethodsWithGenerics(receiver, argumentTypes, candidateMethod, false);
}
private static boolean typeCheckMethodsWithGenerics(final ClassNode receiver, final ClassNode[] argumentTypes, final MethodNode candidateMethod, final boolean isExtensionMethod) {
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 67e0093..171b963 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -1611,6 +1611,11 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
for (MethodNode method : findDGMMethodsByNameAndArguments(getSourceUnit().getClassLoader(), dgmReceiver, "is" + capName, ClassNode.EMPTY_ARRAY)) {
if (Boolean_TYPE.equals(getWrapper(method.getReturnType()))) methods.add(method);
}
+ if (isUsingGenericsOrIsArrayUsingGenerics(dgmReceiver)) {
+ methods.removeIf(method -> // GROOVY-10075: "List<Integer>" vs "List<String>"
+ !typeCheckMethodsWithGenerics(dgmReceiver, ClassNode.EMPTY_ARRAY, method)
+ );
+ }
if (!methods.isEmpty()) {
List<MethodNode> bestMethods = chooseBestMethod(dgmReceiver, methods, ClassNode.EMPTY_ARRAY);
if (bestMethods.size() == 1) {
@@ -5357,7 +5362,7 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
// connect E:T from source to E:Type from target
for (GenericsType placeholder : aNode.getGenericsTypes()) {
for (Map.Entry<GenericsTypeName, GenericsType> e : source.entrySet()) {
- if (e.getValue().getName().equals(placeholder.getName())) {
+ if (e.getValue() == placeholder) {
Optional.ofNullable(target.get(e.getKey()))
// skip "f(g())" for "f(T<String>)" and "<U extends Number> U g()"
.filter(gt -> isAssignableTo(gt.getType(), placeholder.getType()))
diff --git a/src/test/groovy/transform/stc/DefaultGroovyMethodsSTCTest.groovy b/src/test/groovy/transform/stc/DefaultGroovyMethodsSTCTest.groovy
index cf4c8f6..6192bba 100644
--- a/src/test/groovy/transform/stc/DefaultGroovyMethodsSTCTest.groovy
+++ b/src/test/groovy/transform/stc/DefaultGroovyMethodsSTCTest.groovy
@@ -24,37 +24,37 @@ package groovy.transform.stc
class DefaultGroovyMethodsSTCTest extends StaticTypeCheckingTestCase {
void testEach() {
- assertScript """
+ assertScript '''
['a','b'].each { // DGM#each(Object, Closure)
println it // DGM#println(Object,Object)
}
- """
+ '''
- assertScript """
+ assertScript '''
['a','b'].eachWithIndex { it, i ->// DGM#eachWithIndex(Object, Closure)
println it // DGM#println(Object,Object)
}
- """
+ '''
}
void testStringToInteger() {
- assertScript """
- String name = "123"
- name.toInteger() // toInteger() is defined by DGM
- """
+ assertScript '''
+ String name = "123"
+ name.toInteger() // toInteger() is defined by DGM
+ '''
}
void testVariousAssignmentsThenToInteger() {
- assertScript """
- class A {
- void foo() {}
- }
- def name = new A()
- name.foo()
- name = 1
- name = '123'
- name.toInteger() // toInteger() is defined by DGM
- """
+ assertScript '''
+ class A {
+ void foo() {}
+ }
+ def name = new A()
+ name.foo()
+ name = 1
+ name = '123'
+ name.toInteger() // toInteger() is defined by DGM
+ '''
}
void testMethodsOnPrimitiveTypes() {
@@ -76,14 +76,48 @@ class DefaultGroovyMethodsSTCTest extends StaticTypeCheckingTestCase {
}
// GROOVY-5568
- void testDGMMethodAsProperty() {
+ void testPropertySemantics1() {
assertScript '''
- String foo(InputStream input) {
- input.text
+ String test(InputStream input) {
+ input.text // IOGroovyMethods#getText(InputStream)
}
- def text = new ByteArrayInputStream('foo'.getBytes())
- assert foo(text) == 'foo'
+ assert test(new ByteArrayInputStream('foo'.bytes)) == 'foo'
'''
+
+ assertScript '''
+ def chars = new StringBuilder('foo').chars // StringGroovyMethods#getChars(CharSequence)
+ assert chars == new char[] {'f','o','o'}
+ '''
+
+ assertScript '''
+ def a = Character.valueOf((char) 'a')
+ assert a.letter // DefaultGroovyMethods#isLetter(Character)
+ '''
+ }
+
+ // GROOVY-10075
+ void testPropertySemantics2() {
+ // see org.codehaus.groovy.runtime.m12n.TestStringExtension
+
+ assertScript '''
+ List<String> strings = ['x','y','z']
+ assert strings.getSequence() == 'x'
+ assert strings.getString() == 'x'
+ //assert strings.sequence == 'x'
+ //assert strings.string == 'x'
+ '''
+
+ shouldFailWithMessages '''
+ List<Number> numbers = [1, 2, 3]
+ numbers.getSequence()
+ numbers.getString()
+ numbers.sequence
+ numbers.string
+ ''',
+ 'Cannot call <CS extends java.lang.CharSequence> java.util.ArrayList#getSequence() with arguments []',
+ 'Cannot call java.util.ArrayList#getString() with arguments []',
+ 'No such property: sequence for class: java.util.ArrayList',
+ 'No such property: string for class: java.util.ArrayList'
}
// GROOVY-5584
diff --git a/src/test/org/codehaus/groovy/runtime/m12n/TestStringExtension.java b/src/test/org/codehaus/groovy/runtime/m12n/TestStringExtension.java
index fdd5e9f..fbbe8c2 100644
--- a/src/test/org/codehaus/groovy/runtime/m12n/TestStringExtension.java
+++ b/src/test/org/codehaus/groovy/runtime/m12n/TestStringExtension.java
@@ -19,8 +19,16 @@
package org.codehaus.groovy.runtime.m12n;
public class TestStringExtension {
+
public static String reverseToUpperCase(String self) {
- StringBuilder sb = new StringBuilder(self.toUpperCase());
- return sb.reverse().toString();
+ return new StringBuilder(self.toUpperCase()).reverse().toString();
+ }
+
+ public static String getString(java.util.List<String> self) {
+ return self.get(0);
+ }
+
+ public static <CS extends CharSequence> CharSequence getSequence(java.util.List<CS> self) {
+ return self.get(0);
}
}