Skip to content

Commit 526ba6f

Browse files
committed
GROOVY-6603
1 parent e0a9ab0 commit 526ba6f

File tree

6 files changed

+104
-7
lines changed

6 files changed

+104
-7
lines changed

base-test/org.eclipse.jdt.groovy.core.tests.builder/src/org/eclipse/jdt/core/groovy/tests/search/ClosureInferencingTests.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -1394,7 +1394,7 @@ public void testClosureParamsAnnotation1() {
13941394
//@formatter:off
13951395
String contents =
13961396
"import groovy.transform.stc.*\n" +
1397-
"def match(@ClosureParams(value=SimpleType, options=['java.util.regex.Pattern']) Closure block) {\n" +
1397+
"def match(@ClosureParams(value=SimpleType, options='java.util.regex.Pattern') Closure block) {\n" +
13981398
" block(item)\n" +
13991399
"}\n" +
14001400
"\n" +
@@ -1426,7 +1426,7 @@ public void testClosureParamsAnnotation3() {
14261426
String contents =
14271427
"import groovy.transform.stc.*\n" +
14281428
"class C {\n" +
1429-
" C(String s, @ClosureParams(value=SimpleType, options='java.util.List<java.lang.Integer>') Closure c) {\n" +
1429+
" C(String s, @ClosureParams(value=FromString, options='java.util.List<java.lang.Integer>') Closure c) {\n" +
14301430
" }\n" +
14311431
"}\n" +
14321432
"new C('str', { list -> null })\n";
@@ -1440,7 +1440,7 @@ public void testClosureParamsAnnotation4() {
14401440
String contents =
14411441
"import groovy.transform.stc.*\n" +
14421442
"class C {\n" +
1443-
" static m(String s, @ClosureParams(value=SimpleType, options='java.util.List<java.lang.Integer>') Closure c) {\n" +
1443+
" static m(String s, @ClosureParams(value=FromString, options='java.util.List<java.lang.Integer>') Closure c) {\n" +
14441444
" }\n" +
14451445
" static test() {\n" +
14461446
" m('str', { list -> null })\n" +

base-test/org.eclipse.jdt.groovy.core.tests.compiler/src/org/eclipse/jdt/groovy/core/tests/xform/TypeCheckedTests.java

+61-1
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ public void testTypeChecked7() {
170170
"Main.groovy",
171171
"import groovy.transform.stc.*\n" +
172172
"class C {\n" +
173-
" C(String s, @ClosureParams(value=SimpleType, options='java.util.List') Closure<Integer> c) {\n" +
173+
" C(String s, @ClosureParams(value=FromString,options='java.util.List<java.lang.Integer>') Closure<Integer> c) {\n" +
174174
" }\n" +
175175
"}\n" +
176176
"@groovy.transform.TypeChecked\n" +
@@ -633,6 +633,66 @@ public void testTypeChecked6455() {
633633
runConformTest(sources);
634634
}
635635

636+
@Test
637+
public void testTypeChecked6603() {
638+
//@formatter:off
639+
String[] sources = {
640+
"Main.groovy",
641+
"import groovy.transform.stc.*\n" +
642+
"@groovy.transform.TypeChecked\n" +
643+
"void test(@ClosureParams(value=FromString,options='java.lang.Number') Closure<?> c) {\n" +
644+
" c('x')\n" +
645+
"}\n",
646+
};
647+
//@formatter:on
648+
649+
runNegativeTest(sources,
650+
"----------\n" +
651+
"1. ERROR in Main.groovy (at line 4)\n" +
652+
"\tc('x')\n" +
653+
"\t ^^^\n" +
654+
"Groovy:[Static type checking] - Cannot call closure that accepts [java.lang.Number] with [java.lang.String]\n" +
655+
"----------\n");
656+
}
657+
658+
@Test
659+
public void testTypeChecked6603a() {
660+
//@formatter:off
661+
String[] sources = {
662+
"Main.groovy",
663+
"import groovy.transform.stc.*\n" +
664+
"@groovy.transform.TypeChecked\n" +
665+
"void test(@ClosureParams(value=FromString,options='java.util.List<java.lang.Number>') Closure<?> c) {\n" +
666+
" c(['x'])\n" +
667+
"}\n",
668+
};
669+
//@formatter:on
670+
671+
runNegativeTest(sources,
672+
"----------\n" +
673+
"1. ERROR in Main.groovy (at line 4)\n" +
674+
"\tc(['x'])\n" +
675+
"\t ^^^^^\n" +
676+
"Groovy:[Static type checking] - Cannot call closure that accepts [java.util.List<java.lang.Number>] with [java.util.List<java.lang.String>]\n" +
677+
"----------\n");
678+
}
679+
680+
@Test
681+
public void testTypeChecked6603b() {
682+
//@formatter:off
683+
String[] sources = {
684+
"Main.groovy",
685+
"import groovy.transform.stc.*\n" +
686+
"@groovy.transform.TypeChecked\n" +
687+
"void test(@ClosureParams(value=FromString,options='java.util.Collection<java.lang.String>') Closure<?> c) {\n" +
688+
" c(Collections.singletonList('x'))\n" +
689+
"}\n",
690+
};
691+
//@formatter:on
692+
693+
runNegativeTest(sources, "");
694+
}
695+
636696
@Test
637697
public void testTypeChecked6731() {
638698
//@formatter:off

base/org.codehaus.groovy25/src/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java

+12
Original file line numberDiff line numberDiff line change
@@ -2696,6 +2696,18 @@ private void negativeOrPositiveUnary(Expression expression, String name) {
26962696
protected void visitConstructorOrMethod(MethodNode node, boolean isConstructor) {
26972697
typeCheckingContext.pushEnclosingMethod(node);
26982698
if (!isSkipMode(node) && !shouldSkipMethodNode(node)) {
2699+
// GRECLIPSE add -- GROOVY-6603
2700+
for (Parameter parameter : node.getParameters()) {
2701+
for (AnnotationNode annotation : parameter.getAnnotations()) {
2702+
if (annotation.getClassNode().equals(CLOSUREPARAMS_CLASSNODE)) {
2703+
List<ClassNode[]> signatures = getSignaturesFromHint(null, node, annotation.getMember("value"), annotation.getMember("options"));
2704+
if (signatures.size() == 1) {
2705+
parameter.putNodeMetaData(StaticTypesMarker.CLOSURE_ARGUMENTS, Arrays.stream(signatures.get(0)).map(t -> new Parameter(t,"")).toArray(Parameter[]::new));
2706+
}
2707+
}
2708+
}
2709+
}
2710+
// GRECLIPSE end
26992711
super.visitConstructorOrMethod(node, isConstructor);
27002712
// GRECLIPSE add
27012713
if (node.hasDefaultValue())

base/org.codehaus.groovy30/src/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java

+12
Original file line numberDiff line numberDiff line change
@@ -2454,6 +2454,18 @@ private void negativeOrPositiveUnary(final Expression expression, final String n
24542454
protected void visitConstructorOrMethod(final MethodNode node, final boolean isConstructor) {
24552455
typeCheckingContext.pushEnclosingMethod(node);
24562456
if (!isSkipMode(node) && !shouldSkipMethodNode(node)) {
2457+
// GRECLIPSE add -- GROOVY-6603
2458+
for (Parameter parameter : node.getParameters()) {
2459+
for (AnnotationNode annotation : parameter.getAnnotations()) {
2460+
if (annotation.getClassNode().equals(CLOSUREPARAMS_CLASSNODE)) {
2461+
List<ClassNode[]> signatures = getSignaturesFromHint(null, node, annotation.getMember("value"), annotation.getMember("options"));
2462+
if (signatures.size() == 1) {
2463+
parameter.putNodeMetaData(CLOSURE_ARGUMENTS, Arrays.stream(signatures.get(0)).map(t -> new Parameter(t,"")).toArray(Parameter[]::new));
2464+
}
2465+
}
2466+
}
2467+
}
2468+
// GRECLIPSE end
24572469
super.visitConstructorOrMethod(node, isConstructor);
24582470
// GRECLIPSE add
24592471
if (node.hasDefaultValue())

base/org.codehaus.groovy40/src/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java

+14-1
Original file line numberDiff line numberDiff line change
@@ -2595,6 +2595,19 @@ protected void startMethodInference(final MethodNode node, final ErrorCollector
25952595
@Override
25962596
protected void visitConstructorOrMethod(final MethodNode node, final boolean isConstructor) {
25972597
typeCheckingContext.pushEnclosingMethod(node);
2598+
for (Parameter parameter : node.getParameters()) {
2599+
for (AnnotationNode annotation : parameter.getAnnotations()) {
2600+
if (annotation.getClassNode().equals(CLOSUREPARAMS_CLASSNODE)) {
2601+
// GROOVY-6603: propagate closure parameter types
2602+
Expression value = annotation.getMember("value");
2603+
Expression options = annotation.getMember("options");
2604+
List<ClassNode[]> signatures = getSignaturesFromHint(null, node, value, options);
2605+
if (signatures.size() == 1) {
2606+
parameter.putNodeMetaData(CLOSURE_ARGUMENTS, Arrays.stream(signatures.get(0)).map(t -> new Parameter(t,"")).toArray(Parameter[]::new));
2607+
}
2608+
}
2609+
}
2610+
}
25982611
super.visitConstructorOrMethod(node, isConstructor);
25992612
if (node.hasDefaultValue()) {
26002613
for (Parameter parameter : node.getParameters()) {
@@ -3366,7 +3379,7 @@ public void visitMethodCallExpression(final MethodCallExpression call) {
33663379
if (parameters != null) {
33673380
typeCheckClosureCall(callArguments, args, parameters);
33683381
}
3369-
ClassNode type = getType(((ASTNode) variable));
3382+
ClassNode type = getType((ASTNode) variable);
33703383
if (type.equals(CLOSURE_TYPE)) { // GROOVY-10098, et al.
33713384
GenericsType[] genericsTypes = type.getGenericsTypes();
33723385
if (genericsTypes != null && genericsTypes.length == 1

ide-test/org.codehaus.groovy.eclipse.codeassist.test/src/org/codehaus/groovy/eclipse/codeassist/tests/ContentAssistLocationTests.groovy

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2009-2020 the original author or authors.
2+
* Copyright 2009-2021 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -1452,7 +1452,7 @@ final class ContentAssistLocationTests extends CompletionTestSuite {
14521452

14531453
//--------------------------------------------------------------------------
14541454

1455-
private void assertLocation(String contents, ContentAssistLocation expected, @ClosureParams(value=SimpleType, options=['org.codehaus.groovy.eclipse.codeassist.requestor.ContentAssistContext']) @DelegatesTo(value=ContentAssistContext, strategy=Closure.DELEGATE_FIRST) Closure<Void> withContext = null) {
1455+
private void assertLocation(String contents, ContentAssistLocation expected, @ClosureParams(value=SimpleType, options='org.codehaus.groovy.eclipse.codeassist.requestor.ContentAssistContext') @DelegatesTo(value=ContentAssistContext, strategy=Closure.DELEGATE_FIRST) Closure<Void> withContext = null) {
14561456
def unit = addGroovySource(contents.replace('#', ''), nextUnitName()), offset = contents.indexOf('#')
14571457
def context = new GroovyCompletionProposalComputer().createContentAssistContext(unit, offset, new Document(unit.buffer.contents))
14581458

0 commit comments

Comments
 (0)