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

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

commit d35ef2b30a4d89b2f2cb14ff23cab3ef291c97dc
Author: Eric Milles <[email protected]>
AuthorDate: Sun Apr 13 20:25:41 2025 -0500

    GROOVY-11611: outer class super method invocation
---
 .../groovy/classgen/AsmClassGenerator.java         | 11 +++++-----
 .../groovy/classgen/asm/InvocationWriter.java      | 14 ++++++++++---
 .../classgen/asm/indy/InvokeDynamicWriter.java     | 23 ++++++++++-----------
 src/test/gls/innerClass/InnerClassTest.groovy      | 24 ++++++++++++++++++++++
 4 files changed, 52 insertions(+), 20 deletions(-)

diff --git a/src/main/java/org/codehaus/groovy/classgen/AsmClassGenerator.java 
b/src/main/java/org/codehaus/groovy/classgen/AsmClassGenerator.java
index 9bd884ca42..10564ecfcc 100644
--- a/src/main/java/org/codehaus/groovy/classgen/AsmClassGenerator.java
+++ b/src/main/java/org/codehaus/groovy/classgen/AsmClassGenerator.java
@@ -1122,11 +1122,12 @@ public class AsmClassGenerator extends ClassGenerator {
         String propertyName = pexp.getPropertyAsString();
         Expression objectExpression = pexp.getObjectExpression();
 
-        if (objectExpression instanceof ClassExpression && 
"this".equals(propertyName)) {
-            // we have something like A.B.this, and need to make it
-            // into this.this$0.this$0, where this.this$0 returns
-            // A.B and this.this$0.this$0 return A.
-            ClassNode type = objectExpression.getType();
+        ClassNode type = objectExpression.getType();
+        if (objectExpression instanceof ClassExpression && !type.isInterface()
+                && ("this".equals(propertyName) || 
"super".equals(propertyName))) {
+            // we have something like A.B.this and need to make it
+            // into this.this$0.this$0, where this.this$0 produces
+            // A.B and this.this$0.this$0 produces A.
             if (controller.getCompileStack().isInSpecialConstructorCall() && 
type.equals(classNode.getOuterClass())) {
                 // Outer.this in a special constructor call
                 ConstructorNode ctor = controller.getConstructorNode();
diff --git 
a/src/main/java/org/codehaus/groovy/classgen/asm/InvocationWriter.java 
b/src/main/java/org/codehaus/groovy/classgen/asm/InvocationWriter.java
index d5aaa39723..32d1981085 100644
--- a/src/main/java/org/codehaus/groovy/classgen/asm/InvocationWriter.java
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/InvocationWriter.java
@@ -248,7 +248,7 @@ public class InvocationWriter {
         return true;
     }
 
-    private boolean callSuperDefault(ClassNode enclosingClass, MethodNode 
target, Expression receiver) {
+    private boolean callSuperDefault(final ClassNode enclosingClass, final 
MethodNode target, final Expression receiver) {
         ClassNode declaringClass = target.getDeclaringClass();
         if (declaringClass.isInterface() && 
enclosingClass.implementsInterface(declaringClass)) {
             return isClassWithSuper(receiver);
@@ -256,7 +256,7 @@ public class InvocationWriter {
         return false;
     }
 
-    private boolean isClassWithSuper(Expression exp) {
+    private boolean isClassWithSuper(final Expression exp) {
         if (exp instanceof PropertyExpression) {
             PropertyExpression pexp = (PropertyExpression) exp;
             return pexp.getObjectExpression() instanceof ClassExpression && 
"super".equals(pexp.getPropertyAsString());
@@ -264,6 +264,14 @@ public class InvocationWriter {
         return false;
     }
 
+    private boolean isOuterClassSuper(final Expression exp) {
+        if (isClassWithSuper(exp)) {
+            PropertyExpression pexp = (PropertyExpression) exp;
+            return !pexp.getObjectExpression().getType().isInterface();
+        }
+        return false;
+    }
+
     /**
      * Supplements {@link 
org.apache.groovy.ast.tools.ExpressionUtils#isThisExpression isThisExpression}
      * with the ability to see into {@code CheckcastReceiverExpression}.
@@ -481,7 +489,7 @@ public class InvocationWriter {
             if (isFunctionalInterface(type)) call = 
transformToRealMethodCall(call, type);
         }
         MethodCallerMultiAdapter adapter = invokeMethod;
-        if (isSuperExpression(receiver)) {
+        if (isSuperExpression(receiver) || isOuterClassSuper(receiver)) { // 
GROOVY-11611
             adapter = invokeMethodOnSuper;
         } else if (isThisExpression(receiver)) {
             adapter = invokeMethodOnCurrent;
diff --git 
a/src/main/java/org/codehaus/groovy/classgen/asm/indy/InvokeDynamicWriter.java 
b/src/main/java/org/codehaus/groovy/classgen/asm/indy/InvokeDynamicWriter.java
index 4316ddc5a7..0e8245ac5c 100644
--- 
a/src/main/java/org/codehaus/groovy/classgen/asm/indy/InvokeDynamicWriter.java
+++ 
b/src/main/java/org/codehaus/groovy/classgen/asm/indy/InvokeDynamicWriter.java
@@ -132,7 +132,7 @@ public class InvokeDynamicWriter extends InvocationWriter {
     private void makeIndyCall(final MethodCallerMultiAdapter adapter, final 
Expression origReceiver, final boolean implicitThis, final boolean safe, final 
String methodName, final Expression arguments) {
         OperandStack operandStack = controller.getOperandStack();
 
-        Expression receiver = correctReceiverForInterfaceCall(origReceiver, 
operandStack);
+        Expression receiver = correctReceiverForInterfaceCall(origReceiver);
         StringBuilder sig = new StringBuilder(prepareIndyCall(receiver, 
implicitThis));
 
         Label end = null;
@@ -167,7 +167,6 @@ public class InvokeDynamicWriter extends InvocationWriter {
 
         String callSiteName = METHOD.getCallSiteName();
         if (adapter == null) callSiteName = INIT.getCallSiteName();
-        // receiver != origReceiver interface default method call
         if (receiver != origReceiver) callSiteName = 
INTERFACE.getCallSiteName();
 
         int flags = getMethodCallFlags(adapter, false, 
containsSpreadExpression);
@@ -177,19 +176,19 @@ public class InvokeDynamicWriter extends InvocationWriter 
{
         if (end != null) controller.getMethodVisitor().visitLabel(end);
     }
 
-    private Expression correctReceiverForInterfaceCall(Expression exp, 
OperandStack operandStack) {
-        if (exp instanceof PropertyExpression) {
-            PropertyExpression pexp = (PropertyExpression) exp;
-            if (pexp.getObjectExpression() instanceof ClassExpression && 
"super".equals(pexp.getPropertyAsString())) {
-                return bytecodeX(pexp.getObjectExpression().getType(), mv -> 
mv.visitIntInsn(Opcodes.ALOAD, 0));
-            } else if (pexp.getObjectExpression() instanceof ClassExpression 
&& "this".equals(pexp.getPropertyAsString())) {
-                ClassExpression ce = (ClassExpression) 
pexp.getObjectExpression();
-                if (ce.getType().isInterface()) {
-                    return bytecodeX(pexp.getObjectExpression().getType(), mv 
-> mv.visitIntInsn(Opcodes.ALOAD, 0));
+    private Expression correctReceiverForInterfaceCall(final Expression 
receiver) {
+        if (receiver instanceof PropertyExpression) {
+            PropertyExpression pexp = (PropertyExpression) receiver;
+            if (pexp.getObjectExpression() instanceof ClassExpression
+                     && pexp.getProperty() instanceof ConstantExpression) {
+                String name = pexp.getProperty().getText();
+                ClassNode type = pexp.getObjectExpression().getType();
+                if ((name.equals("this") || name.equals("super")) && 
type.isInterface()) {
+                    return bytecodeX(type, mv -> 
mv.visitIntInsn(Opcodes.ALOAD, 0)); // load this with type
                 }
             }
         }
-        return exp;
+        return receiver;
     }
 
     private static int getMethodCallFlags(final MethodCallerMultiAdapter 
adapter, final boolean safe, final boolean spread) {
diff --git a/src/test/gls/innerClass/InnerClassTest.groovy 
b/src/test/gls/innerClass/InnerClassTest.groovy
index 0d72798d9b..d834cb11e3 100644
--- a/src/test/gls/innerClass/InnerClassTest.groovy
+++ b/src/test/gls/innerClass/InnerClassTest.groovy
@@ -1272,6 +1272,30 @@ final class InnerClassTest {
         '''
     }
 
+    // GROOVY-11611
+    @Test
+    void testUsageOfOuterMethodOverridden3() {
+        assertScript '''
+            class C {
+                String value() { 'C' }
+                static class D extends C {
+                    @Override
+                    String value() {
+                        super.value() + 'D'
+                    }
+                    final class B {
+                        def m() {
+                            'B' + D.super.value()
+                        }
+                    }
+                }
+            }
+            def d = new C.D()
+            def b = new C.D.B(d)
+            assert b.m() == 'BC'
+        '''
+    }
+
     @Test
     void testUsageOfOuterType() {
         assertScript '''

Reply via email to