GROOVY-11884: Close gaps in Groovy annotation validation#2407
GROOVY-11884: Close gaps in Groovy annotation validation#2407paulk-asert wants to merge 1 commit intoapache:masterfrom
Conversation
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## master #2407 +/- ##
==================================================
- Coverage 66.4099% 66.4086% -0.0013%
- Complexity 29890 29906 +16
==================================================
Files 1392 1394 +2
Lines 116823 116893 +70
Branches 20675 20682 +7
==================================================
+ Hits 77582 77627 +45
- Misses 32873 32893 +20
- Partials 6368 6373 +5
🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Pull request overview
Adds Groovy-specific annotation target validation to close gaps around annotations applied to imports and loop statements, aligning compiler checks with Groovy language constructs that don’t map to java.lang.annotation.ElementType.
Changes:
- Introduces
@ExtendedTarget/ExtendedElementTypeto declare Groovy-only targets (currentlyIMPORTandLOOP). - Extends compiler verification to validate annotations on import statements and statement-level (loop) annotations.
- Updates core/test annotations and tests/resources to reflect the new validation rules.
Reviewed changes
Copilot reviewed 17 out of 17 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| subprojects/groovy-contracts/src/main/java/groovy/contracts/Invariant.java | Allows @Invariant on loops via @ExtendedTarget(LOOP). |
| src/test/groovy/groovy/annotations/MyIntegerAnno.groovy | Marks test annotation as allowed on imports via @ExtendedTarget(IMPORT). |
| src/test/groovy/gls/annotations/AnnotationTest.groovy | Adds tests for import annotation validation and @ExtendedTarget(IMPORT). |
| src/test-resources/core/AnnotatedLoop_02x.groovy | Updates loop annotation expectations by removing an annotation no longer allowed on loops. |
| src/main/java/org/codehaus/groovy/classgen/ExtendedVerifier.java | Adds validation for import annotations and statement (loop) annotations. |
| src/main/java/org/codehaus/groovy/ast/AnnotationNode.java | Adds IMPORT_TARGET and @ExtendedTarget handling in isTargetAllowed. |
| src/main/java/groovy/transform/Parallel.java | Allows @Parallel on loops via @ExtendedTarget(LOOP). |
| src/main/java/groovy/transform/BaseScript.java | Allows @BaseScript on imports via @ExtendedTarget(IMPORT). |
| src/main/java/groovy/transform/ASTTest.java | Allows @ASTTest on loops via @ExtendedTarget(LOOP). |
| src/main/java/groovy/lang/annotation/ExtendedTarget.java | New meta-annotation for Groovy-only targets. |
| src/main/java/groovy/lang/annotation/ExtendedElementType.java | New enum defining Groovy-only element types (IMPORT, LOOP). |
| src/main/java/groovy/lang/Newify.java | Allows @Newify on imports via @ExtendedTarget(IMPORT). |
| src/main/java/groovy/lang/Grapes.java | Allows @Grapes on imports via @ExtendedTarget(IMPORT). |
| src/main/java/groovy/lang/GrabResolver.java | Allows @GrabResolver on imports via @ExtendedTarget(IMPORT). |
| src/main/java/groovy/lang/GrabExclude.java | Allows @GrabExclude on imports via @ExtendedTarget(IMPORT). |
| src/main/java/groovy/lang/GrabConfig.java | Allows @GrabConfig on imports via @ExtendedTarget(IMPORT). |
| src/main/java/groovy/lang/Grab.java | Allows @Grab on imports via @ExtendedTarget(IMPORT). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| @Override | ||
| protected void visitStatementAnnotations(final Statement statement) { | ||
| for (AnnotationNode annotation : statement.getStatementAnnotations()) { | ||
| ErrorCollector errorCollector = new ErrorCollector(source.getConfiguration()); | ||
| AnnotationVisitor visitor = new AnnotationVisitor(source, errorCollector); | ||
| AnnotationNode visited = visitor.visit(annotation); | ||
| source.getErrorCollector().addCollectorContents(errorCollector); | ||
|
|
||
| if (!visited.isTargetAllowed(STATEMENT_TARGET)) { | ||
| addError("Annotation @" + visited.getClassNode().getName() + " is not allowed on element " | ||
| + AnnotationNode.targetToName(STATEMENT_TARGET), visited); | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
This PR adds new validation for statement annotations via visitStatementAnnotations, but the test additions only cover import-level annotations. Consider adding a focused test that (1) rejects a non-@ExtendedTarget(LOOP) annotation on a loop and (2) accepts an annotation that declares @ExtendedTarget(LOOP), to ensure this new validation path is exercised and doesn’t regress.
| return switch (ExtendedElementType.valueOf(name)) { | ||
| case IMPORT -> IMPORT_TARGET; | ||
| case LOOP -> STATEMENT_TARGET; | ||
| }; |
There was a problem hiding this comment.
extendedElementTypeBits calls ExtendedElementType.valueOf(name) without guarding against name == null or unknown values. If an invalid enum constant is used in @ExtendedTarget(...), the compiler may throw IllegalArgumentException/NPE here (potentially masking the existing validation error) instead of reporting a clean compilation error. Consider handling null/invalid names (e.g., check for null and catch IllegalArgumentException) and returning 0 or producing a targeted error message.
| return switch (ExtendedElementType.valueOf(name)) { | |
| case IMPORT -> IMPORT_TARGET; | |
| case LOOP -> STATEMENT_TARGET; | |
| }; | |
| if (name == null) { | |
| return 0; | |
| } | |
| try { | |
| return switch (ExtendedElementType.valueOf(name)) { | |
| case IMPORT -> IMPORT_TARGET; | |
| case LOOP -> STATEMENT_TARGET; | |
| }; | |
| } catch (IllegalArgumentException ignore) { | |
| // unknown ExtendedElementType value; no extended element type bits | |
| return 0; | |
| } |
| import java.util.ArrayList; | ||
| import java.util.Collections; | ||
| import java.util.HashMap; | ||
| import java.util.HashSet; | ||
| import java.util.Iterator; | ||
| import java.util.LinkedHashMap; | ||
| import java.util.LinkedList; | ||
| import java.util.List; | ||
| import java.util.Map; | ||
| import java.util.Set; |
There was a problem hiding this comment.
Unused import: java.util.Collections is added but not referenced in this file. Please remove it to keep the import list clean and avoid warnings.
88afe5b to
8244ea1
Compare
No description provided.