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 2022/03/01 20:02:35 UTC
[groovy] 02/04: 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 GROOVY_2_5_X
in repository https://gitbox.apache.org/repos/asf/groovy.git
commit aeb81411e82a77426cfac957e157e1c45e604957
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)
Conflicts:
src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
---
.../transform/stc/StaticTypeCheckingSupport.java | 27 +++----
.../transform/stc/StaticTypeCheckingVisitor.java | 5 ++
.../stc/DefaultGroovyMethodsSTCTest.groovy | 84 +++++++++++++++-------
.../groovy/runtime/m12n/TestStringExtension.java | 12 +++-
4 files changed, 85 insertions(+), 43 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 d7b7f72..de5ada0 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
@@ -20,7 +20,6 @@
package org.codehaus.groovy.transform.stc;
import org.codehaus.groovy.GroovyBugError;
-import org.codehaus.groovy.ast.ClassHelper;
import org.codehaus.groovy.ast.ClassNode;
import org.codehaus.groovy.ast.GenericsType;
import org.codehaus.groovy.ast.GenericsType.GenericsTypeName;
@@ -1449,25 +1448,21 @@ public abstract class StaticTypeCheckingSupport {
}
protected static boolean typeCheckMethodsWithGenerics(ClassNode receiver, ClassNode[] arguments, MethodNode candidateMethod) {
- boolean isExtensionMethod = candidateMethod instanceof ExtensionMethodNode;
- if (!isExtensionMethod
- && receiver.isUsingGenerics()
+ if (candidateMethod instanceof ExtensionMethodNode) {
+ ClassNode[] realTypes = new ClassNode[arguments.length + 1];
+ realTypes[0] = receiver; // object expression is first argument
+ System.arraycopy(arguments, 0, realTypes, 1, arguments.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(), arguments, 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[arguments.length + 1];
- dgmArgs[0] = receiver;
- System.arraycopy(arguments, 0, dgmArgs, 1, arguments.length);
- MethodNode extensionMethodNode = ((ExtensionMethodNode) candidateMethod).getExtensionMethodNode();
- return typeCheckMethodsWithGenerics(extensionMethodNode.getDeclaringClass(), dgmArgs, extensionMethodNode, true);
- } else {
- return typeCheckMethodsWithGenerics(receiver, arguments, candidateMethod, false);
- }
+
+ return typeCheckMethodsWithGenerics(receiver, arguments, candidateMethod, false);
}
private static boolean typeCheckMethodsWithGenerics(ClassNode receiver, ClassNode[] arguments, MethodNode candidateMethod, 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 d66f72a..47e733e 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -1581,6 +1581,11 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
for (MethodNode m : findDGMMethodsByNameAndArguments(getSourceUnit().getClassLoader(), dgmReceiver, "is" + capName, ClassNode.EMPTY_ARRAY)) {
if (Boolean_TYPE.equals(getWrapper(m.getReturnType()))) methods.add(m);
}
+ if (isUsingGenericsOrIsArrayUsingGenerics(dgmReceiver)) { // GROOVY-10075: "List<Integer>" vs "List<String>"
+ for (Iterator<MethodNode> it = methods.iterator(); it.hasNext(); ) { MethodNode method = it.next();
+ if (!typeCheckMethodsWithGenerics(dgmReceiver, ClassNode.EMPTY_ARRAY, method)) it.remove();
+ }
+ }
if (!methods.isEmpty()) {
List<MethodNode> methodNodes = chooseBestMethod(dgmReceiver, methods, ClassNode.EMPTY_ARRAY);
if (methodNodes.size() == 1) {
diff --git a/src/test/groovy/transform/stc/DefaultGroovyMethodsSTCTest.groovy b/src/test/groovy/transform/stc/DefaultGroovyMethodsSTCTest.groovy
index 11caeb0..3e271b0 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() {
@@ -66,7 +66,7 @@ class DefaultGroovyMethodsSTCTest extends StaticTypeCheckingTestCase {
true.equals { it }
'''
}
-
+
void testShouldAcceptMethodFromDefaultDateMethods() {
assertScript '''
def s = new Date()
@@ -76,16 +76,50 @@ 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 == 'foo'.toCharArray()
+ '''
+
+ 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 = [(Number)1, 2, 3]
+ numbers.getSequence()
+ numbers.getString()
+ numbers.sequence
+ numbers.string
+ ''',
+ 'Cannot call <CS extends java.lang.CharSequence> java.util.List <java.lang.Number>#getSequence() with arguments []',
+ 'Cannot call java.util.List <java.lang.Number>#getString() with arguments []',
+ 'No such property: sequence for class: java.util.List <java.lang.Number>',
+ 'No such property: string for class: java.util.List <java.lang.Number>'
+ }
+
// GROOVY-5584
void testEachOnMap() {
assertScript '''import org.codehaus.groovy.transform.stc.ExtensionMethodNode
@@ -195,7 +229,7 @@ class DefaultGroovyMethodsSTCTest extends StaticTypeCheckingTestCase {
def results = [:]
Functions.values().eachWithIndex { val, idx -> results[idx] = val.name() }
results
- }
+ }
assert m() == ['A', 'B', 'C']
assert m2() == [0: 'A', 1: 'B', 2: 'C']
'''
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);
}
}