[ 
https://issues.apache.org/jira/browse/GROOVY-12251?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Paul King resolved GROOVY-12251.
--------------------------------
    Fix Version/s: 6.0.0-beta-2
       Resolution: Fixed

> NullChecker: check @NonNull fields are definitely initialized (strict mode)
> ---------------------------------------------------------------------------
>
>                 Key: GROOVY-12251
>                 URL: https://issues.apache.org/jira/browse/GROOVY-12251
>             Project: Groovy
>          Issue Type: Improvement
>          Components: groovy-typecheckers
>            Reporter: Paul King
>            Assignee: Paul King
>            Priority: Major
>             Fix For: 6.0.0-beta-2
>
>
> The {{NullChecker}} type-checking extension catches _assigning_ null to a 
> {{@NonNull}} field, but a {{@NonNull}} field that is simply *never 
> initialized* passes silently — and is then trusted as non-null at every 
> dereference, so the one field guaranteed to hold null is the one the checker 
> never warns about. Definite-initialization checking of non-null fields is a 
> core check in comparable tools (NullAway, the Checker Framework's nullness 
> checker).
> This issue adds, in flow-sensitive mode ({{NullChecker(strict: true)}}), a 
> check that each explicitly-annotated {{@NonNull}} instance field is 
> definitely initialized in one of the accepted ways:
> * at its declaration ({{@NonNull String name = 'unknown'}})
> * in an instance initializer block
> * by *every* declared constructor — a constructor delegating via 
> {{this(...)}} relies on its delegate
> A class with no declared constructor reports {{@NonNull field 'name' is not 
> initialized}}; a class where some but not all constructors assign the field 
> reports {{@NonNull field 'name' is not initialized by all constructors}}.
> Example:
> {code:groovy}
> import groovy.transform.TypeChecked
> @TypeChecked(extensions = 'groovy.typecheckers.NullChecker(strict: true)')
> class Library {
>     @NonNull String catalog                  // never assigned
>     Library(String catalog) { }              // oops — forgot this.catalog = 
> catalog
> }
> {code}
> {noformat}
> [Static type checking] - @NonNull field 'catalog' is not initialized by all 
> constructors
> {noformat}
> Deliberate scoping, to keep the check noise-free for idiomatic Groovy:
> * *Strict mode only.* The lenient checker's contract is incremental adoption; 
> enabling this there would immediately flag existing {{@NonNull}} property 
> classes constructed via named arguments ({{new Foo(name: 'x')}} initializes 
> the property _after_ default construction). Strict mode is documented as the 
> "full coverage" tier, which is where a definite-initialization guarantee 
> belongs. Promoting it to lenient mode later remains open for discussion.
> * *Explicitly-annotated fields only.* Fields that are merely non-null by 
> default (under {{@NullMarked}} / {{@NonNullByDefault}} without their own 
> annotation) are not checked, for the same named-argument-bean reason.
> * *Exclusions:* {{@MonotonicNonNull}} and {{@Lazy}} fields (deliberately 
> initialized late), primitives, and interfaces. Static fields are deferred for 
> now.
> * *Not path-sensitive:* an assignment anywhere in a constructor counts; 
> per-path definite-assignment analysis could tighten this later.



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

Reply via email to