[ 
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)

Reply via email to