@ -6,35 +6,12 @@
* )
* )
open ! IStd
open ! IStd
type violation = { nullsafe_mode : NullsafeMode . t ; base : Nullability . t ; overridden : Nullability . t }
type violation = { base : Nullability . t ; overridden : Nullability . t } [ @@ deriving compare ]
[ @@ deriving compare ]
type type_role = Param | Ret
type type_role = Param | Ret
let is_whitelisted_violation ~ subtype ~ supertype =
module ReportableViolation = struct
(* When both nullabilities are kind-of non-nullable we don't want to raise the
type t = { nullsafe_mode : NullsafeMode . t ; violation : violation }
issue . Without this suppression there will be a lot of non - actionable issues
raised for classes in one [ NullsafeMode ] inheriting from classes in the other
[ NullsafeMode ] . * )
(* TODO ( T62521386 ) : consider using caller context when determining nullability to get
rid of white - lists . * )
Nullability . is_nonnullish subtype && Nullability . is_nonnullish supertype
let check ~ nullsafe_mode type_role ~ base ~ overridden =
let subtype , supertype =
match type_role with
| Ret ->
(* covariance for ret *)
( overridden , base )
| Param ->
(* contravariance for param *)
( base , overridden )
in
Result . ok_if_true
( Nullability . is_subtype ~ subtype ~ supertype | | is_whitelisted_violation ~ subtype ~ supertype )
~ error : { nullsafe_mode ; base ; overridden }
type violation_type =
type violation_type =
| InconsistentParam of { param_description : string ; param_position : int }
| InconsistentParam of { param_description : string ; param_position : int }
@ -43,7 +20,9 @@ type violation_type =
let is_java_lang_object_equals = function
let is_java_lang_object_equals = function
| Procname . Java java_procname -> (
| Procname . Java java_procname -> (
match ( Procname . Java . get_class_name java_procname , Procname . Java . get_method java_procname ) with
match
( Procname . Java . get_class_name java_procname , Procname . Java . get_method java_procname )
with
| " java.lang.Object " , " equals " ->
| " java.lang.Object " , " equals " ->
true
true
| _ ->
| _ ->
@ -52,7 +31,7 @@ let is_java_lang_object_equals = function
false
false
let violation _description _ violation_type ~ base_proc_name ~ overridden_proc_name =
let get _description _ violation_type ~ base_proc_name ~ overridden_proc_name =
let module MF = MarkupFormatter in
let module MF = MarkupFormatter in
let base_method_descr = Procname . to_simplified_string ~ withclass : true base_proc_name in
let base_method_descr = Procname . to_simplified_string ~ withclass : true base_proc_name in
let overridden_method_descr =
let overridden_method_descr =
@ -84,12 +63,38 @@ let violation_description _ violation_type ~base_proc_name ~overridden_proc_name
string_of_int n ^ " th "
string_of_int n ^ " th "
in
in
Format . asprintf
Format . asprintf
" %s parameter %a of method %a is missing `@Nullable` declaration when overriding %a. The \
" %s parameter %a of method %a is missing `@Nullable` declaration when overriding %a. \
parent method declared it can handle ` null ` for this param , so the child should also \
The parent method declared it can handle ` null ` for this param , so the child should \
declare that . "
also declare that . "
( translate_position param_position )
( translate_position param_position )
MF . pp_monospaced param_description MF . pp_monospaced overridden_method_descr
MF . pp_monospaced param_description MF . pp_monospaced overridden_method_descr
MF . pp_monospaced base_method_descr
MF . pp_monospaced base_method_descr
let violation_severity { nullsafe_mode } = NullsafeMode . severity nullsafe_mode
let get_severity { nullsafe_mode } = NullsafeMode . severity nullsafe_mode
end
let check type_role ~ base ~ overridden =
let subtype , supertype =
match type_role with
| Ret ->
(* covariance for ret *)
( overridden , base )
| Param ->
(* contravariance for param *)
( base , overridden )
in
Result . ok_if_true ( Nullability . is_subtype ~ subtype ~ supertype ) ~ error : { base ; overridden }
let to_reportable_violation nullsafe_mode ( { base ; overridden } as violation ) =
if
Nullability . is_nonnullish base && Nullability . is_nonnullish overridden
(* When both nullabilities are kind-of non-nullable we don't want to raise the
issue . Without this suppression there will be a lot of non - actionable issues
raised for classes in one [ NullsafeMode ] inheriting from classes in the other
[ NullsafeMode ] . * )
(* TODO ( T62521386 ) : consider using caller context when determining nullability to get
rid of white - lists . * )
then None
else Some ReportableViolation . { nullsafe_mode ; violation }