[racerd] more precise trace expansion

Reviewed By: mbouaziz

Differential Revision: D13232424

fbshipit-source-id: 9489a319c
master
Nikos Gorogiannis 6 years ago committed by Facebook Github Bot
parent f70d6da8f2
commit 31653ca6c3

@ -74,8 +74,6 @@ val equal : t -> t -> bool
val equal_base : base -> base -> bool val equal_base : base -> base -> bool
val equal_access : access -> access -> bool
val equal_access_list : access list -> access list -> bool val equal_access_list : access list -> access list -> bool
val pp : Format.formatter -> t -> unit val pp : Format.formatter -> t -> unit

@ -229,8 +229,9 @@ module TransferFunctions (CFG : ProcCfg.S) = struct
path path
in in
let expand_precondition (snapshot : AccessSnapshot.t) = let expand_precondition (snapshot : AccessSnapshot.t) =
let access = TraceElem.map ~f:expand_path snapshot.access in let access' = TraceElem.map ~f:expand_path snapshot.access in
AccessSnapshot.make_from_snapshot access snapshot if phys_equal snapshot.access access' then snapshot
else AccessSnapshot.make_from_snapshot access' snapshot
in in
AccessDomain.map expand_precondition accesses AccessDomain.map expand_precondition accesses
@ -781,10 +782,10 @@ let pp_container_access fmt (access_path, access_pname) =
let pp_access fmt sink = let pp_access fmt sink =
match RacerDDomain.PathDomain.Sink.kind sink with match RacerDDomain.PathDomain.Sink.kind sink with
| Read access_path | Write access_path -> | Read {path} | Write {path} ->
(MF.wrap_monospaced AccessPath.pp) fmt access_path (MF.wrap_monospaced AccessPath.pp) fmt path
| ContainerRead (access_path, access_pname) | ContainerWrite (access_path, access_pname) -> | ContainerRead {path; pname} | ContainerWrite {path; pname} ->
pp_container_access fmt (access_path, access_pname) pp_container_access fmt (path, pname)
| InterfaceCall _ as access -> | InterfaceCall _ as access ->
RacerDDomain.Access.pp fmt access RacerDDomain.Access.pp fmt access
@ -796,13 +797,13 @@ let desc_of_sink sink =
if Typ.Procname.equal sink_pname Typ.Procname.empty_block then if Typ.Procname.equal sink_pname Typ.Procname.empty_block then
F.asprintf "access to %a" pp_access sink F.asprintf "access to %a" pp_access sink
else F.asprintf "call to %a" Typ.Procname.pp sink_pname else F.asprintf "call to %a" Typ.Procname.pp sink_pname
| ContainerRead (access_path, access_pname) -> | ContainerRead {path; pname} ->
if Typ.Procname.equal sink_pname access_pname then if Typ.Procname.equal sink_pname pname then
F.asprintf "Read of %a" pp_container_access (access_path, access_pname) F.asprintf "Read of %a" pp_container_access (path, pname)
else F.asprintf "call to %a" Typ.Procname.pp sink_pname else F.asprintf "call to %a" Typ.Procname.pp sink_pname
| ContainerWrite (access_path, access_pname) -> | ContainerWrite {path; pname} ->
if Typ.Procname.equal sink_pname access_pname then if Typ.Procname.equal sink_pname pname then
F.asprintf "Write to %a" pp_container_access (access_path, access_pname) F.asprintf "Write to %a" pp_container_access (path, pname)
else F.asprintf "call to %a" Typ.Procname.pp sink_pname else F.asprintf "call to %a" Typ.Procname.pp sink_pname
| InterfaceCall _ as access -> | InterfaceCall _ as access ->
if Typ.Procname.equal sink_pname Typ.Procname.empty_block then if Typ.Procname.equal sink_pname Typ.Procname.empty_block then
@ -1007,10 +1008,10 @@ end = struct
let of_access (access : RacerDDomain.Access.t) = let of_access (access : RacerDDomain.Access.t) =
match access with match access with
| Read ap | Write ap -> | Read {path} | Write {path} ->
Location ap Location path
| ContainerRead (ap, _) | ContainerWrite (ap, _) -> | ContainerRead {path} | ContainerWrite {path} ->
Container ap Container path
| InterfaceCall pn -> | InterfaceCall pn ->
Call pn Call pn
end end

@ -21,40 +21,34 @@ let should_skip_var v =
module Access = struct module Access = struct
type t = type t =
| Read of AccessPath.t | Read of {path: AccessPath.t; original: AccessPath.t}
| Write of AccessPath.t | Write of {path: AccessPath.t; original: AccessPath.t}
| ContainerRead of AccessPath.t * Typ.Procname.t | ContainerRead of {path: AccessPath.t; original: AccessPath.t; pname: Typ.Procname.t}
| ContainerWrite of AccessPath.t * Typ.Procname.t | ContainerWrite of {path: AccessPath.t; original: AccessPath.t; pname: Typ.Procname.t}
| InterfaceCall of Typ.Procname.t | InterfaceCall of Typ.Procname.t
[@@deriving compare] [@@deriving compare]
let suffix_matches (_, accesses1) (_, accesses2) =
match (List.rev accesses1, List.rev accesses2) with
| access1 :: _, access2 :: _ ->
AccessPath.equal_access access1 access2
| _ ->
false
let matches ~caller ~callee = let matches ~caller ~callee =
match (caller, callee) with match (caller, callee) with
| Read ap1, Read ap2 | Write ap1, Write ap2 -> | Read {original= ap1}, Read {original= ap2} | Write {original= ap1}, Write {original= ap2} ->
suffix_matches ap1 ap2 AccessPath.equal ap1 ap2
| ContainerRead (ap1, pname1), ContainerRead (ap2, pname2) | ContainerRead {original= ap1; pname= pname1}, ContainerRead {original= ap2; pname= pname2}
| ContainerWrite (ap1, pname1), ContainerWrite (ap2, pname2) -> | ContainerWrite {original= ap1; pname= pname1}, ContainerWrite {original= ap2; pname= pname2}
Typ.Procname.equal pname1 pname2 && suffix_matches ap1 ap2 ->
Typ.Procname.equal pname1 pname2 && AccessPath.equal ap1 ap2
| InterfaceCall pname1, InterfaceCall pname2 -> | InterfaceCall pname1, InterfaceCall pname2 ->
Typ.Procname.equal pname1 pname2 Typ.Procname.equal pname1 pname2
| _ -> | _ ->
false false
let make_field_access access_path ~is_write = let make_field_access path ~is_write =
if is_write then Write access_path else Read access_path if is_write then Write {path; original= path} else Read {path; original= path}
let make_container_access access_path pname ~is_write = let make_container_access path pname ~is_write =
if is_write then ContainerWrite (access_path, pname) else ContainerRead (access_path, pname) if is_write then ContainerWrite {path; original= path; pname}
else ContainerRead {path; original= path; pname}
let is_write = function let is_write = function
@ -72,38 +66,39 @@ module Access = struct
let get_access_path = function let get_access_path = function
| Read access_path | Read {path} | Write {path} | ContainerWrite {path} | ContainerRead {path} ->
| Write access_path Some path
| ContainerWrite (access_path, _)
| ContainerRead (access_path, _) ->
Some access_path
| InterfaceCall _ -> | InterfaceCall _ ->
None None
let map ~f = function let map ~f access =
| Read access_path -> match access with
Read (f access_path) | Read ({path} as record) ->
| Write access_path -> let path' = f path in
Write (f access_path) if phys_equal path path' then access else Read {record with path= path'}
| ContainerWrite (access_path, pname) -> | Write ({path} as record) ->
ContainerWrite (f access_path, pname) let path' = f path in
| ContainerRead (access_path, pname) -> if phys_equal path path' then access else Write {record with path= path'}
ContainerRead (f access_path, pname) | ContainerWrite ({path} as record) ->
let path' = f path in
if phys_equal path path' then access else ContainerWrite {record with path= path'}
| ContainerRead ({path} as record) ->
let path' = f path in
if phys_equal path path' then access else ContainerRead {record with path= path'}
| InterfaceCall _ as intfcall -> | InterfaceCall _ as intfcall ->
intfcall intfcall
let pp fmt = function let pp fmt = function
| Read access_path -> | Read {path} ->
F.fprintf fmt "Read of %a" AccessPath.pp access_path F.fprintf fmt "Read of %a" AccessPath.pp path
| Write access_path -> | Write {path} ->
F.fprintf fmt "Write to %a" AccessPath.pp access_path F.fprintf fmt "Write to %a" AccessPath.pp path
| ContainerRead (access_path, pname) -> | ContainerRead {path; pname} ->
F.fprintf fmt "Read of container %a via %a" AccessPath.pp access_path Typ.Procname.pp pname F.fprintf fmt "Read of container %a via %a" AccessPath.pp path Typ.Procname.pp pname
| ContainerWrite (access_path, pname) -> | ContainerWrite {path; pname} ->
F.fprintf fmt "Write to container %a via %a" AccessPath.pp access_path Typ.Procname.pp F.fprintf fmt "Write to container %a via %a" AccessPath.pp path Typ.Procname.pp pname
pname
| InterfaceCall pname -> | InterfaceCall pname ->
F.fprintf fmt "Call to un-annotated interface method %a" Typ.Procname.pp pname F.fprintf fmt "Call to un-annotated interface method %a" Typ.Procname.pp pname
end end
@ -127,7 +122,10 @@ module TraceElem = struct
let pp fmt {site; kind} = F.fprintf fmt "%a at %a" Access.pp kind CallSite.pp site let pp fmt {site; kind} = F.fprintf fmt "%a at %a" Access.pp kind CallSite.pp site
let map ~f {site; kind} = {site; kind= Access.map ~f kind} let map ~f ({kind} as elem) =
let kind' = Access.map ~f kind in
if phys_equal kind kind' then elem else {elem with kind= kind'}
module Set = PrettyPrintable.MakePPSet (struct module Set = PrettyPrintable.MakePPSet (struct
type nonrec t = t type nonrec t = t

@ -9,13 +9,18 @@ open! IStd
module F = Format module F = Format
module Access : sig module Access : sig
type t = private (** Below [original] is the path used to create the access.
| Read of AccessPath.t (** Field or array read *) [path] may differ from [original] because of substitution of actuals *)
| Write of AccessPath.t (** Field or array write *) type t =
| ContainerRead of AccessPath.t * Typ.Procname.t (** Read of container object *) | Read of {path: AccessPath.t; original: AccessPath.t} (** Field or array read *)
| ContainerWrite of AccessPath.t * Typ.Procname.t (** Write to container object *) | Write of {path: AccessPath.t; original: AccessPath.t} (** Field or array write *)
| ContainerRead of {path: AccessPath.t; original: AccessPath.t; pname: Typ.Procname.t}
(** Read of container object *)
| ContainerWrite of {path: AccessPath.t; original: AccessPath.t; pname: Typ.Procname.t}
(** Write to container object *)
| InterfaceCall of Typ.Procname.t | InterfaceCall of Typ.Procname.t
(** Call to method of interface not annotated with @ThreadSafe *) (** Call to method of interface not annotated with @ThreadSafe *)
[@@deriving compare]
include PrettyPrintable.PrintableOrderedType with type t := t include PrettyPrintable.PrintableOrderedType with type t := t

Loading…
Cancel
Save