@ -182,6 +182,38 @@ let check_field_assignment tenv find_canonical_duplicate curr_pdesc node instr_r
( Some instr_ref ) loc curr_pdesc
( Some instr_ref ) loc curr_pdesc
let is_nullable { annotated_type } =
match annotated_type . nullability with
| AnnotatedNullability . Nullable _ ->
true
| AnnotatedNullability . Nonnull _ ->
false
let is_nonnull { annotated_type } =
match annotated_type . nullability with
| AnnotatedNullability . Nullable _ ->
false
| AnnotatedNullability . Nonnull _ ->
true
(* Do we have evidence that the field is annotated as nullable? *)
let is_field_annotated_as_nullable annotated_field_opt =
(* If the field is not present, we optimistically assume it is not nullable.
TODO ( T54687014 ) investigate if this leads to unsoundness issues in practice
* )
Option . exists annotated_field_opt ~ f : is_nullable
(* Do we have evidence that the field is annotated as non-nullable? *)
let is_field_annotated_as_nonnull annotated_field_opt =
(* If the field is not present, we optimistically assume it is not nullable.
TODO ( T54687014 ) investigate if this leads to unsoundness issues in practice
* )
Option . exists annotated_field_opt ~ f : is_nonnull
(* * Check that nonnullable fields are initialized in constructors. *)
(* * Check that nonnullable fields are initialized in constructors. *)
let check_constructor_initialization tenv find_canonical_duplicate curr_pname curr_pdesc start_node
let check_constructor_initialization tenv find_canonical_duplicate curr_pname curr_pdesc start_node
final_initializer_typestates final_constructor_typestates loc : unit =
final_initializer_typestates final_constructor_typestates loc : unit =
@ -192,16 +224,13 @@ let check_constructor_initialization tenv find_canonical_duplicate curr_pname cu
match Tenv . lookup tenv name with
match Tenv . lookup tenv name with
| Some { fields } ->
| Some { fields } ->
let do_field ( fn , ft , _ ) =
let do_field ( fn , ft , _ ) =
let annotated_with f =
let annotated_field = get_field_annotation tenv fn ts in
match get_field_annotation tenv fn ts with
let is_injector_readonly_annotated =
match annotated_field with
| None ->
| None ->
false
false
| Some { annotation_deprecated } ->
| Some { annotation_deprecated } ->
f annotation_deprecated
Annotations . ia_is_field_injector_readonly annotation_deprecated
in
let nullable_annotated = annotated_with Annotations . ia_is_nullable in
let injector_readonly_annotated =
annotated_with Annotations . ia_is_field_injector_readonly
in
in
let final_type_annotation_with unknown list f =
let final_type_annotation_with unknown list f =
let filter_range_opt = function Some ( _ , ta , _ ) -> f ta | None -> unknown in
let filter_range_opt = function Some ( _ , ta , _ ) -> f ta | None -> unknown in
@ -237,19 +266,23 @@ let check_constructor_initialization tenv find_canonical_duplicate curr_pname cu
let fld_cname = Typ . Fieldname . Java . get_class fn in
let fld_cname = Typ . Fieldname . Java . get_class fn in
String . equal ( Typ . Name . name name ) fld_cname
String . equal ( Typ . Name . name name ) fld_cname
in
in
( not i njector_readonly_annotated) && PatternMatch . type_is_class ft
( not i s_i njector_readonly_annotated)
&& in_current_class
&& PatternMatch . type_is_class ft && in_current_class
&& not ( Typ . Fieldname . Java . is_outer_instance fn )
&& not ( Typ . Fieldname . Java . is_outer_instance fn )
in
in
if should_check_field_initialization then (
if should_check_field_initialization then (
(* Check if field is missing annotation. *)
(* Check if non-null field is not initialized. *)
if ( not nullable_annotated ) && not may_be_assigned_in_final_typestate then
if
is_field_annotated_as_nonnull annotated_field
&& not may_be_assigned_in_final_typestate
then
report_error tenv find_canonical_duplicate
report_error tenv find_canonical_duplicate
( TypeErr . Field_not_initialized ( fn , curr_pname ) )
( TypeErr . Field_not_initialized ( fn , curr_pname ) )
None loc curr_pdesc ;
None loc curr_pdesc ;
(* Check if field is over-annotated. *)
(* Check if field is over-annotated. *)
if
if
Config . eradicate_field_over_annotated && nullable_annotated
Config . eradicate_field_over_annotated
&& is_field_annotated_as_nullable annotated_field
&& not ( may_be_nullable_in_final_typestate () )
&& not ( may_be_nullable_in_final_typestate () )
then
then
report_error tenv find_canonical_duplicate
report_error tenv find_canonical_duplicate