This is an automated email from the ASF dual-hosted git repository.

emilles pushed a commit to branch GROOVY_2_5_X
in repository https://gitbox.apache.org/repos/asf/groovy.git


The following commit(s) were added to refs/heads/GROOVY_2_5_X by this push:
     new dd79fdc  GROOVY-10289: check for static enclosing type(s) before 
accessing this$0
dd79fdc is described below

commit dd79fdc25b40829bf71a32b8ceb3b734496f561c
Author: Eric Milles <[email protected]>
AuthorDate: Sat Oct 9 09:24:05 2021 -0500

    GROOVY-10289: check for static enclosing type(s) before accessing this$0
---
 .../groovy/classgen/InnerClassVisitor.java         | 25 ++++---
 .../groovy/classgen/InnerClassVisitorHelper.java   | 11 +--
 src/test/gls/innerClass/InnerClassTest.groovy      | 84 ++++++++++++++++++++++
 3 files changed, 102 insertions(+), 18 deletions(-)

diff --git a/src/main/java/org/codehaus/groovy/classgen/InnerClassVisitor.java 
b/src/main/java/org/codehaus/groovy/classgen/InnerClassVisitor.java
index 9a5826d..095baa9 100644
--- a/src/main/java/org/codehaus/groovy/classgen/InnerClassVisitor.java
+++ b/src/main/java/org/codehaus/groovy/classgen/InnerClassVisitor.java
@@ -273,30 +273,37 @@ public class InnerClassVisitor extends 
InnerClassVisitorHelper implements Opcode
 
     // this is the counterpart of addThisReference(). To non-static inner 
classes, outer this should be
     // passed as the first argument implicitly.
-    private void passThisReference(ConstructorCallExpression call) {
+    private void passThisReference(final ConstructorCallExpression call) {
         ClassNode cn = call.getType().redirect();
         if (!shouldHandleImplicitThisForInnerClass(cn)) return;
 
-        boolean isInStaticContext = true;
+        boolean isInStaticContext;
         if (currentMethod != null)
-            isInStaticContext = 
currentMethod.getVariableScope().isInStaticContext();
+            isInStaticContext = currentMethod.isStatic();
         else if (currentField != null)
             isInStaticContext = currentField.isStatic();
-        else if (processingObjInitStatements)
-            isInStaticContext = false;
+        else
+            isInStaticContext = !processingObjInitStatements;
+
+        // GROOVY-10289
+        ClassNode enclosing = classNode;
+        while (!isInStaticContext && !enclosing.equals(cn.getOuterClass())) {
+            isInStaticContext = (enclosing.getModifiers() & ACC_STATIC) != 0;
+            // TODO: if enclosing is a local type, also test field or method
+            enclosing = enclosing.getOuterClass();
+            if (enclosing == null) break;
+        }
 
-        // if constructor call is not in static context, return
         if (isInStaticContext) {
             // constructor call is in static context and the inner class is 
non-static - 1st arg is supposed to be
             // passed as enclosing "this" instance
-            //
             Expression args = call.getArguments();
             if (args instanceof TupleExpression && ((TupleExpression) 
args).getExpressions().isEmpty()) {
                 addError("No enclosing instance passed in constructor call of 
a non-static inner class", call);
             }
-            return;
+        } else {
+            insertThis0ToSuperCall(call, cn);
         }
-        insertThis0ToSuperCall(call, cn);
     }
 
     private void insertThis0ToSuperCall(final ConstructorCallExpression call, 
final ClassNode cn) {
diff --git 
a/src/main/java/org/codehaus/groovy/classgen/InnerClassVisitorHelper.java 
b/src/main/java/org/codehaus/groovy/classgen/InnerClassVisitorHelper.java
index bc9292a..0fc0707 100644
--- a/src/main/java/org/codehaus/groovy/classgen/InnerClassVisitorHelper.java
+++ b/src/main/java/org/codehaus/groovy/classgen/InnerClassVisitorHelper.java
@@ -127,14 +127,7 @@ public abstract class InnerClassVisitorHelper extends 
ClassCodeVisitorSupport {
     }
 
     protected static boolean shouldHandleImplicitThisForInnerClass(ClassNode 
cn) {
-        if (cn.isEnum() || cn.isInterface()) return false;
-        if ((cn.getModifiers() & Opcodes.ACC_STATIC) != 0) return false;
-
-        if (!(cn instanceof InnerClassNode)) return false;
-        InnerClassNode innerClass = (InnerClassNode) cn;
-        // scope != null means aic, we don't handle that here
-        if (innerClass.getVariableScope() != null) return false;
-        // static inner classes don't need this$0
-        return (innerClass.getModifiers() & Opcodes.ACC_STATIC) == 0;
+        final int explicitOrImplicitStatic = Opcodes.ACC_STATIC | 
Opcodes.ACC_INTERFACE | Opcodes.ACC_ENUM;
+        return (cn.getModifiers() & explicitOrImplicitStatic) == 0 && (cn 
instanceof InnerClassNode && !((InnerClassNode) cn).isAnonymous());
     }
 }
diff --git a/src/test/gls/innerClass/InnerClassTest.groovy 
b/src/test/gls/innerClass/InnerClassTest.groovy
index a6b7abe..7d18553 100644
--- a/src/test/gls/innerClass/InnerClassTest.groovy
+++ b/src/test/gls/innerClass/InnerClassTest.groovy
@@ -899,6 +899,90 @@ final class InnerClassTest {
     }
 
     @Test
+    void testUsageOfOuterType() {
+        assertScript '''
+            class Foo {
+                class Bar {
+                    def test() {
+                        new Baz()
+                    }
+                }
+                class Baz {
+                }
+            }
+            def baz = new Foo.Bar(new Foo()).test()
+            assert baz instanceof Foo.Baz
+        '''
+    }
+
+    @Test
+    void testUsageOfOuterType2() {
+        assertScript '''
+            class Foo {
+                static class Bar {
+                    static test() {
+                        new Baz()
+                    }
+                }
+                static class Baz {
+                }
+            }
+            def baz = Foo.Bar.test()
+            assert baz instanceof Foo.Baz
+        '''
+    }
+
+    @Test
+    void testUsageOfOuterType3() {
+        def err = shouldFail '''
+            class Foo {
+                static class Bar {
+                    static test() {
+                        new Baz()
+                    }
+                }
+                class Baz {
+                }
+            }
+        '''
+        assert err =~ /No enclosing instance passed in constructor call of a 
non-static inner class/
+    }
+
+    @Test // GROOVY-10289
+    void testUsageOfOuterType4() {
+        def err = shouldFail '''
+            class Foo {
+                static class Bar {
+                    def test() {
+                        new Baz()
+                    }
+                }
+                class Baz {
+                }
+            }
+        '''
+        assert err =~ /No enclosing instance passed in constructor call of a 
non-static inner class/
+    }
+
+    @Test
+    void testUsageOfOuterType5() {
+        def err = shouldFail '''
+            class Foo {
+                static class Bar {
+                    class Baz {
+                        def test() {
+                            new Foo.Baz()
+                        }
+                    }
+                }
+                class Baz {
+                }
+            }
+        '''
+        assert err =~ /No enclosing instance passed in constructor call of a 
non-static inner class/
+    }
+
+    @Test
     void testClassOutputOrdering() {
         // this does actually not do much, but before this
         // change the inner class was tried to be executed

Reply via email to