Summary: Move the biabduction-specific payloads (the "`'a spec`" stuff) from specs.ml into a new `BiabductinoSummary` module, similar to other checkers. Reviewed By: ngorogiannis Differential Revision: D7935815 fbshipit-source-id: bdff3b9master
parent
766a16cd90
commit
d207f29287
@ -0,0 +1,301 @@
|
|||||||
|
(*
|
||||||
|
* Copyright (c) 2018 - present Facebook, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the BSD style license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree. An additional grant
|
||||||
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
|
*)
|
||||||
|
|
||||||
|
open! IStd
|
||||||
|
|
||||||
|
(** Specifications and spec table *)
|
||||||
|
|
||||||
|
module L = Logging
|
||||||
|
module F = Format
|
||||||
|
|
||||||
|
(** Module for joined props *)
|
||||||
|
module Jprop = struct
|
||||||
|
(** type aliases for component of t values that compare should ignore *)
|
||||||
|
type id_ = int
|
||||||
|
|
||||||
|
let compare_id_ _ _ = 0
|
||||||
|
|
||||||
|
(** Remember when a prop is obtained as the join of two other props; the first parameter is an id *)
|
||||||
|
type 'a t = Prop of id_ * 'a Prop.t | Joined of id_ * 'a Prop.t * 'a t * 'a t
|
||||||
|
[@@deriving compare]
|
||||||
|
|
||||||
|
(** Comparison for joined_prop *)
|
||||||
|
let compare jp1 jp2 = compare (fun _ _ -> 0) jp1 jp2
|
||||||
|
|
||||||
|
(** Return true if the two join_prop's are equal *)
|
||||||
|
let equal jp1 jp2 = Int.equal (compare jp1 jp2) 0
|
||||||
|
|
||||||
|
let to_prop = function Prop (_, p) -> p | Joined (_, p, _, _) -> p
|
||||||
|
|
||||||
|
let rec sorted_gen_free_vars tenv =
|
||||||
|
let open Sequence.Generator in
|
||||||
|
function
|
||||||
|
| Prop (_, p) ->
|
||||||
|
Prop.dfs_sort tenv p |> Prop.sorted_gen_free_vars
|
||||||
|
| Joined (_, p, jp1, jp2) ->
|
||||||
|
Prop.dfs_sort tenv p |> Prop.sorted_gen_free_vars
|
||||||
|
>>= fun () -> sorted_gen_free_vars tenv jp1 >>= fun () -> sorted_gen_free_vars tenv jp2
|
||||||
|
|
||||||
|
|
||||||
|
let rec normalize tenv = function
|
||||||
|
| Prop (n, p) ->
|
||||||
|
Prop (n, Prop.normalize tenv p)
|
||||||
|
| Joined (n, p, jp1, jp2) ->
|
||||||
|
Joined (n, Prop.normalize tenv p, normalize tenv jp1, normalize tenv jp2)
|
||||||
|
|
||||||
|
|
||||||
|
(** Return a compact representation of the jprop *)
|
||||||
|
let rec compact sh = function
|
||||||
|
| Prop (n, p) ->
|
||||||
|
Prop (n, Prop.prop_compact sh p)
|
||||||
|
| Joined (n, p, jp1, jp2) ->
|
||||||
|
Joined (n, Prop.prop_compact sh p, compact sh jp1, compact sh jp2)
|
||||||
|
|
||||||
|
|
||||||
|
(** Print the toplevel prop *)
|
||||||
|
let pp_short pe f jp = Prop.pp_prop pe f (to_prop jp)
|
||||||
|
|
||||||
|
(** Dump the toplevel prop *)
|
||||||
|
let d_shallow (jp: Prop.normal t) = L.add_print_action (L.PTjprop_short, Obj.repr jp)
|
||||||
|
|
||||||
|
(** Get identifies of the jprop *)
|
||||||
|
let get_id = function Prop (n, _) -> n | Joined (n, _, _, _) -> n
|
||||||
|
|
||||||
|
(** Print a list of joined props, the boolean indicates whether to print subcomponents of joined props *)
|
||||||
|
let pp_list pe shallow f jplist =
|
||||||
|
let rec pp_seq_newline f = function
|
||||||
|
| [] ->
|
||||||
|
()
|
||||||
|
| [Prop (n, p)] ->
|
||||||
|
F.fprintf f "PROP %d:@\n%a" n (Prop.pp_prop pe) p
|
||||||
|
| [Joined (n, p, p1, p2)] ->
|
||||||
|
if not shallow then F.fprintf f "%a@\n" pp_seq_newline [p1] ;
|
||||||
|
if not shallow then F.fprintf f "%a@\n" pp_seq_newline [p2] ;
|
||||||
|
F.fprintf f "PROP %d (join of %d,%d):@\n%a" n (get_id p1) (get_id p2) (Prop.pp_prop pe) p
|
||||||
|
| jp :: l ->
|
||||||
|
F.fprintf f "%a@\n" pp_seq_newline [jp] ;
|
||||||
|
pp_seq_newline f l
|
||||||
|
in
|
||||||
|
pp_seq_newline f jplist
|
||||||
|
|
||||||
|
|
||||||
|
(** dump a joined prop list, the boolean indicates whether to print toplevel props only *)
|
||||||
|
let d_list (shallow: bool) (jplist: Prop.normal t list) =
|
||||||
|
L.add_print_action (L.PTjprop_list, Obj.repr (shallow, jplist))
|
||||||
|
|
||||||
|
|
||||||
|
let rec gen_free_vars =
|
||||||
|
let open Sequence.Generator in
|
||||||
|
function
|
||||||
|
| Prop (_, p) ->
|
||||||
|
Prop.gen_free_vars p
|
||||||
|
| Joined (_, p, jp1, jp2) ->
|
||||||
|
Prop.gen_free_vars p >>= fun () -> gen_free_vars jp1 >>= fun () -> gen_free_vars jp2
|
||||||
|
|
||||||
|
|
||||||
|
let free_vars jp = Sequence.Generator.run (gen_free_vars jp)
|
||||||
|
|
||||||
|
let rec jprop_sub sub = function
|
||||||
|
| Prop (n, p) ->
|
||||||
|
Prop (n, Prop.prop_sub sub p)
|
||||||
|
| Joined (n, p, jp1, jp2) ->
|
||||||
|
let p' = Prop.prop_sub sub p in
|
||||||
|
let jp1' = jprop_sub sub jp1 in
|
||||||
|
let jp2' = jprop_sub sub jp2 in
|
||||||
|
Joined (n, p', jp1', jp2')
|
||||||
|
|
||||||
|
|
||||||
|
let filter (f: 'a t -> 'b option) jpl =
|
||||||
|
let rec do_filter acc = function
|
||||||
|
| [] ->
|
||||||
|
acc
|
||||||
|
| (Prop _ as jp) :: jpl -> (
|
||||||
|
match f jp with Some x -> do_filter (x :: acc) jpl | None -> do_filter acc jpl )
|
||||||
|
| (Joined (_, _, jp1, jp2) as jp) :: jpl ->
|
||||||
|
match f jp with
|
||||||
|
| Some x ->
|
||||||
|
do_filter (x :: acc) jpl
|
||||||
|
| None ->
|
||||||
|
do_filter acc (jpl @ [jp1; jp2])
|
||||||
|
in
|
||||||
|
do_filter [] jpl
|
||||||
|
|
||||||
|
|
||||||
|
let rec map (f: 'a Prop.t -> 'b Prop.t) = function
|
||||||
|
| Prop (n, p) ->
|
||||||
|
Prop (n, f p)
|
||||||
|
| Joined (n, p, jp1, jp2) ->
|
||||||
|
Joined (n, f p, map f jp1, map f jp2)
|
||||||
|
|
||||||
|
(*
|
||||||
|
let rec jprop_sub sub = function
|
||||||
|
| Prop (n, p) -> Prop (n, Prop.prop_sub sub p)
|
||||||
|
| Joined (n, p, jp1, jp2) ->
|
||||||
|
Joined (n, Prop.prop_sub sub p, jprop_sub sub jp1, jprop_sub sub jp2)
|
||||||
|
*)
|
||||||
|
end
|
||||||
|
|
||||||
|
(***** End of module Jprop *****)
|
||||||
|
|
||||||
|
module Visitedset = Caml.Set.Make (struct
|
||||||
|
type t = Procdesc.Node.id * int list
|
||||||
|
|
||||||
|
let compare (node_id1, _) (node_id2, _) = Procdesc.Node.compare_id node_id1 node_id2
|
||||||
|
end)
|
||||||
|
|
||||||
|
let visited_str vis =
|
||||||
|
let s = ref "" in
|
||||||
|
let lines = ref Int.Set.empty in
|
||||||
|
let do_one (_, ns) =
|
||||||
|
(* if List.length ns > 1 then
|
||||||
|
begin
|
||||||
|
let ss = ref "" in
|
||||||
|
List.iter ~f:(fun n -> ss := !ss ^ " " ^ string_of_int n) ns;
|
||||||
|
L.out "Node %d has lines %s@." node !ss
|
||||||
|
end; *)
|
||||||
|
List.iter ~f:(fun n -> lines := Int.Set.add !lines n) ns
|
||||||
|
in
|
||||||
|
Visitedset.iter do_one vis ;
|
||||||
|
Int.Set.iter ~f:(fun n -> s := !s ^ " " ^ string_of_int n) !lines ;
|
||||||
|
!s
|
||||||
|
|
||||||
|
|
||||||
|
(** A spec consists of:
|
||||||
|
pre: a joined prop
|
||||||
|
post: a list of props with path
|
||||||
|
visited: a list of pairs (node_id, line) for the visited nodes *)
|
||||||
|
type 'a spec = {pre: 'a Jprop.t; posts: ('a Prop.t * Paths.Path.t) list; visited: Visitedset.t}
|
||||||
|
|
||||||
|
(** encapsulate type for normalized specs *)
|
||||||
|
module NormSpec : sig
|
||||||
|
type t
|
||||||
|
|
||||||
|
val normalize : Tenv.t -> Prop.normal spec -> t
|
||||||
|
|
||||||
|
val tospecs : t list -> Prop.normal spec list
|
||||||
|
|
||||||
|
val compact : Sil.sharing_env -> t -> t
|
||||||
|
(** Return a compact representation of the spec *)
|
||||||
|
|
||||||
|
val erase_join_info_pre : Tenv.t -> t -> t
|
||||||
|
(** Erase join info from pre of spec *)
|
||||||
|
end = struct
|
||||||
|
type t = Prop.normal spec
|
||||||
|
|
||||||
|
let tospecs specs = specs
|
||||||
|
|
||||||
|
let gen_free_vars tenv (spec: Prop.normal spec) =
|
||||||
|
let open Sequence.Generator in
|
||||||
|
Jprop.sorted_gen_free_vars tenv spec.pre
|
||||||
|
>>= fun () ->
|
||||||
|
ISequence.gen_sequence_list spec.posts ~f:(fun (p, _) ->
|
||||||
|
Prop.dfs_sort tenv p |> Prop.sorted_gen_free_vars )
|
||||||
|
|
||||||
|
|
||||||
|
let free_vars tenv spec = Sequence.Generator.run (gen_free_vars tenv spec)
|
||||||
|
|
||||||
|
let spec_sub tenv sub spec =
|
||||||
|
{ pre= Jprop.normalize tenv (Jprop.jprop_sub sub spec.pre)
|
||||||
|
; posts=
|
||||||
|
List.map ~f:(fun (p, path) -> (Prop.normalize tenv (Prop.prop_sub sub p), path)) spec.posts
|
||||||
|
; visited= spec.visited }
|
||||||
|
|
||||||
|
|
||||||
|
(** Convert spec into normal form w.r.t. variable renaming *)
|
||||||
|
let normalize tenv (spec: Prop.normal spec) : Prop.normal spec =
|
||||||
|
let idlist = free_vars tenv spec |> Ident.hashqueue_of_sequence |> Ident.HashQueue.keys in
|
||||||
|
let count = ref 0 in
|
||||||
|
let sub =
|
||||||
|
Sil.subst_of_list
|
||||||
|
(List.map
|
||||||
|
~f:(fun id -> incr count ; (id, Exp.Var (Ident.create_normal Ident.name_spec !count)))
|
||||||
|
idlist)
|
||||||
|
in
|
||||||
|
spec_sub tenv sub spec
|
||||||
|
|
||||||
|
|
||||||
|
(** Return a compact representation of the spec *)
|
||||||
|
let compact sh spec =
|
||||||
|
let pre = Jprop.compact sh spec.pre in
|
||||||
|
let posts = List.map ~f:(fun (p, path) -> (Prop.prop_compact sh p, path)) spec.posts in
|
||||||
|
{pre; posts; visited= spec.visited}
|
||||||
|
|
||||||
|
|
||||||
|
(** Erase join info from pre of spec *)
|
||||||
|
let erase_join_info_pre tenv spec =
|
||||||
|
let spec' = {spec with pre= Jprop.Prop (1, Jprop.to_prop spec.pre)} in
|
||||||
|
normalize tenv spec'
|
||||||
|
end
|
||||||
|
|
||||||
|
(** Convert spec into normal form w.r.t. variable renaming *)
|
||||||
|
let spec_normalize = NormSpec.normalize
|
||||||
|
|
||||||
|
(** Cast a list of normalized specs to a list of specs *)
|
||||||
|
let normalized_specs_to_specs = NormSpec.tospecs
|
||||||
|
|
||||||
|
type phase = FOOTPRINT | RE_EXECUTION [@@deriving compare]
|
||||||
|
|
||||||
|
let equal_phase = [%compare.equal : phase]
|
||||||
|
|
||||||
|
(** Print the spec *)
|
||||||
|
let pp_spec pe num_opt fmt spec =
|
||||||
|
let num_str =
|
||||||
|
match num_opt with
|
||||||
|
| None ->
|
||||||
|
"----------"
|
||||||
|
| Some (n, tot) ->
|
||||||
|
Format.sprintf "%d of %d [nvisited:%s]" n tot (visited_str spec.visited)
|
||||||
|
in
|
||||||
|
let pre = Jprop.to_prop spec.pre in
|
||||||
|
let pe_post = Prop.prop_update_obj_sub pe pre in
|
||||||
|
let post_list = List.map ~f:fst spec.posts in
|
||||||
|
match pe.Pp.kind with
|
||||||
|
| TEXT ->
|
||||||
|
F.fprintf fmt "--------------------------- %s ---------------------------@\n" num_str ;
|
||||||
|
F.fprintf fmt "PRE:@\n%a@\n" (Prop.pp_prop Pp.text) pre ;
|
||||||
|
F.fprintf fmt "%a@\n" (Propgraph.pp_proplist pe_post "POST" (pre, true)) post_list ;
|
||||||
|
F.pp_print_string fmt "----------------------------------------------------------------"
|
||||||
|
| HTML ->
|
||||||
|
F.fprintf fmt "--------------------------- %s ---------------------------@\n" num_str ;
|
||||||
|
F.fprintf fmt "PRE:@\n%a%a%a@\n" Io_infer.Html.pp_start_color Pp.Blue
|
||||||
|
(Prop.pp_prop (Pp.html Blue))
|
||||||
|
pre Io_infer.Html.pp_end_color () ;
|
||||||
|
(Propgraph.pp_proplist pe_post "POST" (pre, true)) fmt post_list ;
|
||||||
|
F.pp_print_string fmt "----------------------------------------------------------------"
|
||||||
|
|
||||||
|
|
||||||
|
(** Dump a spec *)
|
||||||
|
let d_spec (spec: 'a spec) = L.add_print_action (L.PTspec, Obj.repr spec)
|
||||||
|
|
||||||
|
let pp_specs pe fmt specs =
|
||||||
|
let total = List.length specs in
|
||||||
|
let cnt = ref 0 in
|
||||||
|
match pe.Pp.kind with
|
||||||
|
| TEXT ->
|
||||||
|
List.iter
|
||||||
|
~f:(fun spec ->
|
||||||
|
incr cnt ;
|
||||||
|
(pp_spec pe (Some (!cnt, total))) fmt spec )
|
||||||
|
specs
|
||||||
|
| HTML ->
|
||||||
|
List.iter
|
||||||
|
~f:(fun spec ->
|
||||||
|
incr cnt ;
|
||||||
|
F.fprintf fmt "%a<br>@\n" (pp_spec pe (Some (!cnt, total))) spec )
|
||||||
|
specs
|
||||||
|
|
||||||
|
|
||||||
|
let string_of_phase = function FOOTPRINT -> "FOOTPRINT" | RE_EXECUTION -> "RE_EXECUTION"
|
||||||
|
|
||||||
|
let get_specs_from_preposts preposts = Option.value_map ~f:NormSpec.tospecs ~default:[] preposts
|
||||||
|
|
||||||
|
type t = {preposts: NormSpec.t list; phase: phase}
|
||||||
|
|
||||||
|
let pp pe fmt {preposts; phase} =
|
||||||
|
F.fprintf fmt "phase= %s@\n%a" (string_of_phase phase) (pp_specs pe) (NormSpec.tospecs preposts)
|
@ -0,0 +1,92 @@
|
|||||||
|
(*
|
||||||
|
* Copyright (c) 2018 - present Facebook, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the BSD style license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree. An additional grant
|
||||||
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
|
*)
|
||||||
|
|
||||||
|
open! IStd
|
||||||
|
|
||||||
|
(** Module for joined props: the result of joining together propositions repeatedly *)
|
||||||
|
module Jprop : sig
|
||||||
|
(** Remember when a prop is obtained as the join of two other props; the first parameter is an id *)
|
||||||
|
type 'a t = Prop of int * 'a Prop.t | Joined of int * 'a Prop.t * 'a t * 'a t
|
||||||
|
|
||||||
|
val compare : 'a t -> 'a t -> int
|
||||||
|
(** Comparison for joined_prop *)
|
||||||
|
|
||||||
|
val equal : 'a t -> 'a t -> bool
|
||||||
|
(** Return true if the two join_prop's are equal *)
|
||||||
|
|
||||||
|
val d_shallow : Prop.normal t -> unit
|
||||||
|
(** Dump the toplevel prop *)
|
||||||
|
|
||||||
|
val d_list : bool -> Prop.normal t list -> unit
|
||||||
|
(** dump a joined prop list, the boolean indicates whether to print toplevel props only *)
|
||||||
|
|
||||||
|
val free_vars : Prop.normal t -> Ident.t Sequence.t
|
||||||
|
|
||||||
|
val filter : ('a t -> 'b option) -> 'a t list -> 'b list
|
||||||
|
(** [jprop_filter filter joinedprops] applies [filter] to the elements
|
||||||
|
of [joindeprops] and applies it to the subparts if the result is
|
||||||
|
[None]. Returns the most absract results which pass [filter]. *)
|
||||||
|
|
||||||
|
val jprop_sub : Sil.subst -> Prop.normal t -> Prop.exposed t
|
||||||
|
(** apply a substitution to a jprop *)
|
||||||
|
|
||||||
|
val map : ('a Prop.t -> 'b Prop.t) -> 'a t -> 'b t
|
||||||
|
(** map the function to each prop in the jprop, pointwise *)
|
||||||
|
|
||||||
|
val pp_list : Pp.env -> bool -> Format.formatter -> Prop.normal t list -> unit
|
||||||
|
(** Print a list of joined props, the boolean indicates whether to print subcomponents of joined props *)
|
||||||
|
|
||||||
|
val pp_short : Pp.env -> Format.formatter -> Prop.normal t -> unit
|
||||||
|
(** Print the toplevel prop *)
|
||||||
|
|
||||||
|
val to_prop : 'a t -> 'a Prop.t
|
||||||
|
(** Extract the toplevel jprop of a prop *)
|
||||||
|
end
|
||||||
|
|
||||||
|
(** set of visited nodes: node id and list of lines of all the instructions *)
|
||||||
|
module Visitedset : Caml.Set.S with type elt = Procdesc.Node.id * int list
|
||||||
|
|
||||||
|
(** A spec consists of:
|
||||||
|
pre: a joined prop
|
||||||
|
posts: a list of props with path
|
||||||
|
visited: a list of pairs (node_id, line) for the visited nodes *)
|
||||||
|
type 'a spec = {pre: 'a Jprop.t; posts: ('a Prop.t * Paths.Path.t) list; visited: Visitedset.t}
|
||||||
|
|
||||||
|
(** encapsulate type for normalized specs *)
|
||||||
|
module NormSpec : sig
|
||||||
|
type t
|
||||||
|
|
||||||
|
val compact : Sil.sharing_env -> t -> t
|
||||||
|
(** Return a compact representation of the spec *)
|
||||||
|
|
||||||
|
val erase_join_info_pre : Tenv.t -> t -> t
|
||||||
|
(** Erase join info from pre of spec *)
|
||||||
|
end
|
||||||
|
|
||||||
|
val normalized_specs_to_specs : NormSpec.t list -> Prop.normal spec list
|
||||||
|
(** Cast a list of normalized specs to a list of specs *)
|
||||||
|
|
||||||
|
val d_spec : 'a spec -> unit
|
||||||
|
(** Dump a spec *)
|
||||||
|
|
||||||
|
val spec_normalize : Tenv.t -> Prop.normal spec -> NormSpec.t
|
||||||
|
(** Convert spec into normal form w.r.t. variable renaming *)
|
||||||
|
|
||||||
|
val pp_spec : Pp.env -> (int * int) option -> Format.formatter -> Prop.normal spec -> unit
|
||||||
|
(** Print the spec *)
|
||||||
|
|
||||||
|
type phase = FOOTPRINT | RE_EXECUTION
|
||||||
|
|
||||||
|
val equal_phase : phase -> phase -> bool
|
||||||
|
|
||||||
|
val get_specs_from_preposts : NormSpec.t list option -> Prop.normal spec list
|
||||||
|
|
||||||
|
type t = {preposts: NormSpec.t list; phase: phase}
|
||||||
|
|
||||||
|
val pp : Pp.env -> Format.formatter -> t -> unit
|
Loading…
Reference in new issue