[
https://issues.apache.org/jira/browse/GROOVY-12209?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
Paul King resolved GROOVY-12209.
--------------------------------
Fix Version/s: 6.0.0-beta-1
Assignee: Paul King
Resolution: Fixed
> NullChecker: track nullness through ?., ?:, and ternary results
> ---------------------------------------------------------------
>
> Key: GROOVY-12209
> URL: https://issues.apache.org/jira/browse/GROOVY-12209
> Project: Groovy
> Issue Type: Improvement
> Components: groovy-typecheckers
> Reporter: Paul King
> Assignee: Paul King
> Priority: Major
> Fix For: 6.0.0-beta-1
>
>
> The incubating {{groovy.typecheckers.NullChecker}} tracks nullability per
> *variable*, and already handles several expression forms: dereferencing a
> {{@Nullable}}-returning method call is flagged, strict mode merges
> null-literal branches of ternaries, and elvis assignments over null-literal
> fallbacks are tracked (see {{testNullableMethodReturnDereference}},
> {{testStrictTernary*}}, {{testStrictElvis*}}).
> However, nullness of expression *results* is not propagated in general — the
> null-literal flows work while nullable-expression flows don't. Confirmed gaps:
> * Safe-navigation results: the documented behaviour is unchanged —
> {{input?.length()}} stays OK, since {{?.}} guards the receiver it is applied
> to. The gap is the *result* of a safe navigation used as an unguarded
> receiver afterwards: {{a?.b.c}} parses as {{(a?.b).c}} and throws NPE at
> runtime when {{a}} is null, so it should be flagged ({{a?.b}} is nullable by
> definition, even when {{b}} is {{@NonNull}}), while {{a?.b?.c}} is fine.
> Currently only {{VariableExpression}} and {{MethodCallExpression}} receivers
> are checked in {{checkDereference}}, so a {{PropertyExpression}} receiver
> passes silently.
> * Nullable expressions as arguments: {{isKnownNullable}} recognizes variables
> only, so passing a {{@Nullable}}-returning call or a safe-navigation result
> directly to a {{@NonNull}} parameter (e.g. {{process(repo.findById(id))}}) is
> not caught — only when first assigned to a variable.
> * Ternary/elvis over nullable non-literals: {{cond ? maybeNull : other}} and
> {{x ?: maybeNullCall()}} where a branch is a nullable *variable or call*
> (rather than a null literal) are not merged into the result's nullness.
> * {{@Nullable}} getters dereferenced via property syntax mid-chain: {{x.a.b}}
> where {{getA()}} is {{@Nullable}} is caught when written as {{x.getA().b}}
> but not in property form.
> * Cast and parenthesized expressions should be transparent to nullness in
> {{isKnownNullable}} (they already are in {{isNullExpr}}).
> Together with broadened guard recognition (companion issue), this moves the
> checker from "annotated variables" coverage to "annotated APIs used
> idiomatically" coverage — values obtained from framework calls and used
> inline, which is where most real null-mishandling occurs.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)