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() {
