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 17:15:02 UTC
[groovy] 03/03: GROOVY-10010: check GString element vs String collection for method call
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 2c034e74fcd87453429eb7555c8b18f76c6ca660
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Mon Apr 5 14:13:34 2021 -0500
GROOVY-10010: check GString element vs String collection for method call
Conflicts:
src/main/java/org/codehaus/groovy/ast/GenericsType.java
src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
---
.../java/org/codehaus/groovy/ast/GenericsType.java | 2 +-
.../transform/stc/StaticTypeCheckingVisitor.java | 18 +++--
.../groovy/transform/stc/GenericsSTCTest.groovy | 86 +++++++++++++++-------
3 files changed, 70 insertions(+), 36 deletions(-)
diff --git a/src/main/java/org/codehaus/groovy/ast/GenericsType.java b/src/main/java/org/codehaus/groovy/ast/GenericsType.java
index 1853a10..6f40ec0 100644
--- a/src/main/java/org/codehaus/groovy/ast/GenericsType.java
+++ b/src/main/java/org/codehaus/groovy/ast/GenericsType.java
@@ -464,7 +464,7 @@ public class GenericsType extends ASTNode {
if (!match) break;
}
}
- return match;
+ continue; // GROOVY-10010
} else if (classNodePlaceholders.containsKey(name)) {
redirectBoundType = classNodePlaceholders.get(name);
}
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 edcc351..c310bf2 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -5434,16 +5434,18 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
protected boolean typeCheckMethodsWithGenericsOrFail(ClassNode receiver, ClassNode[] arguments, MethodNode candidateMethod, Expression location) {
if (!typeCheckMethodsWithGenerics(receiver, arguments, candidateMethod)) {
- Map<GenericsTypeName, GenericsType> classGTs = GenericsUtils.extractPlaceholders(receiver);
- ClassNode[] ptypes = new ClassNode[candidateMethod.getParameters().length];
- final Parameter[] parameters = candidateMethod.getParameters();
- for (int i = 0; i < parameters.length; i++) {
- final Parameter parameter = parameters[i];
- ClassNode type = parameter.getType();
- ptypes[i] = fullyResolveType(type, classGTs);
+ Map<GenericsTypeName, GenericsType> spec = GenericsUtils.extractPlaceholders(receiver);
+ Parameter[] parameters = candidateMethod.getParameters();
+ ClassNode[] paramTypes = new ClassNode[parameters.length];
+ for (int i = 0, n = parameters.length; i < n; i += 1) {
+ paramTypes[i] = fullyResolveType(parameters[i].getType(), spec);
+ // GROOVY-10010: check for List<String> parameter and ["foo","$bar"] argument
+ if (i < arguments.length && hasGStringStringError(paramTypes[i], arguments[i], location)) {
+ return false;
+ }
}
addStaticTypeError("Cannot call " + toMethodGenericTypesString(candidateMethod) + receiver.toString(false) + "#" +
- toMethodParametersString(candidateMethod.getName(), ptypes) +
+ toMethodParametersString(candidateMethod.getName(), paramTypes) +
" with arguments " + formatArgumentList(arguments), location);
return false;
}
diff --git a/src/test/groovy/transform/stc/GenericsSTCTest.groovy b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
index 6ac3534..cfdd1c3 100644
--- a/src/test/groovy/transform/stc/GenericsSTCTest.groovy
+++ b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
@@ -26,24 +26,31 @@ import org.codehaus.groovy.tools.javac.JavaAwareCompilationUnit
*/
class GenericsSTCTest extends StaticTypeCheckingTestCase {
- void testDeclaration() {
+ void testDeclaration1() {
assertScript '''
List test = new LinkedList<String>()
'''
}
- void testDeclaration5() {
+ void testDeclaration2() {
assertScript '''
Map<String,Integer> obj = new HashMap<String,Integer>()
'''
}
- void testDeclaration6() {
+ void testDeclaration3() {
shouldFailWithMessages '''
Map<String,String> obj = new HashMap<String,Integer>()
''', 'Incompatible generic argument types. Cannot assign java.util.HashMap <String, Integer> to: java.util.Map <String, String>'
}
+ // GROOVY-10010: check beyond first wildcard
+ void testDeclaration4() {
+ shouldFailWithMessages '''
+ Map<? extends CharSequence,String> obj = new HashMap<String,Integer>()
+ ''', 'Incompatible generic argument types. Cannot assign java.util.HashMap <String, Integer> to: java.util.Map <? extends java.lang.CharSequence, String>'
+ }
+
void testAddOnList() {
shouldFailWithMessages '''
List<String> list = []
@@ -664,34 +671,59 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
'''
}
- // GROOVY-5559
+ // GROOVY-5559, GROOVY-10010
void testGStringInListShouldNotBeConsideredAsAString() {
- assertScript '''import org.codehaus.groovy.ast.tools.WideningCategories.LowestUpperBoundClassNode as LUB
- def bar = 1
- @ASTTest(phase=INSTRUCTION_SELECTION, value={
- assert node.getNodeMetaData(INFERRED_TYPE) == LIST_TYPE
- assert node.getNodeMetaData(INFERRED_TYPE).genericsTypes[0].type instanceof LUB
- })
- def list = ["foo", "$bar"]
+ String base = '''import org.codehaus.groovy.ast.tools.WideningCategories.LowestUpperBoundClassNode as LUB
+ def bar = 1
'''
- shouldFailWithMessages '''import org.codehaus.groovy.ast.tools.WideningCategories.LowestUpperBoundClassNode as LUB
- def bar = 1
- @ASTTest(phase=INSTRUCTION_SELECTION, value={
- assert node.getNodeMetaData(INFERRED_TYPE) == LIST_TYPE
- assert node.getNodeMetaData(INFERRED_TYPE).genericsTypes[0].type instanceof LUB
- })
- List<String> list = ["foo", "$bar"]
- ''', 'You are trying to use a GString'
+ assertScript base + '''
+ @ASTTest(phase=INSTRUCTION_SELECTION, value={
+ assert node.getNodeMetaData(INFERRED_TYPE) == LIST_TYPE
+ assert node.getNodeMetaData(INFERRED_TYPE).genericsTypes[0].type instanceof LUB
+ })
+ def list = ["foo", "$bar"]
+ '''
- shouldFailWithMessages '''
- def bar = 1
- @ASTTest(phase=INSTRUCTION_SELECTION, value={
- assert node.getNodeMetaData(INFERRED_TYPE) == LIST_TYPE
- assert node.getNodeMetaData(INFERRED_TYPE).genericsTypes[0].type == GSTRING_TYPE
- })
- List<String> list = ["$bar"] // single element means no LUB
- ''', 'You are trying to use a GString'
+ shouldFailWithMessages base + '''
+ @ASTTest(phase=INSTRUCTION_SELECTION, value={
+ assert node.getNodeMetaData(INFERRED_TYPE) == LIST_TYPE
+ assert node.getNodeMetaData(INFERRED_TYPE).genericsTypes[0].type instanceof LUB
+ })
+ List<String> list = ["foo", "$bar"]
+ ''', 'You are trying to use a GString in place of a String'
+
+ shouldFailWithMessages base + '''
+ @ASTTest(phase=INSTRUCTION_SELECTION, value={
+ assert node.getNodeMetaData(INFERRED_TYPE) == LIST_TYPE
+ assert node.getNodeMetaData(INFERRED_TYPE).genericsTypes[0].type == GSTRING_TYPE // single element means no LUB
+ })
+ List<String> list = ["$bar"]
+ ''', 'You are trying to use a GString in place of a String'
+
+ shouldFailWithMessages base + '''
+ void m(List<String> list) {}
+ m(["foo", "$bar"])
+ ''', 'You are trying to use a GString in place of a String'
+ }
+
+ // GROOVY-5559, GROOVY-10010
+ void testGStringInMapShouldNotBeConsideredAsAString() {
+ String base = 'def bar = 123'
+
+ shouldFailWithMessages base + '''
+ Map<String,String> map = [x:"foo", y:"$bar"]
+ ''', 'You are trying to use a GString in place of a String'
+
+ shouldFailWithMessages base + '''
+ void m(Map<?,String> map) {}
+ m([x:"foo", y:"$bar"])
+ ''', 'You are trying to use a GString in place of a String'
+
+ shouldFailWithMessages base + '''
+ void m(Map<?,String> map) {}
+ m(x:"foo", y:"$bar")
+ ''', 'You are trying to use a GString in place of a String'
}
// GROOVY-5559: related behaviour