This is an automated email from the ASF dual-hosted git repository.
emilles pushed a commit to branch GROOVY_3_0_X
in repository https://gitbox.apache.org/repos/asf/groovy.git
The following commit(s) were added to refs/heads/GROOVY_3_0_X by this push:
new 386177e4a4 GROOVY-11614: SC: apply enum-case transformation after STC
visitation
386177e4a4 is described below
commit 386177e4a461854823971e78dbd0524904681d1d
Author: Eric Milles <[email protected]>
AuthorDate: Tue Jul 8 14:41:52 2025 -0500
GROOVY-11614: SC: apply enum-case transformation after STC visitation
3_0_X backport
---
.../codehaus/groovy/control/CompilationUnit.java | 32 --------------------
.../VariableExpressionTransformer.java | 16 ++++++++++
.../transform/stc/EnumTypeCheckingExtension.java | 35 ++++++++--------------
src/test/groovy/bugs/Groovy8444.groovy | 22 +++++++-------
4 files changed, 40 insertions(+), 65 deletions(-)
diff --git a/src/main/java/org/codehaus/groovy/control/CompilationUnit.java
b/src/main/java/org/codehaus/groovy/control/CompilationUnit.java
index 39d1882392..7d708b3678 100644
--- a/src/main/java/org/codehaus/groovy/control/CompilationUnit.java
+++ b/src/main/java/org/codehaus/groovy/control/CompilationUnit.java
@@ -22,15 +22,12 @@ import groovy.lang.GroovyClassLoader;
import groovy.lang.GroovyRuntimeException;
import groovy.transform.CompilationUnitAware;
import org.codehaus.groovy.GroovyBugError;
-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.Expression;
-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;
@@ -77,11 +74,8 @@ import java.util.Set;
import java.util.stream.Stream;
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.runtime.StringGroovyMethods.isAtLeast;
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.
@@ -310,32 +304,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;
- }
- }
- 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 cd90269c40..fb41d33248 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
@@ -41,6 +41,9 @@ public class VariableExpressionTransformer {
public Expression transformVariableExpression(final VariableExpression ve)
{
Expression xe = tryTransformImplicitReceiver(ve);
+ if (xe == null) {
+ xe = tryTransformEnumConstantAccess(ve);
+ }
if (xe == null) {
xe = tryTransformPrivateFieldAccess(ve);
}
@@ -81,6 +84,19 @@ public 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..d1e5b241b9 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,32 @@ 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())) {
- vexp.putNodeMetaData(SWITCH_CONDITION_EXPRESSION_TYPE,
type);
+ 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(StaticTypesMarker.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 bb104e177e..e73fc98634 100644
--- a/src/test/groovy/bugs/Groovy8444.groovy
+++ b/src/test/groovy/bugs/Groovy8444.groovy
@@ -19,6 +19,8 @@
package groovy.bugs
import groovy.transform.CompileStatic
+import org.codehaus.groovy.control.CompilerConfiguration
+import org.codehaus.groovy.control.customizers.ASTTransformationCustomizer
import org.junit.Test
import static groovy.test.GroovyAssert.assertScript
@@ -29,11 +31,13 @@ final class Groovy8444 {
@Test
void testAccessingEnumConstantInSwitchCase() {
- assertScript '''\
+ def shell = new GroovyShell(new CompilerConfiguration().tap {
+ addCompilationCustomizers(new
ASTTransformationCustomizer(CompileStatic))
+ })
+ shell.evaluate '''\
enum SomeEnum {
A, B
}
- @groovy.transform.CompileStatic
def meth(SomeEnum e) {
switch (e) {
case A: return 1
@@ -90,7 +94,7 @@ final class Groovy8444 {
def err = shouldFail '''\
enum SomeEnum {
A, B
-
+
static final String C = 'C'
}
@groovy.transform.CompileStatic
@@ -111,7 +115,7 @@ final class Groovy8444 {
def err = shouldFail '''\
enum SomeEnum {
A, B
-
+
SomeEnum C = A
}
@groovy.transform.CompileStatic
@@ -132,7 +136,7 @@ final class Groovy8444 {
def err = shouldFail '''\
enum SomeEnum {
A, B
-
+
static SomeEnum C = A
}
@groovy.transform.CompileStatic
@@ -153,7 +157,7 @@ final class Groovy8444 {
def err = shouldFail '''\
enum SomeEnum {
A, B
-
+
static final SomeEnum C = A
}
@groovy.transform.CompileStatic
@@ -178,7 +182,7 @@ final class Groovy8444 {
@groovy.transform.CompileStatic
def meth(SomeEnum e) {
switch (e) {
- case A:
+ case A:
switch(e) {
case A: return 1.1
case B: return 1.2
@@ -207,7 +211,7 @@ final class Groovy8444 {
@groovy.transform.CompileStatic
def meth(SomeEnum e, OtherEnum e2) {
switch (e) {
- case A:
+ case A:
switch(e2) {
case C: return 1.1
case D: return 1.2
@@ -225,6 +229,4 @@ final class Groovy8444 {
assert 2.2 == meth(SomeEnum.B, OtherEnum.D)
'''
}
-
-
}