You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by em...@apache.org on 2022/11/03 17:52:40 UTC

[groovy] branch GROOVY_4_0_X updated: GROOVY-7025: cannot refer to non-constant static field in `enum` init

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 d859449109 GROOVY-7025: cannot refer to non-constant static field in `enum` init
d859449109 is described below

commit d859449109543a8bd610b765cac5fdb3246c4e16
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Thu Nov 3 12:12:40 2022 -0500

    GROOVY-7025: cannot refer to non-constant static field in `enum` init
---
 .../groovy/classgen/VariableScopeVisitor.java      | 16 +++++++-
 src/test/gls/enums/EnumTest.groovy                 | 45 ++++++++++++++++++++++
 .../groovy/gls/CompilableTestSupport.groovy        | 27 ++++++-------
 3 files changed, 73 insertions(+), 15 deletions(-)

diff --git a/src/main/java/org/codehaus/groovy/classgen/VariableScopeVisitor.java b/src/main/java/org/codehaus/groovy/classgen/VariableScopeVisitor.java
index 6c1f1c6283..29d8517a07 100644
--- a/src/main/java/org/codehaus/groovy/classgen/VariableScopeVisitor.java
+++ b/src/main/java/org/codehaus/groovy/classgen/VariableScopeVisitor.java
@@ -331,7 +331,18 @@ public class VariableScopeVisitor extends ClassCodeVisitorSupport {
     }
 
     private void checkVariableContextAccess(final Variable variable, final Expression expression) {
-        if (variable.isInStaticContext() || !currentScope.isInStaticContext()) return;
+        if (variable.isInStaticContext()) {
+            if (inConstructor && currentClass.isEnum() && variable instanceof FieldNode
+                    && currentClass.equals(((FieldNode) variable).getDeclaringClass())) { // GROOVY-7025
+                if (!isFinal(variable.getModifiers()) || !(ClassHelper.isStaticConstantInitializerType(variable.getOriginType())
+                        || "String".equals(variable.getOriginType().getName()))) { // TODO: String requires constant initializer
+                    addError("Cannot refer to the static enum field '" + variable.getName() + "' within an initializer", expression);
+                }
+            }
+            return;
+        }
+
+        if (!currentScope.isInStaticContext()) return;
 
         addError(variable.getName() + " is declared in a dynamic context, but you tried to access it from a static context.", expression);
 
@@ -340,10 +351,11 @@ public class VariableScopeVisitor extends ClassCodeVisitorSupport {
     }
 
     //--------------------------------------------------------------------------
+
     /**
      * Sets the current class node context.
      */
-    public void prepareVisit(ClassNode node) {
+    public void prepareVisit(final ClassNode node) {
         currentClass = node;
         currentScope.setClassScope(node);
     }
diff --git a/src/test/gls/enums/EnumTest.groovy b/src/test/gls/enums/EnumTest.groovy
index d2982cb8e1..a05e76f4fb 100644
--- a/src/test/gls/enums/EnumTest.groovy
+++ b/src/test/gls/enums/EnumTest.groovy
@@ -187,6 +187,51 @@ class EnumTest extends CompilableTestSupport {
         assert allColors[2] == GroovyColors3161.green
     }
 
+    // GROOVY-7025
+    void testStaticEnumFieldFromInit() {
+        def err = shouldNotCompile '''
+            enum E {
+                FOO('bar');
+                private static final Set<String> names = []
+                E(String name) {
+                    names.add(name)
+                }
+            }
+        '''
+        assert err =~ /Cannot refer to the static enum field 'names' within an initializer/
+
+        shouldCompile '''
+            enum E {
+                FOO;
+                private static final String ONE = 1
+                private final value
+                E() {
+                    value = 1 + ONE
+                }
+            }
+        '''
+        shouldCompile '''
+            enum E {
+                FOO;
+                private static final int ONE = 1
+                private final value
+                E() {
+                    value = 1 + ONE
+                }
+            }
+        '''
+        shouldNotCompile '''
+            enum E {
+                FOO;
+                private static int ONE = 1
+                private final value
+                E() {
+                    value = 1 + ONE
+                }
+            }
+        '''
+    }
+
     // GROOVY-3283
     void testImportStaticMoreThanOneEnum() {
         assertScript """
diff --git a/src/testFixtures/groovy/gls/CompilableTestSupport.groovy b/src/testFixtures/groovy/gls/CompilableTestSupport.groovy
index 79c5354e78..1c8a770b8a 100644
--- a/src/testFixtures/groovy/gls/CompilableTestSupport.groovy
+++ b/src/testFixtures/groovy/gls/CompilableTestSupport.groovy
@@ -19,24 +19,25 @@
 package gls
 
 import groovy.test.GroovyTestCase
+import groovy.transform.AutoFinal
 import groovy.transform.CompileStatic
 import org.codehaus.groovy.control.CompilationFailedException
 
-@CompileStatic
+@AutoFinal @CompileStatic
 abstract class CompilableTestSupport extends GroovyTestCase {
-    protected shouldNotCompile(String script) {
-        try {
-            GroovyClassLoader gcl = new GroovyClassLoader()
-            gcl.parseClass(script, getTestClassName())
-        } catch (CompilationFailedException cfe) {
-            return cfe.message
+
+    protected String shouldNotCompile(String script) {
+        try (def gcl = new GroovyClassLoader()) {
+            gcl.parseClass(script, testClassName)
+        } catch (CompilationFailedException ex) {
+            return ex.message
         }
-        junit.framework.TestCase.fail("the compilation succeeded but should have failed")
+        fail('the compilation succeeded but should have failed')
     }
 
-    protected void shouldCompile(String script) {
-        GroovyClassLoader gcl = new GroovyClassLoader()
-        gcl.parseClass(script, getTestClassName())
-        assert true
+    protected void shouldCompile(final String script) {
+        try (def gcl = new GroovyClassLoader()) {
+            gcl.parseClass(script, testClassName)
+        }
     }
-}
\ No newline at end of file
+}