diff --git a/infer/src/absint/PatternMatch.ml b/infer/src/absint/PatternMatch.ml index cc9b7dcfa..81d7aa490 100644 --- a/infer/src/absint/PatternMatch.ml +++ b/infer/src/absint/PatternMatch.ml @@ -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 diff --git a/infer/src/absint/PatternMatch.mli b/infer/src/absint/PatternMatch.mli index 2eb510dda..770669516 100644 --- a/infer/src/absint/PatternMatch.mli +++ b/infer/src/absint/PatternMatch.mli @@ -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 diff --git a/infer/src/nullsafe/AnnotatedField.ml b/infer/src/nullsafe/AnnotatedField.ml index 721de14d0..7dd9db7a6 100644 --- a/infer/src/nullsafe/AnnotatedField.ml +++ b/infer/src/nullsafe/AnnotatedField.ml @@ -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 diff --git a/infer/src/nullsafe/AnnotatedNullability.ml b/infer/src/nullsafe/AnnotatedNullability.ml index aa596a9d7..afb42077c 100644 --- a/infer/src/nullsafe/AnnotatedNullability.ml +++ b/infer/src/nullsafe/AnnotatedNullability.ml @@ -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 diff --git a/infer/src/nullsafe/AnnotatedNullability.mli b/infer/src/nullsafe/AnnotatedNullability.mli index d9b372459..0aca096d7 100644 --- a/infer/src/nullsafe/AnnotatedNullability.mli +++ b/infer/src/nullsafe/AnnotatedNullability.mli @@ -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. *) diff --git a/infer/src/nullsafe/AnnotatedSignature.ml b/infer/src/nullsafe/AnnotatedSignature.ml index db9463ac1..3d920074d 100644 --- a/infer/src/nullsafe/AnnotatedSignature.ml +++ b/infer/src/nullsafe/AnnotatedSignature.ml @@ -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 diff --git a/infer/src/nullsafe/AnnotatedSignature.mli b/infer/src/nullsafe/AnnotatedSignature.mli index 970d4d7cc..f5867c28b 100644 --- a/infer/src/nullsafe/AnnotatedSignature.mli +++ b/infer/src/nullsafe/AnnotatedSignature.mli @@ -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 diff --git a/infer/src/nullsafe/AssignmentRule.ml b/infer/src/nullsafe/AssignmentRule.ml index a9fe3c458..38e127825 100644 --- a/infer/src/nullsafe/AssignmentRule.ml +++ b/infer/src/nullsafe/AssignmentRule.ml @@ -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 diff --git a/infer/src/nullsafe/AssignmentRule.mli b/infer/src/nullsafe/AssignmentRule.mli index e6c31057f..197098b40 100644 --- a/infer/src/nullsafe/AssignmentRule.mli +++ b/infer/src/nullsafe/AssignmentRule.mli @@ -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 diff --git a/infer/src/nullsafe/DereferenceRule.ml b/infer/src/nullsafe/DereferenceRule.ml index f82436297..49b20a748 100644 --- a/infer/src/nullsafe/DereferenceRule.ml +++ b/infer/src/nullsafe/DereferenceRule.ml @@ -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 diff --git a/infer/src/nullsafe/DereferenceRule.mli b/infer/src/nullsafe/DereferenceRule.mli index de9f2e6e6..af3f709e5 100644 --- a/infer/src/nullsafe/DereferenceRule.mli +++ b/infer/src/nullsafe/DereferenceRule.mli @@ -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 diff --git a/infer/src/nullsafe/InheritanceRule.ml b/infer/src/nullsafe/InheritanceRule.ml index d23d518e4..8b3f495ee 100644 --- a/infer/src/nullsafe/InheritanceRule.ml +++ b/infer/src/nullsafe/InheritanceRule.ml @@ -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 diff --git a/infer/src/nullsafe/InheritanceRule.mli b/infer/src/nullsafe/InheritanceRule.mli index c2841a46e..a80ef473b 100644 --- a/infer/src/nullsafe/InheritanceRule.mli +++ b/infer/src/nullsafe/InheritanceRule.mli @@ -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 diff --git a/infer/src/nullsafe/NullsafeMode.ml b/infer/src/nullsafe/NullsafeMode.ml new file mode 100644 index 000000000..68930cc8a --- /dev/null +++ b/infer/src/nullsafe/NullsafeMode.ml @@ -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) diff --git a/infer/src/nullsafe/NullsafeMode.mli b/infer/src/nullsafe/NullsafeMode.mli new file mode 100644 index 000000000..f800720d4 --- /dev/null +++ b/infer/src/nullsafe/NullsafeMode.mli @@ -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 diff --git a/infer/src/nullsafe/eradicate.ml b/infer/src/nullsafe/eradicate.ml index e14c3701b..5805cf655 100644 --- a/infer/src/nullsafe/eradicate.ml +++ b/infer/src/nullsafe/eradicate.ml @@ -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 diff --git a/infer/src/nullsafe/eradicateChecks.ml b/infer/src/nullsafe/eradicateChecks.ml index b59d12ea4..cbc0f2717 100644 --- a/infer/src/nullsafe/eradicateChecks.ml +++ b/infer/src/nullsafe/eradicateChecks.ml @@ -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 -> diff --git a/infer/src/nullsafe/models.ml b/infer/src/nullsafe/models.ml index 1b9da0e38..3e7b954ce 100644 --- a/infer/src/nullsafe/models.ml +++ b/infer/src/nullsafe/models.ml @@ -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 = diff --git a/infer/src/nullsafe/typeCheck.ml b/infer/src/nullsafe/typeCheck.ml index 7a7864e31..8bf53a45e 100644 --- a/infer/src/nullsafe/typeCheck.ml +++ b/infer/src/nullsafe/typeCheck.ml @@ -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. *) diff --git a/infer/src/nullsafe/typeErr.ml b/infer/src/nullsafe/typeErr.ml index 027691175..a59606d73 100644 --- a/infer/src/nullsafe/typeErr.ml +++ b/infer/src/nullsafe/typeErr.ml @@ -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} -> diff --git a/infer/src/nullsafe/typeErr.mli b/infer/src/nullsafe/typeErr.mli index 29de105ad..eee7000d2 100644 --- a/infer/src/nullsafe/typeErr.mli +++ b/infer/src/nullsafe/typeErr.mli @@ -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 }