Fix cyclic reuse of final static constants: avoid to "optimize" static field expressions
diff --git a/src/main/java/net/hydromatic/linq4j/expressions/DeterministicCodeOptimizer.java b/src/main/java/net/hydromatic/linq4j/expressions/DeterministicCodeOptimizer.java
index c09532a..340ae73 100644
--- a/src/main/java/net/hydromatic/linq4j/expressions/DeterministicCodeOptimizer.java
+++ b/src/main/java/net/hydromatic/linq4j/expressions/DeterministicCodeOptimizer.java
@@ -189,6 +189,17 @@
return result;
}
+ @Override
+ public MemberDeclaration visit(FieldDeclaration fieldDeclaration,
+ Expression initializer) {
+ if (Modifier.isStatic(fieldDeclaration.modifier)) {
+ // Avoid optimization of static fields, since we'll have to track order
+ // of static declarations.
+ return fieldDeclaration;
+ }
+ return super.visit(fieldDeclaration, initializer);
+ }
+
/**
* Processes the list of declarations and learns final static ones as
* effectively constant.
@@ -213,26 +224,6 @@
}
/**
- * Adds new declarations (e.g. final static fields) to the list of existing
- * ones.
- *
- * @param memberDeclarations existing list of declarations
- * @return new list of declarations or the same if no modifications required
- */
- protected List<MemberDeclaration> optimizeDeclarations(
- List<MemberDeclaration> memberDeclarations) {
- if (addedDeclarations.isEmpty()) {
- return memberDeclarations;
- }
- List<MemberDeclaration> newDecls =
- new ArrayList<MemberDeclaration>(memberDeclarations.size()
- + addedDeclarations.size());
- newDecls.addAll(memberDeclarations);
- newDecls.addAll(addedDeclarations);
- return newDecls;
- }
-
- /**
* Finds if there exists ready for reuse declaration for given expression.
*
* @param expression input expression
diff --git a/src/test/java/net/hydromatic/linq4j/test/BlockBuilderBase.java b/src/test/java/net/hydromatic/linq4j/test/BlockBuilderBase.java
index 7082d1c..bb5787b 100644
--- a/src/test/java/net/hydromatic/linq4j/test/BlockBuilderBase.java
+++ b/src/test/java/net/hydromatic/linq4j/test/BlockBuilderBase.java
@@ -44,10 +44,26 @@
return optimize(Expressions.return_(null, expr));
}
+ public static BlockStatement optimizeExpression(Expression expr) {
+ return optimizeStatement(Expressions.return_(null, expr));
+ }
+
public static String optimize(Statement statement) {
+ return optimizeStatement(statement).toString();
+ }
+
+ public static BlockStatement optimizeStatement(Statement statement) {
BlockBuilder b = new BlockBuilder(true);
- b.add(statement);
- return b.toBlock().toString();
+ if (!(statement instanceof BlockStatement)) {
+ b.add(statement);
+ } else {
+ BlockStatement bs = (BlockStatement) statement;
+ for (Statement stmt : bs.statements) {
+ b.add(stmt);
+ }
+ }
+ BlockStatement bs = b.toBlock();
+ return bs;
}
public static ParameterExpression bool(String name) {
diff --git a/src/test/java/net/hydromatic/linq4j/test/DeterministicTest.java b/src/test/java/net/hydromatic/linq4j/test/DeterministicTest.java
index 5c44a2d..bda6599 100644
--- a/src/test/java/net/hydromatic/linq4j/test/DeterministicTest.java
+++ b/src/test/java/net/hydromatic/linq4j/test/DeterministicTest.java
@@ -90,6 +90,30 @@
+ "}\n"));
}
+ @Test public void testFactorOutBinaryAddSurviesMultipleOptimizations() {
+ assertThat(
+ optimize(optimizeExpression(
+ Expressions.new_(
+ Runnable.class,
+ Collections.<Expression>emptyList(),
+ Expressions.methodDecl(
+ 0,
+ int.class,
+ "test",
+ Collections.<ParameterExpression>emptyList(),
+ Blocks.toFunctionBlock(Expressions.add(ONE, TWO)))))),
+ equalTo(
+ "{\n"
+ + " return new Runnable(){\n"
+ + " int test() {\n"
+ + " return $L4J$C$1_2;\n"
+ + " }\n"
+ + "\n"
+ + " static final int $L4J$C$1_2 = 1 + 2;\n"
+ + " };\n"
+ + "}\n"));
+ }
+
@Test public void testFactorOutBinaryAddNameCollision() {
assertThat(
optimize(