[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_access : access -> access -> bool
val equal_access_list : access list -> access list -> bool
val pp : Format.formatter -> t -> unit

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

@ -21,40 +21,34 @@ let should_skip_var v =
module Access = struct
type t =
| Read of AccessPath.t
| Write of AccessPath.t
| ContainerRead of AccessPath.t * Typ.Procname.t
| ContainerWrite of AccessPath.t * Typ.Procname.t
| Read of {path: AccessPath.t; original: AccessPath.t}
| Write of {path: AccessPath.t; original: AccessPath.t}
| ContainerRead of {path: AccessPath.t; original: AccessPath.t; pname: Typ.Procname.t}
| ContainerWrite of {path: AccessPath.t; original: AccessPath.t; pname: Typ.Procname.t}
| InterfaceCall of Typ.Procname.t
[@@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 =
match (caller, callee) with
| Read ap1, Read ap2 | Write ap1, Write ap2 ->
suffix_matches ap1 ap2
| ContainerRead (ap1, pname1), ContainerRead (ap2, pname2)
| ContainerWrite (ap1, pname1), ContainerWrite (ap2, pname2) ->
Typ.Procname.equal pname1 pname2 && suffix_matches ap1 ap2
| Read {original= ap1}, Read {original= ap2} | Write {original= ap1}, Write {original= ap2} ->
AccessPath.equal ap1 ap2
| ContainerRead {original= ap1; pname= pname1}, ContainerRead {original= ap2; pname= pname2}
| ContainerWrite {original= ap1; pname= pname1}, ContainerWrite {original= ap2; pname= pname2}
->
Typ.Procname.equal pname1 pname2 && AccessPath.equal ap1 ap2
| InterfaceCall pname1, InterfaceCall pname2 ->
Typ.Procname.equal pname1 pname2
| _ ->
false
let make_field_access access_path ~is_write =
if is_write then Write access_path else Read access_path
let make_field_access path ~is_write =
if is_write then Write {path; original= path} else Read {path; original= path}
let make_container_access access_path pname ~is_write =
if is_write then ContainerWrite (access_path, pname) else ContainerRead (access_path, pname)
let make_container_access path pname ~is_write =
if is_write then ContainerWrite {path; original= path; pname}
else ContainerRead {path; original= path; pname}
let is_write = function
@ -72,38 +66,39 @@ module Access = struct
let get_access_path = function
| Read access_path
| Write access_path
| ContainerWrite (access_path, _)
| ContainerRead (access_path, _) ->
Some access_path
| Read {path} | Write {path} | ContainerWrite {path} | ContainerRead {path} ->
Some path
| InterfaceCall _ ->
None
let map ~f = function
| Read access_path ->
Read (f access_path)
| Write access_path ->
Write (f access_path)
| ContainerWrite (access_path, pname) ->
ContainerWrite (f access_path, pname)
| ContainerRead (access_path, pname) ->
ContainerRead (f access_path, pname)
let map ~f access =
match access with
| Read ({path} as record) ->
let path' = f path in
if phys_equal path path' then access else Read {record with path= path'}
| Write ({path} as record) ->
let path' = f path in
if phys_equal path path' then access else Write {record with path= path'}
| 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 ->
intfcall
let pp fmt = function
| Read access_path ->
F.fprintf fmt "Read of %a" AccessPath.pp access_path
| Write access_path ->
F.fprintf fmt "Write to %a" AccessPath.pp access_path
| ContainerRead (access_path, pname) ->
F.fprintf fmt "Read of container %a via %a" AccessPath.pp access_path Typ.Procname.pp pname
| ContainerWrite (access_path, pname) ->
F.fprintf fmt "Write to container %a via %a" AccessPath.pp access_path Typ.Procname.pp
pname
| Read {path} ->
F.fprintf fmt "Read of %a" AccessPath.pp path
| Write {path} ->
F.fprintf fmt "Write to %a" AccessPath.pp path
| ContainerRead {path; pname} ->
F.fprintf fmt "Read of container %a via %a" AccessPath.pp path Typ.Procname.pp pname
| ContainerWrite {path; pname} ->
F.fprintf fmt "Write to container %a via %a" AccessPath.pp path Typ.Procname.pp pname
| InterfaceCall pname ->
F.fprintf fmt "Call to un-annotated interface method %a" Typ.Procname.pp pname
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 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
type nonrec t = t

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

Loading…
Cancel
Save