Paul King created GROOVY-12206:
----------------------------------

             Summary: Ingest type-use annotations when reading compiled classes
                 Key: GROOVY-12206
                 URL: https://issues.apache.org/jira/browse/GROOVY-12206
             Project: Groovy
          Issue Type: Improvement
            Reporter: Paul King


Groovy currently discards type-use ({{ElementType.TYPE_USE}}) annotations when 
reading compiled classes, on both resolution paths:

* The ASM decompiler ({{org.codehaus.groovy.ast.decompiled.AsmDecompiler}}) 
only overrides {{visitTypeAnnotation}} for record components, and even there 
discards the {{typeRef}}/{{TypePath}} information. The class, method, and field 
visitors do not collect {{RuntimeVisibleTypeAnnotations}} at all, so type 
annotations on method return types, parameter types, field types, supertypes, 
and generic-signature components of precompiled classes are dropped.
* The reflection path 
({{org.codehaus.groovy.vmplugin.v8.Java8#configureClassNode}}) never consults 
{{java.lang.reflect.AnnotatedType}} ({{getAnnotatedReturnType}}, 
{{getAnnotatedParameterTypes}}, ...), so the same information is lost for 
already-loaded classes.

This matters because pure JSpecify annotations 
({{org.jspecify.annotations.Nullable}} etc.) are {{@Target(TYPE_USE)}} only: in 
bytecode they appear exclusively in the type-annotation attributes, including 
on plain non-generic method returns and parameters. Libraries using 
declaration-targeted annotations (JSR-305 style, Spring 6's 
{{org.springframework.lang.Nullable}}) remain visible to Groovy today, but a 
library annotated with pure JSpecify (e.g. Spring Framework 7) is completely 
invisible to tools such as the incubating {{groovy.typecheckers.NullChecker}}.

Proposed scope (behaviour-neutral metadata ingestion; no change to 
type-checking semantics):
# Collect type annotations in the decompiler stubs for classes, methods, and 
fields, retaining {{typeRef}} and {{TypePath}}.
# Surface annotations for the simple positions first (method return type, 
parameter types, field types, supertypes) onto the corresponding AST nodes / 
per-use {{ClassNode}}s.
# Map {{TypePath}}-addressed annotations onto generic-signature components. 
This requires annotatable per-use ClassNodes when parsing member signatures in 
{{DecompiledClassNode}}/{{MemberSignatureParser}} (note {{GenericsType}} 
extends {{ASTNode}}, not {{AnnotatedNode}}; the annotations attach to the 
type-argument ClassNode as they do for source).
# Mirror the same for the reflection path via {{AnnotatedType}}.

Laziness should be preserved (as for existing decompiled-node attributes) so 
there is no memory overhead when nobody asks for the annotations.

This is prerequisite plumbing for JSpecify-aware null checking (NullChecker 
now, deeper static type checker integration later), but is independently useful 
to any AST transform or tool that needs to see type annotations of dependencies.




--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to