[pulse] define PulseSummary.yojson_of_t

Summary:
Emit the crucial parts of Pulse summaries as json to enable
post-processing by external tools. Stop somewhat arbitrarily at some
datatypes that are just emitted as "opaque" values.

For example:
```
$ infer debug --procedures --procedures-summary-json --select 0
[[["pulse",[["ContinueProgram",{"post":{"heap":[["v3",[[["Dereference"],["v4","_"]]]],["v7",[[["Dereference"],["v3","_"]]]]],"stack":[[["ProgramVar",{"plain":"return","mangled":null}],["v7","_"]]],"attrs":"_"},"pre":{"heap":[],"stack":[],"attrs":"_"},"skipped_calls":"_","path_condition":"_"}],["ContinueProgram",{"post":{"heap":[["v3",[[["Dereference"],["v4","_"]]]],["v8",[[["Dereference"],["v3","_"]]]]],"stack":[[["ProgramVar",{"plain":"return","mangled":null}],["v8","_"]]],"attrs":"_"},"pre":{"heap":[],"stack":[],"attrs":"_"},"skipped_calls":"_","path_condition":"_"}]]]]]
```

Reviewed By: ezgicicek

Differential Revision: D24503387

fbshipit-source-id: 9bd08e93b
master
Jules Villard 4 years ago committed by Facebook GitHub Bot
parent 57114e95e9
commit 46838a45a4

@ -8,7 +8,7 @@
open! IStd open! IStd
module F = Format module F = Format
type t = {class_name: Typ.Name.t; field_name: string} [@@deriving compare, equal] type t = {class_name: Typ.Name.t; field_name: string} [@@deriving compare, equal, yojson_of]
let make class_name field_name = {class_name; field_name} let make class_name field_name = {class_name; field_name}

@ -9,7 +9,7 @@ open! IStd
module F = Format module F = Format
(** Names for fields of class/struct/union *) (** Names for fields of class/struct/union *)
type t [@@deriving compare, equal] type t [@@deriving compare, equal, yojson_of]
val make : Typ.Name.t -> string -> t val make : Typ.Name.t -> string -> t
(** create a field of the given class and fieldname *) (** create a field of the given class and fieldname *)

@ -13,7 +13,8 @@ module Hashtbl = Caml.Hashtbl
module F = Format module F = Format
module Name = struct module Name = struct
type t = Primed | Normal | Footprint | Spec | FromString of string [@@deriving compare] type t = Primed | Normal | Footprint | Spec | FromString of string
[@@deriving compare, yojson_of]
let primed = "t" let primed = "t"
@ -52,7 +53,7 @@ type kind =
| KFootprint | KFootprint
| KNormal | KNormal
| KPrimed | KPrimed
[@@deriving compare] [@@deriving compare, yojson_of]
let kfootprint = KFootprint let kfootprint = KFootprint
@ -65,7 +66,7 @@ let equal_kind = [%compare.equal: kind]
(* timestamp for a path identifier *) (* timestamp for a path identifier *)
let path_ident_stamp = -3 let path_ident_stamp = -3
type t = {kind: kind; name: Name.t; stamp: int} [@@deriving compare] type t = {kind: kind; name: Name.t; stamp: int} [@@deriving compare, yojson_of]
(* most unlikely first *) (* most unlikely first *)
let equal i1 i2 = let equal i1 i2 =

@ -11,7 +11,7 @@
open! IStd open! IStd
(** Program and logical variables. *) (** Program and logical variables. *)
type t [@@deriving compare] type t [@@deriving compare, yojson_of]
val equal : t -> t -> bool val equal : t -> t -> bool
(** Equality for identifiers. *) (** Equality for identifiers. *)

@ -11,7 +11,7 @@
open! IStd open! IStd
module F = Format module F = Format
type t = {plain: string; mangled: string option} [@@deriving compare] type t = {plain: string; mangled: string option} [@@deriving compare, yojson_of]
let equal = [%compare.equal: t] let equal = [%compare.equal: t]

@ -11,7 +11,7 @@ open! IStd
(** Module for Mangled Names *) (** Module for Mangled Names *)
(** Type of mangled names *) (** Type of mangled names *)
type t [@@deriving compare] type t [@@deriving compare, yojson_of]
val equal : t -> t -> bool val equal : t -> t -> bool
(** Equality for mangled names *) (** Equality for mangled names *)

@ -35,6 +35,8 @@ type pvar_kind =
(** Names for program variables. *) (** Names for program variables. *)
type t = {pv_hash: int; pv_name: Mangled.t; pv_kind: pvar_kind} [@@deriving compare] type t = {pv_hash: int; pv_name: Mangled.t; pv_kind: pvar_kind} [@@deriving compare]
let yojson_of_t {pv_name} = [%yojson_of: Mangled.t] pv_name
let build_formal_from_pvar var = let build_formal_from_pvar var =
match var.pv_kind with match var.pv_kind with
| Local_var pname -> | Local_var pname ->

@ -19,7 +19,7 @@ type translation_unit = SourceFile.t option [@@deriving compare]
+ callee program variables, used to handle recursion ([x | callee] is distinguished from [x]) + callee program variables, used to handle recursion ([x | callee] is distinguished from [x])
+ global variables + global variables
+ seed variables, used to store the initial value of formal parameters *) + seed variables, used to store the initial value of formal parameters *)
type t [@@deriving compare] type t [@@deriving compare, yojson_of]
val compare_modulo_this : t -> t -> int val compare_modulo_this : t -> t -> int
(** Comparison considering all pvars named 'this'/'self' to be equal *) (** Comparison considering all pvars named 'this'/'self' to be equal *)

@ -202,6 +202,8 @@ module T = struct
| Template of {mangled: string option; args: template_arg list} | Template of {mangled: string option; args: template_arg list}
[@@deriving compare] [@@deriving compare]
let yojson_of_name = [%yojson_of: _]
let equal_desc = [%compare.equal: desc] let equal_desc = [%compare.equal: desc]
let equal_name = [%compare.equal: name] let equal_name = [%compare.equal: name]
@ -372,7 +374,7 @@ let to_string typ =
module Name = struct module Name = struct
type t = name [@@deriving compare, equal] type t = name [@@deriving compare, equal, yojson_of]
let equal = [%compare.equal: t] let equal = [%compare.equal: t]

@ -185,7 +185,7 @@ val is_strong_pointer : t -> bool
module Name : sig module Name : sig
(** Named types. *) (** Named types. *)
type t = name [@@deriving compare] type t = name [@@deriving compare, yojson_of]
val equal : t -> t -> bool val equal : t -> t -> bool
(** Equality for typenames *) (** Equality for typenames *)

@ -10,7 +10,7 @@ module F = Format
(** Single abstraction for all the kinds of variables in SIL *) (** Single abstraction for all the kinds of variables in SIL *)
type t = LogicalVar of Ident.t | ProgramVar of Pvar.t [@@deriving compare] type t = LogicalVar of Ident.t | ProgramVar of Pvar.t [@@deriving compare, yojson_of]
let equal = [%compare.equal: t] let equal = [%compare.equal: t]

@ -9,7 +9,7 @@ open! IStd
(** Single abstraction for all the kinds of variables in SIL *) (** Single abstraction for all the kinds of variables in SIL *)
type t = private LogicalVar of Ident.t | ProgramVar of Pvar.t [@@deriving compare] type t = private LogicalVar of Ident.t | ProgramVar of Pvar.t [@@deriving compare, yojson_of]
val equal : t -> t -> bool val equal : t -> t -> bool

@ -11,7 +11,7 @@
IBase)) IBase))
(libraries core zarith IStdlib ATDGenerated IBase) (libraries core zarith IStdlib ATDGenerated IBase)
(preprocess (preprocess
(pps ppx_compare))) (pps ppx_compare ppx_yojson_conv)))
(documentation (documentation
(package infer) (package infer)

@ -11,6 +11,8 @@ module L = Logging
type typ_ = Typ.t type typ_ = Typ.t
let yojson_of_typ_ = [%yojson_of: _]
let compare_typ_ _ _ = 0 let compare_typ_ _ _ = 0
module Access = struct module Access = struct
@ -19,7 +21,7 @@ module Access = struct
| ArrayAccess of typ_ * 'array_index | ArrayAccess of typ_ * 'array_index
| TakeAddress | TakeAddress
| Dereference | Dereference
[@@deriving compare] [@@deriving compare, yojson_of]
let pp pp_array_index fmt = function let pp pp_array_index fmt = function
| FieldAccess field_name -> | FieldAccess field_name ->

@ -14,7 +14,7 @@ module Access : sig
| ArrayAccess of Typ.t * 'array_index | ArrayAccess of Typ.t * 'array_index
| TakeAddress | TakeAddress
| Dereference | Dereference
[@@deriving compare] [@@deriving compare, yojson_of]
val pp : (Format.formatter -> 'array_index -> unit) -> Format.formatter -> 'array_index t -> unit val pp : (Format.formatter -> 'array_index -> unit) -> Format.formatter -> 'array_index t -> unit

@ -11,7 +11,7 @@
-open IBase)) -open IBase))
(libraries core IStdlib ATDGenerated IBase IR) (libraries core IStdlib ATDGenerated IBase IR)
(preprocess (preprocess
(pps ppx_compare))) (pps ppx_compare ppx_yojson_conv)))
(documentation (documentation
(package infer) (package infer)

@ -27,7 +27,9 @@ type t =
; uninit: UninitDomain.Summary.t option } ; uninit: UninitDomain.Summary.t option }
[@@deriving fields] [@@deriving fields]
let yojson_of_t = [%yojson_of: _] let yojson_of_t {pulse} =
[%yojson_of: (string * PulseSummary.t option) list] [(Checker.get_id Pulse, pulse)]
type 'a pp = Pp.env -> F.formatter -> 'a -> unit type 'a pp = Pp.env -> F.formatter -> 'a -> unit

@ -19,7 +19,7 @@ module BaseAddressAttributes = PulseBaseAddressAttributes
module type BaseDomainSig = sig module type BaseDomainSig = sig
(* private because the lattice is not the same for preconditions and postconditions so we don't (* private because the lattice is not the same for preconditions and postconditions so we don't
want to confuse them *) want to confuse them *)
type t = private BaseDomain.t type t = private BaseDomain.t [@@deriving yojson_of]
val empty : t val empty : t
@ -83,6 +83,7 @@ type t =
; pre: PreDomain.t (** inferred pre at the current program point *) ; pre: PreDomain.t (** inferred pre at the current program point *)
; skipped_calls: SkippedCalls.t (** set of skipped calls *) ; skipped_calls: SkippedCalls.t (** set of skipped calls *)
; path_condition: PathCondition.t } ; path_condition: PathCondition.t }
[@@deriving yojson_of]
let pp f {post; pre; path_condition; skipped_calls} = let pp f {post; pre; path_condition; skipped_calls} =
F.fprintf f "@[<v>%a@;%a@;PRE=[%a]@;skipped_calls=%a@]" PathCondition.pp path_condition F.fprintf f "@[<v>%a@;%a@;PRE=[%a]@;skipped_calls=%a@]" PathCondition.pp path_condition
@ -428,7 +429,7 @@ let invalidate_locals pdesc astate : t =
else {astate with post= PostDomain.update astate.post ~attrs:attrs'} else {astate with post= PostDomain.update astate.post ~attrs:attrs'}
type summary = t type summary = t [@@deriving yojson_of]
let summary_of_post pdesc astate = let summary_of_post pdesc astate =
let astate = filter_for_summary astate in let astate = filter_for_summary astate in

@ -23,7 +23,9 @@ module BaseStack = PulseBaseStack
module type BaseDomainSig = sig module type BaseDomainSig = sig
(* private because the lattice is not the same for preconditions and postconditions so we don't (* private because the lattice is not the same for preconditions and postconditions so we don't
want to confuse them *) want to confuse them *)
type t = private BaseDomain.t type t = private BaseDomain.t [@@deriving yojson_of]
val yojson_of_t : t -> Yojson.Safe.t
val empty : t val empty : t
@ -159,7 +161,7 @@ val add_skipped_calls : SkippedCalls.t -> t -> t
val set_path_condition : PathCondition.t -> t -> t val set_path_condition : PathCondition.t -> t -> t
(** private type to make sure {!summary_of_post} is always called when creating summaries *) (** private type to make sure {!summary_of_post} is always called when creating summaries *)
type summary = private t type summary = private t [@@deriving yojson_of]
val summary_of_post : Procdesc.t -> t -> summary val summary_of_post : Procdesc.t -> t -> summary
(** trim the state down to just the procedure's interface (formals and globals), and simplify and (** trim the state down to just the procedure's interface (formals and globals), and simplify and

@ -23,6 +23,8 @@ let mk_fresh () =
let pp f l = F.fprintf f "v%d" l let pp f l = F.fprintf f "v%d" l
let yojson_of_t l = `String (F.asprintf "%a" pp l)
let of_id v = v let of_id v = v
module PPKey = struct module PPKey = struct

@ -8,7 +8,7 @@ open! IStd
module F = Format module F = Format
(** An abstract value, eg an address in memory. *) (** An abstract value, eg an address in memory. *)
type t = private int [@@deriving compare] type t = private int [@@deriving compare, yojson_of]
val equal : t -> t -> bool val equal : t -> t -> bool

@ -19,6 +19,8 @@ module Graph = PrettyPrintable.MakePPMonoMap (AbstractValue) (AttributesNoRank)
type t = Graph.t type t = Graph.t
let yojson_of_t = [%yojson_of: _]
let add_one addr attribute attrs = let add_one addr attribute attrs =
match Graph.find_opt addr attrs with match Graph.find_opt addr attrs with
| None -> | None ->

@ -8,7 +8,7 @@ open! IStd
module F = Format module F = Format
open PulseBasicInterface open PulseBasicInterface
type t type t [@@deriving yojson_of]
val empty : t val empty : t

@ -14,7 +14,7 @@ module AddressAttributes = PulseBaseAddressAttributes
(* {2 Abstract domain description } *) (* {2 Abstract domain description } *)
type t = {heap: Memory.t; stack: Stack.t; attrs: AddressAttributes.t} type t = {heap: Memory.t; stack: Stack.t; attrs: AddressAttributes.t} [@@deriving yojson_of]
let empty = let empty =
{ heap= { heap=

@ -10,6 +10,7 @@ open PulseBasicInterface
module F = Format module F = Format
type t = {heap: PulseBaseMemory.t; stack: PulseBaseStack.t; attrs: PulseBaseAddressAttributes.t} type t = {heap: PulseBaseMemory.t; stack: PulseBaseStack.t; attrs: PulseBaseAddressAttributes.t}
[@@deriving yojson_of]
type cell = PulseBaseMemory.Edges.t * Attributes.t type cell = PulseBaseMemory.Edges.t * Attributes.t

@ -11,7 +11,7 @@ open PulseBasicInterface
(* {3 Heap domain } *) (* {3 Heap domain } *)
module Access = struct module Access = struct
type t = AbstractValue.t HilExp.Access.t [@@deriving compare] type t = AbstractValue.t HilExp.Access.t [@@deriving compare, yojson_of]
let equal = [%compare.equal: t] let equal = [%compare.equal: t]
@ -19,7 +19,7 @@ module Access = struct
end end
module AddrTrace = struct module AddrTrace = struct
type t = AbstractValue.t * ValueHistory.t [@@deriving compare] type t = AbstractValue.t * ValueHistory.t [@@deriving compare, yojson_of]
let pp fmt addr_trace = let pp fmt addr_trace =
if Config.debug_level_analysis >= 3 then if Config.debug_level_analysis >= 3 then
@ -27,11 +27,14 @@ module AddrTrace = struct
else AbstractValue.pp fmt (fst addr_trace) else AbstractValue.pp fmt (fst addr_trace)
end end
module Edges = module Edges = struct
RecencyMap.Make (Access) (AddrTrace) include RecencyMap.Make (Access) (AddrTrace)
(struct (struct
let limit = Config.pulse_recency_limit let limit = Config.pulse_recency_limit
end) end)
let yojson_of_t edges = [%yojson_of: (Access.t * AddrTrace.t) list] (bindings edges)
end
module Graph = PrettyPrintable.MakePPMonoMap (AbstractValue) (Edges) module Graph = PrettyPrintable.MakePPMonoMap (AbstractValue) (Edges)
@ -50,4 +53,6 @@ let find_edge_opt addr access memory =
Graph.find_opt addr memory >>= Edges.find_opt access Graph.find_opt addr memory >>= Edges.find_opt access
let yojson_of_t g = [%yojson_of: (AbstractValue.t * Edges.t) list] (Graph.bindings g)
include Graph include Graph

@ -27,3 +27,5 @@ val register_address : AbstractValue.t -> t -> t
val add_edge : AbstractValue.t -> Access.t -> AddrTrace.t -> t -> t val add_edge : AbstractValue.t -> Access.t -> AddrTrace.t -> t -> t
val find_edge_opt : AbstractValue.t -> Access.t -> t -> AddrTrace.t option val find_edge_opt : AbstractValue.t -> Access.t -> t -> AddrTrace.t option
val yojson_of_t : t -> Yojson.Safe.t

@ -19,7 +19,7 @@ module VarAddress = struct
end end
module AddrHistPair = struct module AddrHistPair = struct
type t = AbstractValue.t * ValueHistory.t [@@deriving compare] type t = AbstractValue.t * ValueHistory.t [@@deriving compare, yojson_of]
let pp f addr_trace = let pp f addr_trace =
if Config.debug_level_analysis >= 3 then if Config.debug_level_analysis >= 3 then
@ -37,3 +37,5 @@ let pp fmt m =
let compare = compare AddrHistPair.compare let compare = compare AddrHistPair.compare
let yojson_of_t m = [%yojson_of: (VarAddress.t * AddrHistPair.t) list] (bindings m)

@ -16,3 +16,5 @@ include
val compare : t -> t -> int [@@warning "-32"] val compare : t -> t -> int [@@warning "-32"]
val pp : F.formatter -> t -> unit val pp : F.formatter -> t -> unit
val yojson_of_t : t -> Yojson.Safe.t

@ -19,6 +19,8 @@ type access_to_invalid_address =
; access_trace: Trace.t } ; access_trace: Trace.t }
[@@deriving equal] [@@deriving equal]
let yojson_of_access_to_invalid_address = [%yojson_of: _]
type t = type t =
| AccessToInvalidAddress of access_to_invalid_address | AccessToInvalidAddress of access_to_invalid_address
| MemoryLeak of {procname: Procname.t; allocation_trace: Trace.t; location: Location.t} | MemoryLeak of {procname: Procname.t; allocation_trace: Trace.t; location: Location.t}

@ -22,7 +22,7 @@ type access_to_invalid_address =
; access_trace: Trace.t ; access_trace: Trace.t
(** assuming we are in the calling context, the trace leads to an access to the value (** assuming we are in the calling context, the trace leads to an access to the value
invalidated in [invalidation_trace] without further assumptions *) } invalidated in [invalidation_trace] without further assumptions *) }
[@@deriving equal] [@@deriving equal, yojson_of]
(** an error to report to the user *) (** an error to report to the user *)
type t = type t =

@ -21,6 +21,7 @@ type 'abductive_domain_t base_t =
| ExitProgram of 'abductive_domain_t | ExitProgram of 'abductive_domain_t
| AbortProgram of AbductiveDomain.summary | AbortProgram of AbductiveDomain.summary
| LatentAbortProgram of {astate: AbductiveDomain.summary; latent_issue: LatentIssue.t} | LatentAbortProgram of {astate: AbductiveDomain.summary; latent_issue: LatentIssue.t}
[@@deriving yojson_of]
type t = AbductiveDomain.t base_t type t = AbductiveDomain.t base_t
@ -70,7 +71,7 @@ let map ~f exec_state =
LatentAbortProgram {astate; latent_issue} LatentAbortProgram {astate; latent_issue}
type summary = AbductiveDomain.summary base_t type summary = AbductiveDomain.summary base_t [@@deriving yojson_of]
let summary_of_posts pdesc posts = let summary_of_posts pdesc posts =
List.filter_mapi posts ~f:(fun i exec_state -> List.filter_mapi posts ~f:(fun i exec_state ->

@ -25,6 +25,6 @@ val continue : AbductiveDomain.t -> t
val mk_initial : Procdesc.t -> t val mk_initial : Procdesc.t -> t
type summary = AbductiveDomain.summary base_t type summary = AbductiveDomain.summary base_t [@@deriving yojson_of]
val summary_of_posts : Procdesc.t -> t list -> summary list val summary_of_posts : Procdesc.t -> t list -> summary list

@ -10,7 +10,8 @@ open PulseBasicInterface
module AbductiveDomain = PulseAbductiveDomain module AbductiveDomain = PulseAbductiveDomain
module Arithmetic = PulseArithmetic module Arithmetic = PulseArithmetic
type t = AccessToInvalidAddress of Diagnostic.access_to_invalid_address [@@deriving equal] type t = AccessToInvalidAddress of Diagnostic.access_to_invalid_address
[@@deriving equal, yojson_of]
let to_diagnostic = function let to_diagnostic = function
| AccessToInvalidAddress access_to_invalid_address -> | AccessToInvalidAddress access_to_invalid_address ->

@ -13,7 +13,8 @@ module AbductiveDomain = PulseAbductiveDomain
but we want to delay reporting until we see the conditions for the bug manifest themselves in but we want to delay reporting until we see the conditions for the bug manifest themselves in
some calling context. *) some calling context. *)
type t = AccessToInvalidAddress of Diagnostic.access_to_invalid_address [@@deriving equal] type t = AccessToInvalidAddress of Diagnostic.access_to_invalid_address
[@@deriving equal, yojson_of]
val to_diagnostic : t -> Diagnostic.t val to_diagnostic : t -> Diagnostic.t

@ -34,6 +34,8 @@ type t =
; citvs: CItvs.t ; citvs: CItvs.t
; formula: Formula.t } ; formula: Formula.t }
let yojson_of_t = [%yojson_of: _]
let pp fmt {is_unsat; bo_itvs; citvs; formula} = let pp fmt {is_unsat; bo_itvs; citvs; formula} =
F.fprintf fmt "@[<hv>unsat:%b,@;bo: @[%a@],@;citv: @[%a@],@;formula: @[%a@]@]" is_unsat BoItvs.pp F.fprintf fmt "@[<hv>unsat:%b,@;bo: @[%a@],@;citv: @[%a@],@;formula: @[%a@]@]" is_unsat BoItvs.pp
bo_itvs CItvs.pp citvs Formula.pp formula bo_itvs CItvs.pp citvs Formula.pp formula

@ -10,7 +10,7 @@ module F = Format
module AbstractValue = PulseAbstractValue module AbstractValue = PulseAbstractValue
module ValueHistory = PulseValueHistory module ValueHistory = PulseValueHistory
type t type t [@@deriving yojson_of]
val true_ : t val true_ : t

@ -24,3 +24,5 @@ module SkippedTrace = struct
end end
include AbstractDomain.Map (Procname) (SkippedTrace) include AbstractDomain.Map (Procname) (SkippedTrace)
let yojson_of_t = [%yojson_of: _]

@ -8,3 +8,5 @@
open! IStd open! IStd
include AbstractDomain.MapS with type key = Procname.t and type value = PulseTrace.t include AbstractDomain.MapS with type key = Procname.t and type value = PulseTrace.t
val yojson_of_t : t -> Yojson.Safe.t

@ -9,7 +9,7 @@ open! IStd
module F = Format module F = Format
open PulseDomainInterface open PulseDomainInterface
type t = ExecutionDomain.summary list type t = ExecutionDomain.summary list [@@deriving yojson_of]
let pp fmt summary = let pp fmt summary =
F.open_vbox 0 ; F.open_vbox 0 ;

@ -8,7 +8,7 @@
open! IStd open! IStd
open PulseDomainInterface open PulseDomainInterface
type t = ExecutionDomain.summary list type t = ExecutionDomain.summary list [@@deriving yojson_of]
val of_posts : Procdesc.t -> ExecutionDomain.t list -> t val of_posts : Procdesc.t -> ExecutionDomain.t list -> t

@ -21,6 +21,10 @@ type event =
and t = event list [@@deriving compare, equal] and t = event list [@@deriving compare, equal]
let yojson_of_event = [%yojson_of: _]
let yojson_of_t = [%yojson_of: _]
let pp_event_no_location fmt event = let pp_event_no_location fmt event =
let pp_pvar fmt pvar = let pp_pvar fmt pvar =
if Pvar.is_global pvar then F.fprintf fmt "global variable `%a`" Pvar.pp_value_non_verbose pvar if Pvar.is_global pvar then F.fprintf fmt "global variable `%a`" Pvar.pp_value_non_verbose pvar

@ -19,7 +19,7 @@ type event =
| VariableAccessed of Pvar.t * Location.t | VariableAccessed of Pvar.t * Location.t
| VariableDeclared of Pvar.t * Location.t | VariableDeclared of Pvar.t * Location.t
and t = event list [@@deriving compare, equal] and t = event list [@@deriving compare, equal, yojson_of]
val pp : F.formatter -> t -> unit val pp : F.formatter -> t -> unit

@ -11,4 +11,4 @@
-open IBase -open Absint -open BO)) -open IBase -open Absint -open BO))
(libraries core IStdlib ATDGenerated IBase IR Absint BO) (libraries core IStdlib ATDGenerated IBase IR Absint BO)
(preprocess (preprocess
(pps ppx_compare ppx_variants_conv))) (pps ppx_yojson_conv ppx_compare ppx_variants_conv)))

Loading…
Cancel
Save