This is an automated email from the ASF dual-hosted git repository.
emilles pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/groovy.git
The following commit(s) were added to refs/heads/master by this push:
new e16c9fb618 GROOVY-6526: compute annotation targets and retention
lazily (#2388)
e16c9fb618 is described below
commit e16c9fb618f08b5f8cb0cac152d526d1bffadc04
Author: Eric Milles <[email protected]>
AuthorDate: Sat Mar 7 16:04:26 2026 -0600
GROOVY-6526: compute annotation targets and retention lazily (#2388)
---
.../org/codehaus/groovy/ast/AnnotationNode.java | 134 +++++++++++++--------
.../groovy/ast/decompiled/Annotations.java | 3 +-
.../codehaus/groovy/classgen/ExtendedVerifier.java | 31 +----
.../org/codehaus/groovy/vmplugin/VMPlugin.java | 14 ++-
.../org/codehaus/groovy/vmplugin/v16/Java16.java | 6 -
.../org/codehaus/groovy/vmplugin/v8/Java8.java | 85 ++-----------
.../org/codehaus/groovy/vmplugin/v9/Java9.java | 7 --
.../codehaus/groovy/ast/AnnotationNodeTest.groovy | 81 +++++++++++--
.../ast/visitor/AnnotationProcessorVisitor.java | 2 -
9 files changed, 185 insertions(+), 178 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..94b772f615 100644
--- a/src/main/java/org/codehaus/groovy/ast/AnnotationNode.java
+++ b/src/main/java/org/codehaus/groovy/ast/AnnotationNode.java
@@ -22,7 +22,12 @@ 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.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
@@ -49,8 +54,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) {
classNode = requireNonNull(type);
@@ -77,38 +80,20 @@ public class AnnotationNode extends ASTNode {
}
}
- public void setAllowedTargets(final int bitmap) {
- allowedTargets = bitmap;
+ @Deprecated(since = "6.0.0")
+ public void setAllowedTargets(final int ignored) {
}
- /**
- * Sets the internal flag if the current annotation has
<code>RetentionPolicy.RUNTIME</code>.
- *
- * @param value if <tt>true</tt> then current annotation is marked as
having
- * <code>RetentionPolicy.RUNTIME</code>.
- */
- public void setRuntimeRetention(final boolean value) {
- runtimeRetention = value;
+ @Deprecated(since = "6.0.0")
+ public void setClassRetention(final boolean ignored) {
}
- /**
- * Sets the internal flag if the current annotation has
<code>RetentionPolicy.SOURCE</code>.
- *
- * @param value if <tt>true</tt> then current annotation is marked as
having
- * <code>RetentionPolicy.SOURCE</code>.
- */
- public void setSourceRetention(final boolean value) {
- sourceRetention = value;
+ @Deprecated(since = "6.0.0")
+ public void setSourceRetention(final boolean ignored) {
}
- /**
- * Sets the internal flag if the current annotation has an explicit
<code>RetentionPolicy.CLASS</code>.
- *
- * @param value if <tt>true</tt> then current annotation is marked as
having
- * <code>RetentionPolicy.CLASS</code>.
- */
- public void setClassRetention(final boolean value) {
- classRetention = value;
+ @Deprecated(since = "6.0.0")
+ public void setRuntimeRetention(final boolean ignored) {
}
//--------------------------------------------------------------------------
@@ -137,37 +122,92 @@ 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.redirect().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;
+ }
+
+ private RetentionPolicy getRetentionPolicy() {
+ if (!(classNode.isPrimaryClassNode() || classNode.isResolved()))
+ throw new IllegalStateException("cannot check retention at this
time");
+
+ // GROOVY-6526: check class for @Retention
+ return classNode.redirect().getNodeMetaData(Retention.class, (k) -> {
+ for (AnnotationNode an : classNode.getAnnotations()) {
+ if
("java.lang.annotation.Retention".equals(an.getClassNode().getName())) {
+ if (an.getMember("value") instanceof PropertyExpression
pe) {
+ return
RetentionPolicy.valueOf(pe.getPropertyAsString());
+ }
+ break;
+ }
+ }
+ return null;
+ });
}
/**
* 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() {
- return this.runtimeRetention;
+ return RetentionPolicy.RUNTIME.equals(getRetentionPolicy());
}
/**
* 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() {
- return this.sourceRetention;
+ return RetentionPolicy.SOURCE.equals(getRetentionPolicy());
}
/**
* 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() {
- if (!runtimeRetention && !sourceRetention) return true;
- return this.classRetention;
+ RetentionPolicy retentionPolicy = getRetentionPolicy();
+ return retentionPolicy == null ||
retentionPolicy.equals(RetentionPolicy.CLASS);
}
@Override
@@ -205,17 +245,17 @@ public class AnnotationNode extends ASTNode {
}
public static String targetToName(final int target) {
+ if ((target & 1) == 1) return "TYPE"; // GROOVY-7151
return switch (target) {
- case TYPE_TARGET -> "TYPE";
- case CONSTRUCTOR_TARGET -> "CONSTRUCTOR";
- case METHOD_TARGET -> "METHOD";
- case FIELD_TARGET -> "FIELD";
- case PARAMETER_TARGET -> "PARAMETER";
- case LOCAL_VARIABLE_TARGET -> "LOCAL_VARIABLE";
- case ANNOTATION_TARGET -> "ANNOTATION";
- case PACKAGE_TARGET -> "PACKAGE";
- case TYPE_PARAMETER_TARGET -> "TYPE_PARAMETER";
- case TYPE_USE_TARGET -> "TYPE_USE";
+ case CONSTRUCTOR_TARGET -> "CONSTRUCTOR";
+ case METHOD_TARGET -> "METHOD";
+ case FIELD_TARGET -> "FIELD";
+ case PARAMETER_TARGET -> "PARAMETER";
+ case LOCAL_VARIABLE_TARGET -> "LOCAL_VARIABLE";
+ case ANNOTATION_TARGET -> "ANNOTATION";
+ case PACKAGE_TARGET -> "PACKAGE";
+ case TYPE_PARAMETER_TARGET -> "TYPE_PARAMETER";
+ case TYPE_USE_TARGET -> "TYPE_USE";
case RECORD_COMPONENT_TARGET -> "RECORD_COMPONENT";
default -> "unknown target";
};
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/classgen/ExtendedVerifier.java
b/src/main/java/org/codehaus/groovy/classgen/ExtendedVerifier.java
index 9649ab87c4..7093788260 100644
--- a/src/main/java/org/codehaus/groovy/classgen/ExtendedVerifier.java
+++ b/src/main/java/org/codehaus/groovy/classgen/ExtendedVerifier.java
@@ -35,7 +35,6 @@ import org.codehaus.groovy.ast.expr.ClassExpression;
import org.codehaus.groovy.ast.expr.ConstructorCallExpression;
import org.codehaus.groovy.ast.expr.DeclarationExpression;
import org.codehaus.groovy.ast.expr.Expression;
-import org.codehaus.groovy.ast.expr.PropertyExpression;
import org.codehaus.groovy.ast.stmt.ReturnStatement;
import org.codehaus.groovy.ast.stmt.Statement;
import org.codehaus.groovy.control.AnnotationConstantsVisitor;
@@ -43,7 +42,6 @@ import org.codehaus.groovy.control.ErrorCollector;
import org.codehaus.groovy.control.SourceUnit;
import org.objectweb.asm.Opcodes;
-import java.lang.annotation.Retention;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
@@ -67,13 +65,11 @@ import static
org.codehaus.groovy.ast.AnnotationNode.TYPE_TARGET;
import static org.codehaus.groovy.ast.AnnotationNode.TYPE_USE_TARGET;
import static org.codehaus.groovy.ast.ClassHelper.DEPRECATED_TYPE;
import static org.codehaus.groovy.ast.ClassHelper.isPrimitiveVoid;
-import static org.codehaus.groovy.ast.ClassHelper.makeCached;
import static org.codehaus.groovy.ast.tools.GeneralUtils.listX;
import static
org.codehaus.groovy.ast.tools.GenericsUtils.correctToGenericsSpec;
import static org.codehaus.groovy.ast.tools.GenericsUtils.createGenericsSpec;
import static org.codehaus.groovy.ast.tools.GenericsUtils.parameterizeType;
import static org.codehaus.groovy.ast.tools.ParameterUtils.parametersEqual;
-import static
org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.evaluateExpression;
/**
* A specialized Groovy AST visitor meant to perform additional verifications
upon the
@@ -376,29 +372,12 @@ public class ExtendedVerifier extends
ClassCodeVisitorSupport {
if
(nonSourceAnnotations.containsKey(repeatable.getName())) {
addError("Cannot specify duplicate annotation on the
same member. Explicit " + repeatable.getName() + " found when creating implicit
container for " + entry.getKey(), node);
}
- AnnotationNode collector = new AnnotationNode(repeatable);
- if (repeatee.hasClassRetention()) {
- collector.setClassRetention(true);
- } else if (repeatee.hasRuntimeRetention()) {
- collector.setRuntimeRetention(true);
- } else { // load retention policy from annotation
definition
- List<AnnotationNode> retention =
repeatable.getAnnotations(makeCached(Retention.class));
- if (!retention.isEmpty()) {
- Object policy;
- Expression value =
retention.get(0).getMember("value");
- if (value instanceof PropertyExpression) {
- policy = ((PropertyExpression)
value).getPropertyAsString();
- } else { // NOTE: it is risky to evaluate the
expression from repeatable's source this way:
- policy = evaluateExpression(value,
source.getConfiguration(), source.getClassLoader());
- }
- if ("CLASS".equals(policy)) {
- collector.setClassRetention(true);
- } else if ("RUNTIME".equals(policy)) {
- collector.setRuntimeRetention(true);
- }
- }
- }
+ var collector = new AnnotationNode(repeatable);
+ assert collector.hasClassRetention() ==
repeatee.hasClassRetention();
+ assert collector.hasSourceRetention() ==
repeatee.hasSourceRetention();
+ assert collector.hasRuntimeRetention() ==
repeatee.hasRuntimeRetention();
collector.addMember("value",
listX(entry.getValue().stream().map(AnnotationConstantExpression::new).collect(toList())));
+
node.getAnnotations().removeAll(entry.getValue());
node.addAnnotation(collector);
}
diff --git a/src/main/java/org/codehaus/groovy/vmplugin/VMPlugin.java
b/src/main/java/org/codehaus/groovy/vmplugin/VMPlugin.java
index 602b452bf6..17e7e21686 100644
--- a/src/main/java/org/codehaus/groovy/vmplugin/VMPlugin.java
+++ b/src/main/java/org/codehaus/groovy/vmplugin/VMPlugin.java
@@ -40,13 +40,19 @@ import java.util.Set;
* This interface is for internal use only!
*/
public interface VMPlugin {
- void setAdditionalClassInformation(ClassNode c);
+
Class[] getPluginDefaultGroovyMethods();
Class[] getPluginStaticGroovyMethods();
- void configureAnnotationNodeFromDefinition(AnnotationNode definition,
AnnotationNode root);
- void configureAnnotation(AnnotationNode an);
- void configureClassNode(CompileUnit compileUnit, ClassNode classNode);
+
+ void setAdditionalClassInformation(ClassNode node);
+ void configureClassNode(CompileUnit unit, ClassNode node);
+
+ void configureAnnotation(AnnotationNode node);
+ default void configureAnnotationNodeFromDefinition(AnnotationNode
definition, AnnotationNode node) {
+ }
+
void invalidateCallSites();
+
/**
* Returns a handle with bound receiver to invokeSpecial the given method.
* This method will require at least Java 7, but since the source has to
compile
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..826a177b86 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.
@@ -121,22 +118,6 @@ public class Java8 implements VMPlugin {
}
}
- private static void setRetentionPolicy(final RetentionPolicy value, final
AnnotationNode node) {
- switch (value) {
- case RUNTIME:
- node.setRuntimeRetention(true);
- break;
- case SOURCE:
- node.setSourceRetention(true);
- break;
- case CLASS:
- node.setClassRetention(true);
- break;
- default:
- throw new GroovyBugError("unsupported Retention " + value);
- }
- }
-
//--------------------------------------------------------------------------
@Override
@@ -272,27 +253,19 @@ public class Java8 implements VMPlugin {
}
private void configureAnnotation(final AnnotationNode node, final
Annotation annotation) {
- Class<?> type = annotation.annotationType();
- if (type == Retention.class) {
- Retention r = (Retention) annotation;
- RetentionPolicy value = r.value();
- setRetentionPolicy(value, node);
- node.setMember("value", new PropertyExpression(
- new
ClassExpression(ClassHelper.makeWithoutCaching(RetentionPolicy.class, false)),
- value.toString()));
- } else if (type == Target.class) {
- Target t = (Target) annotation;
- ElementType[] elements = t.value();
- ListExpression elementExprs = new ListExpression();
- for (ElementType element : elements) {
- elementExprs.addExpression(new PropertyExpression(
- new ClassExpression(ClassHelper.ELEMENT_TYPE_TYPE),
element.name()));
+ if (annotation instanceof Retention r) {
+ final ClassNode retentionPolicy =
ClassHelper.makeWithoutCaching(RetentionPolicy.class, false);
+ node.setMember("value", new PropertyExpression(new
ClassExpression(retentionPolicy), r.value().toString()));
+ } else if (annotation instanceof Target t) {
+ var elementExprs = new ListExpression();
+ for (ElementType elementTypes : t.value()) {
+ elementExprs.addExpression(new PropertyExpression(new
ClassExpression(ClassHelper.ELEMENT_TYPE_TYPE), elementTypes.name()));
}
node.setMember("value", elementExprs);
} else {
Method[] declaredMethods;
try {
- declaredMethods = type.getDeclaredMethods();
+ declaredMethods =
annotation.annotationType().getDeclaredMethods();
} catch (SecurityException se) {
declaredMethods = EMPTY_METHOD_ARRAY;
}
@@ -301,7 +274,6 @@ public class Java8 implements VMPlugin {
Object value = declaredMethod.invoke(annotation);
Expression valueExpression =
toAnnotationValueExpression(value);
if (valueExpression != null)
node.setMember(declaredMethod.getName(), valueExpression);
-
} catch (IllegalAccessException | InvocationTargetException
ignore) {
}
}
@@ -344,47 +316,6 @@ 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);
- }
- }
- }
-
@Override
public void configureClassNode(final CompileUnit compileUnit, final
ClassNode classNode) {
try {
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..c52c0531d6 100644
--- a/src/test/groovy/org/codehaus/groovy/ast/AnnotationNodeTest.groovy
+++ b/src/test/groovy/org/codehaus/groovy/ast/AnnotationNodeTest.groovy
@@ -21,21 +21,88 @@ 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-6526
+ @Test
+ void testIsTargetAllowed1() {
+ def node = new AnnotationNode(ClassHelper.OVERRIDE_TYPE)
+
+ 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 testIsTargetAllowed() {
+ void testIsTargetAllowed3() {
+ def node = new AnnotationNode(new ClassNode("A", 0x2000,
ClassHelper.Annotation_TYPE))
+
+ 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
+ void testRetentionPolicy1() {
+ def node = new
AnnotationNode(ClassHelper.make(gls.annotations.HasExplicitClassRetention))
+
+ assertTrue (node.hasClassRetention())
+ assertFalse(node.hasSourceRetention())
+ assertFalse(node.hasRuntimeRetention())
+ }
+
+ @Test
+ void testRetentionPolicy2() {
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))
+ assertFalse(node.hasClassRetention())
+ assertTrue (node.hasSourceRetention())
+ assertFalse(node.hasRuntimeRetention())
+ }
+
+ @Test
+ void testRetentionPolicy3() {
+ def node = new AnnotationNode(ClassHelper.DEPRECATED_TYPE)
+
+ assertFalse(node.hasClassRetention())
+ assertFalse(node.hasSourceRetention())
+ assertTrue (node.hasRuntimeRetention())
+ }
+
+ @Test
+ void testRetentionPolicy4() {
+ 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))
+ assertTrue (node.hasClassRetention())
+ assertFalse(node.hasSourceRetention())
+ assertFalse(node.hasRuntimeRetention())
}
@Test
@@ -47,7 +114,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())
diff --git
a/subprojects/groovy-contracts/src/main/java/org/apache/groovy/contracts/ast/visitor/AnnotationProcessorVisitor.java
b/subprojects/groovy-contracts/src/main/java/org/apache/groovy/contracts/ast/visitor/AnnotationProcessorVisitor.java
index 56d59233df..bcdd4ab96e 100644
---
a/subprojects/groovy-contracts/src/main/java/org/apache/groovy/contracts/ast/visitor/AnnotationProcessorVisitor.java
+++
b/subprojects/groovy-contracts/src/main/java/org/apache/groovy/contracts/ast/visitor/AnnotationProcessorVisitor.java
@@ -199,8 +199,6 @@ public class AnnotationProcessorVisitor extends BaseVisitor
{
if (!AnnotationUtils.hasAnnotationOfType(methodNode,
annotationNode.getClassNode().getName())) {
AnnotationNode markerAnnotation = new
AnnotationNode(annotationNode.getClassNode());
replaceCondition(markerAnnotation, valueExpression);
- markerAnnotation.setRuntimeRetention(true);
- markerAnnotation.setSourceRetention(false);
methodNode.addAnnotation(markerAnnotation);
}
}