diff --git a/infer/src/nullsafe/AssignmentRule.ml b/infer/src/nullsafe/AssignmentRule.ml index cbe578614..aa003cdb3 100644 --- a/infer/src/nullsafe/AssignmentRule.ml +++ b/infer/src/nullsafe/AssignmentRule.ml @@ -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}} =