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 '''