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