[nullsafe] Support Nullsafe(Local, trust=all/none) mode

Summary:
Add support for nullsafe mode with `trust=all` and `trust=none` a case
with a specific trust list is not supported yet and needs to be
implemented separately.

Tests introduce one unexpected
`ERADICATE_INCONSISTENT_SUBCLASS_PARAMETER_ANNOTATION` issue which
complains about `this` having incorrect nullability; it is a bug and
needs to be fixed separately.

Reviewed By: mityal

Differential Revision: D19662708

fbshipit-source-id: 3bc1e3952
master
Artem Pianykh 5 years ago committed by Facebook Github Bot
parent 43b3ef60f8
commit b50f13eb18

@ -412,8 +412,9 @@ OPTIONS
ERADICATE_PARAMETER_NOT_NULLABLE (enabled by default), ERADICATE_PARAMETER_NOT_NULLABLE (enabled by default),
ERADICATE_RETURN_NOT_NULLABLE (enabled by default), ERADICATE_RETURN_NOT_NULLABLE (enabled by default),
ERADICATE_RETURN_OVER_ANNOTATED (enabled by default), ERADICATE_RETURN_OVER_ANNOTATED (enabled by default),
ERADICATE_UNCHECKED_NONSTRICT_FROM_STRICT (enabled by default), ERADICATE_UNCHECKED_USAGE_IN_NULLSAFE (enabled by default),
ERADICATE_UNVETTED_THIRD_PARTY_IN_STRICT (enabled by default), ERADICATE_UNVETTED_THIRD_PARTY_IN_NULLSAFE (enabled by
default),
EXECUTION_TIME_COMPLEXITY_INCREASE (enabled by default), EXECUTION_TIME_COMPLEXITY_INCREASE (enabled by default),
EXECUTION_TIME_COMPLEXITY_INCREASE_COLD_START (enabled by EXECUTION_TIME_COMPLEXITY_INCREASE_COLD_START (enabled by
default), default),

@ -141,8 +141,9 @@ OPTIONS
ERADICATE_PARAMETER_NOT_NULLABLE (enabled by default), ERADICATE_PARAMETER_NOT_NULLABLE (enabled by default),
ERADICATE_RETURN_NOT_NULLABLE (enabled by default), ERADICATE_RETURN_NOT_NULLABLE (enabled by default),
ERADICATE_RETURN_OVER_ANNOTATED (enabled by default), ERADICATE_RETURN_OVER_ANNOTATED (enabled by default),
ERADICATE_UNCHECKED_NONSTRICT_FROM_STRICT (enabled by default), ERADICATE_UNCHECKED_USAGE_IN_NULLSAFE (enabled by default),
ERADICATE_UNVETTED_THIRD_PARTY_IN_STRICT (enabled by default), ERADICATE_UNVETTED_THIRD_PARTY_IN_NULLSAFE (enabled by
default),
EXECUTION_TIME_COMPLEXITY_INCREASE (enabled by default), EXECUTION_TIME_COMPLEXITY_INCREASE (enabled by default),
EXECUTION_TIME_COMPLEXITY_INCREASE_COLD_START (enabled by EXECUTION_TIME_COMPLEXITY_INCREASE_COLD_START (enabled by
default), default),

@ -412,8 +412,9 @@ OPTIONS
ERADICATE_PARAMETER_NOT_NULLABLE (enabled by default), ERADICATE_PARAMETER_NOT_NULLABLE (enabled by default),
ERADICATE_RETURN_NOT_NULLABLE (enabled by default), ERADICATE_RETURN_NOT_NULLABLE (enabled by default),
ERADICATE_RETURN_OVER_ANNOTATED (enabled by default), ERADICATE_RETURN_OVER_ANNOTATED (enabled by default),
ERADICATE_UNCHECKED_NONSTRICT_FROM_STRICT (enabled by default), ERADICATE_UNCHECKED_USAGE_IN_NULLSAFE (enabled by default),
ERADICATE_UNVETTED_THIRD_PARTY_IN_STRICT (enabled by default), ERADICATE_UNVETTED_THIRD_PARTY_IN_NULLSAFE (enabled by
default),
EXECUTION_TIME_COMPLEXITY_INCREASE (enabled by default), EXECUTION_TIME_COMPLEXITY_INCREASE (enabled by default),
EXECUTION_TIME_COMPLEXITY_INCREASE_COLD_START (enabled by EXECUTION_TIME_COMPLEXITY_INCREASE_COLD_START (enabled by
default), default),

@ -45,6 +45,11 @@ let rec has_matching_str_value ~pred = function
false false
let find_parameter t ~name =
let match_name param = Option.exists param.name ~f:(String.equal name) in
List.find t.parameters ~f:match_name |> Option.map ~f:(fun x -> x.value)
(** Pretty print an annotation. *) (** Pretty print an annotation. *)
let prefix = match Language.curr_language_is Java with true -> "@" | false -> "_" let prefix = match Language.curr_language_is Java with true -> "@" | false -> "_"

@ -36,7 +36,9 @@ val final : t
val has_matching_str_value : pred:(string -> bool) -> value -> bool val has_matching_str_value : pred:(string -> bool) -> value -> bool
(** Check if annotation parameter value contains a string satisfying a predicate. For convenience it (** Check if annotation parameter value contains a string satisfying a predicate. For convenience it
works both with raw [Vstr] and [Vstr] inside [Varray]. *) works both with raw [Str] and [Str] inside [Array]. *)
val find_parameter : t -> name:string -> value option
val pp : F.formatter -> t -> unit val pp : F.formatter -> t -> unit
(** Pretty print an annotation. *) (** Pretty print an annotation. *)

@ -277,14 +277,14 @@ let eradicate_return_over_annotated =
register_from_string "ERADICATE_RETURN_OVER_ANNOTATED" ~hum:"Return Over Annotated" register_from_string "ERADICATE_RETURN_OVER_ANNOTATED" ~hum:"Return Over Annotated"
let eradicate_forbidden_non_strict_in_strict = let eradicate_unchecked_usage_in_nullsafe =
register_from_string "ERADICATE_UNCHECKED_NONSTRICT_FROM_STRICT" register_from_string "ERADICATE_UNCHECKED_USAGE_IN_NULLSAFE"
~hum:"Strict mode: unchecked usage of a value from non-strict code" ~hum:"Nullsafe mode: unchecked usage of a value"
let eradicate_unvetted_third_party_in_strict = let eradicate_unvetted_third_party_in_nullsafe =
register_from_string "ERADICATE_UNVETTED_THIRD_PARTY_IN_STRICT" register_from_string "ERADICATE_UNVETTED_THIRD_PARTY_IN_NULLSAFE"
~hum:"Strict mode: unchecked usage of unvetted third-party" ~hum:"Nullsafe mode: unchecked usage of unvetted third-party"
let expensive_cost_call ~kind ~is_on_cold_start ~is_on_ui_thread = let expensive_cost_call ~kind ~is_on_cold_start ~is_on_ui_thread =

@ -166,9 +166,9 @@ val eradicate_return_not_nullable : t
val eradicate_return_over_annotated : t val eradicate_return_over_annotated : t
val eradicate_unvetted_third_party_in_strict : t val eradicate_unvetted_third_party_in_nullsafe : t
val eradicate_forbidden_non_strict_in_strict : t val eradicate_unchecked_usage_in_nullsafe : t
val expensive_cost_call : kind:CostKind.t -> is_on_cold_start:bool -> is_on_ui_thread:bool -> t val expensive_cost_call : kind:CostKind.t -> is_on_cold_start:bool -> is_on_ui_thread:bool -> t

@ -63,6 +63,8 @@ let nullable = "Nullable"
let nullsafe_strict = "NullsafeStrict" let nullsafe_strict = "NullsafeStrict"
let nullsafe = "Nullsafe"
let mainthread = "MainThread" let mainthread = "MainThread"
let nonblocking = "NonBlocking" let nonblocking = "NonBlocking"
@ -142,6 +144,8 @@ let class_name_matches s ((annot : Annot.t), _) = String.equal s annot.class_nam
let ia_ends_with ia ann_name = List.exists ~f:(fun (a, _) -> annot_ends_with a ann_name) ia let ia_ends_with ia ann_name = List.exists ~f:(fun (a, _) -> annot_ends_with a ann_name) ia
let find_ia_ends_with ia ann_name = List.find ~f:(fun (a, _) -> annot_ends_with a ann_name) ia
let ia_contains ia ann_name = List.exists ~f:(class_name_matches ann_name) ia let ia_contains ia ann_name = List.exists ~f:(class_name_matches ann_name) ia
let pdesc_get_return_annot pdesc = let pdesc_get_return_annot pdesc =
@ -192,6 +196,8 @@ let ia_is_nonnull ia = List.exists ~f:(ia_ends_with ia) [nonnull; notnull; camel
let ia_is_nullsafe_strict ia = ia_ends_with ia nullsafe_strict let ia_is_nullsafe_strict ia = ia_ends_with ia nullsafe_strict
let ia_find_nullsafe ia = Option.map (find_ia_ends_with ia nullsafe) ~f:fst
let ia_is_false_on_null ia = ia_ends_with ia false_on_null let ia_is_false_on_null ia = ia_ends_with ia false_on_null
let ia_is_returns_ownership ia = ia_ends_with ia returns_ownership let ia_is_returns_ownership ia = ia_ends_with ia returns_ownership

@ -78,6 +78,8 @@ val ia_is_nullable : Annot.Item.t -> bool
val ia_is_nullsafe_strict : Annot.Item.t -> bool val ia_is_nullsafe_strict : Annot.Item.t -> bool
val ia_find_nullsafe : Annot.Item.t -> Annot.t option
val ia_is_true_on_null : Annot.Item.t -> bool val ia_is_true_on_null : Annot.Item.t -> bool
val ia_is_expensive : Annot.Item.t -> bool val ia_is_expensive : Annot.Item.t -> bool

@ -216,3 +216,14 @@ let move_last_to_first =
move_last_to_first_helper tl (hd :: rev_acc) move_last_to_first_helper tl (hd :: rev_acc)
in in
fun l -> move_last_to_first_helper l [] fun l -> move_last_to_first_helper l []
let traverse_opt xs ~f =
List.fold_until xs ~init:[]
~f:(fun acc x ->
match f x with
| Some r ->
Continue_or_stop.Continue (r :: acc)
| _ ->
Continue_or_stop.Stop None )
~finish:(fun acc -> Some (List.rev acc))

@ -69,3 +69,7 @@ val fold2_result :
-> ('acc, 'err) result Base.List.Or_unequal_lengths.t -> ('acc, 'err) result Base.List.Or_unequal_lengths.t
val move_last_to_first : 'a list -> 'a list val move_last_to_first : 'a list -> 'a list
val traverse_opt : 'a list -> f:('a -> 'b option) -> 'b list option
(** Applies [f] to the elements of the list and returns [None] if any application results in [None]
otherwise returns [Some list']. *)

@ -17,6 +17,7 @@ module F = Format
type t = type t =
| Nullable of nullable_origin | Nullable of nullable_origin
| UncheckedNonnull of unchecked_nonnull_origin (** See {!Nullability.t} for explanation *) | UncheckedNonnull of unchecked_nonnull_origin (** See {!Nullability.t} for explanation *)
| LocallyCheckedNonnull
| StrictNonnull of strict_nonnull_origin | StrictNonnull of strict_nonnull_origin
[@@deriving compare] [@@deriving compare]
@ -52,6 +53,8 @@ let get_nullability = function
Nullability.Nullable Nullability.Nullable
| UncheckedNonnull _ -> | UncheckedNonnull _ ->
Nullability.UncheckedNonnull Nullability.UncheckedNonnull
| LocallyCheckedNonnull ->
Nullability.LocallyCheckedNonnull
| StrictNonnull _ -> | StrictNonnull _ ->
Nullability.StrictNonnull Nullability.StrictNonnull
@ -87,6 +90,8 @@ let pp fmt t =
F.fprintf fmt "Nullable[%s]" (string_of_nullable_origin origin) F.fprintf fmt "Nullable[%s]" (string_of_nullable_origin origin)
| UncheckedNonnull origin -> | UncheckedNonnull origin ->
F.fprintf fmt "UncheckedNonnull[%s]" (string_of_declared_nonnull_origin origin) F.fprintf fmt "UncheckedNonnull[%s]" (string_of_declared_nonnull_origin origin)
| LocallyCheckedNonnull ->
F.fprintf fmt "LocallyCheckedNonnull"
| StrictNonnull origin -> | StrictNonnull origin ->
F.fprintf fmt "StrictNonnull[%s]" (string_of_nonnull_origin origin) F.fprintf fmt "StrictNonnull[%s]" (string_of_nonnull_origin origin)
@ -103,6 +108,8 @@ let of_type_and_annotation ~(nullsafe_mode : NullsafeMode.t) typ annotations =
match nullsafe_mode with match nullsafe_mode with
| NullsafeMode.Strict -> | NullsafeMode.Strict ->
StrictNonnull StrictMode StrictNonnull StrictMode
| NullsafeMode.Local _ ->
LocallyCheckedNonnull
| NullsafeMode.Default -> | NullsafeMode.Default ->
if Annotations.ia_is_nonnull annotations then UncheckedNonnull AnnotatedNonnull if Annotations.ia_is_nonnull annotations then UncheckedNonnull AnnotatedNonnull
(* Currently, we treat not annotated types as nonnull *) (* Currently, we treat not annotated types as nonnull *)

@ -19,6 +19,7 @@ open! IStd
type t = type t =
| Nullable of nullable_origin | Nullable of nullable_origin
| UncheckedNonnull of unchecked_nonnull_origin (** See {!Nullability.t} for explanation *) | UncheckedNonnull of unchecked_nonnull_origin (** See {!Nullability.t} for explanation *)
| LocallyCheckedNonnull
| StrictNonnull of strict_nonnull_origin | StrictNonnull of strict_nonnull_origin
[@@deriving compare] [@@deriving compare]

@ -22,26 +22,38 @@ and function_info =
; param_position: int ; param_position: int
; function_procname: Procname.t } ; function_procname: Procname.t }
let is_whitelisted_assignment ~nullsafe_mode ~lhs ~rhs = (** For better adoption we allow certain conversions. Otherwise using code checked under different
match nullsafe_mode with nullsafe modes becomes a pain because of extra warnings. *)
| NullsafeMode.Default -> ( module AssignmentWhitelist = struct
match (lhs, rhs) with let all_whitelisted =
| Nullability.StrictNonnull, Nullability.UncheckedNonnull -> [ (Nullability.StrictNonnull, Nullability.UncheckedNonnull)
(* We allow UncheckedNonnull -> StrictNonnull conversion outside of strict mode for better adoption. ; (Nullability.LocallyCheckedNonnull, Nullability.UncheckedNonnull)
Otherwise using strictified classes in non-strict context becomes a pain because ; (Nullability.StrictNonnull, Nullability.LocallyCheckedNonnull) ]
of extra warnings.
*)
true let all_whitelisted_in_mode = function
| _ -> | NullsafeMode.Default | NullsafeMode.Local NullsafeMode.Trust.All ->
false ) all_whitelisted
| NullsafeMode.Local (NullsafeMode.Trust.Only ([] as _classes))
| NullsafeMode.Local (NullsafeMode.Trust.Only _classes) ->
(* TODO(T61473665): case with specified non-empty classes not supported now, defaulting to trust=none *)
[(Nullability.StrictNonnull, Nullability.LocallyCheckedNonnull)]
| NullsafeMode.Strict -> | NullsafeMode.Strict ->
false []
let is_allowed_in_mode ~nullsafe_mode ~lhs ~rhs =
List.exists (all_whitelisted_in_mode nullsafe_mode) ~f:(Nullability.equal_pair (lhs, rhs))
let is_potentially_allowed ~lhs ~rhs =
List.exists all_whitelisted ~f:(Nullability.equal_pair (lhs, rhs))
end
let check ~(nullsafe_mode : NullsafeMode.t) ~lhs ~rhs = let check ~(nullsafe_mode : NullsafeMode.t) ~lhs ~rhs =
let is_allowed_assignment = let is_allowed_assignment =
Nullability.is_subtype ~subtype:rhs ~supertype:lhs Nullability.is_subtype ~subtype:rhs ~supertype:lhs
|| is_whitelisted_assignment ~nullsafe_mode ~lhs ~rhs || AssignmentWhitelist.is_allowed_in_mode ~nullsafe_mode ~lhs ~rhs
in in
Result.ok_if_true is_allowed_assignment ~error:{nullsafe_mode; lhs; rhs} Result.ok_if_true is_allowed_assignment ~error:{nullsafe_mode; lhs; rhs}
@ -67,7 +79,7 @@ let pp_param_name fmt mangled =
else Format.fprintf fmt "(%a)" MarkupFormatter.pp_monospaced name else Format.fprintf fmt "(%a)" MarkupFormatter.pp_monospaced name
let bad_param_description let mk_description_for_bad_param_passed
{model_source; param_signature; actual_param_expression; param_position; function_procname} {model_source; param_signature; actual_param_expression; param_position; function_procname}
~param_nullability nullability_evidence = ~param_nullability nullability_evidence =
let nullability_evidence_as_suffix = let nullability_evidence_as_suffix =
@ -83,7 +95,9 @@ let bad_param_description
"`null`" "`null`"
| Nullability.Nullable -> | Nullability.Nullable ->
"nullable" "nullable"
| Nullability.StrictNonnull | Nullability.UncheckedNonnull -> | Nullability.StrictNonnull
| Nullability.UncheckedNonnull
| Nullability.LocallyCheckedNonnull ->
Logging.die InternalError "Invariant violation: unexpected nullability" Logging.die InternalError "Invariant violation: unexpected nullability"
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
@ -102,7 +116,7 @@ let bad_param_description
in in
match suggested_file_to_add_third_party with match suggested_file_to_add_third_party with
| Some sig_file_name -> | Some sig_file_name ->
(* This is a special case. While for FB codebase we can assume "not annotated hence not nullable" rule for all signatures, (* 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, 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: 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. param can be nullable according to API but it was just not annotated.
@ -135,18 +149,6 @@ let bad_param_description
nullability_evidence_as_suffix nullability_evidence_as_suffix
let is_unchecked_nonnull_to_strict_nonnull ~lhs ~rhs =
match (lhs, rhs) with
| Nullability.StrictNonnull, Nullability.UncheckedNonnull ->
true
(* Don't fold those cases into catch-all *)
| Nullability.StrictNonnull, _
| Nullability.UncheckedNonnull, _
| Nullability.Nullable, _
| Nullability.Null, _ ->
false
let get_issue_type = function let get_issue_type = function
| PassingParamToFunction _ -> | PassingParamToFunction _ ->
IssueType.eradicate_parameter_not_nullable IssueType.eradicate_parameter_not_nullable
@ -158,12 +160,12 @@ let get_issue_type = function
let violation_description {nullsafe_mode; lhs; rhs} ~assignment_location assignment_type ~rhs_origin let violation_description {nullsafe_mode; lhs; rhs} ~assignment_location assignment_type ~rhs_origin
= =
if is_unchecked_nonnull_to_strict_nonnull ~lhs ~rhs then ( if AssignmentWhitelist.is_potentially_allowed ~lhs ~rhs then
if not (NullsafeMode.equal nullsafe_mode NullsafeMode.Strict) then (* This type of violation is more subtle than the normal case, so it should
Logging.die InternalError "Unexpected situation: should not be a violation not in strict mode" ; be rendered in a special way. An 'impossible case' is checked in the
(* This type of violation is more subtle than the normal case because, so it should be rendered in a special way *) following call and will cause infer to die. *)
ErrorRenderingUtils.get_strict_mode_violation_issue ~bad_usage_location:assignment_location ErrorRenderingUtils.mk_special_nullsafe_issue ~nullsafe_mode ~bad_nullability:rhs
rhs_origin ) ~bad_usage_location:assignment_location rhs_origin
else else
let nullability_evidence = let nullability_evidence =
get_origin_opt assignment_type rhs_origin get_origin_opt assignment_type rhs_origin
@ -176,30 +178,33 @@ let violation_description {nullsafe_mode; lhs; rhs} ~assignment_location assignm
let error_message = let error_message =
match assignment_type with match assignment_type with
| PassingParamToFunction function_info -> | PassingParamToFunction function_info ->
bad_param_description function_info nullability_evidence ~param_nullability:rhs mk_description_for_bad_param_passed function_info nullability_evidence
~param_nullability:rhs
| AssigningToField field_name -> | AssigningToField field_name ->
let rhs_description = let rhs_description =
Nullability.(
match rhs with match rhs with
| Null -> | Null ->
"`null`" "`null`"
| Nullable -> | Nullable ->
"a nullable" "a nullable"
| StrictNonnull | UncheckedNonnull -> | StrictNonnull | UncheckedNonnull | LocallyCheckedNonnull ->
Logging.die InternalError "Invariant violation: unexpected nullability" Logging.die InternalError "Invariant violation: unexpected nullability")
in in
Format.asprintf "%a is declared non-nullable but is assigned %s%s." MF.pp_monospaced Format.asprintf "%a is declared non-nullable but is assigned %s%s." MF.pp_monospaced
(Fieldname.get_field_name field_name) (Fieldname.get_field_name field_name)
rhs_description nullability_evidence_as_suffix rhs_description nullability_evidence_as_suffix
| ReturningFromFunction function_proc_name -> | ReturningFromFunction function_proc_name ->
let return_description = let return_description =
Nullability.(
match rhs with match rhs with
| Null -> | Null ->
(* Return `null` in all branches *) (* Return `null` in all_whitelisted branches *)
"`null`" "`null`"
| Nullable -> | Nullable ->
"a nullable value" "a nullable value"
| StrictNonnull | UncheckedNonnull -> | StrictNonnull | UncheckedNonnull | LocallyCheckedNonnull ->
Logging.die InternalError "Invariant violation: unexpected nullability" Logging.die InternalError "Invariant violation: unexpected nullability")
in in
Format.asprintf "%a: return type is declared non-nullable but the method returns %s%s." Format.asprintf "%a: return type is declared non-nullable but the method returns %s%s."
MF.pp_monospaced MF.pp_monospaced

@ -21,10 +21,19 @@ let check ~nullsafe_mode nullability =
Error {nullsafe_mode; nullability} Error {nullsafe_mode; nullability}
| Nullability.UncheckedNonnull -> ( | Nullability.UncheckedNonnull -> (
match nullsafe_mode with match nullsafe_mode with
| NullsafeMode.Strict -> | NullsafeMode.Strict | NullsafeMode.Local (NullsafeMode.Trust.Only []) ->
Error {nullsafe_mode; nullability}
| NullsafeMode.Local (NullsafeMode.Trust.Only _typ_names) ->
(* TODO(T61473665). For now treat as trust=none. *)
Error {nullsafe_mode; nullability} Error {nullsafe_mode; nullability}
| NullsafeMode.Default -> | NullsafeMode.Local NullsafeMode.Trust.All | NullsafeMode.Default ->
Ok () ) Ok () )
| Nullability.LocallyCheckedNonnull -> (
match nullsafe_mode with
| NullsafeMode.Default | NullsafeMode.Local _ ->
Ok ()
| NullsafeMode.Strict ->
Error {nullsafe_mode; nullability} )
| Nullability.StrictNonnull -> | Nullability.StrictNonnull ->
Ok () Ok ()
@ -40,15 +49,15 @@ let get_origin_opt ~nullable_object_descr origin =
if should_show_origin then Some origin else None if should_show_origin then Some origin else None
let violation_description {nullability} ~dereference_location dereference_type let violation_description {nullsafe_mode; nullability} ~dereference_location dereference_type
~nullable_object_descr ~nullable_object_origin = ~nullable_object_descr ~nullable_object_origin =
let module MF = MarkupFormatter in let module MF = MarkupFormatter in
match nullability with match nullability with
| Nullability.UncheckedNonnull -> | Nullability.UncheckedNonnull | Nullability.LocallyCheckedNonnull ->
(* This can happen only in strict mode. (* These types of violations are possible in non-default nullsafe mode. For them we
This type of violation is more subtle than the normal case because, so it should be rendered in a special way *) provide tailored error messages. *)
ErrorRenderingUtils.get_strict_mode_violation_issue ~bad_usage_location:dereference_location ErrorRenderingUtils.mk_special_nullsafe_issue ~nullsafe_mode ~bad_nullability:nullability
nullable_object_origin ~bad_usage_location:dereference_location nullable_object_origin
| _ -> | _ ->
let what_is_dereferred_str = let what_is_dereferred_str =
match dereference_type with match dereference_type with
@ -95,7 +104,9 @@ let violation_description {nullability} ~dereference_location dereference_type
| Nullability.Nullable -> | Nullability.Nullable ->
Format.sprintf "%s is nullable and is not locally checked for null when %s%s." Format.sprintf "%s is nullable and is not locally checked for null when %s%s."
what_is_dereferred_str action_descr suffix what_is_dereferred_str action_descr suffix
| Nullability.UncheckedNonnull | Nullability.StrictNonnull -> | Nullability.UncheckedNonnull
| Nullability.LocallyCheckedNonnull
| Nullability.StrictNonnull ->
Logging.die InternalError "Invariant violation: unexpected nullability" Logging.die InternalError "Invariant violation: unexpected nullability"
in in
(description, IssueType.eradicate_nullable_dereference, dereference_location) (description, IssueType.eradicate_nullable_dereference, dereference_location)

@ -83,7 +83,34 @@ let get_field_class_name field_name =
|> Option.value_map ~f:(fun (classname, _) -> classname) ~default:"the field class" |> Option.value_map ~f:(fun (classname, _) -> classname) ~default:"the field class"
let get_info object_origin = let mk_coming_from nullsafe_mode nullability =
match (nullsafe_mode, nullability) with
| NullsafeMode.Strict, Nullability.UncheckedNonnull ->
"non-strict classes"
| NullsafeMode.Strict, Nullability.LocallyCheckedNonnull ->
"nullsafe-local classes"
| NullsafeMode.Local _, Nullability.UncheckedNonnull ->
"non-nullsafe classes"
| (_ as mode), nullability ->
Logging.die InternalError "Unexpected: using %s in %a should not be a violation"
(Nullability.to_string nullability)
NullsafeMode.pp mode
let mk_recommendation nullsafe_mode nullability what =
match (nullsafe_mode, nullability) with
| NullsafeMode.Strict, Nullability.UncheckedNonnull
| NullsafeMode.Strict, Nullability.LocallyCheckedNonnull ->
Format.sprintf "make %s nullsafe strict" what
| NullsafeMode.Local _, Nullability.UncheckedNonnull ->
Format.sprintf "make %s nullsafe" what
| (_ as mode), nullability ->
Logging.die InternalError "Unexpected: using %s in %a should not be a violation"
(Nullability.to_string nullability)
NullsafeMode.pp mode
let get_info object_origin nullsafe_mode bad_nullability =
match object_origin with match object_origin with
| TypeOrigin.MethodCall {pname; call_loc} -> | TypeOrigin.MethodCall {pname; call_loc} ->
let offending_object = let offending_object =
@ -106,15 +133,15 @@ let get_info object_origin =
in in
match suggested_third_party_sig_file with match suggested_third_party_sig_file with
| None -> | None ->
( "non-strict classes" ( mk_coming_from nullsafe_mode bad_nullability
, Format.sprintf "strictify %s" what_to_strictify , mk_recommendation nullsafe_mode bad_nullability what_to_strictify
, IssueType.eradicate_forbidden_non_strict_in_strict ) , IssueType.eradicate_unchecked_usage_in_nullsafe )
| Some sig_file_name -> | Some sig_file_name ->
( "not vetted third party methods" ( "not vetted third party methods"
, Format.sprintf "add the correct signature to %s" , Format.sprintf "add the correct signature to %s"
(ThirdPartyAnnotationGlobalRepo.get_user_friendly_third_party_sig_file_name (ThirdPartyAnnotationGlobalRepo.get_user_friendly_third_party_sig_file_name
~filename:sig_file_name) ~filename:sig_file_name)
, IssueType.eradicate_unvetted_third_party_in_strict ) , IssueType.eradicate_unvetted_third_party_in_nullsafe )
in in
{ offending_object { offending_object
; object_loc ; object_loc
@ -131,9 +158,11 @@ let get_info object_origin =
(* TODO: currently we do not support third-party annotations for fields. Because of this, (* TODO: currently we do not support third-party annotations for fields. Because of this,
render error like it is a non-stict class. *) render error like it is a non-stict class. *)
let what_is_used = "This field" in let what_is_used = "This field" in
let coming_from_explanation = "non-strict classes" in let coming_from_explanation = mk_coming_from nullsafe_mode bad_nullability in
let recommendation = Format.sprintf "strictify %s" (get_field_class_name field_name) in let recommendation =
let issue_type = IssueType.eradicate_forbidden_non_strict_in_strict in mk_recommendation nullsafe_mode bad_nullability (get_field_class_name field_name)
in
let issue_type = IssueType.eradicate_unchecked_usage_in_nullsafe in
{ offending_object { offending_object
; object_loc ; object_loc
; coming_from_explanation ; coming_from_explanation
@ -145,20 +174,20 @@ let get_info object_origin =
"Invariant violation: unexpected origin of declared non-nullable value" "Invariant violation: unexpected origin of declared non-nullable value"
let get_strict_mode_violation_issue ~bad_usage_location object_origin = let mk_special_nullsafe_issue ~nullsafe_mode ~bad_nullability ~bad_usage_location object_origin =
let { offending_object let { offending_object
; object_loc ; object_loc
; coming_from_explanation ; coming_from_explanation
; what_is_used ; what_is_used
; recommendation ; recommendation
; issue_type } = ; issue_type } =
get_info object_origin get_info object_origin nullsafe_mode bad_nullability
in in
let description = let description =
Format.sprintf Format.asprintf
"%s: `@NullsafeStrict` mode prohibits using values coming from %s without a check. %s is \ "%s: `@Nullsafe%a` mode prohibits using values coming from %s without a check. %s is used at \
used at line %d. Either add a local check for null or assertion, or %s." line %d. Either add a local check for null or assertion, or %s."
offending_object coming_from_explanation what_is_used bad_usage_location.Location.line offending_object NullsafeMode.pp nullsafe_mode coming_from_explanation what_is_used
recommendation bad_usage_location.Location.line recommendation
in in
(description, issue_type, object_loc) (description, issue_type, object_loc)

@ -13,9 +13,13 @@ val is_object_nullability_self_explanatory : object_expression:string -> TypeOri
(** In order to understand why such and such object is nullable (or not nullable), we render its (** 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. *) origin. In some cases this is redundant and adds extra noise for the user. *)
val get_strict_mode_violation_issue : val mk_special_nullsafe_issue :
bad_usage_location:Location.t -> TypeOrigin.t -> string * IssueType.t * Location.t nullsafe_mode:NullsafeMode.t
(** Situation when we tried to use UncheckedNonnull as StrictNonnull. This is disallowed only in -> bad_nullability:Nullability.t
strict mode. Returns a tuple (error message, issue type, error location). NOTE: Location of the -> bad_usage_location:Location.t
error will be NOT in the place when the value is used (that is [bad_usage_location]), but where -> TypeOrigin.t
the value is first obtained from. *) -> string * IssueType.t * Location.t
(** Situation when we tried to use nonnull values of incompatible modes. This is disallowed in
strict and local mode. 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. *)

@ -14,6 +14,10 @@ type t =
(** The type comes from a signature that is annotated (explicitly or implicitly according to (** The type comes from a signature that is annotated (explicitly or implicitly according to
conventions) as non-nullable. However, it might still contain null since the truthfulness conventions) as non-nullable. However, it might still contain null since the truthfulness
of the declaration was not checked. *) of the declaration was not checked. *)
| LocallyCheckedNonnull
(** Non-nullable value the comes from a class checked under local mode. Local mode type-checks
files against its dependencies but does not require the dependencies to be transitively
checked. Therefore this type of non-nullable value is differentiated from StrictNonnull. *)
| StrictNonnull | StrictNonnull
(** Non-nullable value with the highest degree of certainty, because it is either: (** Non-nullable value with the highest degree of certainty, because it is either:
@ -27,6 +31,8 @@ type t =
strike the balance between the strictness of analysis, convenience, and real-world risk. *) strike the balance between the strictness of analysis, convenience, and real-world risk. *)
[@@deriving compare, equal] [@@deriving compare, equal]
type pair = t * t [@@deriving compare, equal]
let top = Nullable let top = Nullable
let join x y = let join x y =
@ -39,6 +45,8 @@ let join x y =
Nullable Nullable
| UncheckedNonnull, _ | _, UncheckedNonnull -> | UncheckedNonnull, _ | _, UncheckedNonnull ->
UncheckedNonnull UncheckedNonnull
| LocallyCheckedNonnull, _ | _, LocallyCheckedNonnull ->
LocallyCheckedNonnull
| StrictNonnull, StrictNonnull -> | StrictNonnull, StrictNonnull ->
StrictNonnull StrictNonnull
@ -52,5 +60,7 @@ let to_string = function
"Nullable" "Nullable"
| UncheckedNonnull -> | UncheckedNonnull ->
"UncheckedNonnull" "UncheckedNonnull"
| LocallyCheckedNonnull ->
"LocallyCheckedNonnull"
| StrictNonnull -> | StrictNonnull ->
"StrictNonnull" "StrictNonnull"

@ -22,6 +22,11 @@ type t =
(** The type comes from a signature that is annotated (explicitly or implicitly according to (** The type comes from a signature that is annotated (explicitly or implicitly according to
conventions) as non-nullable. Hovewer, it might still contain null since the truthfullness conventions) as non-nullable. Hovewer, it might still contain null since the truthfullness
of the declaration was not checked. *) of the declaration was not checked. *)
| LocallyCheckedNonnull
(** Non-nullable value that comes from a class checked under local mode. Local mode
type-checks files against its dependencies but does not require the dependencies to be
transitively checked. Therefore this type of non-nullable value is differentiated from
StrictNonnull. *)
| StrictNonnull | StrictNonnull
(** We believe that this value can not be null because it is either a non-null literal, an (** We believe that this value can not be null because it is either a non-null literal, an
expression that semantically cannot be null, or a non-null value that should not be null expression that semantically cannot be null, or a non-null value that should not be null
@ -30,6 +35,8 @@ type t =
programs. *) programs. *)
[@@deriving compare, equal] [@@deriving compare, equal]
type pair = t * t [@@deriving compare, equal]
val top : t val top : t
(** The most generic type. *) (** The most generic type. *)

@ -8,18 +8,89 @@
open! IStd open! IStd
module F = Format module F = Format
type t = Default | Strict [@@deriving compare, equal] module Trust = struct
type t = All | Only of Typ.name list [@@deriving compare, equal]
let none = Only []
let extract_trust_list = function
| Annot.Array class_values ->
(* The only elements of this array can be class names; therefore short-circuit and return None if it's not the case. *)
IList.traverse_opt class_values ~f:(fun el ->
match el with Annot.Class class_typ -> Typ.name class_typ | _ -> None )
| _ ->
None
let of_annot annot =
let open IOption.Let_syntax in
let trust_all = Annot.find_parameter annot ~name:"trustAll" in
let* trust_list = Annot.find_parameter annot ~name:"value" in
let* trust_classes = extract_trust_list trust_list in
match trust_all with
| None ->
return none
| Some (Annot.Bool trust_all') ->
if trust_all' then return All else return (Only trust_classes)
| _ ->
None
let pp fmt t =
match t with
| All ->
F.fprintf fmt "all"
| Only [] ->
F.fprintf fmt "none"
| Only names ->
F.fprintf fmt "[%a]" (F.pp_print_list ~pp_sep:F.pp_print_space Typ.Name.pp) names
end
type t = Default | Local of Trust.t | Strict [@@deriving compare, equal]
let pp fmt t =
match t with
| Default ->
F.fprintf fmt "Def"
| Strict ->
F.fprintf fmt "Strict"
| Local trust ->
F.fprintf fmt "Local(trust=%a)" Trust.pp trust
let of_annot annot =
let open IOption.Let_syntax in
let* mode = Annot.find_parameter annot ~name:"value" in
match mode with
| Annot.Enum {value= "STRICT"} ->
return Strict
| Annot.Enum {value= "LOCAL"} -> (
match Annot.find_parameter annot ~name:"trustOnly" with
| None ->
(* When trustOnly values is missing, the default is in effect, which is Trust.All *)
return (Local Trust.All)
| Some (Annot.Annot trustOnly') ->
let* trust = Trust.of_annot trustOnly' in
return (Local trust)
| Some _ ->
None )
| _ ->
None
let of_class tenv typ_name = let of_class tenv typ_name =
match PatternMatch.type_name_get_annotation tenv typ_name with match PatternMatch.type_name_get_annotation tenv typ_name with
| Some annots -> | Some annots -> (
if Annotations.ia_is_nullsafe_strict annots then Strict else Default if Annotations.ia_is_nullsafe_strict annots then Strict
else
match Annotations.ia_find_nullsafe annots with
| Some nullsafe_annot ->
Option.value_exn (of_annot nullsafe_annot)
~message:"Unexpected change in @Nullsafe annotation format"
| _ ->
Default )
| None -> | None ->
Default Default
let severity = function Strict -> Exceptions.Error | Default -> Exceptions.Warning let severity = function Strict | Local _ -> Exceptions.Error | Default -> Exceptions.Warning
let to_string = function Default -> " Def" | Strict -> "Strict"
let pp fmt t = F.fprintf fmt "%s" (to_string t)

@ -9,7 +9,25 @@ open! IStd
(** Represents a type-checking mode of nullsafe. *) (** Represents a type-checking mode of nullsafe. *)
type t = Default | Strict [@@deriving compare, equal] module Trust : sig
[@@@warning "-32"]
type t = All | Only of Typ.name list [@@deriving compare, equal]
val none : t
val of_annot : Annot.t -> t option
(** Returns [Trust.t] when provided annotation matches the format of [@TrustList], otherwise
[None]. *)
val pp : Format.formatter -> t -> unit
end
type t = Default | Local of Trust.t | Strict [@@deriving compare, equal]
val of_annot : Annot.t -> t option
[@@warning "-32"]
(** Returns [t] when provided annotation matches the format of [@Nullsafe], otherwise [None]. *)
val of_class : Tenv.t -> Typ.name -> t val of_class : Tenv.t -> Typ.name -> t
(** Extracts mode information from class annotations *) (** Extracts mode information from class annotations *)

@ -172,8 +172,8 @@ let is_declared_nonnull AnnotatedField.{annotated_type} =
match annotated_type.nullability with match annotated_type.nullability with
| AnnotatedNullability.Nullable _ -> | AnnotatedNullability.Nullable _ ->
false false
| AnnotatedNullability.UncheckedNonnull _ -> | AnnotatedNullability.UncheckedNonnull _
true | AnnotatedNullability.LocallyCheckedNonnull
| AnnotatedNullability.StrictNonnull _ -> | AnnotatedNullability.StrictNonnull _ ->
true true

@ -129,7 +129,9 @@ let get_method_ret_description pname call_loc
match nullability with match nullability with
| AnnotatedNullability.Nullable _ -> | AnnotatedNullability.Nullable _ ->
"nullable" "nullable"
| AnnotatedNullability.UncheckedNonnull _ | AnnotatedNullability.StrictNonnull _ -> | AnnotatedNullability.UncheckedNonnull _
| AnnotatedNullability.LocallyCheckedNonnull
| AnnotatedNullability.StrictNonnull _ ->
"non-nullable" "non-nullable"
in in
let model_info = let model_info =

@ -23,7 +23,7 @@ let inputs =
; ("4", [4]) ] ; ("4", [4]) ]
let tests = let inter_tests =
let inter_test input1 input2 _ = let inter_test input1 input2 _ =
let using_list = IList.inter ~cmp:Int.compare input1 input2 in let using_list = IList.inter ~cmp:Int.compare input1 input2 in
let using_set = let using_set =
@ -31,9 +31,26 @@ let tests =
in in
assert_equal using_list using_set assert_equal using_list using_set
in in
let tests_ =
List.concat_map inputs ~f:(fun (name1, input1) -> List.concat_map inputs ~f:(fun (name1, input1) ->
List.map inputs ~f:(fun (name2, input2) -> List.map inputs ~f:(fun (name2, input2) ->
"inter_" ^ name1 ^ "_with_" ^ name2 >:: inter_test input1 input2 ) ) "inter_" ^ name1 ^ "_with_" ^ name2 >:: inter_test input1 input2 ) )
let traverse_test =
let test_empty _ = assert_equal (Some []) (IList.traverse_opt [] ~f:(fun _ -> None)) in
let test_none _ = assert_equal None (IList.traverse_opt [42] ~f:(fun _ -> None)) in
let test_none_first _ =
assert_equal None (IList.traverse_opt [42; 43] ~f:(fun n -> Option.some_if (Int.equal n 43) n))
in
let test_none_last _ =
assert_equal None (IList.traverse_opt [42; 43] ~f:(fun n -> Option.some_if (Int.equal n 42) n))
in in
"IList_tests" >::: tests_ let test_some _ = assert_equal (Some [42; 43]) (IList.traverse_opt [42; 43] ~f:Option.some) in
[ "traverse_opt_empty" >:: test_empty
; "traverse_opt_none" >:: test_none
; "traverse_opt_none_first" >:: test_none_first
; "traverse_opt_none_last" >:: test_none_last
; "traverse_opt_some" >:: test_some ]
let tests = "IList_tests" >::: inter_tests @ traverse_test

@ -23,12 +23,28 @@ public class NullsafeMode {
} }
} }
class NonNullsafe extends VariousMethods {} class NonNullsafe extends VariousMethods {
String OK_passUncheckedToLocal(String arg) {
return new TrustAllNullsafe().acceptVal(arg);
}
String OK_passUncheckedToStrictMode(String arg) {
return new NullsafeWithStrictMode().acceptVal(arg);
}
String OK_passUncheckedToStrict(String arg) {
return new StrictNullsafe().acceptVal(arg);
}
}
class AnotherNonNullsafe extends VariousMethods {} class AnotherNonNullsafe extends VariousMethods {}
@Nullsafe(Nullsafe.Mode.LOCAL) @Nullsafe(Nullsafe.Mode.LOCAL)
class TrustAllNullsafe extends VariousMethods { class TrustAllNullsafe extends VariousMethods {
public String acceptVal(String arg) {
return arg;
}
String OK_returnFromAnyNonNullsafe() { String OK_returnFromAnyNonNullsafe() {
String a = new NonNullsafe().returnVal(); String a = new NonNullsafe().returnVal();
String b = new AnotherNonNullsafe().returnVal(); String b = new AnotherNonNullsafe().returnVal();
@ -38,11 +54,24 @@ public class NullsafeMode {
String BAD_returnNullFromNonNulsafe() { String BAD_returnNullFromNonNulsafe() {
return (new NonNullsafe()).returnNull(); return (new NonNullsafe()).returnNull();
} }
String OK_passLocalToStrictMode(String arg) {
return new NullsafeWithStrictMode().acceptVal(arg);
}
String OK_passLocalToStrict(String arg) {
return new StrictNullsafe().acceptVal(arg);
}
} }
@Nullsafe(value = Nullsafe.Mode.LOCAL, trustOnly = @Nullsafe.TrustList({NonNullsafe.class})) @Nullsafe(value = Nullsafe.Mode.LOCAL, trustOnly = @Nullsafe.TrustList({NonNullsafe.class}))
class TrustSomeNullsafe extends VariousMethods { class TrustSomeNullsafe extends VariousMethods {
String OK_returnFromNonNullsafe() { @Override
public String returnVal() {
return "OK";
}
String FP_OK_returnFromNonNullsafe() {
return new NonNullsafe().returnVal(); return new NonNullsafe().returnVal();
} }
@ -73,6 +102,15 @@ public class NullsafeMode {
@Nullsafe(Nullsafe.Mode.STRICT) @Nullsafe(Nullsafe.Mode.STRICT)
class NullsafeWithStrictMode extends VariousMethods { class NullsafeWithStrictMode extends VariousMethods {
@Override
public String returnVal() {
return "OK";
}
public String acceptVal(String arg) {
return arg;
}
String BAD_returnFromNonStrict() { String BAD_returnFromNonStrict() {
return new TrustNoneNullsafe().returnVal(); return new TrustNoneNullsafe().returnVal();
} }
@ -84,6 +122,15 @@ public class NullsafeMode {
@NullsafeStrict @NullsafeStrict
class StrictNullsafe extends VariousMethods { class StrictNullsafe extends VariousMethods {
@Override
public String returnVal() {
return "OK";
}
public String acceptVal(String arg) {
return arg;
}
String BAD_returnFromNonNullsafe() { String BAD_returnFromNonNullsafe() {
return new NonNullsafe().returnVal(); return new NonNullsafe().returnVal();
} }

@ -147,11 +147,15 @@ codetoanalyze/java/nullsafe-default/NullMethodCall.java, codetoanalyze.java.null
codetoanalyze/java/nullsafe-default/NullMethodCall.java, codetoanalyze.java.nullsafe_default.NullMethodCall.testSystemGetenvBad():int, 1, ERADICATE_NULLABLE_DEREFERENCE, no_bucket, WARNING, [`envValue` is nullable and is not locally checked for null when calling `length()`: call to System.getenv(...) at line 240 (nullable according to nullsafe internal models).] codetoanalyze/java/nullsafe-default/NullMethodCall.java, codetoanalyze.java.nullsafe_default.NullMethodCall.testSystemGetenvBad():int, 1, ERADICATE_NULLABLE_DEREFERENCE, no_bucket, WARNING, [`envValue` is nullable and is not locally checked for null when calling `length()`: call to System.getenv(...) at line 240 (nullable according to nullsafe internal models).]
codetoanalyze/java/nullsafe-default/NullMethodCall.java, codetoanalyze.java.nullsafe_default.NullMethodCall.withConditionalAssignemnt(codetoanalyze.java.nullsafe_default.NullMethodCall$AnotherI,boolean,java.lang.Object,java.lang.Object):void, 0, ERADICATE_NULLABLE_DEREFERENCE, no_bucket, WARNING, [`i` is nullable and is not locally checked for null when calling `withObjectParameter(...)`.] codetoanalyze/java/nullsafe-default/NullMethodCall.java, codetoanalyze.java.nullsafe_default.NullMethodCall.withConditionalAssignemnt(codetoanalyze.java.nullsafe_default.NullMethodCall$AnotherI,boolean,java.lang.Object,java.lang.Object):void, 0, ERADICATE_NULLABLE_DEREFERENCE, no_bucket, WARNING, [`i` is nullable and is not locally checked for null when calling `withObjectParameter(...)`.]
codetoanalyze/java/nullsafe-default/NullMethodCall.java, codetoanalyze.java.nullsafe_default.NullMethodCall.withConjuction(codetoanalyze.java.nullsafe_default.NullMethodCall$AnotherI,boolean,boolean):void, 0, ERADICATE_NULLABLE_DEREFERENCE, no_bucket, WARNING, [`i` is nullable and is not locally checked for null when calling `withBooleanParameter(...)`.] codetoanalyze/java/nullsafe-default/NullMethodCall.java, codetoanalyze.java.nullsafe_default.NullMethodCall.withConjuction(codetoanalyze.java.nullsafe_default.NullMethodCall$AnotherI,boolean,boolean):void, 0, ERADICATE_NULLABLE_DEREFERENCE, no_bucket, WARNING, [`i` is nullable and is not locally checked for null when calling `withBooleanParameter(...)`.]
codetoanalyze/java/nullsafe-default/NullsafeMode.java, codetoanalyze.java.nullsafe_default.NullsafeMode$StrictNullsafe.BAD_returnFromNonNullsafe():java.lang.String, 0, ERADICATE_UNCHECKED_NONSTRICT_FROM_STRICT, no_bucket, ERROR, [`NullsafeMode$VariousMethods.returnVal()`: `@NullsafeStrict` mode prohibits using values coming from non-strict classes without a check. Result of this call is used at line 88. Either add a local check for null or assertion, or strictify NullsafeMode$VariousMethods.] codetoanalyze/java/nullsafe-default/NullsafeMode.java, codetoanalyze.java.nullsafe_default.NullsafeMode$NullsafeWithStrictMode.BAD_returnFromNonStrict():java.lang.String, 0, ERADICATE_UNCHECKED_USAGE_IN_NULLSAFE, no_bucket, ERROR, [`NullsafeMode$VariousMethods.returnVal()`: `@NullsafeStrict` mode prohibits using values coming from non-strict classes without a check. Result of this call is used at line 115. Either add a local check for null or assertion, or make NullsafeMode$VariousMethods nullsafe strict.]
codetoanalyze/java/nullsafe-default/NullsafeMode.java, codetoanalyze.java.nullsafe_default.NullsafeMode$StrictNullsafe.OK_returnFromNullsafeWithStrictMode():java.lang.String, 0, ERADICATE_UNCHECKED_NONSTRICT_FROM_STRICT, no_bucket, ERROR, [`NullsafeMode$VariousMethods.returnVal()`: `@NullsafeStrict` mode prohibits using values coming from non-strict classes without a check. Result of this call is used at line 92. Either add a local check for null or assertion, or strictify NullsafeMode$VariousMethods.] codetoanalyze/java/nullsafe-default/NullsafeMode.java, codetoanalyze.java.nullsafe_default.NullsafeMode$StrictNullsafe.BAD_returnFromNonNullsafe():java.lang.String, 0, ERADICATE_UNCHECKED_USAGE_IN_NULLSAFE, no_bucket, ERROR, [`NullsafeMode$VariousMethods.returnVal()`: `@NullsafeStrict` mode prohibits using values coming from non-strict classes without a check. Result of this call is used at line 135. Either add a local check for null or assertion, or make NullsafeMode$VariousMethods nullsafe strict.]
codetoanalyze/java/nullsafe-default/NullsafeMode.java, codetoanalyze.java.nullsafe_default.NullsafeMode$TrustAllNullsafe.BAD_returnNullFromNonNulsafe():java.lang.String, 0, ERADICATE_RETURN_NOT_NULLABLE, no_bucket, WARNING, [`BAD_returnNullFromNonNulsafe()`: return type is declared non-nullable but the method returns a nullable value: call to returnNull() at line 39.] codetoanalyze/java/nullsafe-default/NullsafeMode.java, codetoanalyze.java.nullsafe_default.NullsafeMode$TrustAllNullsafe.BAD_returnNullFromNonNulsafe():java.lang.String, 0, ERADICATE_RETURN_NOT_NULLABLE, no_bucket, ERROR, [`BAD_returnNullFromNonNulsafe()`: return type is declared non-nullable but the method returns a nullable value: call to returnNull() at line 55.]
codetoanalyze/java/nullsafe-default/NullsafeMode.java, codetoanalyze.java.nullsafe_default.NullsafeMode$TrustSomeNullsafe.BAD_returnNullFromNonNulsafe():java.lang.String, 0, ERADICATE_RETURN_NOT_NULLABLE, no_bucket, WARNING, [`BAD_returnNullFromNonNulsafe()`: return type is declared non-nullable but the method returns a nullable value: call to returnNull() at line 59.] codetoanalyze/java/nullsafe-default/NullsafeMode.java, codetoanalyze.java.nullsafe_default.NullsafeMode$TrustNoneNullsafe.BAD_returnFromNonNullsafe():java.lang.String, 0, ERADICATE_UNCHECKED_USAGE_IN_NULLSAFE, no_bucket, ERROR, [`NullsafeMode$VariousMethods.returnVal()`: `@NullsafeLocal(trust=none)` mode prohibits using values coming from non-nullsafe classes without a check. Result of this call is used at line 95. Either add a local check for null or assertion, or make NullsafeMode$VariousMethods nullsafe.]
codetoanalyze/java/nullsafe-default/NullsafeMode.java, codetoanalyze.java.nullsafe_default.NullsafeMode$TrustSomeNullsafe.BAD_returnFromAnotherNonNullsafe():java.lang.String, 0, ERADICATE_UNCHECKED_USAGE_IN_NULLSAFE, no_bucket, ERROR, [`NullsafeMode$VariousMethods.returnVal()`: `@NullsafeLocal(trust=none)` mode prohibits using values coming from non-nullsafe classes without a check. Result of this call is used at line 79. Either add a local check for null or assertion, or make NullsafeMode$VariousMethods nullsafe.]
codetoanalyze/java/nullsafe-default/NullsafeMode.java, codetoanalyze.java.nullsafe_default.NullsafeMode$TrustSomeNullsafe.BAD_returnNullFromNonNulsafe():java.lang.String, 0, ERADICATE_RETURN_NOT_NULLABLE, no_bucket, ERROR, [`BAD_returnNullFromNonNulsafe()`: return type is declared non-nullable but the method returns a nullable value: call to returnNull() at line 88.]
codetoanalyze/java/nullsafe-default/NullsafeMode.java, codetoanalyze.java.nullsafe_default.NullsafeMode$TrustSomeNullsafe.FP_OK_returnFromNonNullsafe():java.lang.String, 0, ERADICATE_UNCHECKED_USAGE_IN_NULLSAFE, no_bucket, ERROR, [`NullsafeMode$VariousMethods.returnVal()`: `@NullsafeLocal(trust=none)` mode prohibits using values coming from non-nullsafe classes without a check. Result of this call is used at line 75. Either add a local check for null or assertion, or make NullsafeMode$VariousMethods nullsafe.]
codetoanalyze/java/nullsafe-default/NullsafeMode.java, codetoanalyze.java.nullsafe_default.NullsafeMode$TrustSomeNullsafe.OK_returnFromAnotherNonNullsafeAsNullable():java.lang.String, 0, ERADICATE_RETURN_OVER_ANNOTATED, no_bucket, WARNING, [Method `OK_returnFromAnotherNonNullsafeAsNullable()` is annotated with `@Nullable` but never returns null.] codetoanalyze/java/nullsafe-default/NullsafeMode.java, codetoanalyze.java.nullsafe_default.NullsafeMode$TrustSomeNullsafe.OK_returnFromAnotherNonNullsafeAsNullable():java.lang.String, 0, ERADICATE_RETURN_OVER_ANNOTATED, no_bucket, WARNING, [Method `OK_returnFromAnotherNonNullsafeAsNullable()` is annotated with `@Nullable` but never returns null.]
codetoanalyze/java/nullsafe-default/NullsafeMode.java, codetoanalyze.java.nullsafe_default.NullsafeMode$TrustSomeNullsafe.returnVal():java.lang.String, 0, ERADICATE_INCONSISTENT_SUBCLASS_PARAMETER_ANNOTATION, no_bucket, ERROR, [0th parameter `this` of method `NullsafeMode$TrustSomeNullsafe.returnVal()` is missing `@Nullable` declaration when overriding `NullsafeMode$VariousMethods.returnVal()`. The parent method declared it can handle `null` for this param, so the child should also declare that.]
codetoanalyze/java/nullsafe-default/ParameterNotNullable.java, codetoanalyze.java.nullsafe_default.ParameterNotNullable$ConstructorCall.<init>(codetoanalyze.java.nullsafe_default.ParameterNotNullable,int), 0, ERADICATE_PARAMETER_NOT_NULLABLE, no_bucket, WARNING, [`ParameterNotNullable$ConstructorCall(...)`: parameter #2(`s`) is declared non-nullable but the argument is `null`.] codetoanalyze/java/nullsafe-default/ParameterNotNullable.java, codetoanalyze.java.nullsafe_default.ParameterNotNullable$ConstructorCall.<init>(codetoanalyze.java.nullsafe_default.ParameterNotNullable,int), 0, ERADICATE_PARAMETER_NOT_NULLABLE, no_bucket, WARNING, [`ParameterNotNullable$ConstructorCall(...)`: parameter #2(`s`) is declared non-nullable but the argument is `null`.]
codetoanalyze/java/nullsafe-default/ParameterNotNullable.java, codetoanalyze.java.nullsafe_default.ParameterNotNullable.callNull():void, 1, ERADICATE_PARAMETER_NOT_NULLABLE, no_bucket, WARNING, [`ParameterNotNullable.test(...)`: parameter #1(`s`) is declared non-nullable but the argument `s` is `null`: null constant at line 39.] codetoanalyze/java/nullsafe-default/ParameterNotNullable.java, codetoanalyze.java.nullsafe_default.ParameterNotNullable.callNull():void, 1, ERADICATE_PARAMETER_NOT_NULLABLE, no_bucket, WARNING, [`ParameterNotNullable.test(...)`: parameter #1(`s`) is declared non-nullable but the argument `s` is `null`: null constant at line 39.]
codetoanalyze/java/nullsafe-default/ParameterNotNullable.java, codetoanalyze.java.nullsafe_default.ParameterNotNullable.callNullable(java.lang.String):void, 0, ERADICATE_PARAMETER_NOT_NULLABLE, no_bucket, WARNING, [`ParameterNotNullable.test(...)`: parameter #1(`s`) is declared non-nullable but the argument `s` is nullable.] codetoanalyze/java/nullsafe-default/ParameterNotNullable.java, codetoanalyze.java.nullsafe_default.ParameterNotNullable.callNullable(java.lang.String):void, 0, ERADICATE_PARAMETER_NOT_NULLABLE, no_bucket, WARNING, [`ParameterNotNullable.test(...)`: parameter #1(`s`) is declared non-nullable but the argument `s` is nullable.]
@ -222,14 +226,14 @@ codetoanalyze/java/nullsafe-default/ReturnNotNullable.java, codetoanalyze.java.n
codetoanalyze/java/nullsafe-default/ReturnNotNullable.java, codetoanalyze.java.nullsafe_default.ReturnNotNullable.return_null_in_catch_after_throw():java.lang.String, 0, ERADICATE_RETURN_NOT_NULLABLE, no_bucket, WARNING, [`return_null_in_catch_after_throw()`: return type is declared non-nullable but the method returns `null`: null constant at line 172.] codetoanalyze/java/nullsafe-default/ReturnNotNullable.java, codetoanalyze.java.nullsafe_default.ReturnNotNullable.return_null_in_catch_after_throw():java.lang.String, 0, ERADICATE_RETURN_NOT_NULLABLE, no_bucket, WARNING, [`return_null_in_catch_after_throw()`: return type is declared non-nullable but the method returns `null`: null constant at line 172.]
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/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, 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.<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_NONSTRICT_FROM_STRICT, 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 strictify NonStrict.] 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.]
codetoanalyze/java/nullsafe-default/StrictMode.java, codetoanalyze.java.nullsafe_default.Strict.nonStrictClass_convertingNonnullToNullableIsOK():java.lang.String, 0, ERADICATE_RETURN_OVER_ANNOTATED, no_bucket, WARNING, [Method `nonStrictClass_convertingNonnullToNullableIsOK()` is annotated with `@Nullable` but never returns null.] codetoanalyze/java/nullsafe-default/StrictMode.java, codetoanalyze.java.nullsafe_default.Strict.nonStrictClass_convertingNonnullToNullableIsOK():java.lang.String, 0, ERADICATE_RETURN_OVER_ANNOTATED, no_bucket, WARNING, [Method `nonStrictClass_convertingNonnullToNullableIsOK()` is annotated with `@Nullable` but never returns null.]
codetoanalyze/java/nullsafe-default/StrictMode.java, codetoanalyze.java.nullsafe_default.Strict.nonStrictClass_convertingNullableToNonnullIsBad():java.lang.String, 0, ERADICATE_RETURN_NOT_NULLABLE, no_bucket, ERROR, [`nonStrictClass_convertingNullableToNonnullIsBad()`: return type is declared non-nullable but the method returns a nullable value: call to getNullable() at line 137.] codetoanalyze/java/nullsafe-default/StrictMode.java, codetoanalyze.java.nullsafe_default.Strict.nonStrictClass_convertingNullableToNonnullIsBad():java.lang.String, 0, ERADICATE_RETURN_NOT_NULLABLE, no_bucket, ERROR, [`nonStrictClass_convertingNullableToNonnullIsBad()`: return type is declared non-nullable but the method returns a nullable value: call to getNullable() at line 137.]
codetoanalyze/java/nullsafe-default/StrictMode.java, codetoanalyze.java.nullsafe_default.Strict.nonStrictClass_dereferenceNonnullFieldAfterCheckIsOK():void, 1, ERADICATE_CONDITION_REDUNDANT, no_bucket, ADVICE, [The condition NonStrict.nonnull might be always true according to the existing annotations.] codetoanalyze/java/nullsafe-default/StrictMode.java, codetoanalyze.java.nullsafe_default.Strict.nonStrictClass_dereferenceNonnullFieldAfterCheckIsOK():void, 1, ERADICATE_CONDITION_REDUNDANT, no_bucket, ADVICE, [The condition NonStrict.nonnull might be always true according to the existing annotations.]
codetoanalyze/java/nullsafe-default/StrictMode.java, codetoanalyze.java.nullsafe_default.Strict.nonStrictClass_dereferenceNonnullFieldIsBad():void, 0, ERADICATE_UNCHECKED_NONSTRICT_FROM_STRICT, no_bucket, ERROR, [`NonStrict.nonnull`: `@NullsafeStrict` mode prohibits using values coming from non-strict classes without a check. This field is used at line 133. Either add a local check for null or assertion, or strictify NonStrict.] codetoanalyze/java/nullsafe-default/StrictMode.java, codetoanalyze.java.nullsafe_default.Strict.nonStrictClass_dereferenceNonnullFieldIsBad():void, 0, ERADICATE_UNCHECKED_USAGE_IN_NULLSAFE, no_bucket, ERROR, [`NonStrict.nonnull`: `@NullsafeStrict` mode prohibits using values coming from non-strict classes without a check. This field is used at line 133. Either add a local check for null or assertion, or make NonStrict nullsafe strict.]
codetoanalyze/java/nullsafe-default/StrictMode.java, codetoanalyze.java.nullsafe_default.Strict.nonStrictClass_dereferenceNonnullMethodAfterCheckIsOK():void, 1, ERADICATE_CONDITION_REDUNDANT, no_bucket, ADVICE, [The condition lang.String(o)V might be always true: `NonStrict.getNonnull()` is not annotated as `@Nullable`.] codetoanalyze/java/nullsafe-default/StrictMode.java, codetoanalyze.java.nullsafe_default.Strict.nonStrictClass_dereferenceNonnullMethodAfterCheckIsOK():void, 1, ERADICATE_CONDITION_REDUNDANT, no_bucket, ADVICE, [The condition lang.String(o)V might be always true: `NonStrict.getNonnull()` is not annotated as `@Nullable`.]
codetoanalyze/java/nullsafe-default/StrictMode.java, codetoanalyze.java.nullsafe_default.Strict.nonStrictClass_dereferenceNonnullMethodIsBad():void, 0, ERADICATE_UNCHECKED_NONSTRICT_FROM_STRICT, 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 115. Either add a local check for null or assertion, or strictify NonStrict.] codetoanalyze/java/nullsafe-default/StrictMode.java, codetoanalyze.java.nullsafe_default.Strict.nonStrictClass_dereferenceNonnullMethodIsBad():void, 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 115. Either add a local check for null or assertion, or make NonStrict nullsafe strict.]
codetoanalyze/java/nullsafe-default/StrictMode.java, codetoanalyze.java.nullsafe_default.Strict.nonStrictClass_dereferenceNonnullStaticMethodIsBad():void, 0, ERADICATE_UNCHECKED_NONSTRICT_FROM_STRICT, no_bucket, ERROR, [`NonStrict.staticNonnull()`: `@NullsafeStrict` mode prohibits using values coming from non-strict classes without a check. Result of this call is used at line 124. Either add a local check for null or assertion, or strictify NonStrict.] codetoanalyze/java/nullsafe-default/StrictMode.java, codetoanalyze.java.nullsafe_default.Strict.nonStrictClass_dereferenceNonnullStaticMethodIsBad():void, 0, ERADICATE_UNCHECKED_USAGE_IN_NULLSAFE, no_bucket, ERROR, [`NonStrict.staticNonnull()`: `@NullsafeStrict` mode prohibits using values coming from non-strict classes without a check. Result of this call is used at line 124. Either add a local check for null or assertion, or make NonStrict nullsafe strict.]
codetoanalyze/java/nullsafe-default/StrictMode.java, codetoanalyze.java.nullsafe_default.Strict.nonStrictClass_dereferenceNullableFieldIsBad():void, 0, ERADICATE_NULLABLE_DEREFERENCE, no_bucket, ERROR, [`__new(...).nullable` is nullable and is not locally checked for null when calling `toString()`.] codetoanalyze/java/nullsafe-default/StrictMode.java, codetoanalyze.java.nullsafe_default.Strict.nonStrictClass_dereferenceNullableFieldIsBad():void, 0, ERADICATE_NULLABLE_DEREFERENCE, no_bucket, ERROR, [`__new(...).nullable` is nullable and is not locally checked for null when calling `toString()`.]
codetoanalyze/java/nullsafe-default/StrictMode.java, codetoanalyze.java.nullsafe_default.Strict.nonStrictClass_dereferenceNullableMethodIsBad():void, 0, ERADICATE_NULLABLE_DEREFERENCE, no_bucket, ERROR, [`__new(...).getNullable()` is nullable and is not locally checked for null when calling `toString()`.] codetoanalyze/java/nullsafe-default/StrictMode.java, codetoanalyze.java.nullsafe_default.Strict.nonStrictClass_dereferenceNullableMethodIsBad():void, 0, ERADICATE_NULLABLE_DEREFERENCE, no_bucket, ERROR, [`__new(...).getNullable()` is nullable and is not locally checked for null when calling `toString()`.]
codetoanalyze/java/nullsafe-default/StrictMode.java, codetoanalyze.java.nullsafe_default.Strict.nonStrictClass_dereferenceNullableStaticMethodIsBad():void, 0, ERADICATE_NULLABLE_DEREFERENCE, no_bucket, ERROR, [`staticNullable()` is nullable and is not locally checked for null when calling `toString()`.] codetoanalyze/java/nullsafe-default/StrictMode.java, codetoanalyze.java.nullsafe_default.Strict.nonStrictClass_dereferenceNullableStaticMethodIsBad():void, 0, ERADICATE_NULLABLE_DEREFERENCE, no_bucket, ERROR, [`staticNullable()` is nullable and is not locally checked for null when calling `toString()`.]
@ -242,7 +246,7 @@ codetoanalyze/java/nullsafe-default/StrictMode.java, codetoanalyze.java.nullsafe
codetoanalyze/java/nullsafe-default/StrictMode.java, codetoanalyze.java.nullsafe_default.Strict.strictClass_dereferenceNullableMethodIsBad():void, 0, ERADICATE_NULLABLE_DEREFERENCE, no_bucket, ERROR, [`__new(...).getNullable()` is nullable and is not locally checked for null when calling `toString()`.] codetoanalyze/java/nullsafe-default/StrictMode.java, codetoanalyze.java.nullsafe_default.Strict.strictClass_dereferenceNullableMethodIsBad():void, 0, ERADICATE_NULLABLE_DEREFERENCE, no_bucket, ERROR, [`__new(...).getNullable()` is nullable and is not locally checked for null when calling `toString()`.]
codetoanalyze/java/nullsafe-default/StrictMode.java, codetoanalyze.java.nullsafe_default.Strict.strictClass_dereferenceNullableStaticMethodIsBad():void, 0, ERADICATE_NULLABLE_DEREFERENCE, no_bucket, ERROR, [`staticNullable()` is nullable and is not locally checked for null when calling `toString()`.] codetoanalyze/java/nullsafe-default/StrictMode.java, codetoanalyze.java.nullsafe_default.Strict.strictClass_dereferenceNullableStaticMethodIsBad():void, 0, ERADICATE_NULLABLE_DEREFERENCE, no_bucket, ERROR, [`staticNullable()` is nullable and is not locally checked for null when calling `toString()`.]
codetoanalyze/java/nullsafe-default/StrictModeForThirdParty.java, codetoanalyze.java.nullsafe_default.StrictModeForThirdParty.dereferenceSpecifiedAsNullableIsBAD():void, 0, ERADICATE_NULLABLE_DEREFERENCE, no_bucket, ERROR, [`StrictModeForThirdParty.obj.returnSpecifiedAsNullable()` is nullable and is not locally checked for null when calling `toString()`: call to ThirdPartyTestClass.returnSpecifiedAsNullable() at line 45 (declared nullable in nullsafe-default/third-party-signatures/some.test.pckg.sig at line 2).] codetoanalyze/java/nullsafe-default/StrictModeForThirdParty.java, codetoanalyze.java.nullsafe_default.StrictModeForThirdParty.dereferenceSpecifiedAsNullableIsBAD():void, 0, ERADICATE_NULLABLE_DEREFERENCE, no_bucket, ERROR, [`StrictModeForThirdParty.obj.returnSpecifiedAsNullable()` is nullable and is not locally checked for null when calling `toString()`: call to ThirdPartyTestClass.returnSpecifiedAsNullable() at line 45 (declared nullable in nullsafe-default/third-party-signatures/some.test.pckg.sig at line 2).]
codetoanalyze/java/nullsafe-default/StrictModeForThirdParty.java, codetoanalyze.java.nullsafe_default.StrictModeForThirdParty.dereferenceUnspecifiedIsBAD():void, 0, ERADICATE_UNVETTED_THIRD_PARTY_IN_STRICT, 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.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.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/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, codetoanalyze.java.nullsafe_default.SwitchCase.getNullableColor():codetoanalyze.java.nullsafe_default.Color, 0, ERADICATE_RETURN_OVER_ANNOTATED, no_bucket, WARNING, [Method `getNullableColor()` is annotated with `@Nullable` but never returns null.] codetoanalyze/java/nullsafe-default/SwitchCase.java, codetoanalyze.java.nullsafe_default.SwitchCase.getNullableColor():codetoanalyze.java.nullsafe_default.Color, 0, ERADICATE_RETURN_OVER_ANNOTATED, no_bucket, WARNING, [Method `getNullableColor()` is annotated with `@Nullable` but never returns null.]

Loading…
Cancel
Save