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

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

commit 88e170b4687eb0545579863091175d9681857ea6
Author: Eric Milles <[email protected]>
AuthorDate: Sun Mar 1 14:28:02 2026 -0600

    GROOVY-6526: compute allowed targets lazily
---
 .../org/codehaus/groovy/ast/AnnotationNode.java    | 55 ++++++++++++++++++----
 .../groovy/ast/decompiled/Annotations.java         |  3 +-
 .../org/codehaus/groovy/vmplugin/v16/Java16.java   |  6 ---
 .../org/codehaus/groovy/vmplugin/v8/Java8.java     | 43 ++---------------
 .../org/codehaus/groovy/vmplugin/v9/Java9.java     |  7 ---
 .../codehaus/groovy/ast/AnnotationNodeTest.groovy  | 47 ++++++++++++++----
 6 files changed, 91 insertions(+), 70 deletions(-)

diff --git a/src/main/java/org/codehaus/groovy/ast/AnnotationNode.java 
b/src/main/java/org/codehaus/groovy/ast/AnnotationNode.java
index b39906a136..d125fff2d6 100644
--- a/src/main/java/org/codehaus/groovy/ast/AnnotationNode.java
+++ b/src/main/java/org/codehaus/groovy/ast/AnnotationNode.java
@@ -22,7 +22,10 @@ import org.codehaus.groovy.GroovyBugError;
 import org.codehaus.groovy.ast.expr.ConstantExpression;
 import org.codehaus.groovy.ast.expr.Expression;
 import org.codehaus.groovy.ast.expr.ListExpression;
+import org.codehaus.groovy.ast.expr.PropertyExpression;
 
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
 import java.util.Collections;
 import java.util.LinkedHashMap;
 import java.util.Map;
@@ -49,7 +52,6 @@ public class AnnotationNode extends ASTNode {
 
     private final ClassNode classNode;
     private Map<String, Expression> members;
-    private int allowedTargets = 0x4FF; // GROOVY-11838: JLS 9.6.4.1
     private boolean runtimeRetention = false, sourceRetention = false, 
/*explicit*/ classRetention = false;
 
     public AnnotationNode(final ClassNode type) {
@@ -77,8 +79,8 @@ public class AnnotationNode extends ASTNode {
         }
     }
 
-    public void setAllowedTargets(final int bitmap) {
-        allowedTargets = bitmap;
+    @Deprecated(since = "6.0.0")
+    public void setAllowedTargets(final int ignored) {
     }
 
     /**
@@ -137,12 +139,48 @@ public class AnnotationNode extends ASTNode {
     }
 
     public boolean isTargetAllowed(final int target) {
-        return (this.allowedTargets & target) == target;
+        if (!(classNode.isPrimaryClassNode() || classNode.isResolved()))
+            throw new IllegalStateException("cannot check target at this 
time");
+
+        // GROOVY-6526: check class for @Target
+        int allowedTargets = classNode.getNodeMetaData(Target.class, (k) -> {
+            for (AnnotationNode an : classNode.getAnnotations()) {
+                if 
("java.lang.annotation.Target".equals(an.getClassNode().getName())
+                        && an.getMember("value") instanceof ListExpression 
list) {
+                    int bits = 0;
+                    for (Expression e : list.getExpressions()) {
+                        if (e instanceof PropertyExpression item) {
+                            String name = item.getPropertyAsString();
+                            bits |= switch (ElementType.valueOf(name)) {
+                                case TYPE             -> TYPE_TARGET;
+                                case FIELD            -> FIELD_TARGET;
+                                case METHOD           -> METHOD_TARGET;
+                                case PARAMETER        -> PARAMETER_TARGET;
+                                case CONSTRUCTOR      -> CONSTRUCTOR_TARGET;
+                                case LOCAL_VARIABLE   -> LOCAL_VARIABLE_TARGET;
+                                case ANNOTATION_TYPE  -> ANNOTATION_TARGET;
+                                case PACKAGE          -> PACKAGE_TARGET;
+                                case TYPE_PARAMETER   -> TYPE_PARAMETER_TARGET;
+                                case TYPE_USE         -> TYPE_USE_TARGET;
+                                case MODULE           -> TYPE_TARGET; //TODO
+                                case RECORD_COMPONENT -> 
RECORD_COMPONENT_TARGET;
+                                default -> throw new 
GroovyBugError("unsupported Target " + name);
+                            };
+                        }
+                    }
+                    return bits;
+                }
+            }
+            return 0x4FF; // GROOVY-11838: JLS 9.6.4.1
+        });
+
+        return (target & allowedTargets) == target;
     }
 
     /**
      * Flag corresponding to <code>RetentionPolicy.RUNTIME</code>.
-     * @return <tt>true</tt> if the annotation should be visible at runtime,
+     *
+     * @return <tt>true</tt> if the annotation should be visible at runtime;
      *         <tt>false</tt> otherwise
      */
     public boolean hasRuntimeRetention() {
@@ -151,7 +189,8 @@ public class AnnotationNode extends ASTNode {
 
     /**
      * Flag corresponding to <code>RetentionPolicy.SOURCE</code>.
-     * @return <tt>true</tt> if the annotation is only allowed in sources
+     *
+     * @return <tt>true</tt> if the annotation is only allowed in sources;
      *         <tt>false</tt> otherwise
      */
     public boolean hasSourceRetention() {
@@ -160,9 +199,9 @@ public class AnnotationNode extends ASTNode {
 
     /**
      * Flag corresponding to <code>RetentionPolicy.CLASS</code>.
-     * This is the default when no <code>RetentionPolicy</code> annotations 
are present.
+     * This is the default when no <code>Retention</code> annotation is 
present.
      *
-     * @return <tt>true</tt> if the annotation is written in the bytecode, but 
not visible at runtime
+     * @return <tt>true</tt> if the annotation is written in the bytecode but 
not visible at runtime;
      *         <tt>false</tt> otherwise
      */
     public boolean hasClassRetention() {
diff --git a/src/main/java/org/codehaus/groovy/ast/decompiled/Annotations.java 
b/src/main/java/org/codehaus/groovy/ast/decompiled/Annotations.java
index dbd671d7e9..713c75c398 100644
--- a/src/main/java/org/codehaus/groovy/ast/decompiled/Annotations.java
+++ b/src/main/java/org/codehaus/groovy/ast/decompiled/Annotations.java
@@ -143,8 +143,7 @@ class Annotations {
         }
 
         @Override
-        public boolean isTargetAllowed(int target) {
-            lazyInit();
+        public boolean isTargetAllowed(final int target) {
             return super.isTargetAllowed(target);
         }
 
diff --git a/src/main/java/org/codehaus/groovy/vmplugin/v16/Java16.java 
b/src/main/java/org/codehaus/groovy/vmplugin/v16/Java16.java
index f8169a73af..46bbcd5f45 100644
--- a/src/main/java/org/codehaus/groovy/vmplugin/v16/Java16.java
+++ b/src/main/java/org/codehaus/groovy/vmplugin/v16/Java16.java
@@ -20,13 +20,11 @@ package org.codehaus.groovy.vmplugin.v16;
 
 import groovy.lang.GroovyRuntimeException;
 import org.apache.groovy.lang.annotation.Incubating;
-import org.codehaus.groovy.ast.AnnotationNode;
 import org.codehaus.groovy.ast.ClassNode;
 import org.codehaus.groovy.ast.CompileUnit;
 import org.codehaus.groovy.ast.RecordComponentNode;
 import org.codehaus.groovy.vmplugin.v10.Java10;
 
-import java.lang.annotation.ElementType;
 import java.lang.invoke.MethodHandle;
 import java.lang.reflect.Method;
 import java.lang.reflect.Proxy;
@@ -37,10 +35,6 @@ import java.util.stream.Collectors;
 
 public class Java16 extends Java10 {
 
-    {
-        elementTypeToTarget.put(ElementType.RECORD_COMPONENT, 
AnnotationNode.RECORD_COMPONENT_TARGET);
-    }
-
     @Override
     public int getVersion() {
         return 16;
diff --git a/src/main/java/org/codehaus/groovy/vmplugin/v8/Java8.java 
b/src/main/java/org/codehaus/groovy/vmplugin/v8/Java8.java
index 67860da52a..2e31e7e3bb 100644
--- a/src/main/java/org/codehaus/groovy/vmplugin/v8/Java8.java
+++ b/src/main/java/org/codehaus/groovy/vmplugin/v8/Java8.java
@@ -20,7 +20,6 @@ package org.codehaus.groovy.vmplugin.v8;
 
 import groovy.lang.MetaClass;
 import groovy.lang.MetaMethod;
-import org.apache.groovy.util.Maps;
 import org.codehaus.groovy.GroovyBugError;
 import org.codehaus.groovy.ast.AnnotatedNode;
 import org.codehaus.groovy.ast.AnnotationNode;
@@ -70,9 +69,7 @@ import java.lang.reflect.TypeVariable;
 import java.lang.reflect.WildcardType;
 import java.security.Permission;
 import java.util.Arrays;
-import java.util.EnumMap;
 import java.util.List;
-import java.util.Map;
 
 /**
  * Java 8 based functions.
@@ -344,44 +341,12 @@ public class Java8 implements VMPlugin {
         return null;
     }
 
-    //
-
-    protected final Map<ElementType, Integer> elementTypeToTarget = new 
EnumMap<>(Maps.of(
-        ElementType.TYPE,            AnnotationNode.TYPE_TARGET,
-        ElementType.FIELD,           AnnotationNode.FIELD_TARGET,
-        ElementType.METHOD,          AnnotationNode.METHOD_TARGET,
-        ElementType.PARAMETER,       AnnotationNode.PARAMETER_TARGET,
-        ElementType.CONSTRUCTOR,     AnnotationNode.CONSTRUCTOR_TARGET,
-        ElementType.LOCAL_VARIABLE,  AnnotationNode.LOCAL_VARIABLE_TARGET,
-        ElementType.ANNOTATION_TYPE, AnnotationNode.ANNOTATION_TARGET,
-        ElementType.PACKAGE,         AnnotationNode.PACKAGE_TARGET,
-        ElementType.TYPE_PARAMETER,  AnnotationNode.TYPE_PARAMETER_TARGET,
-        ElementType.TYPE_USE,        AnnotationNode.TYPE_USE_TARGET
-    ));
-
     @Override
     public void configureAnnotationNodeFromDefinition(final AnnotationNode 
definition, final AnnotationNode node) {
-        switch (definition.getClassNode().getName()) {
-          case "java.lang.annotation.Retention":
-            if (definition.getMember("value") instanceof PropertyExpression 
value) {
-                var policy = 
RetentionPolicy.valueOf(value.getPropertyAsString());
-                setRetentionPolicy(policy, node);
-            }
-            break;
-          case "java.lang.annotation.Target":
-            if (definition.getMember("value") instanceof ListExpression list) {
-                int targets = 0;
-                for (Expression e : list.getExpressions()) {
-                    if (e instanceof PropertyExpression item) {
-                        String name = item.getPropertyAsString();
-                        ElementType type = ElementType.valueOf(name);
-                        Integer target = elementTypeToTarget.get(type);
-                        if (target == null) throw new 
GroovyBugError("unsupported Target " + type);
-                        targets |= target;
-                    }
-                }
-                node.setAllowedTargets(targets);
-            }
+        if 
("java.lang.annotation.Retention".equals(definition.getClassNode().getName())
+                 && definition.getMember("value") instanceof 
PropertyExpression value) {
+            var policy = RetentionPolicy.valueOf(value.getPropertyAsString());
+            setRetentionPolicy(policy, node);
         }
     }
 
diff --git a/src/main/java/org/codehaus/groovy/vmplugin/v9/Java9.java 
b/src/main/java/org/codehaus/groovy/vmplugin/v9/Java9.java
index 6981ee17a2..2f0af57de4 100644
--- a/src/main/java/org/codehaus/groovy/vmplugin/v9/Java9.java
+++ b/src/main/java/org/codehaus/groovy/vmplugin/v9/Java9.java
@@ -56,15 +56,8 @@ import java.util.logging.Level;
 import java.util.logging.Logger;
 import java.util.stream.Collectors;
 
-import static java.lang.annotation.ElementType.MODULE;
-import static org.codehaus.groovy.ast.AnnotationNode.TYPE_TARGET;
-
 public class Java9 extends Java8 {
 
-    {
-        elementTypeToTarget.put(MODULE, TYPE_TARGET); // TODO Add 
MODULE_TARGET?
-    }
-
     @Override
     public int getVersion() {
         return 9;
diff --git a/src/test/groovy/org/codehaus/groovy/ast/AnnotationNodeTest.groovy 
b/src/test/groovy/org/codehaus/groovy/ast/AnnotationNodeTest.groovy
index aa33bcdcc7..ba2d0f671e 100644
--- a/src/test/groovy/org/codehaus/groovy/ast/AnnotationNodeTest.groovy
+++ b/src/test/groovy/org/codehaus/groovy/ast/AnnotationNodeTest.groovy
@@ -21,21 +21,52 @@ package org.codehaus.groovy.ast
 import org.codehaus.groovy.ast.expr.ConstantExpression
 import org.junit.jupiter.api.Test
 
+import static org.codehaus.groovy.ast.AnnotationNode.*
 import static org.junit.jupiter.api.Assertions.*
 
 final class AnnotationNodeTest {
 
-    // GROOVY-11838
+    // GROOVY-6526
     @Test
-    void testIsTargetAllowed() {
+    void testIsTargetAllowed1() {
         def node = new AnnotationNode(ClassHelper.OVERRIDE_TYPE)
 
-        assertTrue(node.isTargetAllowed(AnnotationNode.TYPE_TARGET))
-        assertTrue(node.isTargetAllowed(AnnotationNode.FIELD_TARGET))
-        assertTrue(node.isTargetAllowed(AnnotationNode.METHOD_TARGET))
+        assertTrue(node.isTargetAllowed(METHOD_TARGET))
+
+        for (target in [TYPE_TARGET, CONSTRUCTOR_TARGET, FIELD_TARGET, 
PARAMETER_TARGET,
+                        LOCAL_VARIABLE_TARGET, ANNOTATION_TARGET, 
PACKAGE_TARGET,
+                        TYPE_PARAMETER_TARGET, TYPE_USE_TARGET, 
RECORD_COMPONENT_TARGET]) {
+            assertFalse(node.isTargetAllowed(target))
+        }
+    }
+
+    // GROOVY-6526
+    @Test
+    void testIsTargetAllowed2() {
+        def node = new AnnotationNode(ClassHelper.DEPRECATED_TYPE)
+
+        for (target in [TYPE_TARGET, CONSTRUCTOR_TARGET, METHOD_TARGET, 
FIELD_TARGET,
+                        LOCAL_VARIABLE_TARGET, PARAMETER_TARGET, 
PACKAGE_TARGET]) {
+            assertTrue(node.isTargetAllowed(target))
+        }
+
+        for (target in [TYPE_PARAMETER_TARGET, TYPE_USE_TARGET, 
RECORD_COMPONENT_TARGET]) {
+            assertFalse(node.isTargetAllowed(target))
+        }
+    }
+
+    // GROOVY-11838
+    @Test
+    void testIsTargetAllowed3() {
+        def node = new AnnotationNode(new ClassNode("A", 0x2000, 
ClassHelper.Annotation_TYPE))
 
-        assertFalse(node.isTargetAllowed(AnnotationNode.TYPE_USE_TARGET))
-        assertFalse(node.isTargetAllowed(AnnotationNode.TYPE_PARAMETER_TARGET))
+        for (target in [TYPE_TARGET, CONSTRUCTOR_TARGET, METHOD_TARGET, 
FIELD_TARGET,
+                        PARAMETER_TARGET, LOCAL_VARIABLE_TARGET, 
ANNOTATION_TARGET,
+                        PACKAGE_TARGET, RECORD_COMPONENT_TARGET]) {
+            assertTrue(node.isTargetAllowed(target))
+        }
+        assertFalse(node.isTargetAllowed(TYPE_USE_TARGET))
+        assertFalse(node.isTargetAllowed(TYPE_PARAMETER_TARGET))
     }
 
     @Test
@@ -47,7 +78,7 @@ final class AnnotationNodeTest {
 
     @Test
     void testGetText2() {
-        def node = new AnnotationNode(ClassHelper.make(Deprecated))
+        def node = new AnnotationNode(ClassHelper.DEPRECATED_TYPE)
         node.addMember('since', new ConstantExpression('1.2.3'))
 
         assertEquals('@java.lang.Deprecated(since="1.2.3")', node.getText())

Reply via email to