You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by su...@apache.org on 2017/04/07 13:30:55 UTC

[12/50] [abbrv] groovy git commit: GROOVY-7248: MissingPropertyException: No such property in finally block (closes #501)

GROOVY-7248: MissingPropertyException: No such property in finally block (closes #501)


Project: http://git-wip-us.apache.org/repos/asf/groovy/repo
Commit: http://git-wip-us.apache.org/repos/asf/groovy/commit/d5169447
Tree: http://git-wip-us.apache.org/repos/asf/groovy/tree/d5169447
Diff: http://git-wip-us.apache.org/repos/asf/groovy/diff/d5169447

Branch: refs/heads/parrot
Commit: d51694473e921c7360061f6a4bfe876ea6a401cf
Parents: b32ce96
Author: John Wagenleitner <jw...@apache.org>
Authored: Sun Mar 5 10:39:38 2017 -0800
Committer: John Wagenleitner <jw...@apache.org>
Committed: Thu Mar 9 05:18:29 2017 -0800

----------------------------------------------------------------------
 .../classgen/asm/OptimizingStatementWriter.java | 18 +++++-
 src/test/groovy/bugs/Groovy7248Bug.groovy       | 67 ++++++++++++++++++++
 2 files changed, 83 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/groovy/blob/d5169447/src/main/org/codehaus/groovy/classgen/asm/OptimizingStatementWriter.java
----------------------------------------------------------------------
diff --git a/src/main/org/codehaus/groovy/classgen/asm/OptimizingStatementWriter.java b/src/main/org/codehaus/groovy/classgen/asm/OptimizingStatementWriter.java
index 134600d..8696637 100644
--- a/src/main/org/codehaus/groovy/classgen/asm/OptimizingStatementWriter.java
+++ b/src/main/org/codehaus/groovy/classgen/asm/OptimizingStatementWriter.java
@@ -55,6 +55,7 @@ public class OptimizingStatementWriter extends StatementWriter {
         private boolean optimize=false;
         protected MethodNode target;
         protected ClassNode type;
+        protected VariableExpression declaredVariableExpression;
         protected boolean[] involvedTypes = new boolean[typeMapKeyNames.length];
         public void chainInvolvedTypes(OptimizeFlagsCollector opt) {
             for (int i=0; i<typeMapKeyNames.length; i++) {
@@ -304,6 +305,10 @@ public class OptimizingStatementWriter extends StatementWriter {
         } else {
             StatementMeta meta = (StatementMeta) statement.getNodeMetaData(StatementMeta.class);
             if (isNewPathFork(meta) && writeDeclarationExtraction(statement)) {
+                if (meta.declaredVariableExpression != null) {
+                    // declaration was replaced by assignment so we need to define the variable
+                    controller.getCompileStack().defineVariable(meta.declaredVariableExpression, false);
+                }
                 FastPathData fastPathData = writeGuards(meta, statement);
 
                 boolean oldFastPathBlock = fastPathBlocked;
@@ -342,6 +347,10 @@ public class OptimizingStatementWriter extends StatementWriter {
             // the only case we need to handle is then (2).
 
             if (isNewPathFork(meta) && writeDeclarationExtraction(statement)) {
+                if (meta.declaredVariableExpression != null) {
+                    // declaration was replaced by assignment so we need to define the variable
+                    controller.getCompileStack().defineVariable(meta.declaredVariableExpression, false);
+                }
                 FastPathData fastPathData = writeGuards(meta, statement);
 
                 boolean oldFastPathBlock = fastPathBlocked;
@@ -375,8 +384,13 @@ public class OptimizingStatementWriter extends StatementWriter {
         ex = declaration.getLeftExpression();
         if (ex instanceof TupleExpression) return false;
 
-        // do declaration
-        controller.getCompileStack().defineVariable(declaration.getVariableExpression(), false);
+        // stash declared variable in case we do subsequent visits after we
+        // change to assignment only
+        StatementMeta meta = statement.getNodeMetaData(StatementMeta.class);
+        if (meta != null) {
+            meta.declaredVariableExpression = declaration.getVariableExpression();
+        }
+
         // change statement to do assignment only
         BinaryExpression assignment = new BinaryExpression(
                 declaration.getLeftExpression(),

http://git-wip-us.apache.org/repos/asf/groovy/blob/d5169447/src/test/groovy/bugs/Groovy7248Bug.groovy
----------------------------------------------------------------------
diff --git a/src/test/groovy/bugs/Groovy7248Bug.groovy b/src/test/groovy/bugs/Groovy7248Bug.groovy
new file mode 100644
index 0000000..b8057fb
--- /dev/null
+++ b/src/test/groovy/bugs/Groovy7248Bug.groovy
@@ -0,0 +1,67 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package groovy.bugs
+
+/**
+ * StatementWriter.writeTryCatchFinally visits the finally block
+ * twice, once for the normal path and once again for the "catch all"
+ * path. When the OptimizingStatementWriter is used DeclarationExpressions
+ * are rewritten to BinaryExpressions to allow splitting between fast and
+ * slow paths.  Because the expression is modified variable declarations
+ * are lost if the statement is visited more than once.
+ *
+ * This is not a problem for scripts because the property call that is
+ * generated will succeed because of the script context.  So to reproduce
+ * the issue it must be contained in a class.
+ */
+class Groovy7248Bug extends GroovyTestCase {
+
+    void testFinallyDeclaredVariableExpression() {
+        assertScript '''
+            class Test {
+                long run() {
+                    long dur = 0
+                    long start = 0
+                    try {
+                        start++
+                    } finally {
+                        long end = 2
+                        long time = end - start
+                        dur = time
+                    }
+                    dur
+                }
+            }
+            assert new Test().run() == 1
+        '''
+    }
+
+    void testReturnStatementDeclaration() {
+        assertScript '''
+            class Foo {
+                int test() {
+                    int x = 2
+                    int y = x - 1
+                }
+            }
+            assert new Foo().test() == 1
+        '''
+    }
+
+}