Repository: groovy Updated Branches: refs/heads/master e5e8fe1af -> ca4ffaac1
GROOVY-8474: 'Unexpected super property set for:' when accessing super class property via super.propertyName Project: http://git-wip-us.apache.org/repos/asf/groovy/repo Commit: http://git-wip-us.apache.org/repos/asf/groovy/commit/ca4ffaac Tree: http://git-wip-us.apache.org/repos/asf/groovy/tree/ca4ffaac Diff: http://git-wip-us.apache.org/repos/asf/groovy/diff/ca4ffaac Branch: refs/heads/master Commit: ca4ffaac1dfcaa8c38409a02b08392d0f8b2473f Parents: e5e8fe1 Author: sunlan <sun...@apache.org> Authored: Thu Feb 8 16:12:48 2018 +0800 Committer: sunlan <sun...@apache.org> Committed: Thu Feb 8 16:13:06 2018 +0800 ---------------------------------------------------------------------- .../groovy/classgen/AsmClassGenerator.java | 50 ++++- src/test/groovy/bugs/Groovy8474Bug.groovy | 220 +++++++++++++++++++ 2 files changed, 269 insertions(+), 1 deletion(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/groovy/blob/ca4ffaac/src/main/java/org/codehaus/groovy/classgen/AsmClassGenerator.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/codehaus/groovy/classgen/AsmClassGenerator.java b/src/main/java/org/codehaus/groovy/classgen/AsmClassGenerator.java index 4b7600f..1144b6e 100644 --- a/src/main/java/org/codehaus/groovy/classgen/AsmClassGenerator.java +++ b/src/main/java/org/codehaus/groovy/classgen/AsmClassGenerator.java @@ -1010,7 +1010,10 @@ public class AsmClassGenerator extends ClassGenerator { if (isSuperExpression(objectExpression)) { String prefix; if (controller.getCompileStack().isLHS()) { - throw new GroovyBugError("Unexpected super property set for:" + expression.getText()); + //throw new GroovyBugError("Unexpected super property set for:" + expression.getText()); + setSuperProperty(classNode, expression, mv); + + return; } else { prefix = "get"; } @@ -1082,6 +1085,51 @@ public class AsmClassGenerator extends ClassGenerator { } } + private void setSuperProperty(ClassNode classNode, PropertyExpression expression, MethodVisitor mv) { + String fieldName = expression.getPropertyAsString(); + FieldNode fieldNode = classNode.getSuperClass().getField(fieldName); + + if (null == fieldNode) { + throw new RuntimeParserException("Failed to find field[" + fieldName + "] of " + classNode.getName() + "'s super class", expression); + } + + if (fieldNode.isFinal()) { + throw new RuntimeParserException("Can not modify final field[" + fieldName + "] of " + classNode.getName() + "'s super class", expression); + } + + MethodNode setter = findSetter(classNode, fieldNode); + + if (fieldNode.isPrivate() && null == setter) { + throw new RuntimeParserException("Can not access private field[" + fieldName + "] of " + classNode.getName() + "'s super class", expression); + } + + mv.visitVarInsn(ALOAD, 0); + mv.visitInsn(SWAP); + + String owner = BytecodeHelper.getClassInternalName(classNode.getSuperClass().getName()); + String desc = BytecodeHelper.getTypeDescription(fieldNode.getType()); + if (fieldNode.isPublic() || fieldNode.isProtected()) { + mv.visitFieldInsn(PUTFIELD, owner, fieldName, desc); + } else { + mv.visitMethodInsn(INVOKESPECIAL, owner, setter.getName(), BytecodeHelper.getMethodDescriptor(setter), false); + } + } + + private MethodNode findSetter(ClassNode classNode, FieldNode fieldNode) { + String setMethodName = "set" + MetaClassHelper.capitalize(fieldNode.getName()); + MethodNode mn = classNode.getSuperClass().getMethod(setMethodName, new Parameter[] { new Parameter(fieldNode.getType(), "") }); + + if (null == mn) { + return null; + } + + if (!ClassHelper.VOID_TYPE.equals(mn.getReturnType())) { + return null; + } + + return mn; + } + private boolean isThisOrSuperInStaticContext(Expression objectExpression) { if (controller.isInClosure()) return false; return controller.isStaticContext() && isThisOrSuper(objectExpression); http://git-wip-us.apache.org/repos/asf/groovy/blob/ca4ffaac/src/test/groovy/bugs/Groovy8474Bug.groovy ---------------------------------------------------------------------- diff --git a/src/test/groovy/bugs/Groovy8474Bug.groovy b/src/test/groovy/bugs/Groovy8474Bug.groovy new file mode 100644 index 0000000..4438b24 --- /dev/null +++ b/src/test/groovy/bugs/Groovy8474Bug.groovy @@ -0,0 +1,220 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package groovy.bugs + +class Groovy8474Bug extends GroovyTestCase { + void testSettingSuperProperty() { + assertScript ''' + class T { + String group + } + + class S extends T { + S() { + super.group = 'Hello' + } + } + + assert 'Hello' == new S().group + ''' + } + + void testSettingSuperProperty2() { + assertScript ''' + class T { + String group + String group2 + String group3 + } + + class S extends T { + S() { + super.group = 'Hello' + super.group2 = 'Hello2' + super.group3 = 'Hello3' + } + } + + assert 'Hello' == new S().group + assert 'Hello2' == new S().group2 + assert 'Hello3' == new S().group3 + ''' + } + + void testSettingSuperProperty3() { + assertScript ''' + class K { + String group + } + class T extends K { + + } + class S extends T { + S() { + super.group = 'Hello' + } + } + + assert 'Hello' == new S().group + ''' + } + + void testSettingSuperProtectedField() { + assertScript ''' + class T { + protected String group + } + + class S extends T { + S() { + super.group = 'Hello' + } + } + + assert 'Hello' == new S().group + ''' + } + + void testSettingSuperProtectedField2() { + assertScript ''' + class T { + protected String group + protected String group2 + protected String group3 + } + + class S extends T { + S() { + super.group = 'Hello' + super.group2 = 'Hello2' + super.group3 = 'Hello3' + } + } + + assert 'Hello' == new S().group + assert 'Hello2' == new S().group2 + assert 'Hello3' == new S().group3 + ''' + } + + void testSettingSuperProtectedField3() { + assertScript ''' + class K { + protected String group + } + class T extends K { + + } + + class S extends T { + S() { + super.group = 'Hello' + } + } + + assert 'Hello' == new S().group + ''' + } + + void testSettingSuperPublicField() { + assertScript ''' + class T { + public String group + } + + class S extends T { + S() { + super.group = 'Hello' + } + } + + assert 'Hello' == new S().group + ''' + } + + void testSettingSuperPublicField2() { + assertScript ''' + class T { + public String group + public String group2 + public String group3 + } + + class S extends T { + S() { + super.group = 'Hello' + super.group2 = 'Hello2' + super.group3 = 'Hello3' + } + } + + assert 'Hello' == new S().group + assert 'Hello2' == new S().group2 + assert 'Hello3' == new S().group3 + ''' + } + + void testSettingSuperPublicField3() { + assertScript ''' + class K { + public String group + } + class T extends K { + + } + + class S extends T { + S() { + super.group = 'Hello' + } + } + + assert 'Hello' == new S().group + ''' + } + + void testSettingSuperPrivateProperty() { + def errMsg = shouldFail ''' + class T { + private String group + } + + class S extends T { + S() { + super.group = 'Hello' + } + } + ''' + assert errMsg.contains('Can not access private field') + } + + void testSettingSuperFinalProperty() { + shouldFail ''' + class T { + protected final String group = 'Hi' + } + + class S extends T { + S() { + super.group = 'Hello' + } + } + ''' + } +}