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 '''
