This is an automated email from the ASF dual-hosted git repository.

emilles pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/groovy.git


The following commit(s) were added to refs/heads/master by this push:
     new 81098ecb52 GROOVY-11614: SC: apply enum-case transformation after STC 
visitation
81098ecb52 is described below

commit 81098ecb525b55455fb6490a9fe0ceed5218233c
Author: Eric Milles <eric.mil...@thomsonreuters.com>
AuthorDate: Tue Jul 8 13:50:06 2025 -0500

    GROOVY-11614: SC: apply enum-case transformation after STC visitation
---
 .../codehaus/groovy/control/CompilationUnit.java   | 41 ----------------------
 .../VariableExpressionTransformer.java             | 16 +++++++++
 .../transform/stc/EnumTypeCheckingExtension.java   | 34 +++++++-----------
 src/test/groovy/bugs/Groovy8444.groovy             | 26 +++++++-------
 4 files changed, 42 insertions(+), 75 deletions(-)

diff --git a/src/main/java/org/codehaus/groovy/control/CompilationUnit.java 
b/src/main/java/org/codehaus/groovy/control/CompilationUnit.java
index 5665a6d8d4..43704358d1 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.Optional;
 import java.util.Queue;
 import java.util.Set;
 
-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.
@@ -354,39 +346,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 ecd633b073..7763a0703d 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..e439e1722c 100644
--- 
a/src/main/java/org/codehaus/groovy/transform/stc/EnumTypeCheckingExtension.java
+++ 
b/src/main/java/org/codehaus/groovy/transform/stc/EnumTypeCheckingExtension.java
@@ -21,45 +21,35 @@ package org.codehaus.groovy.transform.stc;
 import org.codehaus.groovy.ast.ClassNode;
 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) 
{
-        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())) {
+    public boolean handleUnresolvedVariableExpression(final VariableExpression 
vexp) {
+        var switchStatement = 
this.typeCheckingVisitor.typeCheckingContext.getEnclosingSwitchStatement();
+        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 dedd9823ff..dc3b59effe 100644
--- a/src/test/groovy/bugs/Groovy8444.groovy
+++ b/src/test/groovy/bugs/Groovy8444.groovy
@@ -18,7 +18,7 @@
  */
 package bugs
 
-import org.junit.Test
+import org.junit.jupiter.api.Test
 
 import static groovy.test.GroovyAssert.assertScript
 import static groovy.test.GroovyAssert.shouldFail
@@ -224,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
@@ -243,8 +245,8 @@ final class Groovy8444 {
         '''
     }
 
-    @Test
     // GROOVY-11614
+    @Test
     void testAccessingEnumConstantInSwitchExprCase2() {
         assertScript '''\
             enum SomeEnum {
@@ -266,8 +268,8 @@ final class Groovy8444 {
         '''
     }
 
-    @Test
     // GROOVY-11614
+    @Test
     void testAccessingEnumConstantInSwitchExprCase3() {
         assertScript '''\
             enum SomeEnum {
@@ -285,8 +287,8 @@ final class Groovy8444 {
         '''
     }
 
-    @Test
     // GROOVY-11614
+    @Test
     void testAccessingNonEnumConstantInSwitchExprCase() {
         def err = shouldFail '''\
             enum SomeEnum {
@@ -307,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 {
@@ -329,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 {
@@ -351,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 {
@@ -373,8 +375,8 @@ final class Groovy8444 {
         assert err.message.contains('@ line 9, column 26.')
     }
 
-    @Test
     // GROOVY-11614
+    @Test
     void testAccessingEnumConstantInNestedSwitchExprCase() {
         assertScript '''\
             enum SomeEnum {
@@ -400,8 +402,8 @@ final class Groovy8444 {
         '''
     }
 
-    @Test
     // GROOVY-11614
+    @Test
     void testAccessingEnumConstantInNestedSwitchExprCase2() {
         assertScript '''\
             enum SomeEnum {

Reply via email to