This is an automated email from the ASF dual-hosted git repository.
emilles 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 8f74d9d747 GROOVY-11614: SC: apply enum-case transformation after STC
visitation
8f74d9d747 is described below
commit 8f74d9d74764d4047dd2d8ef79871b697b65345c
Author: Eric Milles <[email protected]>
AuthorDate: Tue Jul 8 13:50:06 2025 -0500
GROOVY-11614: SC: apply enum-case transformation after STC visitation
4_0_X backport
---
.../codehaus/groovy/control/CompilationUnit.java | 41 ----------------------
.../VariableExpressionTransformer.java | 16 +++++++++
.../transform/stc/EnumTypeCheckingExtension.java | 31 ++++++----------
src/test/groovy/bugs/Groovy8444.groovy | 26 +++++++-------
4 files changed, 40 insertions(+), 74 deletions(-)
diff --git a/src/main/java/org/codehaus/groovy/control/CompilationUnit.java
b/src/main/java/org/codehaus/groovy/control/CompilationUnit.java
index ba51d0bf74..21048ea2ce 100644
--- a/src/main/java/org/codehaus/groovy/control/CompilationUnit.java
+++ b/src/main/java/org/codehaus/groovy/control/CompilationUnit.java
@@ -23,17 +23,12 @@ import groovy.lang.GroovyRuntimeException;
import groovy.transform.CompilationUnitAware;
import org.codehaus.groovy.GroovyBugError;
import org.codehaus.groovy.ast.AnnotationNode;
-import org.codehaus.groovy.ast.ClassCodeExpressionTransformer;
import org.codehaus.groovy.ast.ClassHelper;
import org.codehaus.groovy.ast.ClassNode;
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;
import org.codehaus.groovy.classgen.EnumCompletionVisitor;
@@ -76,10 +71,7 @@ import java.util.Queue;
import java.util.Set;
import static java.util.stream.Collectors.toList;
-import static org.codehaus.groovy.ast.tools.GeneralUtils.classX;
-import static org.codehaus.groovy.ast.tools.GeneralUtils.propX;
import static
org.codehaus.groovy.transform.sc.StaticCompilationMetadataKeys.DYNAMIC_OUTER_NODE_CALLBACK;
-import static
org.codehaus.groovy.transform.stc.StaticTypesMarker.SWITCH_CONDITION_EXPRESSION_TYPE;
/**
* The CompilationUnit collects all compilation data as it is generated by the
compiler system.
@@ -348,39 +340,6 @@ public class CompilationUnit extends ProcessingUnit {
classNode.removeNodeMetaData(DYNAMIC_OUTER_NODE_CALLBACK);
}
}, Phases.INSTRUCTION_SELECTION);
-
- addPhaseOperation((final SourceUnit source, final GeneratorContext
context, final ClassNode classNode) -> {
- // TODO: Can this be moved into
org.codehaus.groovy.transform.sc.transformers.VariableExpressionTransformer?
- GroovyClassVisitor visitor = new ClassCodeExpressionTransformer() {
- @Override
- protected SourceUnit getSourceUnit() {
- return source;
- }
-
- @Override
- public Expression transform(final Expression expression) {
- if (expression instanceof VariableExpression) {
- // check for "switch(enumType) { case CONST: ... }"
- ClassNode enumType =
expression.getNodeMetaData(SWITCH_CONDITION_EXPRESSION_TYPE);
- if (enumType != null) {
- // replace "CONST" variable expression with
"EnumType.CONST" property expression
- Expression propertyExpression =
propX(classX(enumType), expression.getText());
- 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;
- }
- };
- visitor.visitClass(classNode);
- }, Phases.INSTRUCTION_SELECTION);
}
private void applyCompilationCustomizers() {
diff --git
a/src/main/java/org/codehaus/groovy/transform/sc/transformers/VariableExpressionTransformer.java
b/src/main/java/org/codehaus/groovy/transform/sc/transformers/VariableExpressionTransformer.java
index f15915513b..c2d5a07770 100644
---
a/src/main/java/org/codehaus/groovy/transform/sc/transformers/VariableExpressionTransformer.java
+++
b/src/main/java/org/codehaus/groovy/transform/sc/transformers/VariableExpressionTransformer.java
@@ -37,6 +37,9 @@ class VariableExpressionTransformer {
Expression transformVariableExpression(final VariableExpression ve) {
Expression xe = tryTransformImplicitReceiver(ve);
+ if (xe == null) {
+ xe = tryTransformEnumConstantAccess(ve);
+ }
if (xe == null) {
xe = tryTransformPrivateFieldAccess(ve);
}
@@ -77,6 +80,19 @@ class VariableExpressionTransformer {
return pe;
}
+ private static Expression tryTransformEnumConstantAccess(final
VariableExpression ve) {
+ ClassNode enumType =
ve.getNodeMetaData(StaticTypesMarker.SWITCH_CONDITION_EXPRESSION_TYPE);
+ if (enumType == null) {
+ return null;
+ }
+
+ // GROOVY-8444, GROOVY-11614: replace "CONST" expression with an
"EnumType.CONST" expression
+ PropertyExpression pe = propX(classX(enumType), ve.getText());
+ pe.putNodeMetaData(StaticTypesMarker.INFERRED_TYPE, enumType);
+ pe.getProperty().setSourcePosition(ve);
+ return pe;
+ }
+
private static Expression tryTransformPrivateFieldAccess(final
VariableExpression ve) {
FieldNode field =
ve.getNodeMetaData(StaticTypesMarker.PV_FIELDS_ACCESS);
if (field == null) {
diff --git
a/src/main/java/org/codehaus/groovy/transform/stc/EnumTypeCheckingExtension.java
b/src/main/java/org/codehaus/groovy/transform/stc/EnumTypeCheckingExtension.java
index e798f27ea2..23034ab530 100644
---
a/src/main/java/org/codehaus/groovy/transform/stc/EnumTypeCheckingExtension.java
+++
b/src/main/java/org/codehaus/groovy/transform/stc/EnumTypeCheckingExtension.java
@@ -23,43 +23,34 @@ import org.codehaus.groovy.ast.FieldNode;
import org.codehaus.groovy.ast.expr.VariableExpression;
import org.codehaus.groovy.ast.stmt.SwitchStatement;
-import java.lang.reflect.Modifier;
-
import static
org.codehaus.groovy.transform.stc.StaticTypesMarker.SWITCH_CONDITION_EXPRESSION_TYPE;
/**
- * A type checking extension that will take care of handling errors which are
specific to enums. In particular, it will
- * handle the enum constants within switch-case statement.
+ * A type checking extension that will take care of handling errors which are
+ * specific to enums. In particular, it will handle the enum constants within
+ * a switch's case statements.
*
* @since 3.0.0
*/
public class EnumTypeCheckingExtension extends TypeCheckingExtension {
- public EnumTypeCheckingExtension(StaticTypeCheckingVisitor
staticTypeCheckingVisitor) {
+
+ public EnumTypeCheckingExtension(final StaticTypeCheckingVisitor
staticTypeCheckingVisitor) {
super(staticTypeCheckingVisitor);
}
@Override
- public boolean handleUnresolvedVariableExpression(VariableExpression vexp)
{
+ public boolean handleUnresolvedVariableExpression(final VariableExpression
vexp) {
SwitchStatement switchStatement =
this.typeCheckingVisitor.typeCheckingContext.getEnclosingSwitchStatement();
-
- if (null == switchStatement) return false;
-
- ClassNode type =
switchStatement.getExpression().getNodeMetaData(StaticTypesMarker.TYPE);
-
- if (null == type) return false;
-
- if (type.isEnum()) {
- FieldNode fieldNode = type.redirect().getField(vexp.getName());
- if (null != fieldNode) {
- int modifiers = fieldNode.getModifiers();
- if (Modifier.isPublic(modifiers) &&
Modifier.isStatic(modifiers) && Modifier.isFinal(modifiers)
- && type.equals(fieldNode.getType())) {
+ if (switchStatement != null) {
+ ClassNode type =
switchStatement.getExpression().getNodeMetaData(StaticTypesMarker.TYPE);
+ if (type != null && type.isEnum()) {
+ FieldNode fieldNode = type.redirect().getField(vexp.getName());
+ if (fieldNode != null && fieldNode.isEnum()) {
vexp.putNodeMetaData(SWITCH_CONDITION_EXPRESSION_TYPE,
type);
return true;
}
}
}
-
return false;
}
}
diff --git a/src/test/groovy/bugs/Groovy8444.groovy
b/src/test/groovy/bugs/Groovy8444.groovy
index 350b401915..753b6ecfab 100644
--- a/src/test/groovy/bugs/Groovy8444.groovy
+++ b/src/test/groovy/bugs/Groovy8444.groovy
@@ -18,13 +18,11 @@
*/
package bugs
-import groovy.transform.CompileStatic
import org.junit.Test
import static groovy.test.GroovyAssert.assertScript
import static groovy.test.GroovyAssert.shouldFail
-@CompileStatic
final class Groovy8444 {
@Test
@@ -226,14 +224,16 @@ final class Groovy8444 {
'''
}
- @Test
// GROOVY-11614
+ @Test
void testAccessingEnumConstantInSwitchExprCase() {
- assertScript '''\
+ def shell = GroovyShell.withConfig {
+ ast(groovy.transform.CompileStatic)
+ }
+ assertScript shell, '''\
enum SomeEnum {
A, B
}
- @groovy.transform.CompileStatic
def meth(SomeEnum e) {
switch (e) {
case A -> 1
@@ -245,8 +245,8 @@ final class Groovy8444 {
'''
}
- @Test
// GROOVY-11614
+ @Test
void testAccessingEnumConstantInSwitchExprCase2() {
assertScript '''\
enum SomeEnum {
@@ -268,8 +268,8 @@ final class Groovy8444 {
'''
}
- @Test
// GROOVY-11614
+ @Test
void testAccessingEnumConstantInSwitchExprCase3() {
assertScript '''\
enum SomeEnum {
@@ -287,8 +287,8 @@ final class Groovy8444 {
'''
}
- @Test
// GROOVY-11614
+ @Test
void testAccessingNonEnumConstantInSwitchExprCase() {
def err = shouldFail '''\
enum SomeEnum {
@@ -309,8 +309,8 @@ final class Groovy8444 {
assert err.message.contains('@ line 9, column 26.')
}
- @Test
// GROOVY-11614
+ @Test
void testAccessingNonEnumConstantInSwitchExprCase2() {
def err = shouldFail '''\
enum SomeEnum {
@@ -331,8 +331,8 @@ final class Groovy8444 {
assert err.message.contains('@ line 9, column 26.')
}
- @Test
// GROOVY-11614
+ @Test
void testAccessingNonEnumConstantInSwitchExprCase3() {
def err = shouldFail '''\
enum SomeEnum {
@@ -353,8 +353,8 @@ final class Groovy8444 {
assert err.message.contains('@ line 9, column 26.')
}
- @Test
// GROOVY-11614
+ @Test
void testAccessingNonEnumConstantInSwitchExprCase4() {
def err = shouldFail '''\
enum SomeEnum {
@@ -375,8 +375,8 @@ final class Groovy8444 {
assert err.message.contains('@ line 9, column 26.')
}
- @Test
// GROOVY-11614
+ @Test
void testAccessingEnumConstantInNestedSwitchExprCase() {
assertScript '''\
enum SomeEnum {
@@ -402,8 +402,8 @@ final class Groovy8444 {
'''
}
- @Test
// GROOVY-11614
+ @Test
void testAccessingEnumConstantInNestedSwitchExprCase2() {
assertScript '''\
enum SomeEnum {