You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by em...@apache.org on 2020/07/14 17:30:10 UTC

[groovy] branch GROOVY-8999_backport created (now 7bc2675)

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

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


      at 7bc2675  GROOVY-8999: super.@x should fail for private fields; no get workarounds

This branch includes the following new commits:

     new 7bc2675  GROOVY-8999: super.@x should fail for private fields; no get workarounds

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



[groovy] 01/01: GROOVY-8999: super.@x should fail for private fields; no get workarounds

Posted by em...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 7bc26759f23cdfcb5a7c3ddd17964ae3e8e4af6c
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Tue Jul 14 12:22:59 2020 -0500

    GROOVY-8999: super.@x should fail for private fields; no get workarounds
---
 .../groovy/classgen/AsmClassGenerator.java         |   6 +-
 .../groovy/classgen/asm/InvocationWriter.java      |  17 ++-
 .../transform/stc/StaticTypeCheckingVisitor.java   | 133 ++++++++++-----------
 src/test/groovy/ThisAndSuperTest.groovy            | 117 ++++++++++++------
 .../stc/FieldsAndPropertiesSTCTest.groovy          | 113 ++++++++++++-----
 .../stc/TypeCheckingExtensionsTest.groovy          |   3 +-
 .../classgen/asm/sc/bugs/Groovy7300Bug.groovy      |  96 ++++++++-------
 7 files changed, 296 insertions(+), 189 deletions(-)

diff --git a/src/main/java/org/codehaus/groovy/classgen/AsmClassGenerator.java b/src/main/java/org/codehaus/groovy/classgen/AsmClassGenerator.java
index 2fea225..4887026 100644
--- a/src/main/java/org/codehaus/groovy/classgen/AsmClassGenerator.java
+++ b/src/main/java/org/codehaus/groovy/classgen/AsmClassGenerator.java
@@ -183,7 +183,7 @@ public class AsmClassGenerator extends ClassGenerator {
     private final Map genericParameterNames;
     private final SourceUnit source;
     private WriterController controller;
-    
+
     public AsmClassGenerator(
             SourceUnit source, GeneratorContext context,
             ClassVisitor classVisitor, String sourceFile
@@ -1039,7 +1039,7 @@ public class AsmClassGenerator extends ClassGenerator {
                     fieldX(field).visit(this);
                     return;
                 }
-                if (isSuperExpression(objectExpression)) {
+                if (isSuperExpression(objectExpression) && !(expression instanceof AttributeExpression)) {
                     if (controller.getCompileStack().isLHS()) {
                         setPropertyOfSuperClass(classNode, expression, mv);
                     } else {
@@ -2208,7 +2208,7 @@ public class AsmClassGenerator extends ClassGenerator {
         return false;
     }
 
-    private static boolean isSuperExpression(Expression expression) {
+    public static boolean isSuperExpression(Expression expression) {
         if (expression instanceof VariableExpression) {
             VariableExpression varExp = (VariableExpression) expression;
             return varExp.getName().equals("super");
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 79e9946..1e7741e 100644
--- a/src/main/java/org/codehaus/groovy/classgen/asm/InvocationWriter.java
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/InvocationWriter.java
@@ -132,10 +132,19 @@ public class InvocationWriter {
             MethodCallerMultiAdapter adapter,
             boolean safe, boolean spreadSafe, boolean implicitThis
     ) {
-        ClassNode cn = controller.getClassNode();
-        if (controller.isInClosure() && !implicitThis && AsmClassGenerator.isThisExpression(receiver)) cn=cn.getOuterClass();
-        makeCall(origin, new ClassExpression(cn), receiver, message, arguments,
-                adapter, safe, spreadSafe, implicitThis);
+        ClassNode sender = controller.getClassNode();
+        if (AsmClassGenerator.isSuperExpression(receiver) || (AsmClassGenerator.isThisExpression(receiver) && !implicitThis)) {
+            while (sender.getOuterClass() != null && sender.getSuperClass() == ClassHelper.CLOSURE_TYPE) {
+                sender = sender.getOuterClass();
+            }
+            if (AsmClassGenerator.isSuperExpression(receiver)) {
+                sender = sender.getSuperClass(); // GROOVY-4035
+                implicitThis = false; // prevent recursion
+                safe = false; // GROOVY-6045
+            }
+        }
+
+        makeCall(origin, new ClassExpression(sender), receiver, message, arguments, adapter, safe, spreadSafe, implicitThis);
     }
     
     protected boolean writeDirectMethodCall(MethodNode target, boolean implicitThis,  Expression receiver, TupleExpression args) {
diff --git a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
index 89ed0c4..6317fa5 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -193,7 +193,6 @@ import static org.codehaus.groovy.ast.tools.WideningCategories.isLongCategory;
 import static org.codehaus.groovy.ast.tools.WideningCategories.isNumberCategory;
 import static org.codehaus.groovy.ast.tools.WideningCategories.lowestUpperBound;
 import static org.codehaus.groovy.classgen.AsmClassGenerator.MINIMUM_BYTECODE_VERSION;
-import static org.codehaus.groovy.classgen.AsmClassGenerator.isNullConstant;
 import static org.codehaus.groovy.runtime.DefaultGroovyMethods.asBoolean;
 import static org.codehaus.groovy.syntax.Types.ASSIGN;
 import static org.codehaus.groovy.syntax.Types.ASSIGNMENT_OPERATOR;
@@ -760,11 +759,10 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
 
     @Override
     public void visitAttributeExpression(final AttributeExpression expression) {
-        super.visitAttributeExpression(expression);
         if (!existsProperty(expression, true) && !extension.handleUnresolvedAttribute(expression)) {
             Expression objectExpression = expression.getObjectExpression();
-            addStaticTypeError("No such property: " + expression.getPropertyAsString() +
-                    " for class: " + findCurrentInstanceOfClass(objectExpression, objectExpression.getType()), expression);
+            addStaticTypeError("No such attribute: " + expression.getPropertyAsString() +
+                    " for class: " + findCurrentInstanceOfClass(objectExpression, getType(objectExpression)).toString(false), expression);
         }
     }
 
@@ -1418,15 +1416,14 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
         if (propertyName == null) return false;
 
         Expression objectExpression = pexp.getObjectExpression();
-        final ClassNode objectExpressionType = getType(objectExpression);
-
+        ClassNode objectExpressionType = getType(objectExpression);
+        List<ClassNode> enclosingTypes = typeCheckingContext.getEnclosingClassNodes();
         boolean staticOnlyAccess = isClassClassNodeWrappingConcreteType(objectExpressionType);
         if ("this".equals(propertyName) && staticOnlyAccess) {
             // Outer.this for any level of nesting
             ClassNode outerNode = objectExpressionType.getGenericsTypes()[0].getType();
-            List<ClassNode> candidates = typeCheckingContext.getEnclosingClassNodes();
             ClassNode found = null;
-            for (ClassNode current : candidates) {
+            for (ClassNode current : enclosingTypes) {
                 if (!current.isStaticClass() && current instanceof InnerClassNode && outerNode.equals(current.getOuterClass())) {
                     found = current;
                     break;
@@ -1447,30 +1444,34 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
         boolean isAttributeExpression = pexp instanceof AttributeExpression;
         HashSet<ClassNode> handledNodes = new HashSet<ClassNode>();
         for (Receiver<String> receiver : receivers) {
-            ClassNode testClass = receiver.getType();
+            ClassNode receiverType = receiver.getType();
 
-            if (testClass.isArray() && "length".equals(propertyName)) {
+            if (receiverType.isArray() && "length".equals(propertyName)) {
                 storeType(pexp, int_TYPE);
                 if (visitor != null) {
-                    PropertyNode length = new PropertyNode("length", Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL, int_TYPE, testClass, null, null, null);
+                    PropertyNode length = new PropertyNode("length", Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL, int_TYPE, receiverType, null, null, null);
                     visitor.visitProperty(length);
                 }
                 return true;
             }
 
             LinkedList<ClassNode> queue = new LinkedList<>();
-            queue.add(testClass);
-            if (isPrimitiveType(testClass)) {
-                queue.add(getWrapper(testClass));
+            queue.add(receiverType);
+            if (isPrimitiveType(receiverType)) {
+                queue.add(getWrapper(receiverType));
             }
             while (!queue.isEmpty()) {
                 ClassNode current = queue.removeFirst();
-                if (handledNodes.contains(current)) continue;
-                handledNodes.add(current);
-                Set<ClassNode> allInterfaces = current.getAllInterfaces();
-                for (ClassNode intf : allInterfaces) {
-                    //TODO: apply right generics here!
-                    queue.add(GenericsUtils.parameterizeType(current, intf));
+                if (!handledNodes.add(current)) continue;
+
+                FieldNode field = current.getDeclaredField(propertyName);
+                if (field == null) {
+                    if (current.getSuperClass() != null) {
+                        queue.addFirst(current.getUnresolvedSuperClass());
+                    }
+                    for (ClassNode face : current.getAllInterfaces()) {
+                        queue.add(GenericsUtils.parameterizeType(current, face));
+                    }
                 }
 
                 // in case of a lookup on Class we look for instance methods on Class
@@ -1482,10 +1483,9 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
                 } else {
                     staticOnly = staticOnlyAccess;
                 }
-
-                FieldNode field = current.getDeclaredField(propertyName);
                 field = allowStaticAccessToMember(field, staticOnly);
 
+                // GROOVY-9288, GROOVY-9292, GROOVY-9293
                 if (null != field) {
                     int fieldModifiers = field.getModifiers();
                     if (Modifier.isProtected(fieldModifiers) || isPackagePrivate(fieldModifiers)) {
@@ -1495,17 +1495,21 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
                     }
                 }
 
-                if (storeField(field, isAttributeExpression, pexp, current, visitor, receiver.getData(), !readMode)) {
+                // skip property/accessor checks for "x.@field"
+                if (storeField(field, isAttributeExpression, pexp, receiverType, visitor, receiver.getData(), !readMode)) {
                     pexp.removeNodeMetaData(READONLY_PROPERTY);
                     return true;
+                } else if (isAttributeExpression) {
+                    continue;
                 }
 
-                boolean isThisExpression = objectExpression instanceof VariableExpression
-                        && ((VariableExpression) objectExpression).isThisExpression()
-                        && objectExpressionType.equals(current);
-
-                if (storeField(field, isThisExpression, pexp, receiver.getType(), visitor, receiver.getData(), !readMode))
+                // skip property/accessor checks for "field", "this.field", "this.with { field }", etc. in declaring class of field
+                if (storeField(field, enclosingTypes.contains(current), pexp, receiverType, visitor, receiver.getData(), !readMode)) {
+                    pexp.removeNodeMetaData(READONLY_PROPERTY);
                     return true;
+                }
+
+                boolean isThisExpression = enclosingTypes.contains(receiverType);
 
                 MethodNode getter = findGetter(current, "get" + capName, pexp.isImplicitThis());
                 getter = allowStaticAccessToMember(getter, staticOnly);
@@ -1515,13 +1519,12 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
                 List<MethodNode> setters = findSetters(current, setterName, false);
                 setters = allowStaticAccessToMember(setters, staticOnly);
 
-                // TODO: remove this visit
                 // need to visit even if we only look for a setters for compatibility
                 if (visitor != null && getter != null) visitor.visitMethod(getter);
 
                 PropertyNode propertyNode = current.getProperty(propertyName);
                 propertyNode = allowStaticAccessToMember(propertyNode, staticOnly);
-                //prefer explicit getter or setter over property if receiver is not 'this'
+                // prefer explicit getter or setter over property if receiver is not 'this'
                 boolean checkGetterOrSetter = !isThisExpression || propertyNode == null;
 
                 if (readMode && checkGetterOrSetter) {
@@ -1548,8 +1551,6 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
                                 }
                             }
                         }
-                        //TODO: apply generics on parameter[0]?
-//                                storeType(pexp, setter.getParameters()[0].getType());
                         SetterInfo info = new SetterInfo(current, setterName, setters);
                         BinaryExpression enclosingBinaryExpression = typeCheckingContext.getEnclosingBinaryExpression();
                         if (enclosingBinaryExpression != null) {
@@ -1560,26 +1561,25 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
                             pexp.putNodeMetaData(IMPLICIT_RECEIVER, delegationData);
                         }
                         return true;
-                    } else if (getter != null && propertyNode == null) {
-                        pexp.putNodeMetaData(READONLY_PROPERTY, true);
+                    } else if (propertyNode == null) {
+                        if (field != null && hasAccessToField(field, typeCheckingContext.getEnclosingClassNode())) {
+                            pexp.removeNodeMetaData(READONLY_PROPERTY);
+                        } else if (getter != null) {
+                            pexp.putNodeMetaData(READONLY_PROPERTY, Boolean.TRUE);
+                        }
                     }
                 }
-                foundGetterOrSetter = foundGetterOrSetter || !setters.isEmpty() || getter != null;
+                foundGetterOrSetter = (foundGetterOrSetter || !setters.isEmpty() || getter != null);
 
-                if (storeProperty(propertyNode, pexp, current, visitor, receiver.getData())) return true;
+                if (storeProperty(propertyNode, pexp, receiverType, visitor, receiver.getData())) return true;
 
-                if (storeField(field, true, pexp, current, visitor, receiver.getData(), !readMode)) return true;
-                // if the property expression is an attribute expression (o.@attr), then
-                // we stop now, otherwise we must check the parent class
-                if (/*!isAttributeExpression && */current.getSuperClass() != null) {
-                    queue.add(current.getUnresolvedSuperClass());
-                }
+                if (storeField(field, true, pexp, receiverType, visitor, receiver.getData(), !readMode)) return true;
             }
 
             // GROOVY-5568: the property may be defined by DGM
             List<ClassNode> dgmReceivers = new ArrayList<ClassNode>(2);
-            dgmReceivers.add(testClass);
-            if (isPrimitiveType(testClass)) dgmReceivers.add(getWrapper(testClass));
+            dgmReceivers.add(receiverType);
+            if (isPrimitiveType(receiverType)) dgmReceivers.add(getWrapper(receiverType));
             for (ClassNode dgmReceiver : dgmReceivers) {
                 List<MethodNode> methods = findDGMMethodsByNameAndArguments(getTransformLoader(), dgmReceiver, "get" + capName, ClassNode.EMPTY_ARRAY);
                 for (MethodNode m : findDGMMethodsByNameAndArguments(getTransformLoader(), dgmReceiver, "is" + capName, ClassNode.EMPTY_ARRAY)) {
@@ -1601,17 +1601,17 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
             }
 
             // GROOVY-7996: check if receiver implements get(String)/set(String,Object) or propertyMissing(String)
-            if (!testClass.isArray() && !isPrimitiveType(getUnwrapper(testClass))
+            if (!receiverType.isArray() && !isPrimitiveType(getUnwrapper(receiverType))
                     && pexp.isImplicitThis() && typeCheckingContext.getEnclosingClosure() != null) {
                 MethodNode mopMethod;
                 if (readMode) {
-                    mopMethod = testClass.getMethod("get", new Parameter[]{new Parameter(STRING_TYPE, "name")});
+                    mopMethod = receiverType.getMethod("get", new Parameter[]{new Parameter(STRING_TYPE, "name")});
                 } else {
-                    mopMethod = testClass.getMethod("set", new Parameter[]{new Parameter(STRING_TYPE, "name"), new Parameter(OBJECT_TYPE, "value")});
+                    mopMethod = receiverType.getMethod("set", new Parameter[]{new Parameter(STRING_TYPE, "name"), new Parameter(OBJECT_TYPE, "value")});
                 }
-                if (mopMethod == null) mopMethod = testClass.getMethod("propertyMissing", new Parameter[]{new Parameter(STRING_TYPE, "propertyName")});
+                if (mopMethod == null) mopMethod = receiverType.getMethod("propertyMissing", new Parameter[]{new Parameter(STRING_TYPE, "propertyName")});
 
-                if (mopMethod != null) {
+                if (mopMethod != null && !mopMethod.isSynthetic()) {
                     pexp.putNodeMetaData(StaticTypesMarker.DYNAMIC_RESOLUTION, Boolean.TRUE);
                     pexp.removeNodeMetaData(DECLARATION_INFERRED_TYPE);
                     pexp.removeNodeMetaData(INFERRED_TYPE);
@@ -1621,16 +1621,15 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
         }
 
         for (Receiver<String> receiver : receivers) {
-            ClassNode testClass = receiver.getType();
-            ClassNode propertyType = getTypeForMapPropertyExpression(testClass, objectExpressionType, pexp);
+            ClassNode receiverType = receiver.getType();
+            ClassNode propertyType = getTypeForMapPropertyExpression(receiverType, objectExpressionType, pexp);
             if (propertyType == null)
-                propertyType = getTypeForListPropertyExpression(testClass, objectExpressionType, pexp);
-            if (propertyType == null) propertyType = getTypeForSpreadExpression(testClass, objectExpressionType, pexp);
+                propertyType = getTypeForListPropertyExpression(receiverType, objectExpressionType, pexp);
+            if (propertyType == null) propertyType = getTypeForSpreadExpression(receiverType, objectExpressionType, pexp);
             if (propertyType == null) continue;
             if (visitor != null) {
-                // todo : type inference on maps and lists, if possible
-                PropertyNode node = new PropertyNode(propertyName, Opcodes.ACC_PUBLIC, propertyType, receiver.getType(), null, null, null);
-                node.setDeclaringClass(receiver.getType());
+                PropertyNode node = new PropertyNode(propertyName, Opcodes.ACC_PUBLIC, propertyType, receiverType, null, null, null);
+                node.setDeclaringClass(receiverType);
                 visitor.visitProperty(node);
             }
             storeType(pexp, propertyType);
@@ -1638,6 +1637,7 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
             if (delegationData != null) pexp.putNodeMetaData(IMPLICIT_RECEIVER, delegationData);
             return true;
         }
+
         return foundGetterOrSetter;
     }
 
@@ -1646,13 +1646,11 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
     }
 
     private static boolean hasAccessToField(FieldNode field, ClassNode objectExpressionType) {
-        if (field != null) {
-            if (field.isPublic() || field.isProtected()) {
-                return true;
-            }
-            if (!field.isPrivate() && Objects.equals(objectExpressionType.getPackageName(), field.getDeclaringClass().getPackageName())) {
-                return true;
-            }
+        if (field.isPublic() || field.isProtected()) {
+            return true;
+        }
+        if (!field.isPrivate() && Objects.equals(objectExpressionType.getPackageName(), field.getDeclaringClass().getPackageName())) {
+            return true;
         }
         return false;
     }
@@ -1835,7 +1833,6 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
                 String setterName = "set" + capName;
                 List<MethodNode> setterMethods = findSetters(current, setterName, false);
                 if (!setterMethods.isEmpty()) {
-//                    storeType(pexp, setterMethod.getParameters()[0].getType());
                     return new SetterInfo(current, setterName, setterMethods);
                 }
                 if (!isAttributeExpression && current.getSuperClass() != null) {
@@ -3277,7 +3274,7 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
             boolean callArgsVisited = false;
             if (isCallOnClosure) {
                 // this is a closure.call() call
-                if (objectExpression == VariableExpression.THIS_EXPRESSION) {
+                if (objectExpression instanceof VariableExpression && ((VariableExpression) objectExpression).isThisExpression()) {
                     // isClosureCall() check verified earlier that a field exists
                     FieldNode field = typeCheckingContext.getEnclosingClassNode().getDeclaredField(name);
                     GenericsType[] genericsTypes = field.getType().getGenericsTypes();
@@ -3676,7 +3673,7 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
     protected boolean isClosureCall(final String name, final Expression objectExpression, final Expression arguments) {
         if (objectExpression instanceof ClosureExpression && ("call".equals(name) || "doCall".equals(name)))
             return true;
-        if (objectExpression == VariableExpression.THIS_EXPRESSION) {
+        if (objectExpression instanceof VariableExpression && ((VariableExpression) objectExpression).isThisExpression()) {
             FieldNode fieldNode = typeCheckingContext.getEnclosingClassNode().getDeclaredField(name);
             if (fieldNode != null) {
                 ClassNode type = fieldNode.getType();
@@ -4688,8 +4685,8 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
             final VariableExpression vexp = (VariableExpression) exp;
             ClassNode selfTrait = isTraitSelf(vexp);
             if (selfTrait != null) return makeSelf(selfTrait);
-            if (vexp == VariableExpression.THIS_EXPRESSION) return makeThis();
-            if (vexp == VariableExpression.SUPER_EXPRESSION) return makeSuper();
+            if (vexp.isThisExpression()) return makeThis();
+            if (vexp.isSuperExpression()) return makeSuper();
             final Variable variable = vexp.getAccessedVariable();
             if (variable instanceof FieldNode) {
                 FieldNode fieldNode = (FieldNode) variable;
diff --git a/src/test/groovy/ThisAndSuperTest.groovy b/src/test/groovy/ThisAndSuperTest.groovy
index c71e895..4513f53 100644
--- a/src/test/groovy/ThisAndSuperTest.groovy
+++ b/src/test/groovy/ThisAndSuperTest.groovy
@@ -18,20 +18,28 @@
  */
 package groovy
 
-class ThisAndSuperTest extends GroovyTestCase {
+import org.junit.Test
+
+import static groovy.test.GroovyAssert.assertScript
+import static groovy.test.GroovyAssert.shouldFail
+
+final class ThisAndSuperTest {
+
+    @Test
     void testOverwrittenSuperMethod() {
         def helper = new TestForSuperHelper2()
         assert helper.foo() == 2
         assert helper.callFooInSuper() == 1
     }
 
+    @Test
     void testClosureUsingSuperAndThis() {
         def helper = new TestForSuperHelper2()
         assert helper.aClosureUsingThis() == 2
         assert helper.aClosureUsingSuper() == 1
         // accessing private method should not be changed
         // by a public method of the same name and signature!
-        assertEquals "bar", helper.closureUsingPrivateMethod()
+        assert helper.closureUsingPrivateMethod() == "bar"
         assert helper.bar() == "no bar"
 
         assert helper.aField == "I am a field"
@@ -41,6 +49,7 @@ class ThisAndSuperTest extends GroovyTestCase {
         assert helper.aField == 2
     }
 
+    @Test
     void testClosureDelegateAndThis() {
         def map = [:]
         def helper = new TestForSuperHelper2()
@@ -76,6 +85,7 @@ class ThisAndSuperTest extends GroovyTestCase {
         assert map.foo == 1
     }
 
+    @Test
     void testConstructorChain() {
         def helper = new TestForSuperHelper4()
         assert helper.x == 1
@@ -83,6 +93,7 @@ class ThisAndSuperTest extends GroovyTestCase {
         assert helper.x == "Object"
     }
 
+    @Test
     void testChainingForAsType() {
         def helper = new TestForSuperHelper1()
         def ret = helper as Object[]
@@ -94,43 +105,83 @@ class ThisAndSuperTest extends GroovyTestCase {
         }
     }
 
+    @Test
     void testSuperEach() {
         def x = new TestForSuperEach()
         x.each {
             x.res << "I am it: ${it.class.name}"
         }
 
-        assertEquals 3, x.res.size()
-        assertEquals "start each in subclass", x.res[0]
-        assertEquals "I am it: groovy.TestForSuperEach", x.res[1]
-        assertEquals "end of each in subclass", x.res[2]
-    }
-
-// GROOVY-2555
-//    void testCallToAbstractSuperMethodShouldResultInMissingMethod () {
-//        def x = new TestForSuperHelper6()
-//        shouldFail(MissingMethodException) {
-//            x.theMethod()
-//        }
-//    }
-
-    void testDgm() {
-        assertEquals A.empty(), '123'
+        assert x.res.size() == 3
+        assert x.res[0] == "start each in subclass"
+        assert x.res[1] == "I am it: groovy.TestForSuperEach"
+        assert x.res[2] == "end of each in subclass"
     }
 
+    @Test // GROOVY-2555
     void testAbstractSuperMethodShouldBeTreatedLikeMissingMethod() {
-        shouldFail(MissingMethodException) {
-            new TestForSuperHelper6().theMethod()
-        }
-    }
-}
-
-class A {
-    static {
-        A.metaClass.static.empty << {-> '123' }
+        shouldFail MissingMethodException, '''
+            abstract class A {
+                abstract void m()
+            }
+            class B extends A {
+                void m() {
+                    super.m()
+                }
+            }
+            new B().m()
+        '''
+    }
+
+    @Test // GROOVY-8999
+    void testPrivateSuperField1() {
+        def err = shouldFail MissingFieldException, '''
+            abstract class A {
+                private x = 1
+                def getX() { 2 }
+            }
+            class B extends A {
+                private x = 3
+                def m() { super.@x }
+            }
+            assert new B().m() == 1
+        '''
+
+        assert err =~ /No such field: x for class: A/
+    }
+
+    @Test // GROOVY-8999
+    void testPrivateSuperField2() {
+        def err = shouldFail MissingFieldException, '''
+            abstract class A {
+                private x = 1
+                def getX() { 2 }
+                void setX(x) { this.x = 3 }
+            }
+            class B extends A {
+                private x = 4
+                def m() { super.@x = 5; return x }
+            }
+            assert new B().m() == 2
+        '''
+
+        assert err =~ /No such field: x for class: A/
+    }
+
+    // https://github.com/apache/groovy/commit/b62e4d3165b4d899a3b6c71dba2858c9362b2e1b
+    @Test // TODO: Does this belong in another test suite?
+    void testStaticMetaClassClosure() {
+        assertScript '''
+            class A {
+            }
+            A.metaClass.static.something << { -> '123' }
+
+            assert A.something() == '123'
+        '''
     }
 }
 
+//------------------------------------------------------------------------------
 
 class TestForSuperEach {
     def res = []
@@ -191,14 +242,4 @@ class TestForSuperHelper4 extends TestForSuperHelper3 {
     TestForSuperHelper4(Object j) {
         super(j)
     }
-}
-
-abstract class TestForSuperHelper5 {
-    abstract void theMethod()
-}
-
-class TestForSuperHelper6 extends TestForSuperHelper5 {
-    void theMethod() {
-        super.theMethod()
-    }
-}
+}
\ No newline at end of file
diff --git a/src/test/groovy/transform/stc/FieldsAndPropertiesSTCTest.groovy b/src/test/groovy/transform/stc/FieldsAndPropertiesSTCTest.groovy
index 20e7b9c..1b9dd86 100644
--- a/src/test/groovy/transform/stc/FieldsAndPropertiesSTCTest.groovy
+++ b/src/test/groovy/transform/stc/FieldsAndPropertiesSTCTest.groovy
@@ -18,6 +18,8 @@
  */
 package groovy.transform.stc
 
+import groovy.transform.NotYetImplemented
+
 /**
  * Unit tests for static type checking : fields and properties.
  */
@@ -99,14 +101,14 @@ class FieldsAndPropertiesSTCTest extends StaticTypeCheckingTestCase {
         '''
     }
 
-    void testShouldComplainAboutMissingField() {
+    void testShouldComplainAboutMissingProperty() {
         shouldFailWithMessages '''
             Object o = new Object()
             o.x = 0
         ''', 'No such property: x for class: java.lang.Object'
     }
 
-    void testShouldComplainAboutMissingField2() {
+    void testShouldComplainAboutMissingProperty2() {
         shouldFailWithMessages '''
             class A {
             }
@@ -115,19 +117,73 @@ class FieldsAndPropertiesSTCTest extends StaticTypeCheckingTestCase {
         ''', 'No such property: x for class: A'
     }
 
-    void testFieldWithInheritance() {
+    void testShouldComplainAboutMissingAttribute() {
+        shouldFailWithMessages '''
+            Object o = new Object()
+            o.@x = 0
+        ''', 'No such attribute: x for class: java.lang.Object'
+    }
+
+    void testShouldComplainAboutMissingAttribute2() {
+        shouldFailWithMessages '''
+            class A {
+            }
+            A a = new A()
+            a.@x = 0
+        ''', 'No such attribute: x for class: A'
+    }
+
+    void testShouldComplainAboutMissingAttribute3() {
+        shouldFailWithMessages '''
+            class A {
+                def getX() { }
+            }
+            A a = new A()
+            println a.@x
+        ''', 'No such attribute: x for class: A'
+    }
+
+    void testShouldComplainAboutMissingAttribute4() {
+        shouldFailWithMessages '''
+            class A {
+                def setX(x) { }
+            }
+            A a = new A()
+            a.@x = 0
+        ''', 'No such attribute: x for class: A'
+    }
+
+    @NotYetImplemented
+    void testShouldComplainAboutMissingAttribute5() {
+        shouldFailWithMessages '''
+            class A {
+                private x
+            }
+            class B extends A {
+                void test() {
+                    this.@x
+                }
+            }
+        ''', 'The field A.x is not accessible'
+    }
+
+    void testPropertyWithInheritance() {
         assertScript '''
             class A {
                 int x
             }
             class B extends A {
             }
+
             B b = new B()
+            assert b.x == 0
+
             b.x = 2
+            assert b.x == 2
         '''
     }
 
-    void testFieldTypeWithInheritance() {
+    void testPropertyTypeWithInheritance() {
         shouldFailWithMessages '''
             class A {
                 int x
@@ -139,7 +195,7 @@ class FieldsAndPropertiesSTCTest extends StaticTypeCheckingTestCase {
         ''', 'Cannot assign value of type java.lang.String to variable of type int'
     }
 
-    void testFieldWithInheritanceFromAnotherSourceUnit() {
+    void testPropertyWithInheritanceFromAnotherSourceUnit() {
         assertScript '''
             class B extends groovy.transform.stc.FieldsAndPropertiesSTCTest.BaseClass {
             }
@@ -148,7 +204,7 @@ class FieldsAndPropertiesSTCTest extends StaticTypeCheckingTestCase {
         '''
     }
 
-    void testFieldWithInheritanceFromAnotherSourceUnit2() {
+    void testPropertyWithInheritanceFromAnotherSourceUnit2() {
         shouldFailWithMessages '''
             class B extends groovy.transform.stc.FieldsAndPropertiesSTCTest.BaseClass {
             }
@@ -157,7 +213,7 @@ class FieldsAndPropertiesSTCTest extends StaticTypeCheckingTestCase {
         ''', 'Cannot assign value of type java.lang.String to variable of type int'
     }
 
-    void testFieldWithSuperInheritanceFromAnotherSourceUnit() {
+    void testPropertyWithSuperInheritanceFromAnotherSourceUnit() {
         assertScript '''
             class B extends groovy.transform.stc.FieldsAndPropertiesSTCTest.BaseClass2 {
             }
@@ -616,29 +672,30 @@ new FooWorker().doSomething()'''
     }
 
     void testShouldFailWithIncompatibleGenericTypes() {
-        shouldFailWithMessages '''public class Foo {
-
-    private List<String> names;
+        shouldFailWithMessages '''\
+            public class Foo {
+                private List<String> names;
 
-    public List<String> getNames() {
-        return names;
-    }
-
-    public void setNames(List<String> names) {
-        this.names = names;
-    }
-}
+                public List<String> getNames() {
+                    return names;
+                }
 
-class FooWorker {
+                public void setNames(List<String> names) {
+                    this.names = names;
+                }
+            }
 
-    public void doSomething() {
-        new Foo().with {
-            names = new ArrayList<Integer>()
-        }
-    }
-}
+            class FooWorker {
+                public void doSomething() {
+                    new Foo().with {
+                        names = new ArrayList<Integer>()
+                    }
+                }
+            }
 
-new FooWorker().doSomething()''', 'Cannot assign value of type java.util.ArrayList <Integer> to variable of type java.util.List <String>'
+            new FooWorker().doSomething()
+        ''',
+        'Cannot assign value of type java.util.ArrayList <Integer> to variable of type java.util.List <String>'
     }
 
     void testAICAsStaticProperty() {
@@ -804,7 +861,7 @@ import org.codehaus.groovy.ast.stmt.AssertStatement
     void testImplicitPropertyOfDelegateShouldNotPreferField() {
         assertScript '''
             Calendar.instance.with {
-                Date d1 = time
+                Date d1 = time // Date getTime() vs. long time
             }
         '''
     }
@@ -893,4 +950,4 @@ import org.codehaus.groovy.ast.stmt.AssertStatement
 
     static class BaseClass2 extends BaseClass {
     }
-}
+}
\ No newline at end of file
diff --git a/src/test/groovy/transform/stc/TypeCheckingExtensionsTest.groovy b/src/test/groovy/transform/stc/TypeCheckingExtensionsTest.groovy
index 2ae60e4..bb4793d 100644
--- a/src/test/groovy/transform/stc/TypeCheckingExtensionsTest.groovy
+++ b/src/test/groovy/transform/stc/TypeCheckingExtensionsTest.groovy
@@ -20,7 +20,6 @@ package groovy.transform.stc
 
 import org.codehaus.groovy.control.MultipleCompilationErrorsException
 import org.codehaus.groovy.control.customizers.ASTTransformationCustomizer
-import org.codehaus.groovy.transform.stc.GroovyTypeCheckingExtensionSupport
 
 /**
  * Units tests for type checking extensions.
@@ -235,7 +234,7 @@ class TypeCheckingExtensionsTest extends StaticTypeCheckingTestCase {
         extension = null
         shouldFailWithMessages '''
             'str'.@FOO
-        ''', 'No such property: FOO for class: java.lang.String'
+        ''', 'No such attribute: FOO for class: java.lang.String'
 
         extension = 'groovy/transform/stc/UnresolvedAttributeTestExtension.groovy'
         assertScript '''
diff --git a/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7300Bug.groovy b/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7300Bug.groovy
index 33a3cbd..d1af453 100644
--- a/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7300Bug.groovy
+++ b/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7300Bug.groovy
@@ -16,64 +16,68 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-
-
-
-
-
-
 package org.codehaus.groovy.classgen.asm.sc.bugs
 
+import groovy.transform.NotYetImplemented
 import groovy.transform.stc.StaticTypeCheckingTestCase
 import org.codehaus.groovy.classgen.asm.sc.StaticCompilationTestSupport
 
-class Groovy7300Bug extends StaticTypeCheckingTestCase implements StaticCompilationTestSupport {
-    void testShouldNotThrowStackOverflow() {
-        assertScript '''
-class A {
-    private String field1 = 'test'
+final class Groovy7300Bug extends StaticTypeCheckingTestCase implements StaticCompilationTestSupport {
 
-    String getField1() {
-        return this.field1
-   }
-}
-
-class B extends A {
-    @Override
-    String getField1() {
-        super.field1
+    void testUseSuperToBypassOverride1() {
+        assertScript '''
+            abstract class A {
+                protected x = 1
+                def getX() { 2 }
+            }
+            class B extends A {
+                @Override
+                def getX() { super.x }
+            }
+            assert new B().getX() == 1 // TODO: Why use A#x and not A#getX?
+        '''
     }
-}
-
-B b = new B()
 
-assert b.field1 == 'test'
-'''
+    void testUseSuperToBypassOverride1a() {
+        assertScript '''
+            abstract class A {
+                protected x = 1
+                def getX() { 2 }
+            }
+            class B extends A {
+                @Override
+                def getX() { super.@x }
+            }
+            assert new B().getX() == 1
+        '''
     }
 
-    void testShouldNotThrowStackOverflowWithSuper() {
+    void testUseSuperToBypassOverride2() {
         assertScript '''
-class A {
-    private String field1 = 'test'
-
-    void setField1(String val) { field1 = val }
-
-    String getField1() {
-        return this.field1
-   }
-}
-
-class B extends A {
-    @Override
-    String getField1() {
-        super.field1 = 'test 2'
-        super.field1
+            abstract class A {
+                private x = 1
+                def getX() { 2 }
+            }
+            class B extends A {
+                @Override
+                def getX() { super.x }
+            }
+            assert new B().getX() == 2
+        '''
     }
-}
-
-B b = new B()
 
-assert b.field1 == 'test 2'
-'''
+    @NotYetImplemented
+    void testUseSuperToBypassOverride2a() {
+        shouldFailWithMessages '''
+            abstract class A {
+                private x = 1
+                def getX() { 2 }
+            }
+            class B extends A {
+                @Override
+                def getX() { super.@x }
+            }
+            assert false
+        ''', 'The field A.x is not accessible'
     }
 }