[nullsafe] Decouple nullsafe mode from issue calculation, DereferenceRule

Summary:
This diff continues work in D20491716.
This time for Dereference Rule.

Reviewed By: jvillard

Differential Revision: D20492296

fbshipit-source-id: ff7f824f9
master
Mitya Lyubarskiy 5 years ago committed by Facebook GitHub Bot
parent 0bf5298c21
commit 371eed9309

@ -6,26 +6,19 @@
*)
open! IStd
type violation = {nullsafe_mode: NullsafeMode.t; nullability: Nullability.t} [@@deriving compare]
type violation = {nullability: Nullability.t} [@@deriving compare]
type dereference_type =
module ReportableViolation = struct
type t = {nullsafe_mode: NullsafeMode.t; violation: violation}
type dereference_type =
| MethodCall of Procname.t
| AccessToField of Fieldname.t
| AccessByIndex of {index_desc: string}
| ArrayLengthAccess
[@@deriving compare]
[@@deriving compare]
let check ~nullsafe_mode nullability =
match nullability with
| Nullability.Nullable | Nullability.Null ->
Error {nullsafe_mode; nullability}
| other when not (Nullability.is_considered_nonnull ~nullsafe_mode other) ->
Error {nullsafe_mode; nullability}
| _ ->
Ok ()
let get_origin_opt ~nullable_object_descr origin =
let get_origin_opt ~nullable_object_descr origin =
let should_show_origin =
match nullable_object_descr with
| Some object_expression ->
@ -36,8 +29,8 @@ let get_origin_opt ~nullable_object_descr origin =
if should_show_origin then Some origin else None
let violation_description {nullsafe_mode; nullability} ~dereference_location dereference_type
~nullable_object_descr ~nullable_object_origin =
let get_description {nullsafe_mode; violation= {nullability}} ~dereference_location
dereference_type ~nullable_object_descr ~nullable_object_origin =
let module MF = MarkupFormatter in
let special_message =
if not (NullsafeMode.equal NullsafeMode.Default nullsafe_mode) then
@ -97,8 +90,8 @@ let violation_description {nullsafe_mode; nullability} ~dereference_location der
match nullability with
| Nullability.Null ->
Format.sprintf
"NullPointerException will be thrown at this line! %s is `null` and is dereferenced \
via %s%s."
"NullPointerException will be thrown at this line! %s is `null` and is \
dereferenced via %s%s."
what_is_dereferred_str action_descr origin_descr
| Nullability.Nullable ->
Format.sprintf "%s is nullable and is not locally checked for null when %s%s.%s"
@ -111,4 +104,20 @@ let violation_description {nullsafe_mode; nullability} ~dereference_location der
(description, IssueType.eradicate_nullable_dereference, dereference_location)
let violation_severity {nullsafe_mode} = NullsafeMode.severity nullsafe_mode
let get_severity {nullsafe_mode} = NullsafeMode.severity nullsafe_mode
end
let check nullability =
match nullability with
(* StrictNonnull is the only "real" value that is not null according to type system rules.
Other values can not be fully trusted.
*)
| Nullability.StrictNonnull ->
Ok ()
| _ ->
Error {nullability}
let to_reportable_violation nullsafe_mode ({nullability} as violation) =
if Nullability.is_considered_nonnull ~nullsafe_mode nullability then None
else Some ReportableViolation.{nullsafe_mode; violation}

@ -11,23 +11,36 @@ open! IStd
type violation [@@deriving compare]
val check : nullsafe_mode:NullsafeMode.t -> Nullability.t -> (unit, violation) result
val check : Nullability.t -> (unit, violation) result
(** violation of Dereference rule reflects possibility of dereferencing of `null`. Note that this
might or might not be severe enough to be reported to the user, depending on the mode
agreements. *)
type dereference_type =
(** Violation that needs to be reported to the user. *)
module ReportableViolation : sig
type t
type dereference_type =
| MethodCall of Procname.t
| AccessToField of Fieldname.t
| AccessByIndex of {index_desc: string}
| ArrayLengthAccess
[@@deriving compare]
[@@deriving compare]
val get_severity : t -> Exceptions.severity
(** Severity of the violation to be reported *)
val violation_description :
violation
val get_description :
t
-> dereference_location:Location.t
-> dereference_type
-> nullable_object_descr:string option
-> nullable_object_origin:TypeOrigin.t
-> string * IssueType.t * Location.t
(** Given context around violation, return error message together with the info where to put this
(** Given context around violation, return error message together with the info where to put this
message *)
end
val violation_severity : violation -> Exceptions.severity
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. *)

@ -31,8 +31,7 @@ let is_virtual = function
let check_object_dereference ~nullsafe_mode tenv find_canonical_duplicate curr_pname node instr_ref
object_exp dereference_type inferred_nullability loc =
Result.iter_error
(DereferenceRule.check ~nullsafe_mode
(InferredNullability.get_nullability inferred_nullability))
(DereferenceRule.check (InferredNullability.get_nullability inferred_nullability))
~f:(fun dereference_violation ->
let nullable_object_origin = InferredNullability.get_origin inferred_nullability in
let nullable_object_descr = explain_expr tenv node object_exp in
@ -407,7 +406,7 @@ let check_call_receiver ~nullsafe_mode tenv find_canonical_duplicate curr_pdesc
loc
in
check_object_dereference ~nullsafe_mode tenv find_canonical_duplicate curr_pdesc node
instr_ref original_this_e (DereferenceRule.MethodCall callee_pname)
instr_ref original_this_e (DereferenceRule.ReportableViolation.MethodCall callee_pname)
this_inferred_nullability loc
| [] ->
()

@ -165,8 +165,9 @@ let rec typecheck_expr ~nullsafe_mode find_canonical_duplicate visited checks te
in
if checks.eradicate then
EradicateChecks.check_object_dereference ~nullsafe_mode tenv find_canonical_duplicate
curr_pdesc node instr_ref exp (DereferenceRule.AccessToField field_name)
inferred_nullability loc ;
curr_pdesc node instr_ref exp
(DereferenceRule.ReportableViolation.AccessToField field_name) inferred_nullability
loc ;
tr_new
| Exp.Lindex (array_exp, index_exp) ->
let _, inferred_nullability =
@ -179,7 +180,7 @@ let rec typecheck_expr ~nullsafe_mode find_canonical_duplicate visited checks te
if checks.eradicate then
EradicateChecks.check_object_dereference ~nullsafe_mode tenv find_canonical_duplicate
curr_pdesc node instr_ref array_exp
(DereferenceRule.AccessByIndex {index_desc})
(DereferenceRule.ReportableViolation.AccessByIndex {index_desc})
inferred_nullability loc ;
let typ, _ = tr_default in
(typ, InferredNullability.create TypeOrigin.ArrayAccess)
@ -1195,7 +1196,8 @@ let typecheck_instr tenv calls_this checks (node : Procdesc.Node.t) idenv curr_p
in
if checks.eradicate then
EradicateChecks.check_object_dereference ~nullsafe_mode tenv find_canonical_duplicate
curr_pdesc node instr_ref array_exp DereferenceRule.ArrayLengthAccess ta loc ;
curr_pdesc node instr_ref array_exp DereferenceRule.ReportableViolation.ArrayLengthAccess
ta loc ;
TypeState.add_id id
(Typ.mk (Tint Typ.IInt), InferredNullability.create TypeOrigin.ArrayLengthResult)
typestate ~descr:"array.length"

@ -72,7 +72,7 @@ type err_instance =
| Nullable_dereference of
{ dereference_violation: DereferenceRule.violation
; dereference_location: Location.t
; dereference_type: DereferenceRule.dereference_type
; dereference_type: DereferenceRule.ReportableViolation.dereference_type
; nullable_object_descr: string option
; nullable_object_origin: TypeOrigin.t }
| Bad_assignment of
@ -262,15 +262,15 @@ let get_error_info_if_reportable ~nullsafe_mode err_instance =
; nullable_object_descr
; dereference_type
; nullable_object_origin } ->
let+ reportable_violation =
DereferenceRule.to_reportable_violation nullsafe_mode dereference_violation
in
let description, issue_type, error_location =
DereferenceRule.violation_description ~dereference_location dereference_violation
dereference_type ~nullable_object_descr ~nullable_object_origin
DereferenceRule.ReportableViolation.get_description reportable_violation
~dereference_location dereference_type ~nullable_object_descr ~nullable_object_origin
in
Some
( description
, issue_type
, Some error_location
, DereferenceRule.violation_severity dereference_violation )
let severity = DereferenceRule.ReportableViolation.get_severity reportable_violation in
(description, issue_type, Some error_location, severity)
| Inconsistent_subclass
{inheritance_violation; violation_type; base_proc_name; overridden_proc_name} ->
Some

@ -48,7 +48,7 @@ type err_instance =
| Nullable_dereference of
{ dereference_violation: DereferenceRule.violation
; dereference_location: Location.t
; dereference_type: DereferenceRule.dereference_type
; dereference_type: DereferenceRule.ReportableViolation.dereference_type
; nullable_object_descr: string option
; nullable_object_origin: TypeOrigin.t }
| Bad_assignment of

@ -139,7 +139,7 @@ codetoanalyze/java/nullsafe-default/InheritanceForStrictMode.java, codetoanalyze
codetoanalyze/java/nullsafe-default/InheritanceForStrictMode.java, codetoanalyze.java.nullsafe_default.InheritanceForStrictMode$StrictExtendingNonstrict.params(java.lang.String,java.lang.String):void, 0, ERADICATE_INCONSISTENT_SUBCLASS_PARAMETER_ANNOTATION, no_bucket, ERROR, [First parameter `badToRemoveNullableInChildren` of method `InheritanceForStrictMode$StrictExtendingNonstrict.params(...)` is missing `@Nullable` declaration when overriding `InheritanceForStrictMode$NonStrictBase.params(...)`. The parent method declared it can handle `null` for this param, so the child should also declare that.]
codetoanalyze/java/nullsafe-default/InheritanceForStrictMode.java, codetoanalyze.java.nullsafe_default.InheritanceForStrictMode$StrictExtendingStrict.badToAddNullableInChildren():java.lang.String, 0, ERADICATE_INCONSISTENT_SUBCLASS_RETURN_ANNOTATION, no_bucket, ERROR, [Child method `InheritanceForStrictMode$StrictExtendingStrict.badToAddNullableInChildren()` is not substitution-compatible with its parent: the return type is declared as nullable, but parent method `InheritanceForStrictMode$StrictBase.badToAddNullableInChildren()` is missing `@Nullable` declaration. Either mark the parent as `@Nullable` or ensure the child does not return `null`.]
codetoanalyze/java/nullsafe-default/InheritanceForStrictMode.java, codetoanalyze.java.nullsafe_default.InheritanceForStrictMode$StrictExtendingStrict.params(java.lang.String,java.lang.String):void, 0, ERADICATE_INCONSISTENT_SUBCLASS_PARAMETER_ANNOTATION, no_bucket, ERROR, [First parameter `badToRemoveNullableInChildren` of method `InheritanceForStrictMode$StrictExtendingStrict.params(...)` is missing `@Nullable` declaration when overriding `InheritanceForStrictMode$StrictBase.params(...)`. The parent method declared it can handle `null` for this param, so the child should also declare that.]
codetoanalyze/java/nullsafe-default/JunitExample.java, Linters_dummy_method, 1, ERADICATE_META_CLASS_IS_CLEAN, no_bucket, INFO, []
codetoanalyze/java/nullsafe-default/JunitExample.java, Linters_dummy_method, 1, ERADICATE_META_CLASS_NEEDS_FIXING, no_bucket, INFO, []
codetoanalyze/java/nullsafe-default/LibraryCalls.java, Linters_dummy_method, 1, ERADICATE_META_CLASS_NEEDS_FIXING, no_bucket, INFO, []
codetoanalyze/java/nullsafe-default/LibraryCalls.java, codetoanalyze.java.nullsafe_default.LibraryCalls.badAtomicReferenceDereference(java.util.concurrent.atomic.AtomicReference):java.lang.String, 0, ERADICATE_NULLABLE_DEREFERENCE, no_bucket, WARNING, [`ref.get()` is nullable and is not locally checked for null when calling `toString()`: call to AtomicReference.get() at line 35 (nullable according to nullsafe internal models).]
codetoanalyze/java/nullsafe-default/LibraryCalls.java, codetoanalyze.java.nullsafe_default.LibraryCalls.badPhantomReferenceDereference(java.lang.ref.PhantomReference):java.lang.String, 0, ERADICATE_NULLABLE_DEREFERENCE, no_bucket, WARNING, [`ref.get()` is nullable and is not locally checked for null when calling `toString()`: call to PhantomReference.get() at line 27 (nullable according to nullsafe internal models).]
@ -198,7 +198,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, Linters_dummy_method, 1, ERADICATE_META_CLASS_NEEDS_FIXING, no_bucket, INFO, []
@ -229,7 +229,7 @@ codetoanalyze/java/nullsafe-default/NullMethodCall.java, codetoanalyze.java.null
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, []
@ -373,7 +373,7 @@ codetoanalyze/java/nullsafe-default/TrueFalseOnNull.java, Linters_dummy_method,
codetoanalyze/java/nullsafe-default/TrueFalseOnNull.java, Linters_dummy_method, 1, ERADICATE_META_CLASS_IS_CLEAN, no_bucket, INFO, []
codetoanalyze/java/nullsafe-default/TrueFalseOnNull.java, Linters_dummy_method, 1, ERADICATE_META_CLASS_IS_CLEAN, no_bucket, INFO, []
codetoanalyze/java/nullsafe-default/TrueFalseOnNull.java, Linters_dummy_method, 1, ERADICATE_META_CLASS_IS_CLEAN, no_bucket, INFO, []
codetoanalyze/java/nullsafe-default/TrueFalseOnNull.java, Linters_dummy_method, 1, ERADICATE_META_CLASS_IS_CLEAN, no_bucket, INFO, []
codetoanalyze/java/nullsafe-default/TrueFalseOnNull.java, Linters_dummy_method, 1, ERADICATE_META_CLASS_NEEDS_FIXING, no_bucket, INFO, []
codetoanalyze/java/nullsafe-default/TrueFalseOnNull.java, Linters_dummy_method, 1, ERADICATE_META_CLASS_NEEDS_FIXING, no_bucket, INFO, []
codetoanalyze/java/nullsafe-default/TrueFalseOnNull.java, Linters_dummy_method, 1, ERADICATE_META_CLASS_NEEDS_FIXING, no_bucket, INFO, []
codetoanalyze/java/nullsafe-default/TrueFalseOnNull.java, Linters_dummy_method, 1, ERADICATE_META_CLASS_NEEDS_FIXING, no_bucket, INFO, []

Loading…
Cancel
Save