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 2024/05/09 18:48:34 UTC

(groovy) branch GROOVY_4_0_X updated: GROOVY-11373: SC: cross-package direct target of package-private method

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 0456e0e775 GROOVY-11373: SC: cross-package direct target of package-private method
0456e0e775 is described below

commit 0456e0e77567770dfdc68ca1def46c294357b99b
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Thu May 9 11:43:32 2024 -0500

    GROOVY-11373: SC: cross-package direct target of package-private method
    
    4_0_X backport
---
 .../classgen/asm/sc/StaticInvocationWriter.java    | 44 +++++++++++---------
 .../sc/FieldsAndPropertiesStaticCompileTest.groovy |  9 ++---
 .../classgen/asm/sc/bugs/Groovy7325Bug.groovy      | 47 ++++++++++------------
 3 files changed, 50 insertions(+), 50 deletions(-)

diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticInvocationWriter.java b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticInvocationWriter.java
index 9734b1b380..2e3710c5e1 100644
--- a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticInvocationWriter.java
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticInvocationWriter.java
@@ -69,9 +69,11 @@ import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
+import java.util.StringJoiner;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.stream.Collectors;
 
+import static org.apache.groovy.ast.tools.ClassNodeUtils.formatTypeName;
 import static org.apache.groovy.ast.tools.ClassNodeUtils.samePackageName;
 import static org.apache.groovy.ast.tools.ExpressionUtils.isNullConstant;
 import static org.apache.groovy.ast.tools.ExpressionUtils.isSuperExpression;
@@ -346,16 +348,17 @@ public class StaticInvocationWriter extends InvocationWriter {
             return true;
         }
 
-        Expression  fixedReceiver = receiver;
-        boolean fixedImplicitThis = implicitThis;
-        if (target.isProtected()) {
-            ClassNode node = receiver == null ? ClassHelper.OBJECT_TYPE : controller.getTypeChooser().resolveType(receiver, controller.getClassNode());
+        Expression fixedReceiver = receiver;
+        boolean    fixedImplicitThis = implicitThis;
+        if (target.isPackageScope()) { // GROOVY-11373
+            if (!samePackageName(target.getDeclaringClass(), classNode)) {
+                writeMethodAccessError(target, receiver != null ? receiver : args);
+            }
+        } else if (target.isProtected()) {
+            ClassNode node = receiver == null ? ClassHelper.OBJECT_TYPE : controller.getTypeChooser().resolveType(receiver, classNode);
             if (!implicitThis && !isThisOrSuper(receiver) && !samePackageName(node, classNode)
-                    && StaticTypeCheckingSupport.implementsInterfaceOrIsSubclassOf(node,target.getDeclaringClass())) {
-                controller.getSourceUnit().addError(new SyntaxException(
-                        "Method " + target.getName() + " is protected in " + target.getDeclaringClass().toString(false),
-                        receiver != null ? receiver : args
-                ));
+                    && StaticTypeCheckingSupport.implementsInterfaceOrIsSubclassOf(node, target.getDeclaringClass())) {
+                writeMethodAccessError(target, receiver != null ? receiver : args);
             } else if (!node.isDerivedFrom(target.getDeclaringClass()) && tryBridgeMethod(target, receiver, implicitThis, args, classNode)) {
                 return true;
             }
@@ -388,6 +391,16 @@ public class StaticInvocationWriter extends InvocationWriter {
         return super.writeDirectMethodCall(target, implicitThis, receiver, args);
     }
 
+    private void writeMethodAccessError(final MethodNode target, final Expression origin) {
+        StringJoiner descriptor = new StringJoiner(", ", target.getName() + "(", ")");
+        for (Parameter parameter : target.getParameters()) {
+            descriptor.add(formatTypeName(parameter.getOriginType()));
+        }
+        String message = "Cannot access method: " + descriptor + " of class: " + formatTypeName(target.getDeclaringClass());
+
+        controller.getSourceUnit().addError(new SyntaxException(message, origin));
+    }
+
     private boolean tryPrivateMethod(final MethodNode target, final boolean implicitThis, final Expression receiver, final TupleExpression args, final ClassNode classNode) {
         ClassNode declaringClass = target.getDeclaringClass();
         if ((isPrivateBridgeMethodsCallAllowed(declaringClass, classNode) || isPrivateBridgeMethodsCallAllowed(classNode, declaringClass))
@@ -395,21 +408,12 @@ public class StaticInvocationWriter extends InvocationWriter {
                 && !declaringClass.equals(classNode)) {
             if (tryBridgeMethod(target, receiver, implicitThis, args, classNode)) {
                 return true;
-            } else {
-                checkAndAddCannotCallPrivateMethodError(target, receiver, classNode, declaringClass);
             }
         }
-        checkAndAddCannotCallPrivateMethodError(target, receiver, classNode, declaringClass);
-        return false;
-    }
-
-    private void checkAndAddCannotCallPrivateMethodError(final MethodNode target, final Expression receiver, final ClassNode classNode, final ClassNode declaringClass) {
         if (declaringClass != classNode) {
-            controller.getSourceUnit().addError(new SyntaxException(
-                    "Cannot call private method " + (target.isStatic() ? "static " : "") + declaringClass.toString(false) + "#" + target.getName() + " from class " + classNode.toString(false),
-                    receiver
-            ));
+            writeMethodAccessError(target, receiver);
         }
+        return false;
     }
 
     protected static boolean isPrivateBridgeMethodsCallAllowed(final ClassNode receiver, final ClassNode caller) {
diff --git a/src/test/org/codehaus/groovy/classgen/asm/sc/FieldsAndPropertiesStaticCompileTest.groovy b/src/test/org/codehaus/groovy/classgen/asm/sc/FieldsAndPropertiesStaticCompileTest.groovy
index 22964e632e..0cd7e9ba50 100644
--- a/src/test/org/codehaus/groovy/classgen/asm/sc/FieldsAndPropertiesStaticCompileTest.groovy
+++ b/src/test/org/codehaus/groovy/classgen/asm/sc/FieldsAndPropertiesStaticCompileTest.groovy
@@ -866,7 +866,7 @@ final class FieldsAndPropertiesStaticCompileTest extends FieldsAndPropertiesSTCT
         super.testPublicFieldVersusPrivateGetter()
     }
 
-    // GROOVY-11223
+    // GROOVY-11223, GROOVY-11373
     @Override
     void testMapPropertyAccess10() {
         assertScript """
@@ -879,13 +879,12 @@ final class FieldsAndPropertiesStaticCompileTest extends FieldsAndPropertiesSTCT
             def map = new ${MapType.name}()
             map.bar = 22 // protected setter
         """,
-        "Method setBar is protected in ${MapType.name}"
-        /*
+        "Cannot access method: setBar(java.lang.Object) of class: ${MapType.name}"
+
         shouldFailWithMessages """
             def map = new ${MapType.name}()
             map.baz = 33 // package-private setter
         """,
-        "Method setBaz is package-private in ${MapType.name}"
-        */
+        "Cannot access method: setBaz(java.lang.Object) of class: ${MapType.name}"
     }
 }
diff --git a/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7325Bug.groovy b/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7325Bug.groovy
index 49ea6ed365..49ab84ac65 100644
--- a/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7325Bug.groovy
+++ b/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7325Bug.groovy
@@ -16,43 +16,40 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-
-
 package org.codehaus.groovy.classgen.asm.sc.bugs
 
 import groovy.transform.stc.StaticTypeCheckingTestCase
 import org.codehaus.groovy.classgen.asm.sc.StaticCompilationTestSupport
 
-class Groovy7325Bug extends StaticTypeCheckingTestCase implements StaticCompilationTestSupport {
+final class Groovy7325Bug extends StaticTypeCheckingTestCase implements StaticCompilationTestSupport {
 
     void testGenericIdentityWithClosure() {
         assertScript '''
-public static <T> T identity(T self) { self }
-
-@ASTTest(phase=INSTRUCTION_SELECTION,value={
-    assert node.rightExpression.getNodeMetaData(INFERRED_TYPE) == Integer_TYPE
-})
-Integer i = identity(2)
-
-@ASTTest(phase=INSTRUCTION_SELECTION,value={
-    assert node.rightExpression.getNodeMetaData(INFERRED_TYPE) == CLOSURE_TYPE
-})
-Closure c = identity {'foo'}
-'''
+            static <T> T itself(T self) { self }
+
+            @ASTTest(phase=INSTRUCTION_SELECTION,value={
+                assert node.rightExpression.getNodeMetaData(INFERRED_TYPE) == Integer_TYPE
+            })
+            Integer i = itself(2)
+
+            @ASTTest(phase=INSTRUCTION_SELECTION,value={
+                assert node.rightExpression.getNodeMetaData(INFERRED_TYPE) == CLOSURE_TYPE
+            })
+            Closure c = itself {'foo'}
+        '''
     }
 
     void testShouldNotThrowIllegalAccessToProtectedData() {
-        shouldFailWithMessages('''
-            class Test {
-              final Set<String> HISTORY = [] as HashSet
-
-              Set<String> getHistory() {
-                return HISTORY.clone() as HashSet<String>
-              }
+        shouldFailWithMessages '''
+            class C {
+                private final Set<String> history = []
+                Set<String> getHistory() {
+                    (Set<String>) history.clone()
+                }
             }
 
-            Test test = new Test()
-            println test.history
-        ''', 'Method clone is protected in java.lang.Object')
+            def set = new C().history
+        ''',
+        'Cannot access method: clone() of class: java.lang.Object'
     }
 }