[nullsafe] Decouple nullsafe mode from issue calculation, AssignmentRule

Summary:
# Problem

In current design, Rules (assignment rule, dereference rule, inheritance
rule) decide, depending on the mode, wether the issue is legit or not.

If the issue is not actionable for the given mode, it won't be created
and registered.

For meta-issues, we want to be able to do smart things like:
- Identify if we can raise strictness of the mode without
introducing new issues
- Classify classes on "clean" vs "broken", taking into account issues
that are currently invisible.

# Solution
In the new design:

1. Rules are issuing violations independently of mode. This makes sense
semantically. Mode is "level of trust we have for suspicious things",
but the thing does not cease to be suspicious in any mode.
2. Each Rule decides if it is reportable or not in a given mode.
3. `nullsafe_mode` is passed to the function `register_error`, that 1)
adds error so it can be recorded in summary for file-level analysis
phase 2) reports some of them to the user.

# This diff
This diff converts only AssignmentRule, follow up will include
conversion of other rules, so no issue encapsutes the mode.

Reviewed By: jvillard

Differential Revision: D20491716

fbshipit-source-id: af17dd66d
master
Mitya Lyubarskiy 5 years ago committed by Facebook GitHub Bot
parent 25c058f706
commit 0bf5298c21

@ -6,222 +6,225 @@
*)
open! IStd
type violation = {nullsafe_mode: NullsafeMode.t; lhs: Nullability.t; rhs: Nullability.t}
[@@deriving compare]
type assignment_type =
| PassingParamToFunction of function_info
| AssigningToField of Fieldname.t
| ReturningFromFunction of Procname.t
[@@deriving compare]
and function_info =
{ param_signature: AnnotatedSignature.param_signature
; model_source: AnnotatedSignature.model_source option
; actual_param_expression: string
; param_position: int
; function_procname: Procname.t }
let check ~(nullsafe_mode : NullsafeMode.t) ~lhs ~rhs =
let falls_under_optimistic_third_party =
match nullsafe_mode with
| NullsafeMode.Default when Config.nullsafe_optimistic_third_party_params_in_non_strict -> (
match lhs with Nullability.ThirdPartyNonnull -> true | _ -> false )
type violation = {lhs: Nullability.t; rhs: Nullability.t} [@@deriving compare]
module ReportableViolation = struct
type t = {nullsafe_mode: NullsafeMode.t; violation: violation}
type assignment_type =
| PassingParamToFunction of function_info
| AssigningToField of Fieldname.t
| ReturningFromFunction of Procname.t
[@@deriving compare]
and function_info =
{ param_signature: AnnotatedSignature.param_signature
; model_source: AnnotatedSignature.model_source option
; actual_param_expression: string
; param_position: int
; function_procname: Procname.t }
let get_severity {nullsafe_mode} = NullsafeMode.severity nullsafe_mode
let get_origin_opt assignment_type origin =
let should_show_origin =
match assignment_type with
| PassingParamToFunction {actual_param_expression} ->
not
(ErrorRenderingUtils.is_object_nullability_self_explanatory
~object_expression:actual_param_expression origin)
| AssigningToField _ | ReturningFromFunction _ ->
true
in
if should_show_origin then Some origin else None
let pp_param_name fmt mangled =
let name = Mangled.to_string mangled in
if String.is_substring name ~substring:"_arg_" then
(* The real name was not fetched for whatever reason, this is an autogenerated name *)
Format.fprintf fmt ""
else Format.fprintf fmt "(%a)" MarkupFormatter.pp_monospaced name
let mk_description_for_bad_param_passed
{model_source; param_signature; actual_param_expression; param_position; function_procname}
~param_nullability ~nullability_evidence =
let nullability_evidence_as_suffix =
Option.value_map nullability_evidence ~f:(fun evidence -> ": " ^ evidence) ~default:""
in
let annotated_param_nullability = param_signature.param_annotated_type.nullability in
let module MF = MarkupFormatter in
let argument_description =
if String.equal actual_param_expression "null" then "is `null`"
else
let nullability_descr =
match param_nullability with
| Nullability.Null ->
"`null`"
| Nullability.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
match AnnotatedNullability.get_nullability annotated_param_nullability with
| Nullability.Null ->
Logging.die Logging.InternalError "Unexpected param nullability: Null"
| Nullability.Nullable ->
Logging.die Logging.InternalError "Passing anything to a nullable param should be allowed"
| Nullability.ThirdPartyNonnull ->
(* This is a special case. While for FB codebase we can assume "not annotated hence not nullable" rule for all_whitelisted signatures,
This is not the case for third party functions, which can have different conventions,
So we can not just say "param is declared as non-nullable" like we say for FB-internal or modelled case:
param can be nullable according to API but it was just not annotated.
So we phrase it differently to remain truthful, but as specific as possible.
*)
let suggested_third_party_sig_file =
ThirdPartyAnnotationInfo.lookup_related_sig_file_for_proc
(ThirdPartyAnnotationGlobalRepo.get_repo ())
function_procname
in
let where_to_add_signature =
Option.value_map suggested_third_party_sig_file
~f:(fun sig_file_name ->
ThirdPartyAnnotationGlobalRepo.get_user_friendly_third_party_sig_file_name
~filename:sig_file_name )
(* this can happen when third party is registered in a deprecated way (not in third party repository) *)
~default:"the third party signature storage"
in
let procname_str = Procname.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
| Nullability.LocallyCheckedNonnull | Nullability.UncheckedNonnull | Nullability.StrictNonnull
->
let nonnull_evidence =
match model_source with
| None ->
""
| Some InternalModel ->
" (according to nullsafe internal models)"
| Some (ThirdPartyRepo {filename; line_number}) ->
Format.sprintf " (see %s at line %d)"
(ThirdPartyAnnotationGlobalRepo.get_user_friendly_third_party_sig_file_name
~filename)
line_number
in
Format.asprintf "%a: parameter #%d%a is declared non-nullable%s but the argument %s%s."
MF.pp_monospaced
(Procname.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 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
in
match special_message with
| Some desc ->
desc
| _ ->
false
in
let is_allowed_assignment =
Nullability.is_subtype ~supertype:lhs ~subtype:rhs
|| falls_under_optimistic_third_party
(* For better adoption we allow certain conversions. Otherwise using code checked under
different nullsafe modes becomes a pain because of extra warnings. *)
(* TODO(T62521386): consider using caller context when determining nullability to get rid of
white-lists. *)
|| Nullability.is_considered_nonnull ~nullsafe_mode rhs
in
Result.ok_if_true is_allowed_assignment ~error:{nullsafe_mode; lhs; rhs}
let get_origin_opt assignment_type origin =
let should_show_origin =
match assignment_type with
| PassingParamToFunction {actual_param_expression} ->
not
(ErrorRenderingUtils.is_object_nullability_self_explanatory
~object_expression:actual_param_expression origin)
| AssigningToField _ | ReturningFromFunction _ ->
true
in
if should_show_origin then Some origin else None
let pp_param_name fmt mangled =
let name = Mangled.to_string mangled in
if String.is_substring name ~substring:"_arg_" then
(* The real name was not fetched for whatever reason, this is an autogenerated name *)
Format.fprintf fmt ""
else Format.fprintf fmt "(%a)" MarkupFormatter.pp_monospaced name
let mk_description_for_bad_param_passed
{model_source; param_signature; actual_param_expression; param_position; function_procname}
~param_nullability ~nullability_evidence =
let nullability_evidence_as_suffix =
Option.value_map nullability_evidence ~f:(fun evidence -> ": " ^ evidence) ~default:""
in
let annotated_param_nullability = param_signature.param_annotated_type.nullability in
let module MF = MarkupFormatter in
let argument_description =
if String.equal actual_param_expression "null" then "is `null`"
else
let nullability_descr =
match param_nullability with
| Nullability.Null ->
"`null`"
| Nullability.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
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)
end
let check ~lhs ~rhs =
let is_subtype = Nullability.is_subtype ~supertype:lhs ~subtype:rhs in
Result.ok_if_true is_subtype ~error:{lhs; rhs}
let to_reportable_violation nullsafe_mode ({lhs; rhs} as violation) =
let falls_under_optimistic_third_party =
Config.nullsafe_optimistic_third_party_params_in_non_strict
&& NullsafeMode.equal nullsafe_mode Default
&& Nullability.equal lhs ThirdPartyNonnull
in
match AnnotatedNullability.get_nullability annotated_param_nullability with
| Nullability.Null ->
Logging.die Logging.InternalError "Unexpected param nullability: Null"
| Nullability.Nullable ->
Logging.die Logging.InternalError "Passing anything to a nullable param should be allowed"
| Nullability.ThirdPartyNonnull ->
(* This is a special case. While for FB codebase we can assume "not annotated hence not nullable" rule for all_whitelisted signatures,
This is not the case for third party functions, which can have different conventions,
So we can not just say "param is declared as non-nullable" like we say for FB-internal or modelled case:
param can be nullable according to API but it was just not annotated.
So we phrase it differently to remain truthful, but as specific as possible.
*)
let suggested_third_party_sig_file =
ThirdPartyAnnotationInfo.lookup_related_sig_file_for_proc
(ThirdPartyAnnotationGlobalRepo.get_repo ())
function_procname
in
let where_to_add_signature =
Option.value_map suggested_third_party_sig_file
~f:(fun sig_file_name ->
ThirdPartyAnnotationGlobalRepo.get_user_friendly_third_party_sig_file_name
~filename:sig_file_name )
(* this can happen when third party is registered in a deprecated way (not in third party repository) *)
~default:"the third party signature storage"
in
let procname_str = Procname.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
| Nullability.LocallyCheckedNonnull | Nullability.UncheckedNonnull | Nullability.StrictNonnull ->
let nonnull_evidence =
match model_source with
| None ->
""
| Some InternalModel ->
" (according to nullsafe internal models)"
| Some (ThirdPartyRepo {filename; line_number}) ->
Format.sprintf " (see %s at line %d)"
(ThirdPartyAnnotationGlobalRepo.get_user_friendly_third_party_sig_file_name ~filename)
line_number
in
Format.asprintf "%a: parameter #%d%a is declared non-nullable%s but the argument %s%s."
MF.pp_monospaced
(Procname.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 violation_description {nullsafe_mode; rhs} ~assignment_location assignment_type ~rhs_origin =
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 is_non_reportable =
falls_under_optimistic_third_party
|| (* In certain modes, we trust rhs to be non-nullable and don't report violation *)
Nullability.is_considered_nonnull ~nullsafe_mode rhs
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)
let violation_severity {nullsafe_mode} = NullsafeMode.severity nullsafe_mode
if is_non_reportable then None else Some ReportableViolation.{nullsafe_mode; violation}

@ -12,29 +12,40 @@ open! IStd
type violation [@@deriving compare]
val check :
nullsafe_mode:NullsafeMode.t -> lhs:Nullability.t -> rhs:Nullability.t -> (unit, violation) result
type assignment_type =
| PassingParamToFunction of function_info
| AssigningToField of Fieldname.t
| ReturningFromFunction of Procname.t
[@@deriving compare]
and function_info =
{ param_signature: AnnotatedSignature.param_signature
; model_source: AnnotatedSignature.model_source option
; actual_param_expression: string
; param_position: int
; function_procname: Procname.t }
val violation_description :
violation
-> assignment_location:Location.t
-> assignment_type
-> rhs_origin:TypeOrigin.t
-> string * IssueType.t * Location.t
(** Given context around violation, return error message together with the info where to put this
message *)
val violation_severity : violation -> Exceptions.severity
val check : lhs:Nullability.t -> rhs:Nullability.t -> (unit, violation) result
(** If `null` can leak from a "less strict" type to "more strict" type, this is an Assignment Rule
violation. *)
(** Violation that needs to be reported to the user. *)
module ReportableViolation : sig
type t
type assignment_type =
| PassingParamToFunction of function_info
| AssigningToField of Fieldname.t
| ReturningFromFunction of Procname.t
[@@deriving compare]
and function_info =
{ param_signature: AnnotatedSignature.param_signature
; model_source: AnnotatedSignature.model_source option
; actual_param_expression: string
; param_position: int
; function_procname: Procname.t }
val get_severity : t -> Exceptions.severity
(** Severity of the violation to be reported *)
val get_description :
assignment_location:Location.t
-> assignment_type
-> rhs_origin:TypeOrigin.t
-> t
-> string * IssueType.t * Location.t
(** Given context around violation, return error message together with the info where to put this
message *)
end
val to_reportable_violation : NullsafeMode.t -> violation -> ReportableViolation.t option
(** Depending on the mode, violation might or might not be important enough to be reported to the
user. If it should NOT be reported for that mode, this function will return None. *)

@ -242,7 +242,9 @@ module MkCallback (Extension : ExtensionT) : CallBackT = struct
if is_important err_instance then Some err_instance else None )
|> List.length
in
TypeErr.report_forall_checks_and_reset (EradicateCheckers.report_error tenv) proc_desc ;
TypeErr.report_forall_issues_and_reset
(EradicateCheckers.report_error tenv)
~nullsafe_mode:annotated_signature.nullsafe_mode proc_desc ;
Payload.update_summary NullsafeSummary.{type_violation_count} summary
end

@ -11,7 +11,7 @@ open! IStd
module L = Logging
let report_error tenv = TypeErr.report_error (EradicateCheckers.report_error tenv)
let register_error tenv = TypeErr.register_error (EradicateCheckers.report_error tenv)
let explain_expr tenv node e =
match Errdesc.exp_rv_dexp tenv node e with
@ -44,14 +44,15 @@ let check_object_dereference ~nullsafe_mode tenv find_canonical_duplicate curr_p
; dereference_type
; nullable_object_origin }
in
report_error tenv find_canonical_duplicate type_error (Some instr_ref) loc curr_pname )
register_error tenv find_canonical_duplicate type_error (Some instr_ref) ~nullsafe_mode loc
curr_pname )
(** [expr] is an expression that was explicitly compared with `null`. At the same time, [expr] had
[inferred_nullability] before the comparision. Check if the comparision is redundant and emit an
issue, if this is the case. *)
let check_condition_for_redundancy tenv ~is_always_true find_canonical_duplicate curr_pdesc node
expr typ inferred_nullability idenv linereader loc instr_ref : unit =
~nullsafe_mode expr typ inferred_nullability idenv linereader loc instr_ref : unit =
let contains_instanceof_throwable pdesc node =
(* Check if the current procedure has a catch Throwable. *)
(* That always happens in the bytecode generated by try-with-resources. *)
@ -111,9 +112,9 @@ let check_condition_for_redundancy tenv ~is_always_true find_canonical_duplicate
*)
let condition_descr = explain_expr tenv node expr in
let nonnull_origin = InferredNullability.get_origin inferred_nullability in
report_error tenv find_canonical_duplicate
register_error tenv find_canonical_duplicate
(TypeErr.Condition_redundant {is_always_true; condition_descr; nonnull_origin})
(Some instr_ref) loc curr_pdesc
(Some instr_ref) ~nullsafe_mode loc curr_pdesc
(** Check an assignment to a field. *)
@ -144,7 +145,7 @@ let check_field_assignment ~nullsafe_mode tenv find_canonical_duplicate curr_pde
AnnotatedNullability.get_nullability annotated_field.annotated_type.nullability
in
let assignment_check_result =
AssignmentRule.check ~nullsafe_mode ~lhs:declared_nullability
AssignmentRule.check ~lhs:declared_nullability
~rhs:(InferredNullability.get_nullability inferred_nullability_rhs)
in
Result.iter_error assignment_check_result ~f:(fun assignment_violation ->
@ -157,13 +158,13 @@ let check_field_assignment ~nullsafe_mode tenv find_canonical_duplicate curr_pde
in
if should_report then
let rhs_origin = InferredNullability.get_origin inferred_nullability_rhs in
report_error tenv find_canonical_duplicate
register_error tenv find_canonical_duplicate
(TypeErr.Bad_assignment
{ assignment_violation
; assignment_location= loc
; rhs_origin
; assignment_type= AssignmentRule.AssigningToField fname })
(Some instr_ref) loc curr_pdesc ) )
; assignment_type= AssignmentRule.ReportableViolation.AssigningToField fname })
(Some instr_ref) ~nullsafe_mode loc curr_pdesc ) )
(* Check if the field declared as not nullable (implicitly or explicitly). If the field is
@ -304,9 +305,9 @@ let check_constructor_initialization tenv find_canonical_duplicate curr_construc
*)
()
else
report_error tenv find_canonical_duplicate
register_error tenv find_canonical_duplicate
(TypeErr.Field_not_initialized {nullsafe_mode; field_name})
None loc curr_constructor_pdesc ;
None ~nullsafe_mode loc curr_constructor_pdesc ;
(* Check if field is over-annotated. *)
match annotated_field with
| None ->
@ -320,11 +321,11 @@ let check_constructor_initialization tenv find_canonical_duplicate curr_construc
let by_rhs_upper_bound = field_nullability_upper_bound_over_all_typestates () in
Result.iter_error (OverAnnotatedRule.check ~what ~by_rhs_upper_bound)
~f:(fun over_annotated_violation ->
report_error tenv find_canonical_duplicate
register_error tenv find_canonical_duplicate
(TypeErr.Over_annotation
{ over_annotated_violation
; violation_type= OverAnnotatedRule.FieldOverAnnoted field_name })
None loc curr_constructor_pdesc ) )
~nullsafe_mode None loc curr_constructor_pdesc ) )
in
List.iter ~f:do_field fields
| None ->
@ -338,19 +339,19 @@ let check_return_not_nullable ~nullsafe_mode tenv find_canonical_duplicate loc c
(* 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 ~nullsafe_mode ~lhs ~rhs) ~f:(fun assignment_violation ->
Result.iter_error (AssignmentRule.check ~lhs ~rhs) ~f:(fun assignment_violation ->
let rhs_origin = InferredNullability.get_origin ret_inferred_nullability in
report_error tenv find_canonical_duplicate
register_error tenv find_canonical_duplicate
(TypeErr.Bad_assignment
{ assignment_violation
; assignment_location= loc
; rhs_origin
; assignment_type= AssignmentRule.ReturningFromFunction curr_pname })
None loc curr_pdesc )
; assignment_type= AssignmentRule.ReportableViolation.ReturningFromFunction curr_pname })
None ~nullsafe_mode loc curr_pdesc )
let check_return_overrannotated tenv find_canonical_duplicate loc curr_pname curr_pdesc
(ret_signature : AnnotatedSignature.ret_signature) ret_inferred_nullability =
~nullsafe_mode (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 what = AnnotatedNullability.get_nullability ret_signature.ret_annotated_type.nullability in
(* In our CFG implementation, there is only one place where we return from a function
@ -360,11 +361,11 @@ let check_return_overrannotated tenv find_canonical_duplicate loc curr_pname cur
let by_rhs_upper_bound = InferredNullability.get_nullability ret_inferred_nullability in
Result.iter_error (OverAnnotatedRule.check ~what ~by_rhs_upper_bound)
~f:(fun over_annotated_violation ->
report_error tenv find_canonical_duplicate
register_error tenv find_canonical_duplicate
(TypeErr.Over_annotation
{ over_annotated_violation
; violation_type= OverAnnotatedRule.ReturnOverAnnotated curr_pname })
None loc curr_pdesc )
None ~nullsafe_mode loc curr_pdesc )
(** Check the annotations when returning from a method. *)
@ -388,7 +389,8 @@ let check_return_annotation tenv find_canonical_duplicate curr_pdesc ret_range
ret_inferred_nullability ;
if Config.eradicate_return_over_annotated then
check_return_overrannotated tenv find_canonical_duplicate loc curr_pname curr_pdesc
annotated_signature.ret ret_inferred_nullability
annotated_signature.ret ~nullsafe_mode:annotated_signature.nullsafe_mode
ret_inferred_nullability
| None ->
()
@ -422,7 +424,7 @@ let check_call_parameters ~nullsafe_mode ~callee_annotated_signature tenv find_c
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} =
let report assignment_violation =
let report ~nullsafe_mode assignment_violation =
let actual_param_expression =
match explain_expr tenv node orig_e2 with
| Some descr ->
@ -431,26 +433,26 @@ let check_call_parameters ~nullsafe_mode ~callee_annotated_signature tenv find_c
"formal parameter " ^ Mangled.to_string formal.mangled
in
let rhs_origin = InferredNullability.get_origin nullability_actual in
report_error tenv find_canonical_duplicate
register_error tenv find_canonical_duplicate
(TypeErr.Bad_assignment
{ assignment_violation
; assignment_location= loc
; rhs_origin
; assignment_type=
AssignmentRule.PassingParamToFunction
AssignmentRule.ReportableViolation.PassingParamToFunction
{ param_signature= formal
; model_source= callee_annotated_signature.AnnotatedSignature.model_source
; actual_param_expression
; param_position
; function_procname= callee_pname } })
(Some instr_ref) loc curr_pdesc
(Some instr_ref) ~nullsafe_mode loc curr_pdesc
in
if PatternMatch.type_is_class formal.param_annotated_type.typ then
(* Passing a param to a function is essentially an assignment the actual param value
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 ~nullsafe_mode ~lhs ~rhs) ~f:report
Result.iter_error (AssignmentRule.check ~lhs ~rhs) ~f:(report ~nullsafe_mode)
in
List.iter ~f:check resolved_params
@ -461,13 +463,13 @@ let check_inheritance_rule_for_return find_canonical_duplicate tenv loc ~nullsaf
Result.iter_error
(InheritanceRule.check ~nullsafe_mode InheritanceRule.Ret ~base:base_nullability
~overridden:overridden_nullability) ~f:(fun inheritance_violation ->
report_error tenv find_canonical_duplicate
register_error tenv find_canonical_duplicate
(TypeErr.Inconsistent_subclass
{ inheritance_violation
; violation_type= InheritanceRule.InconsistentReturn
; overridden_proc_name
; base_proc_name })
None loc overridden_proc_desc )
None ~nullsafe_mode loc overridden_proc_desc )
let check_inheritance_rule_for_param find_canonical_duplicate tenv loc ~nullsafe_mode
@ -476,7 +478,7 @@ let check_inheritance_rule_for_param find_canonical_duplicate tenv loc ~nullsafe
Result.iter_error
(InheritanceRule.check ~nullsafe_mode InheritanceRule.Param ~base:base_nullability
~overridden:overridden_nullability) ~f:(fun inheritance_violation ->
report_error tenv find_canonical_duplicate
register_error tenv find_canonical_duplicate
(TypeErr.Inconsistent_subclass
{ inheritance_violation
; violation_type=
@ -484,7 +486,7 @@ let check_inheritance_rule_for_param find_canonical_duplicate tenv loc ~nullsafe
{param_position; param_description= Mangled.to_string overridden_param_name}
; base_proc_name
; overridden_proc_name })
None loc overridden_proc_desc )
None ~nullsafe_mode loc overridden_proc_desc )
let check_inheritance_rule_for_params find_canonical_duplicate tenv loc ~nullsafe_mode

@ -479,7 +479,7 @@ let do_preconditions_check_not_null instr_ref tenv find_canonical_duplicate node
curr_pname curr_annotated_signature checks call_params idenv parameter_num ~is_vararg typestate'
=
(* clear the nullable flag of the first parameter of the procedure *)
let clear_nullable_flag typestate'' pvar =
let clear_nullable_flag ~nullsafe_mode typestate'' pvar =
(* remove the nullable flag for the given pvar *)
match TypeState.lookup_pvar pvar typestate'' with
| Some (t, nullability) ->
@ -491,12 +491,12 @@ let do_preconditions_check_not_null instr_ref tenv find_canonical_duplicate node
in
( if checks.eradicate && should_report then
let cond = Exp.BinOp (Binop.Ne, Exp.Lvar pvar, Exp.null) in
EradicateChecks.report_error tenv find_canonical_duplicate
EradicateChecks.register_error tenv find_canonical_duplicate
(TypeErr.Condition_redundant
{ is_always_true= true
; condition_descr= EradicateChecks.explain_expr tenv node cond
; nonnull_origin= InferredNullability.get_origin nullability })
(Some instr_ref) loc curr_pdesc ) ;
(Some instr_ref) ~nullsafe_mode loc curr_pdesc ) ;
let previous_origin = InferredNullability.get_origin nullability in
let new_origin = TypeOrigin.InferredNonnull {previous_origin} in
TypeState.add pvar
@ -521,14 +521,18 @@ let do_preconditions_check_not_null instr_ref tenv find_canonical_duplicate node
match Idenv.expand_expr idenv e with
| Exp.Lvar pvar1 ->
pvar_apply instr_ref idenv tenv curr_pname curr_annotated_signature loc
clear_nullable_flag ts pvar1 node
(clear_nullable_flag
~nullsafe_mode:curr_annotated_signature.AnnotatedSignature.nullsafe_mode)
ts pvar1 node
| _ ->
ts
in
let vararg_values = PatternMatch.java_get_vararg_values node pvar idenv in
List.fold_right ~f:do_vararg_value vararg_values ~init:typestate'
else
pvar_apply instr_ref idenv tenv curr_pname curr_annotated_signature loc clear_nullable_flag
pvar_apply instr_ref idenv tenv curr_pname curr_annotated_signature loc
(clear_nullable_flag
~nullsafe_mode:curr_annotated_signature.AnnotatedSignature.nullsafe_mode)
typestate' pvar node
| None ->
typestate'
@ -808,8 +812,8 @@ let rec check_condition_for_sil_prune tenv idenv calls_this find_canonical_dupli
in
if checks.eradicate then
EradicateChecks.check_condition_for_redundancy ~is_always_true:true_branch tenv
find_canonical_duplicate curr_pdesc original_node pvar_expr typ inferred_nullability idenv
linereader loc instr_ref ) ;
find_canonical_duplicate curr_pdesc original_node pvar_expr typ inferred_nullability
~nullsafe_mode idenv linereader loc instr_ref ) ;
set_nonnull pvar_expr typestate ~descr
in
(* Assuming [expr] is a boolean, this is the branch where, according to PRUNE semantics,

@ -78,7 +78,7 @@ type err_instance =
| Bad_assignment of
{ assignment_violation: AssignmentRule.violation
; assignment_location: Location.t
; assignment_type: AssignmentRule.assignment_type
; assignment_type: AssignmentRule.ReportableViolation.assignment_type
; rhs_origin: TypeOrigin.t }
[@@deriving compare]
@ -151,28 +151,6 @@ let add_err find_canonical_duplicate err_instance instr_ref_opt loc =
not is_forall
let err_instance_get_severity err_instance =
match err_instance with
| Condition_redundant _ ->
(* Condition redundant is a very non-precise issue. Depending on the origin of what is compared with null,
this can have a lot of reasons to be actually nullable.
Until it is made non-precise, it is recommended to not turn this warning on.
But even when it is on, this should not be more than advice.
*)
Exceptions.Advice
| Over_annotation _ ->
(* Very non-precise issue. Should be actually turned off unless for experimental purposes. *)
Exceptions.Advice
| Nullable_dereference {dereference_violation} ->
DereferenceRule.violation_severity dereference_violation
| Field_not_initialized {nullsafe_mode} ->
NullsafeMode.severity nullsafe_mode
| Bad_assignment {assignment_violation} ->
AssignmentRule.violation_severity assignment_violation
| Inconsistent_subclass {inheritance_violation} ->
InheritanceRule.violation_severity inheritance_violation
type st_report_error =
Procname.t
-> Procdesc.t
@ -229,37 +207,55 @@ let get_nonnull_explanation_for_condition_redudant (nonnull_origin : TypeOrigin.
" according to the existing annotations"
let get_error_info err_instance =
(** If error is reportable to the user, return description, severity etc. Otherwise return None. *)
let get_error_info_if_reportable ~nullsafe_mode err_instance =
let open IOption.Let_syntax in
match err_instance with
| Condition_redundant {is_always_true; condition_descr; nonnull_origin} ->
( P.sprintf "The condition %s might be always %b%s."
(Option.value condition_descr ~default:"")
is_always_true
(get_nonnull_explanation_for_condition_redudant nonnull_origin)
, IssueType.eradicate_condition_redundant
, None )
Some
( P.sprintf "The condition %s might be always %b%s."
(Option.value condition_descr ~default:"")
is_always_true
(get_nonnull_explanation_for_condition_redudant nonnull_origin)
, IssueType.eradicate_condition_redundant
, None
, (* Condition redundant is a very non-precise issue. Depending on the origin of what is compared with null,
this can have a lot of reasons to be actually nullable.
Until it is made non-precise, it is recommended to not turn this warning on.
But even when it is on, this should not be more than advice.
*)
Exceptions.Advice )
| Over_annotation {over_annotated_violation; violation_type} ->
( OverAnnotatedRule.violation_description over_annotated_violation violation_type
, ( match violation_type with
| OverAnnotatedRule.FieldOverAnnoted _ ->
IssueType.eradicate_field_over_annotated
| OverAnnotatedRule.ReturnOverAnnotated _ ->
IssueType.eradicate_return_over_annotated )
, None )
Some
( OverAnnotatedRule.violation_description over_annotated_violation violation_type
, ( match violation_type with
| OverAnnotatedRule.FieldOverAnnoted _ ->
IssueType.eradicate_field_over_annotated
| OverAnnotatedRule.ReturnOverAnnotated _ ->
IssueType.eradicate_return_over_annotated )
, None
, (* Very non-precise issue. Should be actually turned off unless for experimental purposes. *)
Exceptions.Advice )
| Field_not_initialized {field_name} ->
( Format.asprintf
"Field %a is declared non-nullable, so it should be initialized in the constructor or in \
an `@Initializer` method"
MF.pp_monospaced
(Fieldname.get_field_name field_name)
, IssueType.eradicate_field_not_initialized
, None )
Some
( Format.asprintf
"Field %a is declared non-nullable, so it should be initialized in the constructor or \
in an `@Initializer` method"
MF.pp_monospaced
(Fieldname.get_field_name field_name)
, IssueType.eradicate_field_not_initialized
, None
, NullsafeMode.severity nullsafe_mode )
| Bad_assignment {rhs_origin; assignment_location; assignment_type; assignment_violation} ->
let+ reportable_violation =
AssignmentRule.to_reportable_violation nullsafe_mode assignment_violation
in
let description, issue_type, error_location =
AssignmentRule.violation_description ~assignment_location assignment_violation
assignment_type ~rhs_origin
AssignmentRule.ReportableViolation.get_description ~assignment_location assignment_type
~rhs_origin reportable_violation
in
(description, issue_type, Some error_location)
let severity = AssignmentRule.ReportableViolation.get_severity reportable_violation in
(description, issue_type, Some error_location, severity)
| Nullable_dereference
{ dereference_violation
; dereference_location
@ -270,48 +266,55 @@ let get_error_info err_instance =
DereferenceRule.violation_description ~dereference_location dereference_violation
dereference_type ~nullable_object_descr ~nullable_object_origin
in
(description, issue_type, Some error_location)
Some
( description
, issue_type
, Some error_location
, DereferenceRule.violation_severity dereference_violation )
| Inconsistent_subclass
{inheritance_violation; violation_type; base_proc_name; overridden_proc_name} ->
( InheritanceRule.violation_description inheritance_violation violation_type ~base_proc_name
~overridden_proc_name
, ( match violation_type with
| InconsistentReturn ->
IssueType.eradicate_inconsistent_subclass_return_annotation
| InconsistentParam _ ->
IssueType.eradicate_inconsistent_subclass_parameter_annotation )
, None )
(** Report an error right now. *)
let report_error_now (st_report_error : st_report_error) err_instance loc pdesc : unit =
Some
( InheritanceRule.violation_description inheritance_violation violation_type ~base_proc_name
~overridden_proc_name
, ( match violation_type with
| InconsistentReturn ->
IssueType.eradicate_inconsistent_subclass_return_annotation
| InconsistentParam _ ->
IssueType.eradicate_inconsistent_subclass_parameter_annotation )
, None
, InheritanceRule.violation_severity inheritance_violation )
let report_now_if_reportable (st_report_error : st_report_error) err_instance ~nullsafe_mode loc
pdesc =
let pname = Procdesc.get_proc_name pdesc in
let err_description, infer_issue_type, updated_location = get_error_info err_instance in
let field_name = get_field_name_for_error_suppressing err_instance in
let severity = err_instance_get_severity err_instance in
let error_location = Option.value updated_location ~default:loc in
st_report_error pname pdesc infer_issue_type error_location ~field_name
~exception_kind:(fun k d -> Exceptions.Eradicate (k, d))
~severity err_description
(** Report an error unless is has been reported already, or unless it's a forall error since it
requires waiting until the end of the analysis and be printed by flush. *)
let report_error (st_report_error : st_report_error) find_canonical_duplicate err_instance
instr_ref_opt loc pdesc =
get_error_info_if_reportable ~nullsafe_mode err_instance
|> Option.iter ~f:(fun (err_description, infer_issue_type, updated_location, severity) ->
let field_name = get_field_name_for_error_suppressing err_instance in
let error_location = Option.value updated_location ~default:loc in
st_report_error pname pdesc infer_issue_type error_location ~field_name
~exception_kind:(fun k d -> Exceptions.Eradicate (k, d))
~severity err_description )
(** Register issue (unless exactly the same issue was already registered). If needed, report this
error immediately. *)
let register_error (st_report_error : st_report_error) find_canonical_duplicate err_instance
~nullsafe_mode instr_ref_opt loc pdesc =
let should_report_now = add_err find_canonical_duplicate err_instance instr_ref_opt loc in
if should_report_now then report_error_now st_report_error err_instance loc pdesc
if should_report_now then
report_now_if_reportable st_report_error err_instance ~nullsafe_mode loc pdesc
(** Report the forall checks at the end of the analysis and reset the error table *)
let report_forall_checks_and_reset st_report_error proc_desc =
let report_forall_issues_and_reset st_report_error ~nullsafe_mode proc_desc =
let iter (err_instance, instr_ref_opt) err_state =
match (instr_ref_opt, get_forall err_instance) with
| Some instr_ref, is_forall ->
let node = InstrRef.get_node instr_ref in
State.set_node node ;
if is_forall && err_state.always then
report_error_now st_report_error err_instance err_state.loc proc_desc
report_now_if_reportable st_report_error err_instance err_state.loc ~nullsafe_mode
proc_desc
| None, _ ->
()
in

@ -54,7 +54,7 @@ type err_instance =
| Bad_assignment of
{ assignment_violation: AssignmentRule.violation
; assignment_location: Location.t
; assignment_type: AssignmentRule.assignment_type
; assignment_type: AssignmentRule.ReportableViolation.assignment_type
; rhs_origin: TypeOrigin.t }
[@@deriving compare]
@ -71,16 +71,21 @@ type st_report_error =
-> string
-> unit
val report_error :
val register_error :
st_report_error
-> (Procdesc.Node.t -> Procdesc.Node.t)
-> err_instance
-> nullsafe_mode:NullsafeMode.t
-> InstrRef.t option
-> Location.t
-> Procdesc.t
-> unit
(** Register the fact that issue happened. Depending on the error and mode, this error might or
might not be reported to the user. *)
val report_forall_checks_and_reset : st_report_error -> Procdesc.t -> unit
val report_forall_issues_and_reset :
st_report_error -> nullsafe_mode:NullsafeMode.t -> Procdesc.t -> unit
(** Report registered "forall" issues (if needed), and reset the error table *)
val reset : unit -> unit

@ -111,7 +111,7 @@ codetoanalyze/java/nullsafe-default/InconsistentSubclassAnnotation.java, Linters
codetoanalyze/java/nullsafe-default/InconsistentSubclassAnnotation.java, Linters_dummy_method, 1, ERADICATE_META_CLASS_IS_CLEAN, no_bucket, INFO, []
codetoanalyze/java/nullsafe-default/InconsistentSubclassAnnotation.java, Linters_dummy_method, 1, ERADICATE_META_CLASS_IS_CLEAN, no_bucket, INFO, []
codetoanalyze/java/nullsafe-default/InconsistentSubclassAnnotation.java, Linters_dummy_method, 1, ERADICATE_META_CLASS_IS_CLEAN, no_bucket, INFO, []
codetoanalyze/java/nullsafe-default/InconsistentSubclassAnnotation.java, Linters_dummy_method, 1, ERADICATE_META_CLASS_IS_CLEAN, no_bucket, INFO, []
codetoanalyze/java/nullsafe-default/InconsistentSubclassAnnotation.java, Linters_dummy_method, 1, ERADICATE_META_CLASS_NEEDS_FIXING, no_bucket, INFO, []
codetoanalyze/java/nullsafe-default/InconsistentSubclassAnnotation.java, Linters_dummy_method, 1, ERADICATE_META_CLASS_NEEDS_FIXING, no_bucket, INFO, []
codetoanalyze/java/nullsafe-default/InconsistentSubclassAnnotation.java, Linters_dummy_method, 1, ERADICATE_META_CLASS_NEEDS_FIXING, no_bucket, INFO, []
codetoanalyze/java/nullsafe-default/InconsistentSubclassAnnotation.java, Linters_dummy_method, 1, ERADICATE_META_CLASS_NEEDS_FIXING, no_bucket, INFO, []
@ -199,7 +199,7 @@ codetoanalyze/java/nullsafe-default/NullMethodCall.java, Linters_dummy_method, 1
codetoanalyze/java/nullsafe-default/NullMethodCall.java, Linters_dummy_method, 1, ERADICATE_META_CLASS_IS_CLEAN, no_bucket, INFO, []
codetoanalyze/java/nullsafe-default/NullMethodCall.java, Linters_dummy_method, 1, ERADICATE_META_CLASS_IS_CLEAN, no_bucket, INFO, []
codetoanalyze/java/nullsafe-default/NullMethodCall.java, Linters_dummy_method, 1, ERADICATE_META_CLASS_IS_CLEAN, no_bucket, INFO, []
codetoanalyze/java/nullsafe-default/NullMethodCall.java, Linters_dummy_method, 1, ERADICATE_META_CLASS_IS_CLEAN, no_bucket, INFO, []
codetoanalyze/java/nullsafe-default/NullMethodCall.java, Linters_dummy_method, 1, ERADICATE_META_CLASS_NEEDS_FIXING, no_bucket, INFO, []
codetoanalyze/java/nullsafe-default/NullMethodCall.java, Linters_dummy_method, 1, ERADICATE_META_CLASS_NEEDS_FIXING, no_bucket, INFO, []
codetoanalyze/java/nullsafe-default/NullMethodCall.java, Linters_dummy_method, 1, ERADICATE_META_CLASS_NEEDS_FIXING, no_bucket, INFO, []
codetoanalyze/java/nullsafe-default/NullMethodCall.java, codetoanalyze.java.nullsafe_default.NullMethodCall$Inner.outerField():int, 1, ERADICATE_NULLABLE_DEREFERENCE, no_bucket, WARNING, [`s` is nullable and is not locally checked for null when calling `length()`: field fld at line 69.]
@ -230,7 +230,7 @@ codetoanalyze/java/nullsafe-default/NullsafeMode.java, Linters_dummy_method, 1,
codetoanalyze/java/nullsafe-default/NullsafeMode.java, Linters_dummy_method, 1, ERADICATE_META_CLASS_IS_CLEAN, no_bucket, INFO, []
codetoanalyze/java/nullsafe-default/NullsafeMode.java, Linters_dummy_method, 1, ERADICATE_META_CLASS_IS_CLEAN, no_bucket, INFO, []
codetoanalyze/java/nullsafe-default/NullsafeMode.java, Linters_dummy_method, 1, ERADICATE_META_CLASS_IS_CLEAN, no_bucket, INFO, []
codetoanalyze/java/nullsafe-default/NullsafeMode.java, Linters_dummy_method, 1, ERADICATE_META_CLASS_IS_CLEAN, no_bucket, INFO, []
codetoanalyze/java/nullsafe-default/NullsafeMode.java, Linters_dummy_method, 1, ERADICATE_META_CLASS_NEEDS_FIXING, no_bucket, INFO, []
codetoanalyze/java/nullsafe-default/NullsafeMode.java, Linters_dummy_method, 1, ERADICATE_META_CLASS_NEEDS_FIXING, no_bucket, INFO, []
codetoanalyze/java/nullsafe-default/NullsafeMode.java, Linters_dummy_method, 1, ERADICATE_META_CLASS_NEEDS_FIXING, no_bucket, INFO, []
codetoanalyze/java/nullsafe-default/NullsafeMode.java, Linters_dummy_method, 1, ERADICATE_META_CLASS_NEEDS_FIXING, no_bucket, INFO, []
@ -317,7 +317,7 @@ codetoanalyze/java/nullsafe-default/PropagatesNullable.java, codetoanalyze.java.
codetoanalyze/java/nullsafe-default/PropagatesNullable.java, codetoanalyze.java.nullsafe_default.TestPropagatesNullable$TestSecondParameter.test(java.lang.String,java.lang.String):void, 9, ERADICATE_NULLABLE_DEREFERENCE, no_bucket, WARNING, [`nullable(...)` is nullable and is not locally checked for null when calling `length()`.]
codetoanalyze/java/nullsafe-default/PropagatesNullable.java, codetoanalyze.java.nullsafe_default.TestPropagatesNullable$TestSecondParameter.test(java.lang.String,java.lang.String):void, 13, ERADICATE_NULLABLE_DEREFERENCE, no_bucket, WARNING, [`nullable(...)` is nullable and is not locally checked for null when calling `length()`.]
codetoanalyze/java/nullsafe-default/ReturnNotNullable.java, Linters_dummy_method, 1, ERADICATE_META_CLASS_IS_CLEAN, no_bucket, INFO, []
codetoanalyze/java/nullsafe-default/ReturnNotNullable.java, Linters_dummy_method, 1, ERADICATE_META_CLASS_IS_CLEAN, no_bucket, INFO, []
codetoanalyze/java/nullsafe-default/ReturnNotNullable.java, Linters_dummy_method, 1, ERADICATE_META_CLASS_NEEDS_FIXING, no_bucket, INFO, []
codetoanalyze/java/nullsafe-default/ReturnNotNullable.java, Linters_dummy_method, 1, ERADICATE_META_CLASS_NEEDS_FIXING, no_bucket, INFO, []
codetoanalyze/java/nullsafe-default/ReturnNotNullable.java, Linters_dummy_method, 1, ERADICATE_META_CLASS_NEEDS_FIXING, no_bucket, INFO, []
codetoanalyze/java/nullsafe-default/ReturnNotNullable.java, codetoanalyze.java.nullsafe_default.ReturnNotNullable$ConditionalAssignment.test(boolean):java.lang.Object, 0, ERADICATE_RETURN_NOT_NULLABLE, no_bucket, WARNING, [`test(...)`: return type is declared non-nullable but the method returns a nullable value: field f1 at line 199.]
@ -334,7 +334,7 @@ codetoanalyze/java/nullsafe-default/ReturnNotNullable.java, codetoanalyze.java.n
codetoanalyze/java/nullsafe-default/ReturnNotNullable.java, codetoanalyze.java.nullsafe_default.ReturnNotNullable.tryWithResourcesReturnNullable(java.lang.String):java.lang.Object, 0, ERADICATE_RETURN_NOT_NULLABLE, no_bucket, WARNING, [`tryWithResourcesReturnNullable(...)`: return type is declared non-nullable but the method returns a nullable value: call to nullToNullableIsOK() at line 142.]
codetoanalyze/java/nullsafe-default/StrictMode.java, Linters_dummy_method, 1, ERADICATE_META_CLASS_IS_CLEAN, no_bucket, INFO, []
codetoanalyze/java/nullsafe-default/StrictMode.java, Linters_dummy_method, 1, ERADICATE_META_CLASS_IS_CLEAN, no_bucket, INFO, []
codetoanalyze/java/nullsafe-default/StrictMode.java, Linters_dummy_method, 1, ERADICATE_META_CLASS_IS_CLEAN, no_bucket, INFO, []
codetoanalyze/java/nullsafe-default/StrictMode.java, Linters_dummy_method, 1, ERADICATE_META_CLASS_NEEDS_FIXING, no_bucket, INFO, []
codetoanalyze/java/nullsafe-default/StrictMode.java, Linters_dummy_method, 1, ERADICATE_META_CLASS_NEEDS_FIXING, no_bucket, INFO, []
codetoanalyze/java/nullsafe-default/StrictMode.java, codetoanalyze.java.nullsafe_default.Strict.<init>(), 0, ERADICATE_FIELD_NOT_INITIALIZED, no_bucket, ERROR, [Field `notInitializedIsBAD` is declared non-nullable, so it should be initialized in the constructor or in an `@Initializer` method]
codetoanalyze/java/nullsafe-default/StrictMode.java, codetoanalyze.java.nullsafe_default.Strict.nonStrictClass_convertingNonnullToNonnullIsBad():java.lang.String, 0, ERADICATE_UNCHECKED_USAGE_IN_NULLSAFE, no_bucket, ERROR, [`NonStrict.getNonnull()`: `@NullsafeStrict` mode prohibits using values coming from non-strict classes without a check. Result of this call is used at line 163. Either add a local check for null or assertion, or make NonStrict nullsafe strict.]
@ -362,7 +362,7 @@ codetoanalyze/java/nullsafe-default/StrictModeForThirdParty.java, codetoanalyze.
codetoanalyze/java/nullsafe-default/StrictModeForThirdParty.java, codetoanalyze.java.nullsafe_default.StrictModeForThirdParty.dereferenceUnspecifiedIsBAD():void, 0, ERADICATE_UNVETTED_THIRD_PARTY_IN_NULLSAFE, no_bucket, ERROR, [`ThirdPartyTestClass.returnUnspecified()`: `@NullsafeStrict` mode prohibits using values coming from not vetted third party methods without a check. Result of this call is used at line 41. Either add a local check for null or assertion, or add the correct signature to nullsafe-default/third-party-signatures/some.test.pckg.sig.]
codetoanalyze/java/nullsafe-default/StrictModeForThirdParty.java, codetoanalyze.java.nullsafe_default.StrictModeForThirdParty.passingNullableParamToUnspecifiedIsBAD():void, 0, ERADICATE_PARAMETER_NOT_NULLABLE, no_bucket, ERROR, [Third-party `ThirdPartyTestClass.paramUnspecified(...)` is missing a signature that would allow passing a nullable to param #1(`param`). Actual argument `getNullable()` is nullable. Consider adding the correct signature of `ThirdPartyTestClass.paramUnspecified(...)` to nullsafe-default/third-party-signatures/some.test.pckg.sig.]
codetoanalyze/java/nullsafe-default/StrictModeForThirdParty.java, codetoanalyze.java.nullsafe_default.StrictModeForThirdParty.passingNullableToParamSpecifiedAsNonnullIsBAD():void, 0, ERADICATE_PARAMETER_NOT_NULLABLE, no_bucket, ERROR, [`ThirdPartyTestClass.secondParamSpecifiedAsNonnull(...)`: parameter #2(`specifiedAsNonnull`) is declared non-nullable (see nullsafe-default/third-party-signatures/some.test.pckg.sig at line 3) but the argument `getNullable()` is nullable.]
codetoanalyze/java/nullsafe-default/SwitchCase.java, Linters_dummy_method, 1, ERADICATE_META_CLASS_IS_CLEAN, no_bucket, INFO, []
codetoanalyze/java/nullsafe-default/SwitchCase.java, Linters_dummy_method, 1, ERADICATE_META_CLASS_NEEDS_FIXING, no_bucket, INFO, []
codetoanalyze/java/nullsafe-default/SwitchCase.java, Linters_dummy_method, 1, ERADICATE_META_CLASS_NEEDS_FIXING, no_bucket, INFO, []
codetoanalyze/java/nullsafe-default/SwitchCase.java, codetoanalyze.java.nullsafe_default.SwitchCase.getNullableColor():codetoanalyze.java.nullsafe_default.Color, 0, ERADICATE_RETURN_OVER_ANNOTATED, no_bucket, ADVICE, [Method `getNullableColor()` is annotated with `@Nullable` but never returns null.]
codetoanalyze/java/nullsafe-default/SwitchCase.java, codetoanalyze.java.nullsafe_default.SwitchCase.switchOnNullIsBad():java.lang.String, 1, ERADICATE_NULLABLE_DEREFERENCE, no_bucket, WARNING, [NullPointerException will be thrown at this line! `color` is `null` and is dereferenced via calling `ordinal()`: null constant at line 14.]

Loading…
Cancel
Save