This is an automated email from the ASF dual-hosted git repository. sunlan pushed a commit to branch GROOVY_3_0_X in repository https://gitbox.apache.org/repos/asf/groovy.git
commit 3c0bf68a30524ac8b1b3f4f2ae5fd875bda625fa Author: Eric Milles <eric.mil...@thomsonreuters.com> AuthorDate: Sat May 23 11:34:20 2020 -0500 GROOVY-5259: refactor handling of "this" reference in special ctor call (cherry picked from commit ba576edfd82e557658224685564d0dfba8f5c43b) --- .../groovy/classgen/AsmClassGenerator.java | 65 ++++++++++------------ src/test/gls/innerClass/InnerClassTest.groovy | 28 +++++----- 2 files changed, 43 insertions(+), 50 deletions(-) diff --git a/src/main/java/org/codehaus/groovy/classgen/AsmClassGenerator.java b/src/main/java/org/codehaus/groovy/classgen/AsmClassGenerator.java index 2afa7a1..15fe90d 100644 --- a/src/main/java/org/codehaus/groovy/classgen/AsmClassGenerator.java +++ b/src/main/java/org/codehaus/groovy/classgen/AsmClassGenerator.java @@ -28,7 +28,6 @@ import org.codehaus.groovy.ast.ClassHelper; import org.codehaus.groovy.ast.ClassNode; import org.codehaus.groovy.ast.ConstructorNode; import org.codehaus.groovy.ast.FieldNode; -import org.codehaus.groovy.ast.GenericsType; import org.codehaus.groovy.ast.InnerClassNode; import org.codehaus.groovy.ast.InterfaceHelperClassNode; import org.codehaus.groovy.ast.MethodNode; @@ -1079,7 +1078,7 @@ public class AsmClassGenerator extends ClassGenerator { } else { field = classNode.getDeclaredField(name); if (field == null && !isValidFieldNodeForByteCodeAccess(classNode.getField(name), classNode)) { - // GROOVY-5259, GROOVY-9501, GROOVY-9569 + // GROOVY-9501, GROOVY-9569 if (checkStaticOuterField(expression, name)) return; } } @@ -1276,28 +1275,29 @@ public class AsmClassGenerator extends ClassGenerator { @Override public void visitVariableExpression(final VariableExpression expression) { - String variableName = expression.getName(); - - //----------------------------------------------------------------------- - // SPECIAL CASES - - // "this" for static methods is the Class instance - ClassNode classNode = controller.getClassNode(); + final String variableName = expression.getName(); if (expression.isThisExpression()) { - if (controller.isStaticMethod() || (!controller.getCompileStack().isImplicitThis() && controller.isStaticContext())) { - if (controller.isInGeneratedFunction()) classNode = controller.getOutermostClass(); - visitClassExpression(new ClassExpression(classNode)); + // "this" in static context is Class instance + if (controller.isStaticMethod() || controller.getCompileStack().isInSpecialConstructorCall() + || (!controller.getCompileStack().isImplicitThis() && controller.isStaticContext())) { + ClassNode thisType = controller.getClassNode(); + if (controller.isInGeneratedFunction()) { + do { thisType = thisType.getOuterClass(); + } while (ClassHelper.isGeneratedFunction(thisType)); + } + classX(thisType).visit(this); } else { loadThis(expression); } return; } - // "super" also requires special handling if (expression.isSuperExpression()) { + // "super" in static context is Class instance if (controller.isStaticMethod()) { - visitClassExpression(new ClassExpression(classNode.getSuperClass())); + ClassNode superType = controller.getClassNode().getSuperClass(); + classX(superType).visit(this); } else { loadThis(expression); } @@ -1305,11 +1305,22 @@ public class AsmClassGenerator extends ClassGenerator { } BytecodeVariable variable = controller.getCompileStack().getVariable(variableName, false); - if (variable == null) { - processClassVariable(expression); - } else { + if (variable != null) { controller.getOperandStack().loadOrStoreVariable(variable, expression.isUseReferenceDirectly()); + } else if (passingParams && controller.isInScriptBody()) { + MethodVisitor mv = controller.getMethodVisitor(); + mv.visitTypeInsn(NEW, "org/codehaus/groovy/runtime/ScriptReference"); + mv.visitInsn(DUP); + loadThisOrOwner(); + mv.visitLdcInsn(variableName); + mv.visitMethodInsn(INVOKESPECIAL, "org/codehaus/groovy/runtime/ScriptReference", "<init>", "(Lgroovy/lang/Script;Ljava/lang/String;)V", false); + } else { + PropertyExpression pexp = thisPropX(true, variableName); + pexp.getObjectExpression().setSourcePosition(expression); + pexp.getProperty().setSourcePosition(expression); + pexp.visit(this); } + if (!controller.getCompileStack().isLHS()) { controller.getAssertionWriter().record(expression); } @@ -1332,26 +1343,6 @@ public class AsmClassGenerator extends ClassGenerator { } } - private void processClassVariable(final VariableExpression expression) { - if (passingParams && controller.isInScriptBody()) { - // TODO: check if this part is actually used - MethodVisitor mv = controller.getMethodVisitor(); - // create a ScriptReference to pass into the closure - mv.visitTypeInsn(NEW, "org/codehaus/groovy/runtime/ScriptReference"); - mv.visitInsn(DUP); - - loadThisOrOwner(); - mv.visitLdcInsn(expression.getName()); - - mv.visitMethodInsn(INVOKESPECIAL, "org/codehaus/groovy/runtime/ScriptReference", "<init>", "(Lgroovy/lang/Script;Ljava/lang/String;)V", false); - } else { - PropertyExpression pexp = thisPropX(true, expression.getName()); - pexp.getObjectExpression().setSourcePosition(expression); - pexp.getProperty().setSourcePosition(expression); - visitPropertyExpression(pexp); - } - } - protected void createInterfaceSyntheticStaticFields() { ClassNode icl = controller.getInterfaceClassLoadingClass(); diff --git a/src/test/gls/innerClass/InnerClassTest.groovy b/src/test/gls/innerClass/InnerClassTest.groovy index ee7c0d7..c07bcbc 100644 --- a/src/test/gls/innerClass/InnerClassTest.groovy +++ b/src/test/gls/innerClass/InnerClassTest.groovy @@ -592,31 +592,33 @@ final class InnerClassTest { ''' } - /*@Test + @Test void testUsageOfOuterField_WrongCallToSuper() { shouldFail ''' - class InnerAccessOuter { + class Outer { protected static final String OUTER_CONSTANT = 'Constant Value' - class InnerClass { - InnerClass() { - // there's no Object#<init>(String) method, but it throws a VerifyError when a new instance - // is created, meaning a wrong super call is generated + class Inner { + Inner() { + // there is no Object#<init>(String) method, but it throws a VerifyError for uninitialized this super(OUTER_CONSTANT) } - String m() { - OUTER_CONSTANT + + String access() { + return OUTER_CONSTANT } } - void testInnerClassAccessOuter() { - def inner = new InnerClass() - inner.m() + void testInnerClassAccessOuterConst() { + def inner = new Inner() + inner.access() } } - new InnerAccessOuter().testInnerClassAccessOuter() + + def outer = new Outer() + outer.testInnerClassAccessOuterConst() ''' - }*/ + } @Test void testUsageOfOuterFieldOverridden() {