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

emilles pushed a commit to branch GROOVY_4_0_X
in repository https://gitbox.apache.org/repos/asf/groovy.git


The following commit(s) were added to refs/heads/GROOVY_4_0_X by this push:
     new cb145400f0 GROOVY-11356: STC: unlink variable expression from an 
inaccessible field
cb145400f0 is described below

commit cb145400f060b06c2a72f51f5a2ced94e2fca220
Author: Eric Milles <eric.mil...@thomsonreuters.com>
AuthorDate: Sat Apr 6 13:09:17 2024 -0500

    GROOVY-11356: STC: unlink variable expression from an inaccessible field
    
    4_0_X backport
---
 .../transform/stc/StaticTypeCheckingVisitor.java   | 41 ++++++++++++++------
 src/test/groovy/bugs/Groovy7165.groovy             |  4 +-
 src/test/groovy/bugs/Groovy9292.groovy             | 15 +++++---
 src/test/groovy/bugs/Groovy9293.groovy             |  7 ++--
 .../packageScope/DifferentPackageTest.groovy       | 44 +++++++++++-----------
 5 files changed, 66 insertions(+), 45 deletions(-)

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 b9107cae1d..a417fd1376 100644
--- 
a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ 
b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -631,18 +631,22 @@ public class StaticTypeCheckingVisitor extends 
ClassCodeVisitorSupport {
         } else if (accessedVariable instanceof FieldNode) {
             FieldNode accessedField = (FieldNode) accessedVariable;
             ClassNode temporaryType = getInferredTypeFromTempInfo(vexp, null); 
// GROOVY-9454
-            if (enclosingClosure != null) {
-                tryVariableExpressionAsProperty(vexp, name);
-            } else if (getOutermost(accessedField.getDeclaringClass()) == 
getOutermost(typeCheckingContext.getEnclosingClassNode())
-                    || !tryVariableExpressionAsProperty(vexp, name)) { // 
GROOVY-10981: check for property before super class field
-                checkOrMarkPrivateAccess(vexp, accessedField, 
typeCheckingContext.isTargetOfEnclosingAssignment(vexp));
-                if (temporaryType == null) storeType(vexp, getType(vexp));
-            }
-            if (temporaryType != null && !isObjectType(temporaryType)) {
-                vexp.putNodeMetaData(INFERRED_TYPE, temporaryType);
+            // GROOVY-10981: prior to Groovy 5, outer class field is preferred 
over self-type property
+            boolean declaredInScope = enclosingClosure == null && 
getOutermost(accessedField.getDeclaringClass()) == 
getOutermost(typeCheckingContext.getEnclosingClassNode());
+            if (declaredInScope || tryVariableExpressionAsProperty(vexp, 
name)) {
+                if (temporaryType == null) {
+                    storeType(vexp, getType(vexp));
+                } else if (!isObjectType(temporaryType)) {
+                    vexp.putNodeMetaData(INFERRED_TYPE, temporaryType);
+                }
+                if (declaredInScope) {
+                    checkOrMarkPrivateAccess(vexp, accessedField, 
typeCheckingContext.isTargetOfEnclosingAssignment(vexp));
+                }
+            } else if (!extension.handleUnresolvedVariableExpression(vexp)) {
+                addStaticTypeError("No such property: " + name + " for class: 
" + prettyPrintTypeName(typeCheckingContext.getEnclosingClassNode()), vexp);
             }
         } else if (accessedVariable instanceof PropertyNode) {
-            // we must be careful, because the property node may be of a wrong 
type:
+            // we must be careful -- the property node may be of a wrong type:
             // if a class contains a getter and a setter of different types or
             // overloaded setters, the type of the property node is arbitrary!
             if (tryVariableExpressionAsProperty(vexp, name)) {
@@ -1671,6 +1675,21 @@ public class StaticTypeCheckingVisitor extends 
ClassCodeVisitorSupport {
             return true;
         }
 
+        if (pexp.isImplicitThis() && isThisExpression(objectExpression)) {
+            Iterator<ClassNode> iter = enclosingTypes.iterator(); // first 
enclosing is "this" type
+            boolean staticOnly = Modifier.isStatic(iter.next().getModifiers()) 
|| staticOnlyAccess;
+            while (iter.hasNext()) {
+                ClassNode outer = iter.next();
+                // GROOVY-7994, GROOVY-11198: try "this.propertyName" as 
"Outer.propertyName" or "Outer.this.propertyName"
+                PropertyExpression pe = propX(staticOnly ? classX(outer) : 
propX(classX(outer), "this"), pexp.getProperty());
+                if (existsProperty(pe, readMode, visitor)) {
+                    pexp.copyNodeMetaData(pe);
+                    return true;
+                }
+                staticOnly = staticOnly || 
Modifier.isStatic(outer.getModifiers());
+            }
+        }
+
         return foundGetterOrSetter;
     }
 
@@ -1810,7 +1829,7 @@ public class StaticTypeCheckingVisitor extends 
ClassCodeVisitorSupport {
         if (!accessible) {
             if (expressionToStoreOn instanceof AttributeExpression) {
                 addStaticTypeError("Cannot access field: " + field.getName() + 
" of class: " + prettyPrintTypeName(field.getDeclaringClass()), 
expressionToStoreOn.getProperty());
-            } else if (field.isPrivate()) {
+            } else if (!field.isProtected()) { // private or package-private
                 return false;
             }
         }
diff --git a/src/test/groovy/bugs/Groovy7165.groovy 
b/src/test/groovy/bugs/Groovy7165.groovy
index 5880057ad9..99663df647 100644
--- a/src/test/groovy/bugs/Groovy7165.groovy
+++ b/src/test/groovy/bugs/Groovy7165.groovy
@@ -73,8 +73,7 @@ final class Groovy7165 {
             }
             new B().test()
         '''
-
-        assert err =~ /Access to B#CONST is forbidden/
+        assert err =~ /No such property: CONST for class: B/
     }
 
     @Test
@@ -91,7 +90,6 @@ final class Groovy7165 {
             }
             assert false : 'compilation should fail'
         '''
-
         assert err =~ /Access to A#CONST is forbidden/
     }
 }
diff --git a/src/test/groovy/bugs/Groovy9292.groovy 
b/src/test/groovy/bugs/Groovy9292.groovy
index 2dc077c246..6d74ffeed8 100644
--- a/src/test/groovy/bugs/Groovy9292.groovy
+++ b/src/test/groovy/bugs/Groovy9292.groovy
@@ -29,9 +29,9 @@ final class Groovy9292 {
         ast(groovy.transform.CompileStatic)
     }
 
-    @Test
+    @Test // GROOVY-11356
     void 'test accessing a private super class field inside a closure - same 
module'() {
-        shouldFail shell, MissingPropertyException, '''
+        def err = shouldFail shell, '''
             package a
 
             class A {
@@ -46,9 +46,10 @@ final class Groovy9292 {
 
             new B().test()
         '''
+        assert err =~ /No such property: superField for class: a.B/
     }
 
-    @Test
+    @Test // GROOVY-11356
     void 'test accessing a private super class field inside a closure - same 
package'() {
         assertScript shell, '''
             package a
@@ -59,7 +60,7 @@ final class Groovy9292 {
 
             assert true
         '''
-        shouldFail shell, MissingPropertyException, '''
+        def err = shouldFail shell, '''
             package a
 
             class B extends A {
@@ -70,9 +71,10 @@ final class Groovy9292 {
 
             new B().test()
         '''
+        assert err =~ /No such property: superField for class: a.B/
     }
 
-    @Test
+    @Test // GROOVY-11356
     void 'test accessing a private super class field inside a closure - diff 
package'() {
         assertScript shell, '''
             package a
@@ -83,7 +85,7 @@ final class Groovy9292 {
 
             assert true
         '''
-        shouldFail shell, MissingPropertyException, '''
+        def err = shouldFail shell, '''
             package b
 
             class B extends a.A {
@@ -94,6 +96,7 @@ final class Groovy9292 {
 
             new B().test()
         '''
+        assert err =~ /No such property: superField for class: b.B/
     }
 
     @Test
diff --git a/src/test/groovy/bugs/Groovy9293.groovy 
b/src/test/groovy/bugs/Groovy9293.groovy
index 1a2ae0a028..344448fcea 100644
--- a/src/test/groovy/bugs/Groovy9293.groovy
+++ b/src/test/groovy/bugs/Groovy9293.groovy
@@ -51,7 +51,7 @@ final class Groovy9293 {
         '''
     }
 
-    @Test
+    @Test // GROOVY-11356
     void 'test accessing a package-private super class field inside a closure 
- diff package'() {
         assertScript shell, '''
             package a
@@ -62,7 +62,7 @@ final class Groovy9293 {
 
             assert true
         '''
-        shouldFail shell, MissingPropertyException, '''
+        def err = shouldFail shell, '''
             package b
 
             class B extends a.A {
@@ -73,6 +73,7 @@ final class Groovy9293 {
 
             new B().test()
         '''
+        assert err =~ /No such property: superField for class: b.B/
     }
 
     @Test
@@ -138,7 +139,7 @@ final class Groovy9293 {
         '''
     }
 
-    @Test
+    @Test // GROOVY-9293
     void 'test accessing a package-private super class field inside a closure 
- diff package, this qualifier'() {
         assertScript shell, '''
             package a
diff --git 
a/src/test/org/codehaus/groovy/transform/packageScope/DifferentPackageTest.groovy
 
b/src/test/org/codehaus/groovy/transform/packageScope/DifferentPackageTest.groovy
index f5650b3d19..e898bdb53b 100644
--- 
a/src/test/org/codehaus/groovy/transform/packageScope/DifferentPackageTest.groovy
+++ 
b/src/test/org/codehaus/groovy/transform/packageScope/DifferentPackageTest.groovy
@@ -192,20 +192,20 @@ final class DifferentPackageTest {
     void testDifferentPackageShouldNotSeeInstanceProps() {
         def err = shouldFail CompilationFailedException, {
             addSources(
-                    One: P_DOT_ONE,
-                    Two: '''
-                        package q
-
-                        @groovy.transform.CompileStatic
-                        class Two extends p.One {
-                            int valueSize() {
-                                value.size() // not visible
-                            }
+                One: P_DOT_ONE,
+                Two: '''
+                    package q
+
+                    @groovy.transform.CompileStatic
+                    class Two extends p.One {
+                        int valueSize() {
+                            value.size() // not visible
                         }
-                    ''')
+                    }
+                ''')
         }
 
-        assert err.message =~ /Access to q.Two#value is forbidden/
+        assert err.message =~ /No such property: value for class: q.Two/
     }
 
     // GROOVY-9093
@@ -213,20 +213,20 @@ final class DifferentPackageTest {
     void testDifferentPackageShouldNotSeeStaticProps1() {
         def err = shouldFail CompilationFailedException, {
             addSources(
-                    One: P_DOT_ONE,
-                    Two: '''
-                        package q
-
-                        @groovy.transform.CompileStatic
-                        class Two extends p.One {
-                            static def half() {
-                                (CONST / 2) // not visible
-                            }
+                One: P_DOT_ONE,
+                Two: '''
+                    package q
+
+                    @groovy.transform.CompileStatic
+                    class Two extends p.One {
+                        static def half() {
+                            (CONST / 2) // not visible
                         }
-                    ''')
+                    }
+                ''')
         }
 
-        assert err.message =~ /Access to q.Two#CONST is forbidden/
+        assert err.message =~ /No such property: CONST for class: q.Two/
     }
 
     @Test

Reply via email to