diff --git a/infer/src/checkers/LithoDomain.ml b/infer/src/checkers/LithoDomain.ml index 8f7fb9bb8..0a0c25115 100644 --- a/infer/src/checkers/LithoDomain.ml +++ b/infer/src/checkers/LithoDomain.ml @@ -45,6 +45,34 @@ module MethodCall = struct let procname_to_string {procname} = Typ.Procname.get_method procname end +module MethodCallPrefix = struct + type t = + { (* TODO: We can remove the [receiver] field after we replace the old checker *) + receiver: LocalAccessPath.t [@compare.ignore] + ; prefix: string + ; procname: Typ.Procname.t [@compare.ignore] + ; location: Location.t [@compare.ignore] } + [@@deriving compare] + + let make receiver procname location = + let method_name = Typ.Procname.get_method procname in + let prefix_opt = + String.Set.find_map suffixes ~f:(fun suffix -> String.chop_suffix method_name ~suffix) + in + let prefix = Option.value prefix_opt ~default:method_name in + {receiver; prefix; procname; location} + + + let pp fmt {receiver; procname} = + F.fprintf fmt "%a.%a" LocalAccessPath.pp receiver Typ.Procname.pp procname + + + let procname_to_string {procname} = Typ.Procname.get_method procname + + (* NOTE: This is only for sharing some code with the previous version of the checker. *) + let to_method_call {receiver; procname; location} = MethodCall.make receiver procname location +end + module CallSet = AbstractDomain.FiniteSet (MethodCall) module OldDomain = AbstractDomain.Map (LocalAccessPath) (CallSet) @@ -66,42 +94,7 @@ module NewDomain = struct module MethodCalls = struct module IsBuildMethodCalled = AbstractDomain.BooleanAnd - - module S = AbstractDomain.InvertedSet (struct - include MethodCall - - let compare_procname p1 p2 = - let chopped_opt pname = - let method_name = Typ.Procname.get_method pname in - String.Set.find_map suffixes ~f:(fun suffix -> String.chop_suffix method_name ~suffix) - in - let replace_both s p = - match p with - | Typ.Procname.Java java_pname -> - (* This is a bit of a hack to quickly compare based on only - method names *) - Typ.Procname.Java - ( Typ.Procname.Java.replace_method_name s java_pname - |> Typ.Procname.Java.replace_parameters [] ) - | _ -> - p - in - let p1, p2 = - match (chopped_opt p1, chopped_opt p2) with - | Some chopped1, Some chopped2 -> - (replace_both chopped1 p1, replace_both chopped2 p2) - | Some chopped1, None -> - (replace_both chopped1 p1, Typ.Procname.replace_parameters [] p2) - | None, Some chopped2 -> - (Typ.Procname.replace_parameters [] p1, replace_both chopped2 p2) - | _ -> - (p1, p2) - in - Typ.Procname.compare p1 p2 - - - let compare x y = compare_procname x.procname y.procname - end) + module S = AbstractDomain.InvertedSet (MethodCallPrefix) type t = {is_build_method_called: IsBuildMethodCalled.t; method_calls: S.t} @@ -140,7 +133,7 @@ module NewDomain = struct let to_string_set method_calls = let accum_as_string method_call acc = - String.Set.add acc (MethodCall.procname_to_string method_call) + String.Set.add acc (MethodCallPrefix.procname_to_string method_call) in S.fold accum_as_string method_calls String.Set.empty diff --git a/infer/src/checkers/LithoDomain.mli b/infer/src/checkers/LithoDomain.mli index dd6338ee4..c7c43eb4e 100644 --- a/infer/src/checkers/LithoDomain.mli +++ b/infer/src/checkers/LithoDomain.mli @@ -35,6 +35,18 @@ module MethodCall : sig val procname_to_string : t -> string end +module MethodCallPrefix : sig + type t + + val make : LocalAccessPath.t -> Typ.Procname.t -> Location.t -> t + + val pp : F.formatter -> t -> unit + + val procname_to_string : t -> string + + val to_method_call : t -> MethodCall.t +end + module CallSet : module type of AbstractDomain.FiniteSet (MethodCall) module OldDomain : module type of AbstractDomain.Map (LocalAccessPath) (CallSet) @@ -60,18 +72,19 @@ val assign : lhs:LocalAccessPath.t -> rhs:LocalAccessPath.t -> t -> t val call_create : LocalAccessPath.t -> Typ.name -> Location.t -> t -> t (** Semantics of builder creation method *) -val call_builder : ret:LocalAccessPath.t -> receiver:LocalAccessPath.t -> MethodCall.t -> t -> t +val call_builder : + ret:LocalAccessPath.t -> receiver:LocalAccessPath.t -> MethodCallPrefix.t -> t -> t (** Semantics of builder's methods, e.g. [prop] *) val call_build_method : ret:LocalAccessPath.t -> receiver:LocalAccessPath.t -> t -> t (** Semantics of builder's final build method *) val check_required_props : - check_on_string_set:(Typ.name -> MethodCall.t list -> String.Set.t -> unit) -> t -> unit + check_on_string_set:(Typ.name -> MethodCallPrefix.t list -> String.Set.t -> unit) -> t -> unit val check_required_props_of_receiver : pname:Typ.Procname.t - -> check_on_string_set:(Typ.name -> MethodCall.t list -> String.Set.t -> unit) + -> check_on_string_set:(Typ.name -> MethodCallPrefix.t list -> String.Set.t -> unit) -> HilExp.access_expression -> t -> unit diff --git a/infer/src/checkers/LithoFramework.ml b/infer/src/checkers/LithoFramework.ml index 4ecd9a0e1..cae7cca17 100644 --- a/infer/src/checkers/LithoFramework.ml +++ b/infer/src/checkers/LithoFramework.ml @@ -175,7 +175,8 @@ struct | _ -> astate else if is_component_builder callee_pname tenv then - Domain.call_builder ~ret:return_access_path ~receiver callee astate + let callee_prefix = Domain.MethodCallPrefix.make receiver callee_pname location in + Domain.call_builder ~ret:return_access_path ~receiver callee_prefix astate else astate else (* treat it like a normal call *) diff --git a/infer/src/checkers/RequiredProps.ml b/infer/src/checkers/RequiredProps.ml index 8829e0122..7d773d26c 100644 --- a/infer/src/checkers/RequiredProps.ml +++ b/infer/src/checkers/RequiredProps.ml @@ -160,6 +160,11 @@ module LithoContext = struct (Summary.get_loc summary) call_chain ) + let check_on_string_set_prefix tenv summary parent_typename call_chain_prefix prop_set = + let call_chain = List.map call_chain_prefix ~f:Domain.MethodCallPrefix.to_method_call in + check_on_string_set tenv summary parent_typename call_chain prop_set + + let report_on_post astate tenv summary = let check_required_prop_chain _ call_chain = let call_chain = @@ -184,7 +189,10 @@ module LithoContext = struct | _ -> () in - Domain.iter_call_chains ~f:check_required_prop_chain astate + if Config.new_litho_domain then + let check_on_string_set_prefix = check_on_string_set_prefix tenv summary in + Domain.check_required_props ~check_on_string_set:check_on_string_set_prefix astate + else Domain.iter_call_chains ~f:check_required_prop_chain astate let report_on_inv_map ~inv_map_iter tenv summary = @@ -202,10 +210,11 @@ module LithoContext = struct None ) in let pname = Summary.get_proc_name summary in - let check_on_string_set = check_on_string_set tenv summary in + let check_on_string_set_prefix = check_on_string_set_prefix tenv summary in inv_map_iter ~f:(fun instrs astate -> Option.iter (find_return_instr instrs) ~f:(fun receiver -> - Domain.check_required_props_of_receiver ~pname ~check_on_string_set receiver astate ) ) + Domain.check_required_props_of_receiver ~pname + ~check_on_string_set:check_on_string_set_prefix receiver astate ) ) let session_name = "litho required props"