Skip to content

Commit 609d125

Browse files
committed
If an enum had static fields and also a static block, statements for initializing static fields were getting positioned after the static block causing un-initialized values of such static fields to be seen inside the static block. Corrected the positioning of static field init statements. git-svn-id: http://svn.codehaus.org/groovy/trunk/groovy/groovy-core@17420 a5544e8c-8a19-0410-ba12-f9af4593a198
1 parent 3eacf13 commit 609d125

File tree

3 files changed

+60
-13
lines changed

3 files changed

+60
-13
lines changed

src/main/org/codehaus/groovy/ast/ClassNode.java

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,12 @@
1616
package org.codehaus.groovy.ast;
1717

1818
import org.codehaus.groovy.GroovyBugError;
19+
import org.codehaus.groovy.ast.expr.BinaryExpression;
1920
import org.codehaus.groovy.ast.expr.Expression;
21+
import org.codehaus.groovy.ast.expr.FieldExpression;
2022
import org.codehaus.groovy.ast.expr.MapExpression;
2123
import org.codehaus.groovy.ast.expr.TupleExpression;
24+
import org.codehaus.groovy.ast.stmt.ExpressionStatement;
2225
import org.codehaus.groovy.ast.stmt.Statement;
2326
import org.codehaus.groovy.ast.stmt.BlockStatement;
2427
import org.codehaus.groovy.control.CompilePhase;
@@ -697,17 +700,22 @@ public List<Statement> getObjectInitializerStatements() {
697700
return objectInitializers;
698701
}
699702

700-
public void addStaticInitializerStatements(List<Statement> staticStatements, boolean fieldInit) {
703+
private MethodNode getOrAddStaticConstructorNode() {
701704
MethodNode method = null;
702-
List<MethodNode> declaredMethods = getDeclaredMethods("<clinit>");
705+
List declaredMethods = getDeclaredMethods("<clinit>");
703706
if (declaredMethods.isEmpty()) {
704707
method =
705708
addMethod("<clinit>", ACC_STATIC, ClassHelper.VOID_TYPE, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, new BlockStatement());
706709
method.setSynthetic(true);
707710
}
708711
else {
709-
method = declaredMethods.get(0);
712+
method = (MethodNode) declaredMethods.get(0);
710713
}
714+
return method;
715+
}
716+
717+
public void addStaticInitializerStatements(List<Statement> staticStatements, boolean fieldInit) {
718+
MethodNode method = getOrAddStaticConstructorNode();
711719
BlockStatement block = null;
712720
Statement statement = method.getCode();
713721
if (statement == null) {
@@ -735,6 +743,33 @@ else if (statement instanceof BlockStatement) {
735743
}
736744
}
737745

746+
public void positionStmtsAfterEnumInitStmts(List<Statement> staticFieldStatements) {
747+
MethodNode method = getOrAddStaticConstructorNode();
748+
Statement statement = method.getCode();
749+
if (statement instanceof BlockStatement) {
750+
BlockStatement block = (BlockStatement) statement;
751+
// add given statements for explicitly declared static fields just after enum-special fields
752+
// are found - the $VALUES binary expression marks the end of such fields.
753+
List<Statement> blockStatements = block.getStatements();
754+
ListIterator<Statement> litr = blockStatements.listIterator();
755+
while(litr.hasNext()) {
756+
Statement stmt = litr.next();
757+
if(stmt instanceof ExpressionStatement &&
758+
((ExpressionStatement)stmt).getExpression() instanceof BinaryExpression) {
759+
BinaryExpression bExp = (BinaryExpression) ((ExpressionStatement)stmt).getExpression();
760+
if (bExp.getLeftExpression() instanceof FieldExpression) {
761+
FieldExpression fExp = (FieldExpression) bExp.getLeftExpression();
762+
if(fExp.getFieldName().equals("$VALUES")) {
763+
for(Statement tmpStmt : staticFieldStatements) {
764+
litr.add(tmpStmt);
765+
}
766+
}
767+
}
768+
}
769+
}
770+
}
771+
}
772+
738773
/**
739774
* This methods returns a list of all methods of the given name
740775
* defined in the current class

src/main/org/codehaus/groovy/classgen/Verifier.java

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -746,10 +746,10 @@ protected void addInitialization(ClassNode node, ConstructorNode constructorNode
746746

747747
List statements = new ArrayList();
748748
List staticStatements = new ArrayList();
749-
final boolean isEnumClassNode = isEnum(node);
750-
List initStmtsAfterEnumValuesInit = new ArrayList();
749+
final boolean isEnum = node.isEnum();
750+
List<Statement> initStmtsAfterEnumValuesInit = new ArrayList();
751751
Set explicitStaticPropsInEnum = new HashSet();
752-
if(isEnumClassNode) {
752+
if(isEnum) {
753753
for (Iterator iter = node.getProperties().iterator(); iter.hasNext();) {
754754
PropertyNode propNode = (PropertyNode) iter.next();
755755
if(!propNode.isSynthetic() && propNode.getField().isStatic()) {
@@ -759,7 +759,7 @@ protected void addInitialization(ClassNode node, ConstructorNode constructorNode
759759
}
760760
for (Iterator iter = node.getFields().iterator(); iter.hasNext();) {
761761
addFieldInitialization(statements, staticStatements,
762-
(FieldNode) iter.next(), isEnumClassNode,
762+
(FieldNode) iter.next(), isEnum,
763763
initStmtsAfterEnumValuesInit, explicitStaticPropsInEnum);
764764
}
765765
statements.addAll(node.getObjectInitializerStatements());
@@ -788,26 +788,22 @@ else if (code != null) {
788788
}
789789

790790
if (!staticStatements.isEmpty()) {
791-
if(isEnumClassNode) {
791+
if(isEnum) {
792792
/*
793793
* GROOVY-3161: initialize statements for explicitly declared static fields
794794
* inside an enum should come after enum values are initialized
795795
*/
796796
staticStatements.removeAll(initStmtsAfterEnumValuesInit);
797797
node.addStaticInitializerStatements(staticStatements, true);
798798
if(!initStmtsAfterEnumValuesInit.isEmpty()) {
799-
node.addStaticInitializerStatements(initStmtsAfterEnumValuesInit, false);
799+
node.positionStmtsAfterEnumInitStmts(initStmtsAfterEnumValuesInit);
800800
}
801801
} else {
802802
node.addStaticInitializerStatements(staticStatements, true);
803803
}
804804
}
805805
}
806806

807-
private boolean isEnum(ClassNode node) {
808-
return (node.getModifiers() & Opcodes.ACC_ENUM) != 0;
809-
}
810-
811807
private ConstructorCallExpression getFirstIfSpecialConstructorCall(Statement code) {
812808
if (code == null || !(code instanceof ExpressionStatement)) return null;
813809

src/test/gls/enums/EnumTest.groovy

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,11 @@ class EnumTest extends GroovyTestCase {
270270
assert obj.getEnumVar() == Class3110.Enum3110.FOO
271271
"""
272272
}
273+
274+
void testStaticFieldInitValuesInAStaticBlock() {
275+
// GROOVY-3693 - trigger enum class load to test it - asserts are present in the enum
276+
GrooyColors3693.r
277+
}
273278
}
274279

275280
enum UsCoin {
@@ -292,4 +297,15 @@ enum Foo3284 {
292297
call = c
293298
}
294299
final Closure call
300+
}
301+
302+
enum GrooyColors3693 {
303+
r, g, b
304+
static List list = [1, 2]
305+
static init() {
306+
assert list == [1, 2]
307+
}
308+
static {
309+
init()
310+
}
295311
}

0 commit comments

Comments
 (0)