[nullsafe] Introduce NullsafeMode as a replacement for `is_strict_mode`

Summary:
Refactor all occurences of `is_strict_mode` to use `NullsafeMode`
instead. This will allow introducing _local_ typechecking modes for
nullsafe in the follow up patches.

Reviewed By: ezgicicek

Differential Revision: D19639883

fbshipit-source-id: bdf535b66
master
Artem Pianykh 5 years ago committed by Facebook Github Bot
parent 355ff5c202
commit c735b6f0a5

@ -120,10 +120,14 @@ let type_get_direct_supertypes tenv (typ : Typ.t) =
let type_get_class_name {Typ.desc} = match desc with Typ.Tptr (typ, _) -> Typ.name typ | _ -> None
let type_name_get_annotation tenv (name : Typ.name) : Annot.Item.t option =
match Tenv.lookup tenv name with Some {annots} -> Some annots | None -> None
let type_get_annotation tenv (typ : Typ.t) : Annot.Item.t option =
match typ.desc with
| Tptr ({desc= Tstruct name}, _) | Tstruct name -> (
match Tenv.lookup tenv name with Some {annots} -> Some annots | None -> None )
| Tptr ({desc= Tstruct name}, _) | Tstruct name ->
type_name_get_annotation tenv name
| _ ->
None

@ -122,6 +122,8 @@ val override_iter : (Procname.t -> unit) -> Tenv.t -> Procname.t -> unit
val lookup_attributes : Tenv.t -> Procname.t -> ProcAttributes.t option
val type_name_get_annotation : Tenv.t -> Typ.name -> Annot.Item.t option
val type_get_annotation : Tenv.t -> Typ.t -> Annot.Item.t option
val type_get_class_name : Typ.t -> Typ.Name.t option

@ -12,14 +12,6 @@ open! IStd
*)
type t = {annotation_deprecated: Annot.Item.t; annotated_type: AnnotatedType.t}
let is_class_in_strict_mode tenv typ =
match PatternMatch.type_get_annotation tenv typ with
| Some ia ->
Annotations.ia_is_nullsafe_strict ia
| None ->
false
let rec get_type_name {Typ.desc} =
match desc with Typ.Tstruct name -> Some name | Typ.Tptr (t, _) -> get_type_name t | _ -> None
@ -47,12 +39,15 @@ let is_enum_value tenv ~class_typ (field_info : Struct.field_info) =
let get tenv field_name class_typ =
let lookup = Tenv.lookup tenv in
(* We currently don't support field-level strict mode annotation, so fetch it from class *)
let is_strict_mode = is_class_in_strict_mode tenv class_typ in
let nullsafe_mode =
Typ.name class_typ
|> Option.value_map ~f:(NullsafeMode.of_class tenv) ~default:NullsafeMode.Default
in
Struct.get_field_info ~lookup field_name class_typ
|> Option.map ~f:(fun (Struct.{typ= field_typ; annotations} as field_info) ->
let is_enum_value = is_enum_value tenv ~class_typ field_info in
let nullability =
AnnotatedNullability.of_type_and_annotation field_typ annotations ~is_strict_mode
AnnotatedNullability.of_type_and_annotation field_typ annotations ~nullsafe_mode
in
let corrected_nullability =
match nullability with

@ -91,7 +91,7 @@ let pp fmt t =
F.fprintf fmt "StrictNonnull[%s]" (string_of_nonnull_origin origin)
let of_type_and_annotation ~is_strict_mode typ annotations =
let of_type_and_annotation ~(nullsafe_mode : NullsafeMode.t) typ annotations =
if not (PatternMatch.type_is_class typ) then StrictNonnull PrimitiveType
else if Annotations.ia_is_nullable annotations then
let nullable_origin =
@ -99,7 +99,11 @@ let of_type_and_annotation ~is_strict_mode typ annotations =
else AnnotatedNullable
in
Nullable nullable_origin
else if is_strict_mode then StrictNonnull StrictMode
else if Annotations.ia_is_nonnull annotations then UncheckedNonnull AnnotatedNonnull
(* Currently, we treat not annotated types as nonnull *)
else UncheckedNonnull ImplicitlyNonnull
else
match nullsafe_mode with
| NullsafeMode.Strict ->
StrictNonnull StrictMode
| NullsafeMode.Default ->
if Annotations.ia_is_nonnull annotations then UncheckedNonnull AnnotatedNonnull
(* Currently, we treat not annotated types as nonnull *)
else UncheckedNonnull ImplicitlyNonnull

@ -51,7 +51,7 @@ and strict_nonnull_origin =
val get_nullability : t -> Nullability.t
val of_type_and_annotation : is_strict_mode:bool -> Typ.t -> Annot.Item.t -> t
val of_type_and_annotation : nullsafe_mode:NullsafeMode.t -> Typ.t -> Annot.Item.t -> t
(** Given the type and its annotations, returns its nullability. NOTE: it does not take into account
models etc., so this is intended to be used as a helper function for more high-level annotation
processing. *)

@ -16,7 +16,7 @@ module L = Logging
*)
type t =
{ is_strict_mode: bool
{ nullsafe_mode: NullsafeMode.t
; model_source: model_source option
; ret: ret_signature
; params: param_signature list }
@ -35,10 +35,10 @@ and model_source = InternalModel | ThirdPartyRepo of {filename: string; line_num
[@@deriving compare]
(* get nullability of method's return type given its annotations and information about its params *)
let nullability_for_return ret_type ret_annotations ~is_strict_mode
~has_propagates_nullable_in_param =
let nullability_for_return ret_type ret_annotations ~nullsafe_mode ~has_propagates_nullable_in_param
=
let nullability =
AnnotatedNullability.of_type_and_annotation ~is_strict_mode ret_type ret_annotations
AnnotatedNullability.of_type_and_annotation ~nullsafe_mode ret_type ret_annotations
in
(* if any param is annotated with propagates nullable, then the result is nullable *)
match nullability with
@ -53,10 +53,10 @@ let nullability_for_return ret_type ret_annotations ~is_strict_mode
(* Given annotations for method signature, extract nullability information
for return type and params *)
let extract_nullability ~is_strict_mode ret_type ret_annotations param_annotated_types =
let extract_nullability ~nullsafe_mode ret_type ret_annotations param_annotated_types =
let params_nullability =
List.map param_annotated_types ~f:(fun (typ, annotations) ->
AnnotatedNullability.of_type_and_annotation typ annotations ~is_strict_mode )
AnnotatedNullability.of_type_and_annotation typ annotations ~nullsafe_mode )
in
let has_propagates_nullable_in_param =
List.exists params_nullability ~f:(function
@ -66,13 +66,12 @@ let extract_nullability ~is_strict_mode ret_type ret_annotations param_annotated
false )
in
let return_nullability =
nullability_for_return ret_type ret_annotations ~is_strict_mode
~has_propagates_nullable_in_param
nullability_for_return ret_type ret_annotations ~nullsafe_mode ~has_propagates_nullable_in_param
in
(return_nullability, params_nullability)
let get ~is_strict_mode proc_attributes : t =
let get ~nullsafe_mode proc_attributes : t =
let Annot.Method.{return= ret_annotation; params= original_params_annotation} =
proc_attributes.ProcAttributes.method_annotation
in
@ -101,7 +100,7 @@ let get ~is_strict_mode proc_attributes : t =
List.map params_with_annotations ~f:(fun ((_, typ), annotations) -> (typ, annotations))
in
let return_nullability, params_nullability =
extract_nullability ~is_strict_mode ret_type ret_annotation param_annotated_types
extract_nullability ~nullsafe_mode ret_type ret_annotation param_annotated_types
in
let ret =
{ ret_annotation_deprecated= ret_annotation
@ -114,7 +113,7 @@ let get ~is_strict_mode proc_attributes : t =
; mangled
; param_annotated_type= AnnotatedType.{nullability; typ} } )
in
{is_strict_mode; model_source= None; ret; params}
{nullsafe_mode; model_source= None; ret; params}
let param_has_annot predicate pvar ann_sig =
@ -131,9 +130,8 @@ let pp proc_name fmt annotated_signature =
Mangled.pp mangled
in
let {ret_annotation_deprecated; ret_annotated_type} = annotated_signature.ret in
let mode_as_string = if annotated_signature.is_strict_mode then "Strict" else "Def" in
F.fprintf fmt "[%s] %a%a %a (%a )" mode_as_string pp_ia ret_annotation_deprecated AnnotatedType.pp
ret_annotated_type
F.fprintf fmt "[%a] %a%a %a (%a )" NullsafeMode.pp annotated_signature.nullsafe_mode pp_ia
ret_annotation_deprecated AnnotatedType.pp ret_annotated_type
(Procname.pp_simplified_string ~withclass:false)
proc_name (Pp.comma_seq pp_annotated_param) annotated_signature.params

@ -10,7 +10,7 @@
open! IStd
type t =
{ is_strict_mode: bool
{ nullsafe_mode: NullsafeMode.t
; model_source: model_source option (** None, if signature is not modelled *)
; ret: ret_signature
; params: param_signature list }
@ -35,7 +35,7 @@ val set_modelled_nullability : Procname.t -> t -> model_source -> bool * bool li
(** Override nullability for a function signature given its modelled nullability (for ret value and
params) *)
val get : is_strict_mode:bool -> ProcAttributes.t -> t
val get : nullsafe_mode:NullsafeMode.t -> ProcAttributes.t -> t
(** Get a method signature with annotations from a proc_attributes. *)
val pp : Procname.t -> Format.formatter -> t -> unit

@ -6,7 +6,8 @@
*)
open! IStd
type violation = {is_strict_mode: bool; lhs: Nullability.t; rhs: Nullability.t} [@@deriving compare]
type violation = {nullsafe_mode: NullsafeMode.t; lhs: Nullability.t; rhs: Nullability.t}
[@@deriving compare]
type assignment_type =
| PassingParamToFunction of function_info
@ -21,24 +22,28 @@ and function_info =
; param_position: int
; function_procname: Procname.t }
let is_whitelisted_assignment ~is_strict_mode ~lhs ~rhs =
match (is_strict_mode, lhs, rhs) with
| false, Nullability.StrictNonnull, Nullability.UncheckedNonnull ->
(* We allow UncheckedNonnull -> StrictNonnull conversion outside of strict mode for better adoption.
Otherwise using strictified classes in non-strict context becomes a pain because
of extra warnings.
*)
true
| _ ->
let is_whitelisted_assignment ~nullsafe_mode ~lhs ~rhs =
match nullsafe_mode with
| NullsafeMode.Default -> (
match (lhs, rhs) with
| Nullability.StrictNonnull, Nullability.UncheckedNonnull ->
(* We allow UncheckedNonnull -> StrictNonnull conversion outside of strict mode for better adoption.
Otherwise using strictified classes in non-strict context becomes a pain because
of extra warnings.
*)
true
| _ ->
false )
| NullsafeMode.Strict ->
false
let check ~is_strict_mode ~lhs ~rhs =
let check ~(nullsafe_mode : NullsafeMode.t) ~lhs ~rhs =
let is_allowed_assignment =
Nullability.is_subtype ~subtype:rhs ~supertype:lhs
|| is_whitelisted_assignment ~is_strict_mode ~lhs ~rhs
|| is_whitelisted_assignment ~nullsafe_mode ~lhs ~rhs
in
Result.ok_if_true is_allowed_assignment ~error:{is_strict_mode; lhs; rhs}
Result.ok_if_true is_allowed_assignment ~error:{nullsafe_mode; lhs; rhs}
let get_origin_opt assignment_type origin =
@ -130,11 +135,15 @@ let bad_param_description
nullability_evidence_as_suffix
let is_declared_nonnull_to_nonnull ~lhs ~rhs =
let is_unchecked_nonnull_to_strict_nonnull ~lhs ~rhs =
match (lhs, rhs) with
| Nullability.StrictNonnull, Nullability.UncheckedNonnull ->
true
| _ ->
(* Don't fold those cases into catch-all *)
| Nullability.StrictNonnull, _
| Nullability.UncheckedNonnull, _
| Nullability.Nullable, _
| Nullability.Null, _ ->
false
@ -147,10 +156,10 @@ let get_issue_type = function
IssueType.eradicate_return_not_nullable
let violation_description {is_strict_mode; lhs; rhs} ~assignment_location assignment_type
~rhs_origin =
if is_declared_nonnull_to_nonnull ~lhs ~rhs then (
if not is_strict_mode then
let violation_description {nullsafe_mode; lhs; rhs} ~assignment_location assignment_type ~rhs_origin
=
if is_unchecked_nonnull_to_strict_nonnull ~lhs ~rhs then (
if not (NullsafeMode.equal nullsafe_mode NullsafeMode.Strict) then
Logging.die InternalError "Unexpected situation: should not be a violation not in strict mode" ;
(* This type of violation is more subtle than the normal case because, so it should be rendered in a special way *)
ErrorRenderingUtils.get_strict_mode_violation_issue ~bad_usage_location:assignment_location
@ -201,5 +210,4 @@ let violation_description {is_strict_mode; lhs; rhs} ~assignment_location assign
(error_message, issue_type, assignment_location)
let violation_severity {is_strict_mode} =
if is_strict_mode then Exceptions.Error else Exceptions.Warning
let violation_severity {nullsafe_mode} = NullsafeMode.severity nullsafe_mode

@ -13,7 +13,7 @@ open! IStd
type violation [@@deriving compare]
val check :
is_strict_mode:bool -> lhs:Nullability.t -> rhs:Nullability.t -> (unit, violation) result
nullsafe_mode:NullsafeMode.t -> lhs:Nullability.t -> rhs:Nullability.t -> (unit, violation) result
type assignment_type =
| PassingParamToFunction of function_info

@ -6,7 +6,7 @@
*)
open! IStd
type violation = {is_strict_mode: bool; nullability: Nullability.t} [@@deriving compare]
type violation = {nullsafe_mode: NullsafeMode.t; nullability: Nullability.t} [@@deriving compare]
type dereference_type =
| MethodCall of Procname.t
@ -15,12 +15,16 @@ type dereference_type =
| ArrayLengthAccess
[@@deriving compare]
let check ~is_strict_mode nullability =
let check ~nullsafe_mode nullability =
match nullability with
| Nullability.Nullable | Nullability.Null ->
Error {is_strict_mode; nullability}
| Nullability.UncheckedNonnull ->
if is_strict_mode then Error {is_strict_mode; nullability} else Ok ()
Error {nullsafe_mode; nullability}
| Nullability.UncheckedNonnull -> (
match nullsafe_mode with
| NullsafeMode.Strict ->
Error {nullsafe_mode; nullability}
| NullsafeMode.Default ->
Ok () )
| Nullability.StrictNonnull ->
Ok ()
@ -97,5 +101,4 @@ let violation_description {nullability} ~dereference_location dereference_type
(description, IssueType.eradicate_nullable_dereference, dereference_location)
let violation_severity {is_strict_mode} =
if is_strict_mode then Exceptions.Error else Exceptions.Warning
let violation_severity {nullsafe_mode} = NullsafeMode.severity nullsafe_mode

@ -11,7 +11,7 @@ open! IStd
type violation [@@deriving compare]
val check : is_strict_mode:bool -> Nullability.t -> (unit, violation) result
val check : nullsafe_mode:NullsafeMode.t -> Nullability.t -> (unit, violation) result
type dereference_type =
| MethodCall of Procname.t

@ -6,7 +6,7 @@
*)
open! IStd
type violation = {is_strict_mode: bool; base: Nullability.t; overridden: Nullability.t}
type violation = {nullsafe_mode: NullsafeMode.t; base: Nullability.t; overridden: Nullability.t}
[@@deriving compare]
type type_role = Param | Ret
@ -23,7 +23,7 @@ let is_whitelisted_violation ~subtype ~supertype =
false
let check ~is_strict_mode type_role ~base ~overridden =
let check ~nullsafe_mode type_role ~base ~overridden =
let subtype, supertype =
match type_role with
| Ret ->
@ -35,7 +35,7 @@ let check ~is_strict_mode type_role ~base ~overridden =
in
Result.ok_if_true
(Nullability.is_subtype ~subtype ~supertype || is_whitelisted_violation ~subtype ~supertype)
~error:{is_strict_mode; base; overridden}
~error:{nullsafe_mode; base; overridden}
type violation_type =
@ -94,5 +94,4 @@ let violation_description _ violation_type ~base_proc_name ~overridden_proc_name
MF.pp_monospaced base_method_descr
let violation_severity {is_strict_mode} =
if is_strict_mode then Exceptions.Error else Exceptions.Warning
let violation_severity {nullsafe_mode} = NullsafeMode.severity nullsafe_mode

@ -27,7 +27,7 @@ type violation_type =
type type_role = Param | Ret
val check :
is_strict_mode:bool
nullsafe_mode:NullsafeMode.t
-> type_role
-> base:Nullability.t
-> overridden:Nullability.t

@ -0,0 +1,25 @@
(*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*)
open! IStd
module F = Format
type t = Default | Strict [@@deriving compare, equal]
let of_class tenv typ_name =
match PatternMatch.type_name_get_annotation tenv typ_name with
| Some annots ->
if Annotations.ia_is_nullsafe_strict annots then Strict else Default
| None ->
Default
let severity = function Strict -> Exceptions.Error | Default -> Exceptions.Warning
let to_string = function Default -> " Def" | Strict -> "Strict"
let pp fmt t = F.fprintf fmt "%s" (to_string t)

@ -0,0 +1,20 @@
(*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*)
open! IStd
(** Represents a type-checking mode of nullsafe. *)
type t = Default | Strict [@@deriving compare, equal]
val of_class : Tenv.t -> Typ.name -> t
(** Extracts mode information from class annotations *)
val severity : t -> Exceptions.severity
(** Provides a default choice of issue severity for a particular mode *)
val pp : Format.formatter -> t -> unit

@ -164,7 +164,7 @@ module MkCallback (Extension : ExtensionT) : CallBackT = struct
in
EradicateChecks.check_constructor_initialization tenv find_canonical_duplicate curr_pname
curr_pdesc start_node
~is_strict_mode:annotated_signature.AnnotatedSignature.is_strict_mode
~nullsafe_mode:annotated_signature.AnnotatedSignature.nullsafe_mode
~typestates_for_curr_constructor_and_all_initializer_methods
~typestates_for_all_constructors_incl_current proc_loc ;
if Config.eradicate_verbose then L.result "Final Typestate@\n%a@." TypeState.pp typestate

@ -26,10 +26,10 @@ let is_virtual = function
false
let check_object_dereference ~is_strict_mode tenv find_canonical_duplicate curr_pname node instr_ref
let check_object_dereference ~nullsafe_mode tenv find_canonical_duplicate curr_pname node instr_ref
object_exp dereference_type inferred_nullability loc =
Result.iter_error
(DereferenceRule.check ~is_strict_mode
(DereferenceRule.check ~nullsafe_mode
(InferredNullability.get_nullability inferred_nullability))
~f:(fun dereference_violation ->
let nullable_object_origin = InferredNullability.get_origin inferred_nullability in
@ -126,7 +126,7 @@ let check_nonzero tenv find_canonical_duplicate =
(** Check an assignment to a field. *)
let check_field_assignment ~is_strict_mode tenv find_canonical_duplicate curr_pdesc node instr_ref
let check_field_assignment ~nullsafe_mode tenv find_canonical_duplicate curr_pdesc node instr_ref
typestate exp_lhs exp_rhs typ loc fname annotated_field_opt typecheck_expr : unit =
let curr_pname = Procdesc.get_proc_name curr_pdesc in
let curr_pattrs = Procdesc.get_attributes curr_pdesc in
@ -156,7 +156,7 @@ let check_field_assignment ~is_strict_mode tenv find_canonical_duplicate curr_pd
Annotations.ia_is_cleanup ret_annotation_deprecated
in
let assignment_check_result =
AssignmentRule.check ~is_strict_mode
AssignmentRule.check ~nullsafe_mode
~lhs:(InferredNullability.get_nullability inferred_nullability_lhs)
~rhs:(InferredNullability.get_nullability inferred_nullability_rhs)
in
@ -241,7 +241,7 @@ let get_nullability_upper_bound field_name typestate_list =
(** Check field initialization for a given constructor *)
let check_constructor_initialization tenv find_canonical_duplicate curr_constructor_pname
curr_constructor_pdesc start_node ~is_strict_mode
curr_constructor_pdesc start_node ~nullsafe_mode
~typestates_for_curr_constructor_and_all_initializer_methods
~typestates_for_all_constructors_incl_current loc : unit =
State.set_node start_node ;
@ -305,7 +305,7 @@ let check_constructor_initialization tenv find_canonical_duplicate curr_construc
then
if
Config.nullsafe_disable_field_not_initialized_in_nonstrict_classes
&& not is_strict_mode
&& NullsafeMode.equal nullsafe_mode NullsafeMode.Default
then
(* Behavior needed for backward compatibility, where we are not ready to surface this type of errors by default.
Hovewer, this error should be always turned on for @NullsafeStrict classes.
@ -313,7 +313,7 @@ let check_constructor_initialization tenv find_canonical_duplicate curr_construc
()
else
report_error tenv find_canonical_duplicate
(TypeErr.Field_not_initialized {is_strict_mode; field_name})
(TypeErr.Field_not_initialized {nullsafe_mode; field_name})
None loc curr_constructor_pdesc ;
(* Check if field is over-annotated. *)
match annotated_field with
@ -341,12 +341,12 @@ let check_constructor_initialization tenv find_canonical_duplicate curr_construc
()
let check_return_not_nullable ~is_strict_mode tenv find_canonical_duplicate loc curr_pname
curr_pdesc (ret_signature : AnnotatedSignature.ret_signature) ret_inferred_nullability =
let check_return_not_nullable ~nullsafe_mode tenv find_canonical_duplicate loc curr_pname curr_pdesc
(ret_signature : AnnotatedSignature.ret_signature) ret_inferred_nullability =
(* Returning from a function is essentially an assignment the actual return value to the formal `return` *)
let lhs = AnnotatedNullability.get_nullability ret_signature.ret_annotated_type.nullability in
let rhs = InferredNullability.get_nullability ret_inferred_nullability in
Result.iter_error (AssignmentRule.check ~is_strict_mode ~lhs ~rhs) ~f:(fun assignment_violation ->
Result.iter_error (AssignmentRule.check ~nullsafe_mode ~lhs ~rhs) ~f:(fun assignment_violation ->
let rhs_origin = InferredNullability.get_origin ret_inferred_nullability in
report_error tenv find_canonical_duplicate
(TypeErr.Bad_assignment
@ -391,7 +391,7 @@ let check_return_annotation tenv find_canonical_duplicate curr_pdesc ret_range
| Some (_, ret_inferred_nullability) ->
(* TODO(T54308240) Model ret_implicitly_nullable in AnnotatedNullability *)
if not ret_implicitly_nullable then
check_return_not_nullable ~is_strict_mode:annotated_signature.is_strict_mode tenv
check_return_not_nullable ~nullsafe_mode:annotated_signature.nullsafe_mode tenv
find_canonical_duplicate loc curr_pname curr_pdesc annotated_signature.ret
ret_inferred_nullability ;
if Config.eradicate_return_over_annotated then
@ -402,7 +402,7 @@ let check_return_annotation tenv find_canonical_duplicate curr_pdesc ret_range
(** Check the receiver of a virtual call. *)
let check_call_receiver ~is_strict_mode tenv find_canonical_duplicate curr_pdesc node typestate
let check_call_receiver ~nullsafe_mode tenv find_canonical_duplicate curr_pdesc node typestate
call_params callee_pname (instr_ref : TypeErr.InstrRef.t) loc typecheck_expr : unit =
match call_params with
| ((original_this_e, this_e), typ) :: _ ->
@ -412,7 +412,7 @@ let check_call_receiver ~is_strict_mode tenv find_canonical_duplicate curr_pdesc
(typ, InferredNullability.create TypeOrigin.OptimisticFallback)
loc
in
check_object_dereference ~is_strict_mode tenv find_canonical_duplicate curr_pdesc node
check_object_dereference ~nullsafe_mode tenv find_canonical_duplicate curr_pdesc node
instr_ref original_this_e (DereferenceRule.MethodCall callee_pname)
this_inferred_nullability loc
| [] ->
@ -452,7 +452,7 @@ let is_third_party_without_model proc_name model_source =
(** Check the parameters of a call. *)
let check_call_parameters ~is_strict_mode ~callee_annotated_signature tenv find_canonical_duplicate
let check_call_parameters ~nullsafe_mode ~callee_annotated_signature tenv find_canonical_duplicate
curr_pdesc node callee_attributes resolved_params loc instr_ref : unit =
let callee_pname = callee_attributes.ProcAttributes.proc_name in
let check {num= param_position; formal; actual= orig_e2, nullability_actual} =
@ -484,12 +484,13 @@ let check_call_parameters ~is_strict_mode ~callee_annotated_signature tenv find_
to the formal param *)
let lhs = AnnotatedNullability.get_nullability formal.param_annotated_type.nullability in
let rhs = InferredNullability.get_nullability nullability_actual in
Result.iter_error (AssignmentRule.check ~is_strict_mode ~lhs ~rhs) ~f:report
Result.iter_error (AssignmentRule.check ~nullsafe_mode ~lhs ~rhs) ~f:report
in
let should_ignore_parameters_check =
(* TODO(T52947663) model params in third-party non modelled method as a dedicated nullability type,
so this logic can be moved to [AssignmentRule.check] *)
(not is_strict_mode) && Config.nullsafe_optimistic_third_party_params_in_non_strict
NullsafeMode.equal nullsafe_mode NullsafeMode.Default
&& Config.nullsafe_optimistic_third_party_params_in_non_strict
&& is_third_party_without_model callee_pname
callee_annotated_signature.AnnotatedSignature.model_source
in
@ -498,11 +499,11 @@ let check_call_parameters ~is_strict_mode ~callee_annotated_signature tenv find_
List.iter ~f:check resolved_params
let check_inheritance_rule_for_return find_canonical_duplicate tenv loc ~is_strict_mode
let check_inheritance_rule_for_return find_canonical_duplicate tenv loc ~nullsafe_mode
~base_proc_name ~overridden_proc_name ~overridden_proc_desc ~base_nullability
~overridden_nullability =
Result.iter_error
(InheritanceRule.check ~is_strict_mode InheritanceRule.Ret ~base:base_nullability
(InheritanceRule.check ~nullsafe_mode InheritanceRule.Ret ~base:base_nullability
~overridden:overridden_nullability) ~f:(fun inheritance_violation ->
report_error tenv find_canonical_duplicate
(TypeErr.Inconsistent_subclass
@ -513,11 +514,11 @@ let check_inheritance_rule_for_return find_canonical_duplicate tenv loc ~is_stri
None loc overridden_proc_desc )
let check_inheritance_rule_for_param find_canonical_duplicate tenv loc ~is_strict_mode
let check_inheritance_rule_for_param find_canonical_duplicate tenv loc ~nullsafe_mode
~overridden_param_name ~base_proc_name ~overridden_proc_name ~overridden_proc_desc
~param_position ~base_nullability ~overridden_nullability =
Result.iter_error
(InheritanceRule.check ~is_strict_mode InheritanceRule.Param ~base:base_nullability
(InheritanceRule.check ~nullsafe_mode InheritanceRule.Param ~base:base_nullability
~overridden:overridden_nullability) ~f:(fun inheritance_violation ->
report_error tenv find_canonical_duplicate
(TypeErr.Inconsistent_subclass
@ -530,7 +531,7 @@ let check_inheritance_rule_for_param find_canonical_duplicate tenv loc ~is_stric
None loc overridden_proc_desc )
let check_inheritance_rule_for_params find_canonical_duplicate tenv loc ~is_strict_mode
let check_inheritance_rule_for_params find_canonical_duplicate tenv loc ~nullsafe_mode
~base_proc_name ~overridden_proc_name ~overridden_proc_desc ~base_signature
~overridden_signature =
let base_params = base_signature.AnnotatedSignature.params in
@ -547,7 +548,7 @@ let check_inheritance_rule_for_params find_canonical_duplicate tenv loc ~is_stri
{ mangled= overridden_param_name
; param_annotated_type= {nullability= annotated_nullability_overridden} } )
->
check_inheritance_rule_for_param find_canonical_duplicate tenv loc ~is_strict_mode
check_inheritance_rule_for_param find_canonical_duplicate tenv loc ~nullsafe_mode
~overridden_param_name ~base_proc_name ~overridden_proc_name ~overridden_proc_desc
~param_position:(if should_index_from_zero then index else index + 1)
~base_nullability:(AnnotatedNullability.get_nullability annotated_nullability_base)
@ -560,13 +561,12 @@ let check_inheritance_rule_for_params find_canonical_duplicate tenv loc ~is_stri
(* Check both params and return values for complying for co- and contravariance *)
let check_inheritance_rule_for_signature find_canonical_duplicate tenv loc ~is_strict_mode
let check_inheritance_rule_for_signature find_canonical_duplicate tenv loc ~nullsafe_mode
~base_proc_name ~overridden_proc_name ~overridden_proc_desc ~base_signature
~overridden_signature =
(* Check params *)
check_inheritance_rule_for_params find_canonical_duplicate tenv loc ~is_strict_mode
~base_proc_name ~overridden_proc_name ~overridden_proc_desc ~base_signature
~overridden_signature ;
check_inheritance_rule_for_params find_canonical_duplicate tenv loc ~nullsafe_mode ~base_proc_name
~overridden_proc_name ~overridden_proc_desc ~base_signature ~overridden_signature ;
(* Check return value *)
match base_proc_name with
(* TODO model this as unknown nullability and get rid of that check *)
@ -580,7 +580,7 @@ let check_inheritance_rule_for_signature find_canonical_duplicate tenv loc ~is_s
AnnotatedNullability.get_nullability
overridden_signature.AnnotatedSignature.ret.ret_annotated_type.nullability
in
check_inheritance_rule_for_return find_canonical_duplicate tenv loc ~is_strict_mode
check_inheritance_rule_for_return find_canonical_duplicate tenv loc ~nullsafe_mode
~base_proc_name ~overridden_proc_name ~overridden_proc_desc ~base_nullability
~overridden_nullability
| _ ->
@ -599,7 +599,7 @@ let check_overridden_annotations find_canonical_duplicate tenv proc_name proc_de
| Some base_attributes ->
let base_signature = Models.get_modelled_annotated_signature tenv base_attributes in
check_inheritance_rule_for_signature
~is_strict_mode:annotated_signature.AnnotatedSignature.is_strict_mode
~nullsafe_mode:annotated_signature.AnnotatedSignature.nullsafe_mode
find_canonical_duplicate tenv loc ~base_proc_name ~overridden_proc_name:proc_name
~overridden_proc_desc:proc_desc ~base_signature ~overridden_signature:annotated_signature
| None ->

@ -33,7 +33,9 @@ let table_has_procedure table proc_name =
*)
let get_modelled_annotated_signature_for_biabduction proc_attributes =
let proc_name = proc_attributes.ProcAttributes.proc_name in
let annotated_signature = AnnotatedSignature.get ~is_strict_mode:false proc_attributes in
let annotated_signature =
AnnotatedSignature.get ~nullsafe_mode:NullsafeMode.Default proc_attributes
in
let proc_id = Procname.to_unique_id proc_name in
let lookup_models_nullable ann_sig =
try
@ -66,10 +68,11 @@ let to_modelled_nullability ThirdPartyMethod.{ret_nullability; param_nullability
take precedence over internal ones. *)
let get_modelled_annotated_signature tenv proc_attributes =
let proc_name = proc_attributes.ProcAttributes.proc_name in
let is_strict_mode =
PatternMatch.check_current_class_attributes Annotations.ia_is_nullsafe_strict tenv proc_name
let nullsafe_mode =
Procname.get_class_type_name proc_name
|> Option.value_map ~default:NullsafeMode.Default ~f:(NullsafeMode.of_class tenv)
in
let annotated_signature = AnnotatedSignature.get ~is_strict_mode proc_attributes in
let annotated_signature = AnnotatedSignature.get ~nullsafe_mode proc_attributes in
let proc_id = Procname.to_unique_id proc_name in
(* Look in the infer internal models *)
let correct_by_internal_models ann_sig =

@ -108,7 +108,7 @@ type find_canonical_duplicate = Procdesc.Node.t -> Procdesc.Node.t
type checks = {eradicate: bool; check_ret_type: check_return_type list}
(** Typecheck an expression. *)
let rec typecheck_expr ~is_strict_mode find_canonical_duplicate visited checks tenv node instr_ref
let rec typecheck_expr ~nullsafe_mode find_canonical_duplicate visited checks tenv node instr_ref
(curr_pdesc : Procdesc.t) typestate e tr_default loc : TypeState.range =
match e with
(* null literal or 0 *)
@ -131,12 +131,12 @@ let rec typecheck_expr ~is_strict_mode find_canonical_duplicate visited checks t
| Exp.Var id ->
Option.value (TypeState.lookup_id id typestate) ~default:tr_default
| Exp.Exn e1 ->
typecheck_expr ~is_strict_mode find_canonical_duplicate visited checks tenv node instr_ref
typecheck_expr ~nullsafe_mode find_canonical_duplicate visited checks tenv node instr_ref
curr_pdesc typestate e1 tr_default loc
| Exp.Lfield (exp, field_name, typ) ->
let _, _ = tr_default in
let _, inferred_nullability =
typecheck_expr ~is_strict_mode find_canonical_duplicate visited checks tenv node instr_ref
typecheck_expr ~nullsafe_mode find_canonical_duplicate visited checks tenv node instr_ref
curr_pdesc typestate exp
(* TODO(T54687014) optimistic default might be an unsoundness issue - investigate *)
(typ, InferredNullability.create TypeOrigin.OptimisticFallback)
@ -153,20 +153,20 @@ let rec typecheck_expr ~is_strict_mode find_canonical_duplicate visited checks t
tr_default
in
if checks.eradicate then
EradicateChecks.check_object_dereference ~is_strict_mode tenv find_canonical_duplicate
EradicateChecks.check_object_dereference ~nullsafe_mode tenv find_canonical_duplicate
curr_pdesc node instr_ref exp (DereferenceRule.AccessToField field_name)
inferred_nullability loc ;
tr_new
| Exp.Lindex (array_exp, index_exp) ->
let _, inferred_nullability =
typecheck_expr ~is_strict_mode find_canonical_duplicate visited checks tenv node instr_ref
typecheck_expr ~nullsafe_mode find_canonical_duplicate visited checks tenv node instr_ref
curr_pdesc typestate array_exp tr_default loc
in
let index_desc =
match EradicateChecks.explain_expr tenv node index_exp with Some s -> s | None -> "?"
in
if checks.eradicate then
EradicateChecks.check_object_dereference ~is_strict_mode tenv find_canonical_duplicate
EradicateChecks.check_object_dereference ~nullsafe_mode tenv find_canonical_duplicate
curr_pdesc node instr_ref array_exp
(DereferenceRule.AccessByIndex {index_desc})
inferred_nullability loc ;
@ -421,20 +421,20 @@ let pvar_apply instr_ref idenv tenv curr_pname curr_annotated_signature loc hand
(* typecheck_expr with fewer parameters, using a common template for typestate range *)
let typecheck_expr_simple ~is_strict_mode find_canonical_duplicate curr_pdesc calls_this checks tenv
let typecheck_expr_simple ~nullsafe_mode find_canonical_duplicate curr_pdesc calls_this checks tenv
node instr_ref typestate1 exp1 typ1 origin1 loc1 =
typecheck_expr ~is_strict_mode find_canonical_duplicate calls_this checks tenv node instr_ref
typecheck_expr ~nullsafe_mode find_canonical_duplicate calls_this checks tenv node instr_ref
curr_pdesc typestate1 exp1
(typ1, InferredNullability.create origin1)
loc1
(* check if there are errors in exp1 *)
let typecheck_expr_for_errors ~is_strict_mode find_canonical_duplicate curr_pdesc calls_this checks
let typecheck_expr_for_errors ~nullsafe_mode find_canonical_duplicate curr_pdesc calls_this checks
tenv node instr_ref typestate1 exp1 loc1 : unit =
ignore
(typecheck_expr_simple ~is_strict_mode find_canonical_duplicate curr_pdesc calls_this checks
tenv node instr_ref typestate1 exp1 Typ.void TypeOrigin.Undef loc1)
(typecheck_expr_simple ~nullsafe_mode find_canonical_duplicate curr_pdesc calls_this checks tenv
node instr_ref typestate1 exp1 Typ.void TypeOrigin.Undef loc1)
(* Handle Preconditions.checkNotNull. *)
@ -559,7 +559,7 @@ let do_preconditions_check_state instr_ref idenv tenv curr_pname curr_annotated_
(* Handle m.put(k,v) as assignment pvar = v for the pvar associated to m.get(k) *)
let do_map_put call_params callee_pname tenv loc node curr_pname curr_pdesc calls_this checks
instr_ref ~is_strict_mode find_canonical_duplicate typestate' =
instr_ref ~nullsafe_mode find_canonical_duplicate typestate' =
(* Get the proc name for map.get() from map.put() *)
let pname_get_from_pname_put pname_put =
let object_t = Typ.Name.Java.Split.java_lang_object in
@ -590,7 +590,7 @@ let do_map_put call_params callee_pname tenv loc node curr_pname curr_pdesc call
| Some map_get_str ->
let pvar_map_get = Pvar.mk (Mangled.from_string map_get_str) curr_pname in
TypeState.add pvar_map_get
(typecheck_expr_simple ~is_strict_mode find_canonical_duplicate curr_pdesc calls_this
(typecheck_expr_simple ~nullsafe_mode find_canonical_duplicate curr_pdesc calls_this
checks tenv node instr_ref typestate' exp_value typ_value TypeOrigin.Undef loc)
typestate'
| None ->
@ -652,7 +652,7 @@ let normalize_cond_for_sil_prune idenv ~node cond =
let rec check_condition_for_sil_prune tenv idenv calls_this find_canonical_duplicate loc curr_pname
curr_pdesc curr_annotated_signature linereader typestate checks true_branch instr_ref
~is_strict_mode ~original_node ~node c : TypeState.t =
~nullsafe_mode ~original_node ~node c : TypeState.t =
(* check if the expression is coming from a call, and return the argument *)
let from_call filter_callee e : Exp.t option =
match e with
@ -700,9 +700,8 @@ let rec check_condition_for_sil_prune tenv idenv calls_this find_canonical_dupli
let pvar = Pvar.mk (Mangled.from_string e_str) curr_pname in
let e1 = Exp.Lvar pvar in
let typ, ta =
typecheck_expr_simple ~is_strict_mode find_canonical_duplicate curr_pdesc calls_this
checks tenv original_node instr_ref typestate e1 Typ.void TypeOrigin.OptimisticFallback
loc
typecheck_expr_simple ~nullsafe_mode find_canonical_duplicate curr_pdesc calls_this checks
tenv original_node instr_ref typestate e1 Typ.void TypeOrigin.OptimisticFallback loc
in
let range = (typ, ta) in
let typestate1 = TypeState.add pvar range typestate in
@ -734,8 +733,8 @@ let rec check_condition_for_sil_prune tenv idenv calls_this find_canonical_dupli
| Exp.BinOp (Binop.Eq, Exp.Const (Const.Cint i), e)
| Exp.BinOp (Binop.Eq, e, Exp.Const (Const.Cint i))
when IntLit.iszero i -> (
typecheck_expr_for_errors ~is_strict_mode find_canonical_duplicate curr_pdesc calls_this
checks tenv original_node instr_ref typestate e loc ;
typecheck_expr_for_errors ~nullsafe_mode find_canonical_duplicate curr_pdesc calls_this checks
tenv original_node instr_ref typestate e loc ;
let typestate1, e1, from_call =
match from_is_true_on_null e with
| Some e1 ->
@ -748,7 +747,7 @@ let rec check_condition_for_sil_prune tenv idenv calls_this find_canonical_dupli
~original_node ~is_assignment:false e1 typestate1 loc
in
let typ, inferred_nullability =
typecheck_expr_simple ~is_strict_mode find_canonical_duplicate curr_pdesc calls_this checks
typecheck_expr_simple ~nullsafe_mode find_canonical_duplicate curr_pdesc calls_this checks
tenv original_node instr_ref typestate2 e' Typ.void TypeOrigin.OptimisticFallback loc
in
if checks.eradicate then
@ -764,8 +763,8 @@ let rec check_condition_for_sil_prune tenv idenv calls_this find_canonical_dupli
| Exp.BinOp (Binop.Ne, Exp.Const (Const.Cint i), e)
| Exp.BinOp (Binop.Ne, e, Exp.Const (Const.Cint i))
when IntLit.iszero i -> (
typecheck_expr_for_errors ~is_strict_mode find_canonical_duplicate curr_pdesc calls_this
checks tenv original_node instr_ref typestate e loc ;
typecheck_expr_for_errors ~nullsafe_mode find_canonical_duplicate curr_pdesc calls_this checks
tenv original_node instr_ref typestate e loc ;
let typestate1, e1, from_call =
match from_instanceof e with
| Some e1 ->
@ -784,7 +783,7 @@ let rec check_condition_for_sil_prune tenv idenv calls_this find_canonical_dupli
~original_node ~is_assignment:false e1 typestate1 loc
in
let typ, inferred_nullability =
typecheck_expr_simple ~is_strict_mode find_canonical_duplicate curr_pdesc calls_this checks
typecheck_expr_simple ~nullsafe_mode find_canonical_duplicate curr_pdesc calls_this checks
tenv original_node instr_ref typestate2 e' Typ.void TypeOrigin.OptimisticFallback loc
in
if checks.eradicate then
@ -801,12 +800,12 @@ let rec check_condition_for_sil_prune tenv idenv calls_this find_canonical_dupli
| Exp.UnOp (Unop.LNot, Exp.BinOp (Binop.Eq, e1, e2), _) ->
check_condition_for_sil_prune tenv idenv calls_this find_canonical_duplicate loc curr_pname
curr_pdesc curr_annotated_signature linereader typestate checks true_branch instr_ref
~is_strict_mode ~original_node ~node
~nullsafe_mode ~original_node ~node
(Exp.BinOp (Binop.Ne, e1, e2))
| Exp.UnOp (Unop.LNot, Exp.BinOp (Binop.Ne, e1, e2), _) ->
check_condition_for_sil_prune tenv idenv calls_this find_canonical_duplicate loc curr_pname
curr_pdesc curr_annotated_signature linereader typestate checks true_branch instr_ref
~is_strict_mode ~original_node ~node
~nullsafe_mode ~original_node ~node
(Exp.BinOp (Binop.Eq, e1, e2))
| _ ->
(* TODO(T54687014): silenced warning may be an unsoundeness issue; investigate *)
@ -841,11 +840,11 @@ let clarify_ret_by_propagates_nullable ret (resolved_params : EradicateChecks.re
let calc_typestate_after_call find_canonical_duplicate calls_this checks tenv idenv instr_ref
signature_params cflags call_params ~is_anonymous_inner_class_constructor
~callee_annotated_signature ~callee_attributes ~callee_pname ~callee_pname_java ~curr_pname
~curr_pdesc ~curr_annotated_signature ~is_strict_mode ~typestate ~typestate1 loc node =
~curr_pdesc ~curr_annotated_signature ~nullsafe_mode ~typestate ~typestate1 loc node =
let resolve_param i (formal_param, actual_param) =
let (orig_e2, e2), t2 = actual_param in
let _, inferred_nullability_actual =
typecheck_expr ~is_strict_mode find_canonical_duplicate calls_this checks tenv node instr_ref
typecheck_expr ~nullsafe_mode find_canonical_duplicate calls_this checks tenv node instr_ref
curr_pdesc typestate e2
(* TODO(T54687014) optimistic default might be an unsoundness issue - investigate *)
(t2, InferredNullability.create TypeOrigin.OptimisticFallback)
@ -900,11 +899,11 @@ let calc_typestate_after_call find_canonical_duplicate calls_this checks tenv id
let typestate_after_call =
if not is_anonymous_inner_class_constructor then (
if cflags.CallFlags.cf_virtual && checks.eradicate then
EradicateChecks.check_call_receiver ~is_strict_mode tenv find_canonical_duplicate curr_pdesc
EradicateChecks.check_call_receiver ~nullsafe_mode tenv find_canonical_duplicate curr_pdesc
node typestate1 call_params callee_pname instr_ref loc
(typecheck_expr ~is_strict_mode find_canonical_duplicate calls_this checks) ;
(typecheck_expr ~nullsafe_mode find_canonical_duplicate calls_this checks) ;
if checks.eradicate then
EradicateChecks.check_call_parameters ~is_strict_mode ~callee_annotated_signature tenv
EradicateChecks.check_call_parameters ~nullsafe_mode ~callee_annotated_signature tenv
find_canonical_duplicate curr_pdesc node callee_attributes resolved_params loc instr_ref ;
if Models.is_check_not_null callee_pname then
match Models.get_check_not_null_parameter callee_pname with
@ -927,7 +926,7 @@ let calc_typestate_after_call find_canonical_duplicate calls_this checks tenv id
call_params loc node typestate1
else if Models.is_mapPut callee_pname then
do_map_put call_params callee_pname tenv loc node curr_pname curr_pdesc calls_this checks
instr_ref ~is_strict_mode find_canonical_duplicate typestate1
instr_ref ~nullsafe_mode find_canonical_duplicate typestate1
else typestate1 )
else typestate1
in
@ -936,7 +935,7 @@ let calc_typestate_after_call find_canonical_duplicate calls_this checks tenv id
(* SIL instruction in form of [ret = fun(args);] where fun is a non-builtin Java function *)
let typecheck_sil_call_function find_canonical_duplicate checks tenv instr_ref typestate idenv
~callee_pname ~curr_pname curr_pdesc curr_annotated_signature calls_this ~is_strict_mode
~callee_pname ~curr_pname curr_pdesc curr_annotated_signature calls_this ~nullsafe_mode
ret_id_typ etl_ loc callee_pname_java cflags node =
let callee_attributes =
match PatternMatch.lookup_attributes tenv callee_pname with
@ -965,8 +964,8 @@ let typecheck_sil_call_function find_canonical_duplicate checks tenv instr_ref t
let etl = drop_unchecked_params calls_this curr_pname callee_attributes etl_ in
let call_params, typestate1 =
let handle_et (e1, t1) (etl1, typestate1) =
typecheck_expr_for_errors ~is_strict_mode find_canonical_duplicate curr_pdesc calls_this
checks tenv node instr_ref typestate e1 loc ;
typecheck_expr_for_errors ~nullsafe_mode find_canonical_duplicate curr_pdesc calls_this checks
tenv node instr_ref typestate e1 loc ;
let e2, typestate2 =
convert_complex_exp_to_pvar tenv idenv curr_pname curr_annotated_signature ~node
~original_node:node ~is_assignment:false e1 typestate1 loc
@ -991,7 +990,7 @@ let typecheck_sil_call_function find_canonical_duplicate checks tenv instr_ref t
calc_typestate_after_call find_canonical_duplicate calls_this checks tenv idenv instr_ref
signature_params cflags call_params ~is_anonymous_inner_class_constructor
~callee_annotated_signature ~callee_attributes ~callee_pname ~callee_pname_java ~curr_pname
~curr_pdesc ~curr_annotated_signature ~is_strict_mode ~typestate ~typestate1 loc node
~curr_pdesc ~curr_annotated_signature ~nullsafe_mode ~typestate ~typestate1 loc node
in
do_return finally_resolved_ret typestate_after_call
@ -1004,7 +1003,7 @@ let typecheck_instr tenv calls_this checks (node : Procdesc.Node.t) idenv curr_p
let ret_pvar = Procdesc.get_ret_var curr_pdesc in
Pvar.equal pvar ret_pvar
in
let is_strict_mode = curr_annotated_signature.is_strict_mode in
let nullsafe_mode = curr_annotated_signature.nullsafe_mode in
match instr with
| Sil.Metadata (ExitScope (vars, _)) ->
List.fold_right vars ~init:typestate ~f:(fun var astate ->
@ -1016,22 +1015,22 @@ let typecheck_instr tenv calls_this checks (node : Procdesc.Node.t) idenv curr_p
| Sil.Metadata (Abstract _ | Nullify _ | Skip | VariableLifetimeBegins _) ->
typestate
| Sil.Load {id; e; typ; loc} ->
typecheck_expr_for_errors ~is_strict_mode find_canonical_duplicate curr_pdesc calls_this
checks tenv node instr_ref typestate e loc ;
typecheck_expr_for_errors ~nullsafe_mode find_canonical_duplicate curr_pdesc calls_this checks
tenv node instr_ref typestate e loc ;
let e', typestate' =
convert_complex_exp_to_pvar tenv idenv curr_pname curr_annotated_signature ~node
~original_node:node ~is_assignment:false e typestate loc
in
TypeState.add_id id
(typecheck_expr_simple ~is_strict_mode find_canonical_duplicate curr_pdesc calls_this checks
(typecheck_expr_simple ~nullsafe_mode find_canonical_duplicate curr_pdesc calls_this checks
tenv node instr_ref typestate' e' typ TypeOrigin.Undef loc)
typestate'
| Sil.Store {e1= Exp.Lvar pvar; e2= Exp.Exn _} when is_return pvar ->
(* skip assignment to return variable where it is an artifact of a throw instruction *)
typestate
| Sil.Store {e1; typ; e2; loc} ->
typecheck_expr_for_errors ~is_strict_mode find_canonical_duplicate curr_pdesc calls_this
checks tenv node instr_ref typestate e1 loc ;
typecheck_expr_for_errors ~nullsafe_mode find_canonical_duplicate curr_pdesc calls_this checks
tenv node instr_ref typestate e1 loc ;
let e1', typestate1 =
convert_complex_exp_to_pvar tenv idenv curr_pname curr_annotated_signature ~node
~original_node:node ~is_assignment:true e1 typestate loc
@ -1041,9 +1040,9 @@ let typecheck_instr tenv calls_this checks (node : Procdesc.Node.t) idenv curr_p
| Exp.Lfield (_, fn, f_typ) ->
let field_type_opt = AnnotatedField.get tenv fn f_typ in
if checks.eradicate then
EradicateChecks.check_field_assignment ~is_strict_mode tenv find_canonical_duplicate
EradicateChecks.check_field_assignment ~nullsafe_mode tenv find_canonical_duplicate
curr_pdesc node instr_ref typestate1 e1' e2 typ loc fn field_type_opt
(typecheck_expr ~is_strict_mode find_canonical_duplicate calls_this checks tenv)
(typecheck_expr ~nullsafe_mode find_canonical_duplicate calls_this checks tenv)
| _ ->
()
in
@ -1051,7 +1050,7 @@ let typecheck_instr tenv calls_this checks (node : Procdesc.Node.t) idenv curr_p
match e1' with
| Exp.Lvar pvar ->
TypeState.add pvar
(typecheck_expr_simple ~is_strict_mode find_canonical_duplicate curr_pdesc calls_this
(typecheck_expr_simple ~nullsafe_mode find_canonical_duplicate curr_pdesc calls_this
checks tenv node instr_ref typestate1 e2 typ TypeOrigin.Undef loc)
typestate1
| Exp.Lfield _ ->
@ -1068,29 +1067,29 @@ let typecheck_instr tenv calls_this checks (node : Procdesc.Node.t) idenv curr_p
(* Type cast *)
| Sil.Call ((id, _), Exp.Const (Const.Cfun pn), (e, typ) :: _, loc, _)
when Procname.equal pn BuiltinDecl.__cast ->
typecheck_expr_for_errors ~is_strict_mode find_canonical_duplicate curr_pdesc calls_this
checks tenv node instr_ref typestate e loc ;
typecheck_expr_for_errors ~nullsafe_mode find_canonical_duplicate curr_pdesc calls_this checks
tenv node instr_ref typestate e loc ;
let e', typestate' =
convert_complex_exp_to_pvar tenv idenv curr_pname curr_annotated_signature ~node
~original_node:node ~is_assignment:false e typestate loc
in
(* cast copies the type of the first argument *)
TypeState.add_id id
(typecheck_expr_simple ~is_strict_mode find_canonical_duplicate curr_pdesc calls_this checks
(typecheck_expr_simple ~nullsafe_mode find_canonical_duplicate curr_pdesc calls_this checks
tenv node instr_ref typestate' e' typ TypeOrigin.OptimisticFallback loc)
typestate'
(* myarray.length *)
| Sil.Call ((id, _), Exp.Const (Const.Cfun pn), [(array_exp, t)], loc, _)
when Procname.equal pn BuiltinDecl.__get_array_length ->
let _, ta =
typecheck_expr ~is_strict_mode find_canonical_duplicate calls_this checks tenv node
instr_ref curr_pdesc typestate array_exp
typecheck_expr ~nullsafe_mode find_canonical_duplicate calls_this checks tenv node instr_ref
curr_pdesc typestate array_exp
(* TODO(T54687014) optimistic default might be an unsoundness issue - investigate *)
(t, InferredNullability.create TypeOrigin.OptimisticFallback)
loc
in
if checks.eradicate then
EradicateChecks.check_object_dereference ~is_strict_mode tenv find_canonical_duplicate
EradicateChecks.check_object_dereference ~nullsafe_mode tenv find_canonical_duplicate
curr_pdesc node instr_ref array_exp DereferenceRule.ArrayLengthAccess ta loc ;
TypeState.add_id id
(Typ.mk (Tint Typ.IInt), InferredNullability.create TypeOrigin.ArrayLengthResult)
@ -1106,7 +1105,7 @@ let typecheck_instr tenv calls_this checks (node : Procdesc.Node.t) idenv curr_p
, loc
, cflags ) ->
typecheck_sil_call_function find_canonical_duplicate checks tenv instr_ref typestate idenv
~callee_pname ~curr_pname curr_pdesc curr_annotated_signature calls_this ~is_strict_mode
~callee_pname ~curr_pname curr_pdesc curr_annotated_signature calls_this ~nullsafe_mode
ret_id_typ etl_ loc callee_pname_java cflags node
(* Calls instruction that is not a function call *)
| Sil.Call _ ->
@ -1119,7 +1118,7 @@ let typecheck_instr tenv calls_this checks (node : Procdesc.Node.t) idenv curr_p
let node', normalized_cond = normalize_cond_for_sil_prune idenv ~node cond in
check_condition_for_sil_prune tenv idenv calls_this find_canonical_duplicate loc curr_pname
curr_pdesc curr_annotated_signature linereader typestate checks true_branch instr_ref
~is_strict_mode ~node:node' ~original_node:node normalized_cond
~nullsafe_mode ~node:node' ~original_node:node normalized_cond
(** Typecheck the instructions in a cfg node. *)

@ -65,7 +65,7 @@ type err_instance =
; violation_type: InheritanceRule.violation_type
; base_proc_name: Procname.t
; overridden_proc_name: Procname.t }
| Field_not_initialized of {is_strict_mode: bool; field_name: Fieldname.t}
| Field_not_initialized of {nullsafe_mode: NullsafeMode.t; field_name: Fieldname.t}
| Over_annotation of
{ over_annotated_violation: OverAnnotatedRule.violation
; violation_type: OverAnnotatedRule.violation_type }
@ -194,9 +194,8 @@ module Severity = struct
Some Exceptions.Advice
| Over_annotation _ ->
None
| Field_not_initialized {is_strict_mode} ->
(* TODO: show strict mode violations as errors *)
Some (if is_strict_mode then Exceptions.Error else Exceptions.Warning)
| Field_not_initialized {nullsafe_mode} ->
Some (NullsafeMode.severity nullsafe_mode)
| Bad_assignment {assignment_violation} ->
Some (AssignmentRule.violation_severity assignment_violation)
| Inconsistent_subclass {inheritance_violation} ->

@ -41,7 +41,7 @@ type err_instance =
; violation_type: InheritanceRule.violation_type
; base_proc_name: Procname.t
; overridden_proc_name: Procname.t }
| Field_not_initialized of {is_strict_mode: bool; field_name: Fieldname.t}
| Field_not_initialized of {nullsafe_mode: NullsafeMode.t; field_name: Fieldname.t}
| Over_annotation of
{ over_annotated_violation: OverAnnotatedRule.violation
; violation_type: OverAnnotatedRule.violation_type }

Loading…
Cancel
Save