[nullsafe][refactor] More functional-style code for building errors

Summary:
We in fact build NullsafeIssue.t by parts, filling needed details until
all the info is provided.

This is nicely expressed via partial functions.

See the next diff that uses this to add additional information to the created
`NullsafeIssue.t`

Reviewed By: skcho

Differential Revision: D23706674

fbshipit-source-id: ca5fac704
master
Mitya Lyubarskiy 5 years ago committed by Facebook GitHub Bot
parent 91a33f6edc
commit 190216ca3a

@ -59,9 +59,24 @@ module ReportableViolation = struct
else Format.fprintf fmt "(%a)" MarkupFormatter.pp_monospaced name else Format.fprintf fmt "(%a)" MarkupFormatter.pp_monospaced name
let mk_description_for_bad_param_passed (* A slight adapter over [NullsafeIssue.make]: the same signature but additionally accepts an alternative method *)
let make_issue_with_recommendation ~alternative_method ~description =
(* If there is an alternative method to propose, tell about it at the end of the description *)
let alternative_recommendation =
Option.value_map alternative_method
~f:
(Format.asprintf " If you don't expect null, use %a instead."
MarkupFormatter.pp_monospaced)
~default:""
in
let full_description = Format.sprintf "%s%s" description alternative_recommendation in
NullsafeIssue.make ~description:full_description
let mk_issue_for_bad_param_passed
{kind; param_signature; actual_param_expression; param_position; function_procname} {kind; param_signature; actual_param_expression; param_position; function_procname}
~param_nullability_kind ~nullability_evidence = ~param_nullability_kind ~nullability_evidence
~(make_issue_fn : description:string -> issue_type:IssueType.t -> NullsafeIssue.t) =
let nullability_evidence_as_suffix = let nullability_evidence_as_suffix =
Option.value_map nullability_evidence ~f:(fun evidence -> ": " ^ evidence) ~default:"" Option.value_map nullability_evidence ~f:(fun evidence -> ": " ^ evidence) ~default:""
in in
@ -79,6 +94,7 @@ module ReportableViolation = struct
in in
Format.asprintf "%a is %s" MF.pp_monospaced actual_param_expression nullability_descr Format.asprintf "%a is %s" MF.pp_monospaced actual_param_expression nullability_descr
in in
let issue_type = IssueType.eradicate_parameter_not_nullable in
match AnnotatedNullability.get_nullability annotated_param_nullability with match AnnotatedNullability.get_nullability annotated_param_nullability with
| Nullability.Null -> | Nullability.Null ->
Logging.die Logging.InternalError "Unexpected param nullability: Null" Logging.die Logging.InternalError "Unexpected param nullability: Null"
@ -105,12 +121,15 @@ module ReportableViolation = struct
~default:"the third party signature storage" ~default:"the third party signature storage"
in in
let procname_str = Procname.Java.to_simplified_string ~withclass:true function_procname in let procname_str = Procname.Java.to_simplified_string ~withclass:true function_procname in
Format.asprintf let description =
"Third-party %a is missing a signature that would allow passing a nullable to param \ Format.asprintf
#%d%a. Actual argument %s%s. Consider adding the correct signature of %a to %s." "Third-party %a is missing a signature that would allow passing a nullable to param \
MF.pp_monospaced procname_str param_position pp_param_name param_signature.mangled #%d%a. Actual argument %s%s. Consider adding the correct signature of %a to %s."
argument_description nullability_evidence_as_suffix MF.pp_monospaced procname_str MF.pp_monospaced procname_str param_position pp_param_name param_signature.mangled
where_to_add_signature argument_description nullability_evidence_as_suffix MF.pp_monospaced procname_str
where_to_add_signature
in
make_issue_fn ~description ~issue_type
| Nullability.LocallyCheckedNonnull | Nullability.LocallyCheckedNonnull
| Nullability.LocallyTrustedNonnull | Nullability.LocallyTrustedNonnull
| Nullability.UncheckedNonnull | Nullability.UncheckedNonnull
@ -127,24 +146,18 @@ module ReportableViolation = struct
~filename) ~filename)
line_number line_number
in in
Format.asprintf "%a: parameter #%d%a is declared non-nullable%s but the argument %s%s." let description =
MF.pp_monospaced Format.asprintf "%a: parameter #%d%a is declared non-nullable%s but the argument %s%s."
(Procname.Java.to_simplified_string ~withclass:true function_procname) MF.pp_monospaced
param_position pp_param_name param_signature.mangled nonnull_evidence argument_description (Procname.Java.to_simplified_string ~withclass:true function_procname)
nullability_evidence_as_suffix param_position pp_param_name param_signature.mangled nonnull_evidence
argument_description nullability_evidence_as_suffix
in
let get_issue_type = function make_issue_fn ~description ~issue_type
| PassingParamToFunction _ ->
IssueType.eradicate_parameter_not_nullable
| AssigningToField _ ->
IssueType.eradicate_field_not_nullable
| ReturningFromFunction _ ->
IssueType.eradicate_return_not_nullable
let mk_nullsafe_issue_for_explicitly_nullable_values ~assignment_type ~rhs_origin let mk_nullsafe_issue_for_explicitly_nullable_values ~assignment_type ~rhs_origin ~nullsafe_mode
~explicit_rhs_nullable_kind ~assignment_location ~nullsafe_mode = ~explicit_rhs_nullable_kind ~assignment_location =
let nullability_evidence = let nullability_evidence =
get_origin_opt assignment_type rhs_origin get_origin_opt assignment_type rhs_origin
|> Option.bind ~f:(fun origin -> TypeOrigin.get_description origin) |> Option.bind ~f:(fun origin -> TypeOrigin.get_description origin)
@ -152,51 +165,51 @@ module ReportableViolation = struct
let nullability_evidence_as_suffix = let nullability_evidence_as_suffix =
Option.value_map nullability_evidence ~f:(fun evidence -> ": " ^ evidence) ~default:"" Option.value_map nullability_evidence ~f:(fun evidence -> ": " ^ evidence) ~default:""
in in
let module MF = MarkupFormatter in (* A functor for creating the nullsafe issue: the alternative method, location,
let alternative_method_description = and severity are known at this point.
ErrorRenderingUtils.find_alternative_nonnull_method_description rhs_origin The rest to be filled by the client *)
in let make_issue_fn =
let alternative_recommendation = make_issue_with_recommendation
Option.value_map alternative_method_description ~alternative_method:
~f:(fun descr -> (ErrorRenderingUtils.find_alternative_nonnull_method_description rhs_origin)
Format.asprintf " If you don't expect null, use %a instead." MF.pp_monospaced descr ) ~severity:(NullsafeMode.severity nullsafe_mode)
~default:"" ~loc:assignment_location
in in
let description = match assignment_type with
match assignment_type with | PassingParamToFunction function_info ->
| PassingParamToFunction function_info -> mk_issue_for_bad_param_passed function_info ~nullability_evidence
Format.sprintf "%s%s" ~param_nullability_kind:explicit_rhs_nullable_kind ~make_issue_fn
(mk_description_for_bad_param_passed function_info ~nullability_evidence | AssigningToField field_name ->
~param_nullability_kind:explicit_rhs_nullable_kind) let rhs_description =
alternative_recommendation match explicit_rhs_nullable_kind with
| AssigningToField field_name -> | ErrorRenderingUtils.UserFriendlyNullable.Null ->
let rhs_description = "`null`"
match explicit_rhs_nullable_kind with | ErrorRenderingUtils.UserFriendlyNullable.Nullable ->
| ErrorRenderingUtils.UserFriendlyNullable.Null -> "a nullable"
"`null`" in
| ErrorRenderingUtils.UserFriendlyNullable.Nullable -> let description =
"a nullable" Format.asprintf "%a is declared non-nullable but is assigned %s%s."
in MarkupFormatter.pp_monospaced
Format.asprintf "%a is declared non-nullable but is assigned %s%s.%s" MF.pp_monospaced
(Fieldname.get_field_name field_name) (Fieldname.get_field_name field_name)
rhs_description nullability_evidence_as_suffix alternative_recommendation rhs_description nullability_evidence_as_suffix
| ReturningFromFunction function_proc_name -> in
let return_description = make_issue_fn ~description ~issue_type:IssueType.eradicate_field_not_nullable
match explicit_rhs_nullable_kind with | ReturningFromFunction function_proc_name ->
| ErrorRenderingUtils.UserFriendlyNullable.Null -> let return_description =
(* Return `null` in all_whitelisted branches *) match explicit_rhs_nullable_kind with
"`null`" | ErrorRenderingUtils.UserFriendlyNullable.Null ->
| ErrorRenderingUtils.UserFriendlyNullable.Nullable -> (* Return `null` in all_whitelisted branches *)
"a nullable value" "`null`"
in | ErrorRenderingUtils.UserFriendlyNullable.Nullable ->
Format.asprintf "%a: return type is declared non-nullable but the method returns %s%s.%s" "a nullable value"
MF.pp_monospaced in
let description =
Format.asprintf "%a: return type is declared non-nullable but the method returns %s%s."
MarkupFormatter.pp_monospaced
(Procname.Java.to_simplified_string ~withclass:false function_proc_name) (Procname.Java.to_simplified_string ~withclass:false function_proc_name)
return_description nullability_evidence_as_suffix alternative_recommendation return_description nullability_evidence_as_suffix
in in
let issue_type = get_issue_type assignment_type in make_issue_fn ~description ~issue_type:IssueType.eradicate_return_not_nullable
NullsafeIssue.make ~description ~issue_type ~loc:assignment_location
~severity:(NullsafeMode.severity nullsafe_mode)
let make_nullsafe_issue ~assignment_location assignment_type {nullsafe_mode; violation= {rhs}} = let make_nullsafe_issue ~assignment_location assignment_type {nullsafe_mode; violation= {rhs}} =

Loading…
Cancel
Save