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

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

commit 491c5e7a0d62a60821c3ef1006dd8c9323809990
Author: Eric Milles <[email protected]>
AuthorDate: Sun Apr 27 18:15:20 2025 -0500

    GROOVY-11641: index trait field under original name
---
 src/main/java/groovy/lang/MetaClassImpl.java       | 17 ++++++++++--
 .../transform/trait/TraitReceiverTransformer.java  |  2 ++
 .../codehaus/groovy/transform/trait/Traits.java    |  1 -
 .../org/codehaus/groovy/vmplugin/v8/Selector.java  |  4 +--
 .../traitx/TraitASTTransformationTest.groovy       | 31 ++++++++++++++++++++++
 5 files changed, 50 insertions(+), 5 deletions(-)

diff --git a/src/main/java/groovy/lang/MetaClassImpl.java 
b/src/main/java/groovy/lang/MetaClassImpl.java
index 495639eac8..0029c23c79 100644
--- a/src/main/java/groovy/lang/MetaClassImpl.java
+++ b/src/main/java/groovy/lang/MetaClassImpl.java
@@ -110,6 +110,7 @@ import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 import java.util.function.BiConsumer;
+import java.util.regex.Pattern;
 
 import static groovy.lang.Tuple.tuple;
 import static java.lang.Character.isUpperCase;
@@ -144,6 +145,11 @@ public class MetaClassImpl implements MetaClass, 
MutableMetaClass {
     private static final MetaMethod AMBIGUOUS_LISTENER_METHOD = new 
DummyMetaMethod();
     private static final Comparator<CachedClass> CACHED_CLASS_NAME_COMPARATOR 
= Comparator.comparing(CachedClass::getName);
     private static final boolean PERMISSIVE_PROPERTY_ACCESS = 
SystemUtil.getBooleanSafe("groovy.permissive.property.access");
+    private static final Pattern TRAIT_FIELD;
+    static {
+        final var identifier = 
"[\\p{javaJavaIdentifierStart}&&[^_$]][\\p{javaJavaIdentifierPart}&&[^_$]]*"; 
// _ and $ are special
+        TRAIT_FIELD = Pattern.compile("(?:" + identifier + "_)*" + identifier 
+ "(?:\\$" + identifier + ")*__(" + identifier + ")");
+    }
     private static final VMPlugin VM_PLUGIN = VMPluginFactory.getPlugin();
 
     protected final Class theClass;
@@ -2367,8 +2373,15 @@ public class MetaClassImpl implements MetaClass, 
MutableMetaClass {
             } else {
                 prop = null; // ignore all other types
             }
-
-            if (prop != null) staticPropertyIndex.put(name, prop);
+            if (prop != null) {
+                staticPropertyIndex.put(name, prop);
+                if (!name.startsWith("$") && name.contains("__")) {
+                    var matcher = TRAIT_FIELD.matcher(name);
+                    if (matcher.matches()) { // GROOVY-11641
+                        staticPropertyIndex.putIfAbsent(matcher.group(1), 
prop);
+                    }
+                }
+            }
         };
 
         classPropertyIndex.computeIfAbsent(theCachedClass, x -> new 
LinkedHashMap<>()).forEach(indexStaticProperty);
diff --git 
a/src/main/java/org/codehaus/groovy/transform/trait/TraitReceiverTransformer.java
 
b/src/main/java/org/codehaus/groovy/transform/trait/TraitReceiverTransformer.java
index 9d62cb37c0..9baf3bf1b8 100644
--- 
a/src/main/java/org/codehaus/groovy/transform/trait/TraitReceiverTransformer.java
+++ 
b/src/main/java/org/codehaus/groovy/transform/trait/TraitReceiverTransformer.java
@@ -55,6 +55,7 @@ import static 
org.codehaus.groovy.ast.tools.GeneralUtils.isInstanceOfX;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.propX;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.ternaryX;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.varX;
+import static 
org.codehaus.groovy.transform.stc.StaticTypesMarker.DYNAMIC_RESOLUTION;
 
 /**
  * This expression transformer is used internally by the {@link 
org.codehaus.groovy.transform.trait.TraitASTTransformation
@@ -123,6 +124,7 @@ class TraitReceiverTransformer extends 
ClassCodeExpressionTransformer {
                 }
             } else if (accessedVariable instanceof DynamicVariable && 
!inClosure) { // GROOVY-9386
                 PropertyExpression propertyExpression = propX(varX(weaved), 
vexp.getName());
+                propertyExpression.putNodeMetaData(DYNAMIC_RESOLUTION, 
Boolean.TRUE);
                 propertyExpression.getProperty().setSourcePosition(exp);
                 return propertyExpression;
             }
diff --git a/src/main/java/org/codehaus/groovy/transform/trait/Traits.java 
b/src/main/java/org/codehaus/groovy/transform/trait/Traits.java
index 31ca6a88e2..ce078f3789 100644
--- a/src/main/java/org/codehaus/groovy/transform/trait/Traits.java
+++ b/src/main/java/org/codehaus/groovy/transform/trait/Traits.java
@@ -244,7 +244,6 @@ public abstract class Traits {
         return null;
     }
 
-
     /**
      * Converts a class implementing some trait into a target class. If the 
trait is a dynamic proxy and
      * that the target class is assignable to the target object of the proxy, 
then the target object is
diff --git a/src/main/java/org/codehaus/groovy/vmplugin/v8/Selector.java 
b/src/main/java/org/codehaus/groovy/vmplugin/v8/Selector.java
index be586fdff0..8d7ea2c196 100644
--- a/src/main/java/org/codehaus/groovy/vmplugin/v8/Selector.java
+++ b/src/main/java/org/codehaus/groovy/vmplugin/v8/Selector.java
@@ -285,8 +285,8 @@ public abstract class Selector {
     private static class PropertySelector extends MethodSelector {
         private boolean insertName;
 
-        public PropertySelector(CacheableCallSite callSite, Class<?> sender, 
String methodName, CallType callType, boolean safeNavigation, boolean thisCall, 
boolean spreadCall, Object[] arguments) {
-            super(callSite, sender, methodName, callType, safeNavigation, 
thisCall, spreadCall, arguments);
+        public PropertySelector(CacheableCallSite callSite, Class<?> sender, 
String propertyName, CallType callType, boolean safeNavigation, boolean 
thisCall, boolean spreadCall, Object[] arguments) {
+            super(callSite, sender, propertyName, callType, safeNavigation, 
thisCall, spreadCall, arguments);
         }
 
         /**
diff --git 
a/src/test/groovy/org/codehaus/groovy/transform/traitx/TraitASTTransformationTest.groovy
 
b/src/test/groovy/org/codehaus/groovy/transform/traitx/TraitASTTransformationTest.groovy
index aa8357f963..d90290e21e 100644
--- 
a/src/test/groovy/org/codehaus/groovy/transform/traitx/TraitASTTransformationTest.groovy
+++ 
b/src/test/groovy/org/codehaus/groovy/transform/traitx/TraitASTTransformationTest.groovy
@@ -3717,6 +3717,37 @@ final class TraitASTTransformationTest {
         """
     }
 
+    // GROOVY-11641
+    @CompileModesTest
+    void testTraitAccessToInheritedStaticMethods4(String mode) {
+        assertScript shell, """
+            $mode
+            trait Foo {
+                public static final String BANG = '!'
+            }
+            $mode
+            trait Bar extends Foo {
+                static staticMethod(String string) {
+                    string + BANG
+                }
+            }
+            $mode
+            class Main implements Bar {
+                static test1() {
+                    String result = staticMethod('works')
+                    assert result == 'works!'
+                }
+                void test2() {
+                    String result = staticMethod('works')
+                    assert result == 'works!'
+                }
+            }
+
+            Main.test1()
+            new Main().test2()
+        """
+    }
+
     // GROOVY-9386
     @Test
     void testTraitPropertyInitializedByTap() {

Reply via email to