[nullsafe] Introduce LocallyTrustedNonnull nullability

Summary: This diff finishes the stack fixing wrong promotion recommendations!

Reviewed By: artempyanykh

Differential Revision: D20949029

fbshipit-source-id: 59b6ad93f
master
Mitya Lyubarskiy 5 years ago committed by Facebook GitHub Bot
parent 199d53f748
commit 9397b68650

@ -19,6 +19,7 @@ type t =
| Nullable of nullable_origin | Nullable of nullable_origin
| ThirdPartyNonnull | ThirdPartyNonnull
| UncheckedNonnull of unchecked_nonnull_origin | UncheckedNonnull of unchecked_nonnull_origin
| LocallyTrustedNonnull
| LocallyCheckedNonnull | LocallyCheckedNonnull
| StrictNonnull of strict_nonnull_origin | StrictNonnull of strict_nonnull_origin
[@@deriving compare] [@@deriving compare]
@ -47,6 +48,8 @@ let get_nullability = function
Nullability.ThirdPartyNonnull Nullability.ThirdPartyNonnull
| UncheckedNonnull _ -> | UncheckedNonnull _ ->
Nullability.UncheckedNonnull Nullability.UncheckedNonnull
| LocallyTrustedNonnull ->
Nullability.LocallyTrustedNonnull
| LocallyCheckedNonnull -> | LocallyCheckedNonnull ->
Nullability.LocallyCheckedNonnull Nullability.LocallyCheckedNonnull
| StrictNonnull _ -> | StrictNonnull _ ->
@ -88,6 +91,8 @@ let pp fmt t =
F.fprintf fmt "ThirdPartyNonnull" F.fprintf fmt "ThirdPartyNonnull"
| 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)
| LocallyTrustedNonnull ->
F.fprintf fmt "LocallyTrustedNonnull"
| LocallyCheckedNonnull -> | LocallyCheckedNonnull ->
F.fprintf fmt "LocallyCheckedNonnull" F.fprintf fmt "LocallyCheckedNonnull"
| StrictNonnull origin -> | StrictNonnull origin ->
@ -131,4 +136,4 @@ let of_type_and_annotation ~is_callee_in_trust_list ~nullsafe_mode ~is_third_par
if Annotations.ia_is_nonnull annotations then UncheckedNonnull AnnotatedNonnull if Annotations.ia_is_nonnull annotations then UncheckedNonnull AnnotatedNonnull
else UncheckedNonnull ImplicitlyNonnull else UncheckedNonnull ImplicitlyNonnull
in in
if is_callee_in_trust_list then LocallyCheckedNonnull else preliminary_nullability if is_callee_in_trust_list then LocallyTrustedNonnull else preliminary_nullability

@ -21,6 +21,7 @@ type t =
| Nullable of nullable_origin | Nullable of nullable_origin
| ThirdPartyNonnull | ThirdPartyNonnull
| UncheckedNonnull of unchecked_nonnull_origin | UncheckedNonnull of unchecked_nonnull_origin
| LocallyTrustedNonnull
| LocallyCheckedNonnull | LocallyCheckedNonnull
| StrictNonnull of strict_nonnull_origin | StrictNonnull of strict_nonnull_origin
[@@deriving compare] [@@deriving compare]

@ -113,8 +113,10 @@ module ReportableViolation = struct
MF.pp_monospaced procname_str param_position pp_param_name param_signature.mangled MF.pp_monospaced procname_str param_position pp_param_name param_signature.mangled
argument_description nullability_evidence_as_suffix MF.pp_monospaced procname_str argument_description nullability_evidence_as_suffix MF.pp_monospaced procname_str
where_to_add_signature where_to_add_signature
| Nullability.LocallyCheckedNonnull | Nullability.UncheckedNonnull | Nullability.StrictNonnull | Nullability.LocallyCheckedNonnull
-> | Nullability.LocallyTrustedNonnull
| Nullability.UncheckedNonnull
| Nullability.StrictNonnull ->
let nonnull_evidence = let nonnull_evidence =
match model_source with match model_source with
| None -> | None ->

@ -26,6 +26,9 @@ module UserFriendlyNullable = struct
Some (UntrustedNonnull LocallyCheckedNonnull) Some (UntrustedNonnull LocallyCheckedNonnull)
| Nullability.ThirdPartyNonnull -> | Nullability.ThirdPartyNonnull ->
Some (UntrustedNonnull ThirdPartyNonnull) Some (UntrustedNonnull ThirdPartyNonnull)
| Nullability.LocallyTrustedNonnull ->
(* The value is trusted in the current mode by definition, hence is not treated as nullable. *)
None
| Nullability.StrictNonnull -> | Nullability.StrictNonnull ->
None None
end end

@ -13,6 +13,7 @@ type t =
| Nullable | Nullable
| ThirdPartyNonnull | ThirdPartyNonnull
| UncheckedNonnull | UncheckedNonnull
| LocallyTrustedNonnull
| LocallyCheckedNonnull | LocallyCheckedNonnull
| StrictNonnull | StrictNonnull
[@@deriving compare, equal] [@@deriving compare, equal]
@ -33,6 +34,8 @@ let join x y =
ThirdPartyNonnull ThirdPartyNonnull
| UncheckedNonnull, _ | _, UncheckedNonnull -> | UncheckedNonnull, _ | _, UncheckedNonnull ->
UncheckedNonnull UncheckedNonnull
| LocallyTrustedNonnull, _ | _, LocallyTrustedNonnull ->
LocallyTrustedNonnull
| LocallyCheckedNonnull, _ | _, LocallyCheckedNonnull -> | LocallyCheckedNonnull, _ | _, LocallyCheckedNonnull ->
LocallyCheckedNonnull LocallyCheckedNonnull
| StrictNonnull, StrictNonnull -> | StrictNonnull, StrictNonnull ->
@ -46,12 +49,17 @@ let is_considered_nonnull ~nullsafe_mode nullability =
match nullsafe_mode with match nullsafe_mode with
| NullsafeMode.Strict -> | NullsafeMode.Strict ->
StrictNonnull StrictNonnull
| NullsafeMode.Local (NullsafeMode.Trust.Only _classes) -> | NullsafeMode.Local (NullsafeMode.Trust.Only []) ->
(* TODO(T61473665). For now treat trust with specified classes as trust=none. *) (* Though "trust none" is technically a subcase of trust some,
we need this pattern to be different from the one below so we can detect possible
promotions from "trust some" to "trust none" *)
LocallyCheckedNonnull LocallyCheckedNonnull
| NullsafeMode.Local (NullsafeMode.Trust.Only _classes) ->
LocallyTrustedNonnull
| NullsafeMode.Local NullsafeMode.Trust.All -> | NullsafeMode.Local NullsafeMode.Trust.All ->
UncheckedNonnull UncheckedNonnull
| NullsafeMode.Default -> | NullsafeMode.Default ->
(* In default mode, we trust everything, even not annotated third party. *)
ThirdPartyNonnull ThirdPartyNonnull
in in
is_subtype ~subtype:nullability ~supertype:least_required is_subtype ~subtype:nullability ~supertype:least_required
@ -68,6 +76,8 @@ let to_string = function
"ThirdPartyNonnull" "ThirdPartyNonnull"
| UncheckedNonnull -> | UncheckedNonnull ->
"UncheckedNonnull" "UncheckedNonnull"
| LocallyTrustedNonnull ->
"LocallyTrustedNonnull"
| LocallyCheckedNonnull -> | LocallyCheckedNonnull ->
"LocallyCheckedNonnull" "LocallyCheckedNonnull"
| StrictNonnull -> | StrictNonnull ->

@ -28,6 +28,10 @@ type t =
conventions) as non-nullable. Hovewer, the class is not checked under [@Nullsafe], so its conventions) as non-nullable. Hovewer, the class is not checked under [@Nullsafe], so its
actual nullability is not truthworhy, as the class might contain arbitrary number of actual nullability is not truthworhy, as the class might contain arbitrary number of
nullability issues *) nullability issues *)
| LocallyTrustedNonnull
(** The same as [UncheckedNonnull], but the value comes from a class explicitly listed as
trusted in the class under analysis. It is less truthworthy than [LocallyCheckedNonnull]
as no actual verification were performed. *)
| LocallyCheckedNonnull | LocallyCheckedNonnull
(** Non-nullable value that comes from a class checked under [@NullsafeLocal] mode. Local mode (** Non-nullable value that comes from a class checked under [@NullsafeLocal] mode. Local mode
type-checks files against its dependencies but does not require the dependencies to be type-checks files against its dependencies but does not require the dependencies to be

@ -66,6 +66,7 @@ let get_nullability = function
Nullability.Nullable Nullability.Nullable
| AnnotatedNullability.UncheckedNonnull _ | AnnotatedNullability.UncheckedNonnull _
| AnnotatedNullability.ThirdPartyNonnull | AnnotatedNullability.ThirdPartyNonnull
| AnnotatedNullability.LocallyTrustedNonnull
| AnnotatedNullability.LocallyCheckedNonnull | AnnotatedNullability.LocallyCheckedNonnull
| AnnotatedNullability.StrictNonnull _ -> | AnnotatedNullability.StrictNonnull _ ->
(* Nonnull param should be treated as trusted inside this function context: (* Nonnull param should be treated as trusted inside this function context:
@ -131,6 +132,7 @@ let get_method_ret_description pname call_loc
"nullable" "nullable"
| AnnotatedNullability.ThirdPartyNonnull | AnnotatedNullability.ThirdPartyNonnull
| AnnotatedNullability.UncheckedNonnull _ | AnnotatedNullability.UncheckedNonnull _
| AnnotatedNullability.LocallyTrustedNonnull
| AnnotatedNullability.LocallyCheckedNonnull | AnnotatedNullability.LocallyCheckedNonnull
| AnnotatedNullability.StrictNonnull _ -> | AnnotatedNullability.StrictNonnull _ ->
"non-nullable" "non-nullable"

@ -81,11 +81,10 @@ class TrustSome_DoesNotUseTrusted_CanBePromotedToTrustNone {
} }
} }
// FIXME: promo is incorrectly calculated as trust none
@Nullsafe( @Nullsafe(
value = Nullsafe.Mode.LOCAL, value = Nullsafe.Mode.LOCAL,
trustOnly = @Nullsafe.TrustList({Default_NoDeps_CanBePromotedToStrict.class})) trustOnly = @Nullsafe.TrustList({Default_NoDeps_CanBePromotedToStrict.class}))
class TrustSome_UsesTrusted_NoPromo_FIXME { class TrustSome_UsesTrusted_NoPromo {
static String f() { static String f() {
return Default_NoDeps_CanBePromotedToStrict.f(); return Default_NoDeps_CanBePromotedToStrict.f();
} }

@ -172,7 +172,7 @@ codetoanalyze/java/nullsafe-default/ModePromotions.java, Linters_dummy_method, 1
codetoanalyze/java/nullsafe-default/ModePromotions.java, Linters_dummy_method, 1, ERADICATE_META_CLASS_IS_NULLSAFE, no_bucket, INFO, [], Strict_NoDeps_NoPromos, codetoanalyze.java.nullsafe_default, issues: 0, curr_mode: "Strict" codetoanalyze/java/nullsafe-default/ModePromotions.java, Linters_dummy_method, 1, ERADICATE_META_CLASS_IS_NULLSAFE, no_bucket, INFO, [], Strict_NoDeps_NoPromos, codetoanalyze.java.nullsafe_default, issues: 0, curr_mode: "Strict"
codetoanalyze/java/nullsafe-default/ModePromotions.java, Linters_dummy_method, 1, ERADICATE_META_CLASS_IS_NULLSAFE, no_bucket, INFO, [], TrustSome_DoesNotUseTrusted_CanBePromotedToTrustNone, codetoanalyze.java.nullsafe_default, issues: 0, curr_mode: "LocalTrustSome", promote_mode: "LocalTrustNone" codetoanalyze/java/nullsafe-default/ModePromotions.java, Linters_dummy_method, 1, ERADICATE_META_CLASS_IS_NULLSAFE, no_bucket, INFO, [], TrustSome_DoesNotUseTrusted_CanBePromotedToTrustNone, codetoanalyze.java.nullsafe_default, issues: 0, curr_mode: "LocalTrustSome", promote_mode: "LocalTrustNone"
codetoanalyze/java/nullsafe-default/ModePromotions.java, Linters_dummy_method, 1, ERADICATE_META_CLASS_IS_NULLSAFE, no_bucket, INFO, [], TrustSome_TrustToLocalIsNotNeeded_CanBePromotedToTrustNone, codetoanalyze.java.nullsafe_default, issues: 0, curr_mode: "LocalTrustSome", promote_mode: "LocalTrustNone" codetoanalyze/java/nullsafe-default/ModePromotions.java, Linters_dummy_method, 1, ERADICATE_META_CLASS_IS_NULLSAFE, no_bucket, INFO, [], TrustSome_TrustToLocalIsNotNeeded_CanBePromotedToTrustNone, codetoanalyze.java.nullsafe_default, issues: 0, curr_mode: "LocalTrustSome", promote_mode: "LocalTrustNone"
codetoanalyze/java/nullsafe-default/ModePromotions.java, Linters_dummy_method, 1, ERADICATE_META_CLASS_IS_NULLSAFE, no_bucket, INFO, [], TrustSome_UsesTrusted_NoPromo_FIXME, codetoanalyze.java.nullsafe_default, issues: 0, curr_mode: "LocalTrustSome", promote_mode: "LocalTrustNone" codetoanalyze/java/nullsafe-default/ModePromotions.java, Linters_dummy_method, 1, ERADICATE_META_CLASS_IS_NULLSAFE, no_bucket, INFO, [], TrustSome_UsesTrusted_NoPromo, codetoanalyze.java.nullsafe_default, issues: 0, curr_mode: "LocalTrustSome"
codetoanalyze/java/nullsafe-default/MyPreconditions.java, Linters_dummy_method, 1, ERADICATE_META_CLASS_CAN_BE_NULLSAFE, no_bucket, ADVICE, [Congrats! Class codetoanalyze.java.nullsafe_default.MyPreconditions is free of nullability issues. Mark it `@Nullsafe(Nullsafe.Mode.Local)` to prevent regressions.], MyPreconditions, codetoanalyze.java.nullsafe_default, issues: 0, curr_mode: "Default", promote_mode: "Strict" codetoanalyze/java/nullsafe-default/MyPreconditions.java, Linters_dummy_method, 1, ERADICATE_META_CLASS_CAN_BE_NULLSAFE, no_bucket, ADVICE, [Congrats! Class codetoanalyze.java.nullsafe_default.MyPreconditions is free of nullability issues. Mark it `@Nullsafe(Nullsafe.Mode.Local)` to prevent regressions.], MyPreconditions, codetoanalyze.java.nullsafe_default, issues: 0, curr_mode: "Default", promote_mode: "Strict"
codetoanalyze/java/nullsafe-default/NestedFieldAccess.java, Linters_dummy_method, 1, ERADICATE_META_CLASS_CAN_BE_NULLSAFE, no_bucket, ADVICE, [Congrats! Class codetoanalyze.java.nullsafe_default.NestedFieldAccess is free of nullability issues. Mark it `@Nullsafe(Nullsafe.Mode.Local)` to prevent regressions.], NestedFieldAccess, codetoanalyze.java.nullsafe_default, issues: 0, curr_mode: "Default", promote_mode: "Strict" codetoanalyze/java/nullsafe-default/NestedFieldAccess.java, Linters_dummy_method, 1, ERADICATE_META_CLASS_CAN_BE_NULLSAFE, no_bucket, ADVICE, [Congrats! Class codetoanalyze.java.nullsafe_default.NestedFieldAccess is free of nullability issues. Mark it `@Nullsafe(Nullsafe.Mode.Local)` to prevent regressions.], NestedFieldAccess, codetoanalyze.java.nullsafe_default, issues: 0, curr_mode: "Default", promote_mode: "Strict"
codetoanalyze/java/nullsafe-default/NestedFieldAccess.java, Linters_dummy_method, 1, ERADICATE_META_CLASS_CAN_BE_NULLSAFE, no_bucket, ADVICE, [Congrats! Class codetoanalyze.java.nullsafe_default.NestedFieldAccess$C is free of nullability issues. Mark it `@Nullsafe(Nullsafe.Mode.Local)` to prevent regressions.], NestedFieldAccess$C, codetoanalyze.java.nullsafe_default, issues: 0, curr_mode: "Default", promote_mode: "Strict" codetoanalyze/java/nullsafe-default/NestedFieldAccess.java, Linters_dummy_method, 1, ERADICATE_META_CLASS_CAN_BE_NULLSAFE, no_bucket, ADVICE, [Congrats! Class codetoanalyze.java.nullsafe_default.NestedFieldAccess$C is free of nullability issues. Mark it `@Nullsafe(Nullsafe.Mode.Local)` to prevent regressions.], NestedFieldAccess$C, codetoanalyze.java.nullsafe_default, issues: 0, curr_mode: "Default", promote_mode: "Strict"

Loading…
Cancel
Save