You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
60 lines
2.7 KiB
60 lines
2.7 KiB
5 years ago
|
(*
|
||
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
||
|
*
|
||
|
* This source code is licensed under the MIT license found in the
|
||
|
* LICENSE file in the root directory of this source tree.
|
||
|
*)
|
||
|
|
||
|
open! IStd
|
||
|
|
||
|
let is_object_nullability_self_explanatory ~object_expression object_origin =
|
||
|
(* Fundamentally, object can be of two kinds:
|
||
|
1. Indirect: local variable that was instantiated before.
|
||
|
In this case, normally origin is NOT trivial
|
||
|
(because for complex flows it might be tricky to figure out where the offending
|
||
|
initialization came from, and it is a good idea to at least point to the line).
|
||
|
2. Direct: some sort of expression. In this case, this expression itself is often
|
||
|
self-explanatory and it is OK to be offended.Infer
|
||
|
NOTE: code below is heuristic, it indends to cover most practical cases and does not try
|
||
|
to be 100% precise.
|
||
|
*)
|
||
|
match object_origin with
|
||
|
| TypeOrigin.NullConst _ ->
|
||
|
(* Expect either a local variable or null literal (latter case is trivial) *)
|
||
|
String.equal object_expression "null"
|
||
|
| TypeOrigin.MethodParameter {mangled} ->
|
||
|
(* Either local variable or literally parameter. In latter case, its nullability is
|
||
|
self-explanatory because the user can quickly see the current method signature.
|
||
|
*)
|
||
|
let param_name = Mangled.to_string mangled in
|
||
|
String.equal object_expression param_name
|
||
|
| TypeOrigin.Field {field_name} ->
|
||
|
(* Either local variable or expression like `<smth>.field_name`. Latter case is trivial:
|
||
|
the user can quickly go to field_name definition and see if its annotation. *)
|
||
|
let field_name_str = Typ.Fieldname.to_flat_string field_name in
|
||
|
String.is_suffix object_expression ~suffix:field_name_str
|
||
|
| TypeOrigin.MethodCall {pname} ->
|
||
|
(* TODO: take into account external models as well *)
|
||
|
let is_modelled = Models.is_modelled_for_nullability_as_internal pname in
|
||
|
if is_modelled then (* This is non-trivial and should always be explained to the user *)
|
||
|
false
|
||
|
else
|
||
|
(* Either local variable or expression like <smth>.method_name(...).
|
||
|
Latter case is self-explanatory: it is easy to the user to jump to definition
|
||
|
and check out the method annotation.
|
||
|
*)
|
||
|
let method_name = Typ.Procname.to_simplified_string pname in
|
||
|
String.is_suffix object_expression ~suffix:method_name
|
||
|
(* These cases are not yet supported because they normally mean non-nullable case, for which
|
||
|
we don't render important messages yet.
|
||
|
*)
|
||
|
| TypeOrigin.NonnullConst _
|
||
|
| TypeOrigin.This
|
||
|
| TypeOrigin.New
|
||
|
| TypeOrigin.ArrayLengthResult
|
||
|
| TypeOrigin.ArrayAccess
|
||
|
| TypeOrigin.InferredNonnull _
|
||
|
| TypeOrigin.OptimisticFallback
|
||
|
| TypeOrigin.Undef ->
|
||
|
false
|