[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 4 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
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}
~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 =
Option.value_map nullability_evidence ~f:(fun evidence -> ": " ^ evidence) ~default:""
in
@ -79,6 +94,7 @@ module ReportableViolation = struct
in
Format.asprintf "%a is %s" MF.pp_monospaced actual_param_expression nullability_descr
in
let issue_type = IssueType.eradicate_parameter_not_nullable in
match AnnotatedNullability.get_nullability annotated_param_nullability with
| Nullability.Null ->
Logging.die Logging.InternalError "Unexpected param nullability: Null"
@ -105,12 +121,15 @@ module ReportableViolation = struct
~default:"the third party signature storage"
in
let procname_str = Procname.Java.to_simplified_string ~withclass:true function_procname in
Format.asprintf
"Third-party %a is missing a signature that would allow passing a nullable to param \
#%d%a. Actual argument %s%s. Consider adding the correct signature of %a to %s."
MF.pp_monospaced procname_str param_position pp_param_name param_signature.mangled
argument_description nullability_evidence_as_suffix MF.pp_monospaced procname_str
where_to_add_signature
let description =
Format.asprintf
"Third-party %a is missing a signature that would allow passing a nullable to param \
#%d%a. Actual argument %s%s. Consider adding the correct signature of %a to %s."
MF.pp_monospaced procname_str param_position pp_param_name param_signature.mangled
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.LocallyTrustedNonnull
| Nullability.UncheckedNonnull
@ -127,24 +146,18 @@ module ReportableViolation = struct
~filename)
line_number
in
Format.asprintf "%a: parameter #%d%a is declared non-nullable%s but the argument %s%s."
MF.pp_monospaced
(Procname.Java.to_simplified_string ~withclass:true function_procname)
param_position pp_param_name param_signature.mangled nonnull_evidence argument_description
nullability_evidence_as_suffix
let get_issue_type = function
| PassingParamToFunction _ ->
IssueType.eradicate_parameter_not_nullable
| AssigningToField _ ->
IssueType.eradicate_field_not_nullable
| ReturningFromFunction _ ->
IssueType.eradicate_return_not_nullable
let description =
Format.asprintf "%a: parameter #%d%a is declared non-nullable%s but the argument %s%s."
MF.pp_monospaced
(Procname.Java.to_simplified_string ~withclass:true function_procname)
param_position pp_param_name param_signature.mangled nonnull_evidence
argument_description nullability_evidence_as_suffix
in
make_issue_fn ~description ~issue_type
let mk_nullsafe_issue_for_explicitly_nullable_values ~assignment_type ~rhs_origin
~explicit_rhs_nullable_kind ~assignment_location ~nullsafe_mode =
let mk_nullsafe_issue_for_explicitly_nullable_values ~assignment_type ~rhs_origin ~nullsafe_mode
~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)
@ -152,51 +165,51 @@ module ReportableViolation = struct
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:""
(* A functor for creating the nullsafe issue: the alternative method, location,
and severity are known at this point.
The rest to be filled by the client *)
let make_issue_fn =
make_issue_with_recommendation
~alternative_method:
(ErrorRenderingUtils.find_alternative_nonnull_method_description rhs_origin)
~severity:(NullsafeMode.severity nullsafe_mode)
~loc:assignment_location
in
let description =
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
match assignment_type with
| PassingParamToFunction function_info ->
mk_issue_for_bad_param_passed function_info ~nullability_evidence
~param_nullability_kind:explicit_rhs_nullable_kind ~make_issue_fn
| AssigningToField field_name ->
let rhs_description =
match explicit_rhs_nullable_kind with
| ErrorRenderingUtils.UserFriendlyNullable.Null ->
"`null`"
| ErrorRenderingUtils.UserFriendlyNullable.Nullable ->
"a nullable"
in
let description =
Format.asprintf "%a is declared non-nullable but is assigned %s%s."
MarkupFormatter.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
rhs_description nullability_evidence_as_suffix
in
make_issue_fn ~description ~issue_type:IssueType.eradicate_field_not_nullable
| 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
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)
return_description nullability_evidence_as_suffix alternative_recommendation
in
let issue_type = get_issue_type assignment_type in
NullsafeIssue.make ~description ~issue_type ~loc:assignment_location
~severity:(NullsafeMode.severity nullsafe_mode)
return_description nullability_evidence_as_suffix
in
make_issue_fn ~description ~issue_type:IssueType.eradicate_return_not_nullable
let make_nullsafe_issue ~assignment_location assignment_type {nullsafe_mode; violation= {rhs}} =

Loading…
Cancel
Save