[nullsafe] Make ErrorRenderingUtils `None`-safe

Summary:
# Problem

Yes, nullsafe is not null-safe, such an irony.

ErrorRenderingUtils overuses `option` and `let+` constructions. Most of
internal functions can return `None` when "something is wrong".

On top of this, "default" pattern match is overused either.

Because of this, `ErrorRenderingUtils.mk_nullsafe_special_issue` returns
optional type. In practice, this result can be None for many unclear
reasons, and it is super tricky to even understand them all.

This in turn forced AssignmentRule and DereferenceRule to process this
None is defensive way. The rules have some theory why None was returned,
and have assertions along the way.

Turns out those theories might be wrong. This diff will make triaging wrong assumptions easier.

Reviewed By: artempyanykh

Differential Revision: D20535720

fbshipit-source-id: 2b81e25b7
master
Mitya Lyubarskiy 5 years ago committed by Facebook GitHub Bot
parent ce1ba6a8c6
commit e826736a06

@ -63,7 +63,7 @@ module ReportableViolation = struct
let mk_description_for_bad_param_passed
{model_source; param_signature; actual_param_expression; param_position; function_procname}
~param_nullability ~nullability_evidence =
~param_nullability_kind ~nullability_evidence =
let nullability_evidence_as_suffix =
Option.value_map nullability_evidence ~f:(fun evidence -> ": " ^ evidence) ~default:""
in
@ -73,15 +73,11 @@ module ReportableViolation = struct
if String.equal actual_param_expression "null" then "is `null`"
else
let nullability_descr =
match param_nullability with
| Nullability.Null ->
match param_nullability_kind with
| ErrorRenderingUtils.UserFriendlyNullable.Null ->
"`null`"
| Nullability.Nullable ->
| ErrorRenderingUtils.UserFriendlyNullable.Nullable ->
"nullable"
| other ->
Logging.die InternalError
"mk_description_for_bad_param:: invariant violation: unexpected nullability %a"
Nullability.pp other
in
Format.asprintf "%a is %s" MF.pp_monospaced actual_param_expression nullability_descr
in
@ -147,82 +143,81 @@ module ReportableViolation = struct
IssueType.eradicate_return_not_nullable
let mk_nullsafe_issue_for_explicitly_nullable_values ~assignment_type ~rhs_origin
~explicit_rhs_nullable_kind ~assignment_location =
let nullability_evidence =
get_origin_opt assignment_type rhs_origin
|> Option.bind ~f:(fun origin -> TypeOrigin.get_description origin)
in
let nullability_evidence_as_suffix =
Option.value_map nullability_evidence ~f:(fun evidence -> ": " ^ evidence) ~default:""
in
let module MF = MarkupFormatter in
let alternative_method_description =
ErrorRenderingUtils.find_alternative_nonnull_method_description rhs_origin
in
let alternative_recommendation =
Option.value_map alternative_method_description
~f:(fun descr ->
Format.asprintf " If you don't expect null, use %a instead." MF.pp_monospaced descr )
~default:""
in
let error_message =
match assignment_type with
| PassingParamToFunction function_info ->
Format.sprintf "%s%s"
(mk_description_for_bad_param_passed function_info ~nullability_evidence
~param_nullability_kind:explicit_rhs_nullable_kind)
alternative_recommendation
| AssigningToField field_name ->
let rhs_description =
match explicit_rhs_nullable_kind with
| ErrorRenderingUtils.UserFriendlyNullable.Null ->
"`null`"
| ErrorRenderingUtils.UserFriendlyNullable.Nullable ->
"a nullable"
in
Format.asprintf "%a is declared non-nullable but is assigned %s%s.%s" MF.pp_monospaced
(Fieldname.get_field_name field_name)
rhs_description nullability_evidence_as_suffix alternative_recommendation
| ReturningFromFunction function_proc_name ->
let return_description =
match explicit_rhs_nullable_kind with
| ErrorRenderingUtils.UserFriendlyNullable.Null ->
(* Return `null` in all_whitelisted branches *)
"`null`"
| ErrorRenderingUtils.UserFriendlyNullable.Nullable ->
"a nullable value"
in
Format.asprintf "%a: return type is declared non-nullable but the method returns %s%s.%s"
MF.pp_monospaced
(Procname.to_simplified_string ~withclass:false function_proc_name)
return_description nullability_evidence_as_suffix alternative_recommendation
in
let issue_type = get_issue_type assignment_type in
(error_message, issue_type, assignment_location)
let get_description ~assignment_location assignment_type ~rhs_origin
{nullsafe_mode; violation= {rhs}} =
let special_message =
if not (NullsafeMode.equal NullsafeMode.Default nullsafe_mode) then
ErrorRenderingUtils.mk_special_nullsafe_issue ~nullsafe_mode ~bad_nullability:rhs
~bad_usage_location:assignment_location rhs_origin
else None
let user_friendly_nullable =
ErrorRenderingUtils.UserFriendlyNullable.from_nullability rhs
|> IOption.if_none_eval ~f:(fun () ->
Logging.die InternalError
"get_description:: Assignment violation should not be possible for non-nullable \
values on right hand side" )
in
match special_message with
| Some desc ->
desc
| _ ->
let nullability_evidence =
get_origin_opt assignment_type rhs_origin
|> Option.bind ~f:(fun origin -> TypeOrigin.get_description origin)
in
let nullability_evidence_as_suffix =
Option.value_map nullability_evidence ~f:(fun evidence -> ": " ^ evidence) ~default:""
in
let module MF = MarkupFormatter in
let alternative_method_description =
ErrorRenderingUtils.find_alternative_nonnull_method_description rhs_origin
in
let alternative_recommendation =
Option.value_map alternative_method_description
~f:(fun descr ->
Format.asprintf " If you don't expect null, use %a instead." MF.pp_monospaced descr )
~default:""
in
let error_message =
match assignment_type with
| PassingParamToFunction function_info ->
Format.sprintf "%s%s"
(mk_description_for_bad_param_passed function_info ~nullability_evidence
~param_nullability:rhs)
alternative_recommendation
| AssigningToField field_name ->
let rhs_description =
Nullability.(
match rhs with
| Null ->
"`null`"
| Nullable ->
"a nullable"
| other ->
Logging.die InternalError
"violation_description(assign_field):: invariant violation: unexpected \
nullability %a"
Nullability.pp other)
in
Format.asprintf "%a is declared non-nullable but is assigned %s%s.%s" MF.pp_monospaced
(Fieldname.get_field_name field_name)
rhs_description nullability_evidence_as_suffix alternative_recommendation
| ReturningFromFunction function_proc_name ->
let return_description =
Nullability.(
match rhs with
| Null ->
(* Return `null` in all_whitelisted branches *)
"`null`"
| Nullable ->
"a nullable value"
| other ->
Logging.die InternalError
"violation_description(ret_fun):: invariant violation: unexpected \
nullability %a"
Nullability.pp other)
in
Format.asprintf
"%a: return type is declared non-nullable but the method returns %s%s.%s"
MF.pp_monospaced
(Procname.to_simplified_string ~withclass:false function_proc_name)
return_description nullability_evidence_as_suffix alternative_recommendation
in
let issue_type = get_issue_type assignment_type in
(error_message, issue_type, assignment_location)
match user_friendly_nullable with
| ErrorRenderingUtils.UserFriendlyNullable.UntrustedNonnull untrusted_kind ->
(* Attempt to assigning a value which is not explictly declared as nullable,
but still can not be trusted in this particular mode.
*)
ErrorRenderingUtils.mk_nullsafe_issue_for_untrusted_values ~nullsafe_mode ~untrusted_kind
~bad_usage_location:assignment_location rhs_origin
| ErrorRenderingUtils.UserFriendlyNullable.ExplainablyNullable explicit_kind ->
(* Attempt to assigning a value that can be explained to the user as nullable. *)
mk_nullsafe_issue_for_explicitly_nullable_values ~assignment_type ~rhs_origin
~explicit_rhs_nullable_kind:explicit_kind ~assignment_location
end
let check ~lhs ~rhs =

@ -34,79 +34,87 @@ module ReportableViolation = struct
if should_show_origin then Some origin else None
let mk_nullsafe_issue_for_explicitly_nullable_values ~explicit_kind ~dereference_type
dereference_location ~nullable_object_descr ~nullable_object_origin =
let module MF = MarkupFormatter in
let what_is_dereferred_str =
match dereference_type with
| MethodCall _ | AccessToField _ -> (
match nullable_object_descr with
| None ->
"Object"
(* Just describe an object itself *)
| Some descr ->
MF.monospaced_to_string descr )
| ArrayLengthAccess | AccessByIndex _ -> (
(* In Java, those operations can be applied only to arrays *)
match nullable_object_descr with
| None ->
"Array"
| Some descr ->
Format.sprintf "Array %s" (MF.monospaced_to_string descr) )
in
let action_descr =
match dereference_type with
| MethodCall method_name ->
Format.sprintf "calling %s"
(MF.monospaced_to_string (Procname.to_simplified_string method_name))
| AccessToField field_name ->
Format.sprintf "accessing field %s"
(MF.monospaced_to_string (Fieldname.to_simplified_string field_name))
| AccessByIndex {index_desc} ->
Format.sprintf "accessing at index %s" (MF.monospaced_to_string index_desc)
| ArrayLengthAccess ->
"accessing its length"
in
let origin_descr =
get_origin_opt ~nullable_object_descr nullable_object_origin
|> Option.bind ~f:(fun origin -> TypeOrigin.get_description origin)
|> Option.value_map ~f:(fun origin -> ": " ^ origin) ~default:""
in
let alternative_method_description =
ErrorRenderingUtils.find_alternative_nonnull_method_description nullable_object_origin
in
let alternative_recommendation =
Option.value_map alternative_method_description
~f:(fun descr ->
Format.asprintf " If this is intentional, use %a instead." MF.pp_monospaced descr )
~default:""
in
let description =
match explicit_kind with
| ErrorRenderingUtils.UserFriendlyNullable.Null ->
Format.sprintf
"NullPointerException will be thrown at this line! %s is `null` and is dereferenced \
via %s%s."
what_is_dereferred_str action_descr origin_descr
| ErrorRenderingUtils.UserFriendlyNullable.Nullable ->
Format.sprintf "%s is nullable and is not locally checked for null when %s%s.%s"
what_is_dereferred_str action_descr origin_descr alternative_recommendation
in
(description, IssueType.eradicate_nullable_dereference, dereference_location)
let get_description {nullsafe_mode; violation= {nullability}} ~dereference_location
dereference_type ~nullable_object_descr ~nullable_object_origin =
let module MF = MarkupFormatter in
let special_message =
if not (NullsafeMode.equal NullsafeMode.Default nullsafe_mode) then
ErrorRenderingUtils.mk_special_nullsafe_issue ~nullsafe_mode ~bad_nullability:nullability
~bad_usage_location:dereference_location nullable_object_origin
else None
let user_friendly_nullable =
ErrorRenderingUtils.UserFriendlyNullable.from_nullability nullability
|> IOption.if_none_eval ~f:(fun () ->
Logging.die InternalError
"get_description:: Dereference violation should not be possible for non-nullable \
values" )
in
match special_message with
| Some desc ->
desc
| _ ->
let what_is_dereferred_str =
match dereference_type with
| MethodCall _ | AccessToField _ -> (
match nullable_object_descr with
| None ->
"Object"
(* Just describe an object itself *)
| Some descr ->
MF.monospaced_to_string descr )
| ArrayLengthAccess | AccessByIndex _ -> (
(* In Java, those operations can be applied only to arrays *)
match nullable_object_descr with
| None ->
"Array"
| Some descr ->
Format.sprintf "Array %s" (MF.monospaced_to_string descr) )
in
let action_descr =
match dereference_type with
| MethodCall method_name ->
Format.sprintf "calling %s"
(MF.monospaced_to_string (Procname.to_simplified_string method_name))
| AccessToField field_name ->
Format.sprintf "accessing field %s"
(MF.monospaced_to_string (Fieldname.to_simplified_string field_name))
| AccessByIndex {index_desc} ->
Format.sprintf "accessing at index %s" (MF.monospaced_to_string index_desc)
| ArrayLengthAccess ->
"accessing its length"
in
let origin_descr =
get_origin_opt ~nullable_object_descr nullable_object_origin
|> Option.bind ~f:(fun origin -> TypeOrigin.get_description origin)
|> Option.value_map ~f:(fun origin -> ": " ^ origin) ~default:""
in
let alternative_method_description =
ErrorRenderingUtils.find_alternative_nonnull_method_description nullable_object_origin
in
let alternative_recommendation =
Option.value_map alternative_method_description
~f:(fun descr ->
Format.asprintf " If this is intentional, use %a instead." MF.pp_monospaced descr )
~default:""
in
let description =
match nullability with
| Nullability.Null ->
Format.sprintf
"NullPointerException will be thrown at this line! %s is `null` and is \
dereferenced via %s%s."
what_is_dereferred_str action_descr origin_descr
| Nullability.Nullable ->
Format.sprintf "%s is nullable and is not locally checked for null when %s%s.%s"
what_is_dereferred_str action_descr origin_descr alternative_recommendation
| other ->
Logging.die InternalError
"violation_description:: invariant violation: unexpected nullability %a"
Nullability.pp other
in
(description, IssueType.eradicate_nullable_dereference, dereference_location)
match user_friendly_nullable with
| ErrorRenderingUtils.UserFriendlyNullable.UntrustedNonnull untrusted_kind ->
(* Attempt to dereference a value which is not explictly declared as nullable,
but still can not be trusted in this particular mode.
*)
ErrorRenderingUtils.mk_nullsafe_issue_for_untrusted_values ~nullsafe_mode ~untrusted_kind
~bad_usage_location:dereference_location nullable_object_origin
| ErrorRenderingUtils.UserFriendlyNullable.ExplainablyNullable explicit_kind ->
(* Attempt to dereference value that can be explained to the user as nullable. *)
mk_nullsafe_issue_for_explicitly_nullable_values ~explicit_kind ~dereference_type
dereference_location ~nullable_object_descr ~nullable_object_origin
let get_severity {nullsafe_mode} = NullsafeMode.severity nullsafe_mode

@ -8,6 +8,28 @@
open! IStd
module F = Format
module UserFriendlyNullable = struct
type t = ExplainablyNullable of explainably_nullable_kind | UntrustedNonnull of untrusted_kind
and explainably_nullable_kind = Nullable | Null
and untrusted_kind = ThirdPartyNonnull | UncheckedNonnull | LocallyCheckedNonnull
let from_nullability = function
| Nullability.Nullable ->
Some (ExplainablyNullable Nullable)
| Nullability.Null ->
Some (ExplainablyNullable Null)
| Nullability.UncheckedNonnull ->
Some (UntrustedNonnull UncheckedNonnull)
| Nullability.LocallyCheckedNonnull ->
Some (UntrustedNonnull LocallyCheckedNonnull)
| Nullability.ThirdPartyNonnull ->
Some (UntrustedNonnull ThirdPartyNonnull)
| Nullability.StrictNonnull ->
None
end
let is_object_nullability_self_explanatory ~object_expression (object_origin : TypeOrigin.t) =
(* Fundamentally, object can be of two kinds:
1. Indirect: local variable that was instantiated before.
@ -83,28 +105,40 @@ let get_field_class_name field_name =
|> Option.value_map ~f:(fun (classname, _) -> classname) ~default:"the field class"
let mk_coming_from_unchecked_or_locally_checked_case_only nullsafe_mode nullability =
match (nullsafe_mode, nullability) with
| NullsafeMode.Strict, Nullability.UncheckedNonnull ->
let mk_coming_from_unchecked_or_locally_checked_case_only nullsafe_mode untrusted_kind =
match (nullsafe_mode, untrusted_kind) with
| NullsafeMode.Strict, UserFriendlyNullable.UncheckedNonnull ->
"non-strict classes"
| NullsafeMode.Strict, Nullability.LocallyCheckedNonnull ->
| NullsafeMode.Strict, UserFriendlyNullable.LocallyCheckedNonnull ->
"nullsafe-local classes"
| NullsafeMode.Local _, Nullability.UncheckedNonnull ->
| NullsafeMode.Local _, _ ->
"non-nullsafe classes"
| _ ->
Logging.die Logging.InternalError
"Should be called only for locally checked or unchecked nonnull cases"
| NullsafeMode.Default, _ ->
Logging.die InternalError
"mk_coming_from_unchecked_or_locally_checked_case_only:: not applicable to default mode"
| _, UserFriendlyNullable.ThirdPartyNonnull ->
Logging.die InternalError
"mk_coming_from_unchecked_or_locally_checked_case_only:: not applicable to \
ThirdPartyNonnull case"
let mk_recommendation nullsafe_mode nullability what =
match (nullsafe_mode, nullability) with
| NullsafeMode.Strict, Nullability.UncheckedNonnull
| NullsafeMode.Strict, Nullability.LocallyCheckedNonnull ->
Some (F.sprintf "make %s nullsafe strict" what)
| NullsafeMode.Local _, Nullability.UncheckedNonnull ->
Some (F.sprintf "make %s nullsafe" what)
| _ ->
None
let mk_strictification_advice_unchecked_or_locally_checked_case_only nullsafe_mode untrusted_kind
~what_to_strictify =
match untrusted_kind with
| UserFriendlyNullable.UncheckedNonnull | UserFriendlyNullable.LocallyCheckedNonnull -> (
match nullsafe_mode with
| NullsafeMode.Strict ->
F.sprintf "make %s nullsafe strict" what_to_strictify
| NullsafeMode.Local _ ->
F.sprintf "make %s nullsafe" what_to_strictify
| NullsafeMode.Default ->
Logging.die InternalError
"mk_recommendation_unchecked_or_locally_checked_case_only:: should not be called for \
default mode" )
| UserFriendlyNullable.ThirdPartyNonnull ->
Logging.die InternalError
"mk_recommendation_unchecked_or_locally_checked_case_only:: not applicable to \
ThirdPartyNonnull case"
let mk_recommendation_for_third_party_field nullsafe_mode field =
@ -114,12 +148,12 @@ let mk_recommendation_for_third_party_field nullsafe_mode field =
| NullsafeMode.Local _ ->
F.sprintf "access %s via a nullsafe getter" field
| NullsafeMode.Default ->
Logging.die Logging.InternalError
"Should not happen: we should tolerate third party in default mode"
Logging.die InternalError
"mk_recommendation_for_third_party_field:: Should not happen: we should tolerate third \
party in default mode"
let get_info object_origin nullsafe_mode bad_nullability =
let open IOption.Let_syntax in
let get_info object_origin nullsafe_mode untrusted_kind =
match object_origin with
| TypeOrigin.MethodCall {pname; call_loc} ->
let offending_object =
@ -128,14 +162,9 @@ let get_info object_origin nullsafe_mode bad_nullability =
in
let object_loc = call_loc in
let what_is_used = "Result of this call" in
let+ coming_from_explanation, recommendation, issue_type =
match bad_nullability with
| Nullability.Null | Nullability.Nullable ->
(* This method makes sense only for non-nullable violations *)
None
| Nullability.StrictNonnull ->
Logging.die InternalError "There should not be type violations involving StrictNonnull"
| Nullability.ThirdPartyNonnull ->
let coming_from_explanation, recommendation, issue_type =
match untrusted_kind with
| UserFriendlyNullable.ThirdPartyNonnull ->
let suggested_third_party_sig_file =
ThirdPartyAnnotationInfo.lookup_related_sig_file_for_proc
(ThirdPartyAnnotationGlobalRepo.get_repo ())
@ -149,19 +178,19 @@ let get_info object_origin nullsafe_mode bad_nullability =
(* this can happen when third party is registered in a deprecated way (not in third party repository) *)
~default:"the third party signature storage"
in
return
( "not vetted third party methods"
, F.sprintf "add the correct signature to %s" where_to_add_signature
, IssueType.eradicate_unvetted_third_party_in_nullsafe )
| Nullability.UncheckedNonnull | Nullability.LocallyCheckedNonnull ->
( "not vetted third party methods"
, F.sprintf "add the correct signature to %s" where_to_add_signature
, IssueType.eradicate_unvetted_third_party_in_nullsafe )
| UserFriendlyNullable.UncheckedNonnull | UserFriendlyNullable.LocallyCheckedNonnull ->
let from =
mk_coming_from_unchecked_or_locally_checked_case_only nullsafe_mode bad_nullability
mk_coming_from_unchecked_or_locally_checked_case_only nullsafe_mode untrusted_kind
in
let+ recommendation =
let recommendation =
let what_to_strictify =
Option.value (get_method_class_name pname) ~default:offending_object
in
mk_recommendation nullsafe_mode bad_nullability what_to_strictify
mk_strictification_advice_unchecked_or_locally_checked_case_only nullsafe_mode
untrusted_kind ~what_to_strictify
in
let issue_type = IssueType.eradicate_unchecked_usage_in_nullsafe in
(from, recommendation, issue_type)
@ -183,24 +212,19 @@ let get_info object_origin nullsafe_mode bad_nullability =
(* TODO: currently we do not support third-party annotations for fields. Because of this,
render error like it is a non-stict class. *)
let what_is_used = "This field" in
let+ coming_from_explanation, recommendation, issue_type =
match bad_nullability with
| Nullability.Null | Nullability.Nullable ->
(* This method makes sense only for non-nullable violations *)
None
| Nullability.StrictNonnull ->
Logging.die InternalError "There should not be type violations involving StrictNonnull"
| Nullability.ThirdPartyNonnull ->
return
( "third-party classes"
, mk_recommendation_for_third_party_field nullsafe_mode unqualified_name
, IssueType.eradicate_unvetted_third_party_in_nullsafe )
| Nullability.UncheckedNonnull | Nullability.LocallyCheckedNonnull ->
let coming_from_explanation, recommendation, issue_type =
match untrusted_kind with
| UserFriendlyNullable.ThirdPartyNonnull ->
( "third-party classes"
, mk_recommendation_for_third_party_field nullsafe_mode unqualified_name
, IssueType.eradicate_unvetted_third_party_in_nullsafe )
| UserFriendlyNullable.UncheckedNonnull | UserFriendlyNullable.LocallyCheckedNonnull ->
let from =
mk_coming_from_unchecked_or_locally_checked_case_only nullsafe_mode bad_nullability
mk_coming_from_unchecked_or_locally_checked_case_only nullsafe_mode untrusted_kind
in
let+ recommendation =
mk_recommendation nullsafe_mode bad_nullability (get_field_class_name field_name)
let recommendation =
mk_strictification_advice_unchecked_or_locally_checked_case_only nullsafe_mode
untrusted_kind ~what_to_strictify:(get_field_class_name field_name)
in
(from, recommendation, IssueType.eradicate_unchecked_usage_in_nullsafe)
in
@ -210,19 +234,22 @@ let get_info object_origin nullsafe_mode bad_nullability =
; what_is_used
; recommendation
; issue_type }
| _ ->
None
| other ->
Logging.die InternalError
"get_info:: untrusted_kind is possible only for MethodCall and Field origins, got %s \
instead"
(TypeOrigin.to_string other)
let mk_special_nullsafe_issue ~nullsafe_mode ~bad_nullability ~bad_usage_location object_origin =
let open IOption.Let_syntax in
let+ { offending_object
; object_loc
; coming_from_explanation
; what_is_used
; recommendation
; issue_type } =
get_info object_origin nullsafe_mode bad_nullability
let mk_nullsafe_issue_for_untrusted_values ~nullsafe_mode ~untrusted_kind ~bad_usage_location
object_origin =
let { offending_object
; object_loc
; coming_from_explanation
; what_is_used
; recommendation
; issue_type } =
get_info object_origin nullsafe_mode untrusted_kind
in
let description =
F.asprintf

@ -9,22 +9,44 @@
open! IStd
(** "Effectively nullable values" from the user perspective. Depending on context, convention, and
mode, Nullsafe treats such and such things as nullable or non-null. At some point this needs to
be explain to the user. *)
module UserFriendlyNullable : sig
type t =
| ExplainablyNullable of explainably_nullable_kind
(** Value that is nullable according to nullsafe semantics and conventions. It can be
nullable because of an explicit annotation, models, default nullability conventions,
etc. *)
| UntrustedNonnull of untrusted_kind
(** Value is not nullable per se, but we still can not treat it as non-null in current mode.
From the user perspective, it is a very different case: violations of this type need to
be explained in a way so that it is clear why exactly can not nullsafe trust it in this
context. *)
and explainably_nullable_kind = Nullable | Null
and untrusted_kind = ThirdPartyNonnull | UncheckedNonnull | LocallyCheckedNonnull
val from_nullability : Nullability.t -> t option
end
val is_object_nullability_self_explanatory : object_expression:string -> TypeOrigin.t -> bool
(** In order to understand why such and such object is nullable (or not nullable), we render its
origin. In some cases this is redundant and adds extra noise for the user. *)
val mk_special_nullsafe_issue :
val mk_nullsafe_issue_for_untrusted_values :
nullsafe_mode:NullsafeMode.t
-> bad_nullability:Nullability.t
-> untrusted_kind:UserFriendlyNullable.untrusted_kind
-> bad_usage_location:Location.t
-> TypeOrigin.t
-> (string * IssueType.t * Location.t) option
-> string * IssueType.t * Location.t
(** Situation when we tried to use nonnull values in a nullsafe mode that does not trust them to be
non-nullable. From the user perspective, this case is different from normal nullable assignment
or dereference violation: what needs to be described is why does not this mode trust this value
(and what are possible actions). Returns a tuple (error message, issue type, error location).
NOTE: Location of the error will be NOT in the place when the value is used (that is
[bad_usage_location]), but where the value is first obtained from. *)
non-nullable: [untrusted_kind]. From the user perspective, this case is different from normal
nullable assignment or dereference violation: what needs to be described is why does not this
mode trust this value (and what are possible actions). Returns a tuple (error message, issue
type, error location). NOTE: Location of the error will be NOT in the place when the value is
used (that is [bad_usage_location]), but where the value is first obtained from. *)
val find_alternative_nonnull_method_description : TypeOrigin.t -> string option
(** If type origin is the result of a nullable method call that have a known nonnullable alternative

Loading…
Cancel
Save