This is an automated email from the ASF dual-hosted git repository.
sunlan pushed a commit to branch GROOVY_4_0_X
in repository https://gitbox.apache.org/repos/asf/groovy.git
The following commit(s) were added to refs/heads/GROOVY_4_0_X by this push:
new 54b5244dd6 GROOVY-11614: Enums in switch/case statements that are not
fully qualified will cause a groovy compile error for switch expressions even
with type checking enabled
54b5244dd6 is described below
commit 54b5244dd6a63fbaaeb949446757deb77943480f
Author: Paul King <[email protected]>
AuthorDate: Thu Apr 17 15:14:34 2025 +0900
GROOVY-11614: Enums in switch/case statements that are not fully qualified
will cause a groovy compile error for switch expressions even with type
checking enabled
(cherry picked from commit d77d909df28896a21fe4958a201f98c891d5cb51)
---
.../codehaus/groovy/control/CompilationUnit.java | 9 +
src/test/groovy/bugs/Groovy8444.groovy | 206 +++++++++++++++++++++
2 files changed, 215 insertions(+)
diff --git a/src/main/java/org/codehaus/groovy/control/CompilationUnit.java
b/src/main/java/org/codehaus/groovy/control/CompilationUnit.java
index 4df0164d70..ba51d0bf74 100644
--- a/src/main/java/org/codehaus/groovy/control/CompilationUnit.java
+++ b/src/main/java/org/codehaus/groovy/control/CompilationUnit.java
@@ -30,7 +30,9 @@ import org.codehaus.groovy.ast.CompileUnit;
import org.codehaus.groovy.ast.GroovyClassVisitor;
import org.codehaus.groovy.ast.InnerClassNode;
import org.codehaus.groovy.ast.ModuleNode;
+import org.codehaus.groovy.ast.expr.ClosureExpression;
import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.expr.MethodCallExpression;
import org.codehaus.groovy.ast.expr.VariableExpression;
import org.codehaus.groovy.classgen.AsmClassGenerator;
import org.codehaus.groovy.classgen.ClassCompletionVerifier;
@@ -366,6 +368,13 @@ public class CompilationUnit extends ProcessingUnit {
setSourcePosition(propertyExpression, expression);
return propertyExpression;
}
+ } else if (expression instanceof MethodCallExpression) {
+ // we wrap SwitchExpressions into a method call on a
ClosureExpression
+ MethodCallExpression mce = (MethodCallExpression)
expression;
+ if (mce.getObjectExpression() instanceof
ClosureExpression) {
+ expression.visit(this);
+ return expression;
+ }
}
return expression;
}
diff --git a/src/test/groovy/bugs/Groovy8444.groovy
b/src/test/groovy/bugs/Groovy8444.groovy
index ff22c19def..350b401915 100644
--- a/src/test/groovy/bugs/Groovy8444.groovy
+++ b/src/test/groovy/bugs/Groovy8444.groovy
@@ -226,5 +226,211 @@ final class Groovy8444 {
'''
}
+ @Test
+ // GROOVY-11614
+ void testAccessingEnumConstantInSwitchExprCase() {
+ assertScript '''\
+ enum SomeEnum {
+ A, B
+ }
+ @groovy.transform.CompileStatic
+ def meth(SomeEnum e) {
+ switch (e) {
+ case A -> 1
+ case B -> 2
+ }
+ }
+ assert 1 == meth(SomeEnum.A)
+ assert 2 == meth(SomeEnum.B)
+ '''
+ }
+
+ @Test
+ // GROOVY-11614
+ void testAccessingEnumConstantInSwitchExprCase2() {
+ assertScript '''\
+ enum SomeEnum {
+ A, B
+ }
+ @groovy.transform.CompileStatic
+ def meth(SomeEnum e) {
+ switch (same(e)) {
+ case A -> 1
+ case B -> 2
+ }
+ }
+ @groovy.transform.CompileStatic
+ SomeEnum same(SomeEnum e) {
+ return e
+ }
+ assert 1 == meth(SomeEnum.A)
+ assert 2 == meth(SomeEnum.B)
+ '''
+ }
+
+ @Test
+ // GROOVY-11614
+ void testAccessingEnumConstantInSwitchExprCase3() {
+ assertScript '''\
+ enum SomeEnum {
+ A, B
+ }
+ @groovy.transform.CompileStatic
+ def meth(SomeEnum e) {
+ switch ([e][0]) {
+ case A -> 1
+ case B -> 2
+ }
+ }
+ assert 1 == meth(SomeEnum.A)
+ assert 2 == meth(SomeEnum.B)
+ '''
+ }
+
+ @Test
+ // GROOVY-11614
+ void testAccessingNonEnumConstantInSwitchExprCase() {
+ def err = shouldFail '''\
+ enum SomeEnum {
+ A, B
+
+ static final String C = 'C'
+ }
+ @groovy.transform.CompileStatic
+ def meth(SomeEnum e) {
+ switch (e) {
+ case C -> 3
+ }
+ }
+ meth(SomeEnum.C)
+ '''
+
+ assert err.message.contains('[Static type checking] - The variable [C]
is undeclared')
+ assert err.message.contains('@ line 9, column 26.')
+ }
+
+ @Test
+ // GROOVY-11614
+ void testAccessingNonEnumConstantInSwitchExprCase2() {
+ def err = shouldFail '''\
+ enum SomeEnum {
+ A, B
+
+ SomeEnum C = A
+ }
+ @groovy.transform.CompileStatic
+ def meth(SomeEnum e) {
+ switch (e) {
+ case C -> 3
+ }
+ }
+ meth(SomeEnum.C)
+ '''
+
+ assert err.message.contains('[Static type checking] - The variable [C]
is undeclared')
+ assert err.message.contains('@ line 9, column 26.')
+ }
+
+ @Test
+ // GROOVY-11614
+ void testAccessingNonEnumConstantInSwitchExprCase3() {
+ def err = shouldFail '''\
+ enum SomeEnum {
+ A, B
+
+ static SomeEnum C = A
+ }
+ @groovy.transform.CompileStatic
+ def meth(SomeEnum e) {
+ switch (e) {
+ case C -> 3
+ }
+ }
+ meth(SomeEnum.C)
+ '''
+
+ assert err.message.contains('[Static type checking] - The variable [C]
is undeclared')
+ assert err.message.contains('@ line 9, column 26.')
+ }
+
+ @Test
+ // GROOVY-11614
+ void testAccessingNonEnumConstantInSwitchExprCase4() {
+ def err = shouldFail '''\
+ enum SomeEnum {
+ A, B
+ static final SomeEnum C = A
+ }
+ @groovy.transform.CompileStatic
+ def meth(SomeEnum e) {
+ switch (e) {
+ case C -> 3
+ }
+ }
+ meth(SomeEnum.C)
+ '''
+
+ assert err.message.contains('[Static type checking] - The variable [C]
is undeclared')
+ assert err.message.contains('@ line 9, column 26.')
+ }
+
+ @Test
+ // GROOVY-11614
+ void testAccessingEnumConstantInNestedSwitchExprCase() {
+ assertScript '''\
+ enum SomeEnum {
+ A, B
+ }
+ @groovy.transform.CompileStatic
+ def meth(SomeEnum e) {
+ switch (e) {
+ case A ->
+ switch(e) {
+ case A -> 1.1
+ case B -> 1.2
+ }
+ case B ->
+ switch(e) {
+ case A -> 2.1
+ case B -> 2.2
+ }
+ }
+ }
+ assert 1.1 == meth(SomeEnum.A)
+ assert 2.2 == meth(SomeEnum.B)
+ '''
+ }
+
+ @Test
+ // GROOVY-11614
+ void testAccessingEnumConstantInNestedSwitchExprCase2() {
+ assertScript '''\
+ enum SomeEnum {
+ A, B
+ }
+ enum OtherEnum {
+ C, D
+ }
+ @groovy.transform.CompileStatic
+ def meth(SomeEnum e, OtherEnum e2) {
+ switch (e) {
+ case A ->
+ switch(e2) {
+ case C -> 1.1
+ case D -> 1.2
+ }
+ case B ->
+ switch(e2) {
+ case C -> 2.1
+ case D -> 2.2
+ }
+ }
+ }
+ assert 1.1 == meth(SomeEnum.A, OtherEnum.C)
+ assert 1.2 == meth(SomeEnum.A, OtherEnum.D)
+ assert 2.1 == meth(SomeEnum.B, OtherEnum.C)
+ assert 2.2 == meth(SomeEnum.B, OtherEnum.D)
+ '''
+ }
}