[litho] Add a domain for created locations

Summary: This adds a  map from access expressions to locations where specific object is created by `create` method call.

Reviewed By: ezgicicek

Differential Revision: D18779985

fbshipit-source-id: f327450cd
master
Sungkeun Cho 5 years ago committed by Facebook Github Bot
parent f16534f390
commit 060a0914ba

@ -40,31 +40,59 @@ module CallSet = AbstractDomain.FiniteSet (MethodCall)
module OldDomain = AbstractDomain.Map (LocalAccessPath) (CallSet) module OldDomain = AbstractDomain.Map (LocalAccessPath) (CallSet)
module NewDomain = struct module NewDomain = struct
include AbstractDomain.Empty module CreatedLocation = struct
type t = Location.t [@@deriving compare]
let pp fmt location = F.fprintf fmt "Created at %a" Location.pp location
end
module CreatedLocations = AbstractDomain.InvertedSet (CreatedLocation)
module Created = struct
include AbstractDomain.InvertedMap (LocalAccessPath) (CreatedLocations)
let lookup k x = Option.value (find_opt k x) ~default:CreatedLocations.empty
end
include Created
let assign ~lhs ~rhs x = Created.add lhs (Created.lookup rhs x) x
let call_create lhs location x = Created.add lhs (CreatedLocations.singleton location) x
let call_builder ~ret ~receiver x = Created.add ret (Created.lookup receiver x) x
end end
include struct include struct
include AbstractDomain.Pair (OldDomain) (NewDomain) include AbstractDomain.Pair (OldDomain) (NewDomain)
let lift f (o, _) = f o let lift_old f (o, _) = f o
let map_old f (o, n) = (f o, n) let map_old f (o, n) = (f o, n)
let empty = (OldDomain.empty, ()) let map_new f (o, n) = (o, f n)
let empty = (OldDomain.empty, NewDomain.empty)
let add k v = map_old (OldDomain.add k v) let add k v = map_old (OldDomain.add k v)
let remove k = map_old (OldDomain.remove k) let remove k = map_old (OldDomain.remove k)
let bindings = lift OldDomain.bindings let bindings = lift_old OldDomain.bindings
let find k = lift (OldDomain.find k) let find k = lift_old (OldDomain.find k)
let mem k = lift (OldDomain.mem k) let mem k = lift_old (OldDomain.mem k)
let iter f = lift (OldDomain.iter f) let iter f = lift_old (OldDomain.iter f)
let fold f (o, _) init = OldDomain.fold f o init let fold f (o, _) init = OldDomain.fold f o init
let assign ~lhs ~rhs = map_new (NewDomain.assign ~lhs ~rhs)
let call_create ret location = map_new (NewDomain.call_create ret location)
let call_builder ~ret ~receiver = map_new (NewDomain.call_builder ~ret ~receiver)
end end
let substitute ~(f_sub : LocalAccessPath.t -> LocalAccessPath.t option) astate = let substitute ~(f_sub : LocalAccessPath.t -> LocalAccessPath.t option) astate =

@ -33,7 +33,7 @@ module CallSet : module type of AbstractDomain.FiniteSet (MethodCall)
module OldDomain : module type of AbstractDomain.Map (LocalAccessPath) (CallSet) module OldDomain : module type of AbstractDomain.Map (LocalAccessPath) (CallSet)
module NewDomain : module type of AbstractDomain.Empty module NewDomain : AbstractDomain.S
include module type of AbstractDomain.Pair (OldDomain) (NewDomain) include module type of AbstractDomain.Pair (OldDomain) (NewDomain)
@ -49,6 +49,12 @@ val find : LocalAccessPath.t -> t -> CallSet.t
val bindings : t -> (LocalAccessPath.t * CallSet.t) list val bindings : t -> (LocalAccessPath.t * CallSet.t) list
val assign : lhs:LocalAccessPath.t -> rhs:LocalAccessPath.t -> t -> t
val call_create : LocalAccessPath.t -> Location.t -> t -> t
val call_builder : ret:LocalAccessPath.t -> receiver:LocalAccessPath.t -> t -> t
val substitute : f_sub:(LocalAccessPath.t -> LocalAccessPath.t option) -> t -> t val substitute : f_sub:(LocalAccessPath.t -> LocalAccessPath.t option) -> t -> t
(** Substitute each access path in the domain using [f_sub]. If [f_sub] returns None, the original (** Substitute each access path in the domain using [f_sub]. If [f_sub] returns None, the original
access path is retained; otherwise, the new one is used *) access path is retained; otherwise, the new one is used *)

@ -137,7 +137,12 @@ struct
(try Domain.find return_access_path astate with Caml.Not_found -> Domain.CallSet.empty) (try Domain.find return_access_path astate with Caml.Not_found -> Domain.CallSet.empty)
|> Domain.CallSet.add (Domain.MethodCall.make receiver callee_pname location) |> Domain.CallSet.add (Domain.MethodCall.make receiver callee_pname location)
in in
Domain.add return_access_path return_calls astate let astate = Domain.add return_access_path return_calls astate in
if is_component_create_method callee_pname tenv then
Domain.call_create return_access_path location astate
else if is_component_builder callee_pname tenv then
Domain.call_builder ~ret:return_access_path ~receiver astate
else astate
else else
(* treat it like a normal call *) (* treat it like a normal call *)
apply_callee_summary callee_summary_opt caller_pname return_base actuals astate apply_callee_summary callee_summary_opt caller_pname return_base actuals astate
@ -146,7 +151,7 @@ struct
Payload.read ~caller_summary:summary ~callee_pname:callee_procname Payload.read ~caller_summary:summary ~callee_pname:callee_procname
in in
apply_callee_summary callee_summary_opt caller_pname ret_id_typ actuals astate apply_callee_summary callee_summary_opt caller_pname ret_id_typ actuals astate
| Assign (lhs_ae, HilExp.AccessExpression rhs_ae, _) -> ( | Assign (lhs_ae, HilExp.AccessExpression rhs_ae, _) ->
(* creating an alias for the rhs binding; assume all reads will now occur through the (* creating an alias for the rhs binding; assume all reads will now occur through the
alias. this helps us keep track of chains in cases like tmp = getFoo(); x = tmp; alias. this helps us keep track of chains in cases like tmp = getFoo(); x = tmp;
tmp.getBar() *) tmp.getBar() *)
@ -156,10 +161,13 @@ struct
let rhs_access_path = let rhs_access_path =
Domain.LocalAccessPath.make (HilExp.AccessExpression.to_access_path rhs_ae) caller_pname Domain.LocalAccessPath.make (HilExp.AccessExpression.to_access_path rhs_ae) caller_pname
in in
let astate =
try try
let call_set = Domain.find rhs_access_path astate in let call_set = Domain.find rhs_access_path astate in
Domain.remove rhs_access_path astate |> Domain.add lhs_access_path call_set Domain.remove rhs_access_path astate |> Domain.add lhs_access_path call_set
with Caml.Not_found -> astate ) with Caml.Not_found -> astate
in
Domain.assign ~lhs:lhs_access_path ~rhs:rhs_access_path astate
| _ -> | _ ->
astate astate

Loading…
Cancel
Save