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)