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 2e3f300fb1 GROOVY-10811: check for no-arg constructor for each no-arg 
enum constant
2e3f300fb1 is described below

commit 2e3f300fb19bf87c2e41c6c5e356db2f8b328e70
Author: Eric Milles <[email protected]>
AuthorDate: Tue Dec 10 15:54:28 2024 -0600

    GROOVY-10811: check for no-arg constructor for each no-arg enum constant
---
 .../apache/groovy/ast/tools/ClassNodeUtils.java    |  5 ++-
 .../org/codehaus/groovy/classgen/EnumVisitor.java  | 44 ++++++++++------------
 src/test/gls/enums/EnumTest.groovy                 | 19 ++++++++++
 3 files changed, 42 insertions(+), 26 deletions(-)

diff --git a/src/main/java/org/apache/groovy/ast/tools/ClassNodeUtils.java 
b/src/main/java/org/apache/groovy/ast/tools/ClassNodeUtils.java
index 2ad8badba1..9bb68de1b8 100644
--- a/src/main/java/org/apache/groovy/ast/tools/ClassNodeUtils.java
+++ b/src/main/java/org/apache/groovy/ast/tools/ClassNodeUtils.java
@@ -468,8 +468,9 @@ public class ClassNodeUtils {
      */
     public static boolean hasNoArgConstructor(final ClassNode cNode) {
         List<ConstructorNode> constructors = cNode.getDeclaredConstructors();
-        for (ConstructorNode next : constructors) {
-            if (next.getParameters().length == 0) {
+        for (ConstructorNode ctor : constructors) {
+            if (ctor.getParameters().length == 0 || (ctor.hasDefaultValue()
+                    && 
Arrays.stream(ctor.getParameters()).allMatch(Parameter::hasInitialExpression))) 
{
                 return true;
             }
         }
diff --git a/src/main/java/org/codehaus/groovy/classgen/EnumVisitor.java 
b/src/main/java/org/codehaus/groovy/classgen/EnumVisitor.java
index 4d5b3dd16d..d73339304f 100644
--- a/src/main/java/org/codehaus/groovy/classgen/EnumVisitor.java
+++ b/src/main/java/org/codehaus/groovy/classgen/EnumVisitor.java
@@ -48,6 +48,7 @@ import java.util.List;
 import java.util.StringJoiner;
 
 import static org.apache.groovy.ast.tools.ClassNodeUtils.addGeneratedMethod;
+import static org.apache.groovy.ast.tools.ClassNodeUtils.hasNoArgConstructor;
 import static org.codehaus.groovy.ast.ClassHelper.int_TYPE;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.args;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.arrayX;
@@ -249,43 +250,38 @@ public class EnumVisitor extends ClassCodeVisitorSupport {
         // static init
         List<FieldNode> fields = enumClass.getFields();
         List<Expression> arrayInit = new ArrayList<>();
-        int value = -1;
         List<Statement> block = new ArrayList<>();
+        int index = -1;
         FieldNode tempMin = null;
         FieldNode tempMax = null;
         for (FieldNode field : fields) {
             if (!field.isEnum()) continue;
-            value += 1;
+            index += 1; // the next ordinal
             if (tempMin == null) tempMin = field;
             tempMax = field;
 
-            ClassNode enumBase = enumClass;
-            ArgumentListExpression args = args(constX(field.getName()), 
constX(value));
+            ClassNode enumType = enumClass;
+            ArgumentListExpression args = args(constX(field.getName()), 
constX(index));
             if (field.getInitialExpression() == null) {
                 if (enumClass.isAbstract()) {
-                    addError(field, "The enum constant " + field.getName() + " 
must override abstract methods from " + enumBase.getName() + ".");
-                    continue;
+                    addError(field, "The enum constant " + field.getName() + " 
must override abstract methods from " + enumClass.getName() + ".");
+                }
+                if (!(hasNoArgConstructor(enumClass) || 
enumClass.getDeclaredConstructors().isEmpty())) { // GROOVY-10811
+                    addError(field, "The constructor " + 
enumClass.getNameWithoutPackage() + "() is undefined.");
                 }
             } else {
-                ListExpression oldArgs = (ListExpression) 
field.getInitialExpression();
+                var initList = (ListExpression) field.getInitialExpression();
+                field.setInitialValueExpression(null);
                 List<MapEntryExpression> savedMapEntries = new ArrayList<>();
-                for (Expression exp : oldArgs.getExpressions()) {
+                for (Expression exp : initList.getExpressions()) {
                     if (exp instanceof MapEntryExpression) {
                         savedMapEntries.add((MapEntryExpression) exp);
                         continue;
                     }
 
-                    InnerClassNode inner = null;
-                    if (exp instanceof ClassExpression) {
-                        ClassExpression clazzExp = (ClassExpression) exp;
-                        ClassNode ref = clazzExp.getType();
-                        if (ref instanceof EnumConstantClassNode) {
-                            inner = (InnerClassNode) ref;
-                        }
-                    }
-                    if (inner != null) {
-                        List<MethodNode> baseMethods = enumBase.getMethods();
-                        for (MethodNode methodNode : baseMethods) {
+                    if (exp instanceof ClassExpression && exp.getType() 
instanceof EnumConstantClassNode) {
+                        InnerClassNode inner = (InnerClassNode) exp.getType();
+                        for (MethodNode methodNode : enumClass.getMethods()) {
                             if (!methodNode.isAbstract()) continue;
                             MethodNode enumConstMethod = 
inner.getMethod(methodNode.getName(), methodNode.getParameters());
                             if (enumConstMethod == null || 
enumConstMethod.isAbstract()) {
@@ -293,7 +289,7 @@ public class EnumVisitor extends ClassCodeVisitorSupport {
                             }
                         }
                         if (inner.getVariableScope() == null) {
-                            enumBase = inner;
+                            enumType = inner;
                             /*
                              * GROOVY-3985: Remove the final modifier from 
$INIT method in this case
                              * so that subclasses of enum generated for enum 
constants (aic) can provide
@@ -309,9 +305,8 @@ public class EnumVisitor extends ClassCodeVisitorSupport {
                     args.getExpressions().add(2, mapX(savedMapEntries));
                 }
             }
-            field.setInitialValueExpression(null);
-            block.add(assignS(fieldX(field), callX(enumBase, "$INIT", args)));
             arrayInit.add(fieldX(field));
+            block.add(assignS(fieldX(field), callX(enumType, "$INIT", args)));
         }
 
         if (!isAIC) {
@@ -325,13 +320,14 @@ public class EnumVisitor extends ClassCodeVisitorSupport {
             block.add(assignS(fieldX(values), arrayX(enumClass, arrayInit)));
             enumClass.addField(values);
         }
+
         enumClass.addStaticInitializerStatements(block, true);
     }
 
-    private void addError(final AnnotatedNode exp, final String msg) {
+    private void addError(final AnnotatedNode an, final String msg) {
         getSourceUnit().getErrorCollector().addErrorAndContinue(
                 new SyntaxErrorMessage(
-                        new SyntaxException(msg + '\n', exp),
+                        new SyntaxException(msg + '\n', an),
                         getSourceUnit()
                 )
         );
diff --git a/src/test/gls/enums/EnumTest.groovy 
b/src/test/gls/enums/EnumTest.groovy
index ab736d037f..d0e1255d3d 100644
--- a/src/test/gls/enums/EnumTest.groovy
+++ b/src/test/gls/enums/EnumTest.groovy
@@ -860,6 +860,25 @@ class EnumTest extends CompilableTestSupport {
         }
     }
 
+    // GROOVY-10811
+    void testConstructorCheck() {
+        shouldNotCompile '''
+            enum E {
+                FOO;
+                E(x) {
+                }
+            }
+        '''
+
+        shouldCompile '''
+            enum E {
+                FOO;
+                E(x=null) {
+                }
+            }
+        '''
+    }
+
     // GROOVY-10811
     void testSuperCtorCall() {
         shouldNotCompile '''

Reply via email to