[nullsafe] Fix a bug in handling of modelled nullable fields

Summary:
The problem is that `Models.is_field_nonnullable` didn't differentiate
between
- having a nullable model (in which case we want the field to be NULLABLE),
- not having a model at all (in which case we want the field to be THIRDPARTY_NONNULL).

The problem was noticed only now because previously we didn't have any
NULLABLE field models.

Reviewed By: ngorogiannis

Differential Revision: D27709508

fbshipit-source-id: b98c8f86f
master
Artem Pianykh 4 years ago committed by Facebook GitHub Bot
parent 341169ff0f
commit a2bc973125

@ -89,9 +89,14 @@ let get tenv field_name ~class_typ ~class_under_analysis =
(* This field is artifact of codegen and is not visible to the user.
Surfacing it as non-strict is non-actionable for the user *)
AnnotatedNullability.StrictNonnull SyntheticField
else if Models.is_field_nonnullable field_name then
else
match Models.is_field_nonnullable field_name with
| Some true ->
AnnotatedNullability.StrictNonnull ModelledNonnull
else nullability
| Some false ->
AnnotatedNullability.Nullable ModelledNullable
| _ ->
nullability
else nullability
in
let field_class =

@ -747,6 +747,7 @@ let field_nullability =
; ( "android.content.pm.ResolveInfo.providerInfo"
, n (* Exactly one of activityInfo, serviceInfo, or providerInfo will be non-null. *) )
; ("android.content.res.Configuration.locale", o)
; ("android.graphics.BitmapFactory$Options.inBitmap", n)
; ("android.graphics.Paint.Align.CENTER", o)
; ("android.graphics.Paint.Align.LEFT", o)
; ("android.graphics.Paint.Align.RIGHT", o)

@ -134,5 +134,12 @@ let find_nonnullable_alternative proc_name =
let is_field_nonnullable field_name =
Hashtbl.find_opt field_nullability_table (Fieldname.to_full_string field_name)
|> Option.value_map ~f:(fun is_nullable -> not is_nullable) ~default:false
Logging.d_with_indent ~name:"is_field_nonnullable" (fun () ->
let full_name = Fieldname.to_full_string field_name in
let from_model =
Hashtbl.find_opt field_nullability_table full_name
(* Models return `is_nullable`, we need `is_notnull` *)
|> Option.map ~f:not
in
Logging.d_printfln "Model for %s: %a" full_name (Pp.option Format.pp_print_bool) from_model ;
from_model )

@ -48,5 +48,5 @@ val find_nonnullable_alternative : Procname.Java.t -> ModelTables.nonnull_altern
(** Check if a (nullable) method has a non-nullable alternative: A method that does the same as
[proc_name] but asserts the result is not null before returning to the caller. *)
val is_field_nonnullable : Fieldname.t -> bool
(** Check if a given field is known to be a non-nullable *)
val is_field_nonnullable : Fieldname.t -> bool option
(** Check if a given field has known nullability: true = nonnull, false = null *)

@ -260,20 +260,26 @@ let funcall_exp_to_original_pvar_exp tenv curr_pname typestate exp ~is_assignmen
let add_field_to_typestate_if_absent tenv access_loc typestate pvar object_origin field_name
~field_class_typ ~class_under_analysis =
L.d_with_indent ~name:"add_field_to_typestate_if_absent" (fun () ->
match TypeState.lookup_pvar pvar typestate with
| Some _ ->
typestate
| None -> (
match AnnotatedField.get tenv field_name ~class_typ:field_class_typ ~class_under_analysis with
match
AnnotatedField.get tenv field_name ~class_typ:field_class_typ ~class_under_analysis
with
| Some AnnotatedField.{annotated_type= field_type} ->
let range =
( field_type.typ
, InferredNullability.create
(TypeOrigin.Field {object_origin; field_name; field_type; access_loc}) )
in
let _, inferred_nullability = range in
L.d_printfln "Fieldname %a: typ=%a, inferred_nullability=%a" Fieldname.pp field_name
AnnotatedType.pp field_type InferredNullability.pp inferred_nullability ;
TypeState.add ~descr:"add_field_to_typestate_if_absent" pvar range typestate
| None ->
typestate )
typestate ) )
(* This does two things:

Loading…
Cancel
Save