[infer][IR] introduce a fold function over the procedure descriptions in a file to avoid make copies of mutable data-structures

Summary: This should avoid making copies of procedure descriptions which are mutable data-stuctures.

Reviewed By: sblackshear

Differential Revision: D6658527

fbshipit-source-id: 688a142
master
Jeremy Dubreil 8 years ago committed by Facebook Github Bot
parent b089486b5a
commit 6e1979a3e0

@ -24,6 +24,8 @@ let remove_proc_desc cfg pname = Typ.Procname.Hash.remove cfg pname
let iter_proc_desc cfg f = Typ.Procname.Hash.iter f cfg let iter_proc_desc cfg f = Typ.Procname.Hash.iter f cfg
let fold_proc_desc cfg f init = Typ.Procname.Hash.fold f cfg init
let find_proc_desc_from_name cfg pname = let find_proc_desc_from_name cfg pname =
try Some (Typ.Procname.Hash.find cfg pname) with Not_found -> None try Some (Typ.Procname.Hash.find cfg pname) with Not_found -> None
@ -59,9 +61,6 @@ let get_all_procs cfg =
iter_proc_desc cfg f ; !procs iter_proc_desc cfg f ; !procs
(** Get the procedures whose body is defined in this cfg *)
let get_defined_procs cfg = List.filter ~f:Procdesc.is_defined (get_all_procs cfg)
(** checks whether a cfg is connected or not *) (** checks whether a cfg is connected or not *)
let check_cfg_connectedness cfg = let check_cfg_connectedness cfg =
let is_exit_node n = let is_exit_node n =
@ -83,15 +82,13 @@ let check_cfg_connectedness cfg =
(* if the if brances end with a return *) (* if the if brances end with a return *)
match succs with [n'] when is_exit_node n' -> false | _ -> Int.equal (List.length preds) 0 match succs with [n'] when is_exit_node n' -> false | _ -> Int.equal (List.length preds) 0
in in
let do_pdesc pd = let do_pdesc pname pd =
let pname = Procdesc.get_proc_name pd in
let nodes = Procdesc.get_nodes pd in let nodes = Procdesc.get_nodes pd in
(* TODO (T20302015): also check the CFGs for the C-like procedures *) (* TODO (T20302015): also check the CFGs for the C-like procedures *)
if not Config.keep_going && Typ.Procname.is_java pname && List.exists ~f:broken_node nodes then if not Config.keep_going && Typ.Procname.is_java pname && List.exists ~f:broken_node nodes then
L.(die InternalError) "Broken CFG on %a" Typ.Procname.pp pname L.(die InternalError) "Broken CFG on %a" Typ.Procname.pp pname
in in
let pdescs = get_all_procs cfg in iter_proc_desc cfg do_pdesc
List.iter ~f:do_pdesc pdescs
let get_load_statement = let get_load_statement =
@ -112,7 +109,7 @@ let load source =
(** Save the .attr files for the procedures in the cfg. *) (** Save the .attr files for the procedures in the cfg. *)
let save_attributes source_file cfg = let save_attributes source_file cfg =
let save_proc pdesc = let save_proc _ pdesc =
let attributes = Procdesc.get_attributes pdesc in let attributes = Procdesc.get_attributes pdesc in
let loc = attributes.loc in let loc = attributes.loc in
let attributes' = let attributes' =
@ -121,7 +118,7 @@ let save_attributes source_file cfg =
in in
Attributes.store attributes' Attributes.store attributes'
in in
List.iter ~f:save_proc (get_all_procs cfg) iter_proc_desc cfg save_proc
(** Inline a synthetic (access or bridge) method. *) (** Inline a synthetic (access or bridge) method. *)

@ -32,15 +32,12 @@ val create_proc_desc : t -> ProcAttributes.t -> Procdesc.t
val iter_proc_desc : t -> (Typ.Procname.t -> Procdesc.t -> unit) -> unit val iter_proc_desc : t -> (Typ.Procname.t -> Procdesc.t -> unit) -> unit
(** Iterate over all the procdesc's *) (** Iterate over all the procdesc's *)
val fold_proc_desc : t -> (Typ.Procname.t -> Procdesc.t -> 'a -> 'a) -> 'a -> 'a
(** Fold over all the procdesc's *)
val find_proc_desc_from_name : t -> Typ.Procname.t -> Procdesc.t option val find_proc_desc_from_name : t -> Typ.Procname.t -> Procdesc.t option
(** Find the procdesc given the proc name. Return None if not found. *) (** Find the procdesc given the proc name. Return None if not found. *)
val get_all_procs : t -> Procdesc.t list
(** Get all the procedures (defined and declared) *)
val get_defined_procs : t -> Procdesc.t list
(** Get the procedures whose body is defined in this cfg *)
val iter_all_nodes : ?sorted:bool -> (Procdesc.t -> Procdesc.Node.t -> unit) -> t -> unit val iter_all_nodes : ?sorted:bool -> (Procdesc.t -> Procdesc.Node.t -> unit) -> t -> unit
(** Iterate over all the nodes in the cfg *) (** Iterate over all the nodes in the cfg *)
@ -58,10 +55,10 @@ val specialize_types : Procdesc.t -> Typ.Procname.t -> (Exp.t * Typ.t) list -> P
val specialize_with_block_args : val specialize_with_block_args :
Procdesc.t -> Typ.Procname.t -> Exp.closure option list -> Procdesc.t Procdesc.t -> Typ.Procname.t -> Exp.closure option list -> Procdesc.t
(** Creates a copy of a procedure description given a list of possible closures (** Creates a copy of a procedure description given a list of possible closures
that are passed as arguments to the method. The resulting procdesc is isomorphic but that are passed as arguments to the method. The resulting procdesc is isomorphic but
a) the block parameters are replaces with the closures a) the block parameters are replaces with the closures
b) the parameters of the method are extended with parameters for the captured variables b) the parameters of the method are extended with parameters for the captured variables
in the closures *) in the closures *)
val pp_proc_signatures : Format.formatter -> t -> unit val pp_proc_signatures : Format.formatter -> t -> unit

@ -55,7 +55,7 @@ let iterate_procedure_callbacks get_proc_desc exe_env summary proc_desc =
let get_procs_in_file proc_name = let get_procs_in_file proc_name =
match Exe_env.get_cfg exe_env proc_name with match Exe_env.get_cfg exe_env proc_name with
| Some cfg -> | Some cfg ->
List.map ~f:Procdesc.get_proc_name (Cfg.get_all_procs cfg) Cfg.fold_proc_desc cfg (fun pname _ accu -> pname :: accu) []
| None -> | None ->
[] []
in in

@ -546,15 +546,19 @@ let write_all_html_files cluster =
let linereader = LineReader.create () in let linereader = LineReader.create () in
Exe_env.iter_files Exe_env.iter_files
(fun _ cfg -> (fun _ cfg ->
let source_files_in_cfg = let source_files_in_cfg, pdescs_in_cfg =
let files = ref SourceFile.Set.empty in Cfg.fold_proc_desc cfg
Cfg.iter_proc_desc cfg (fun _ proc_desc -> (fun _ proc_desc (files, pdescs) ->
if Procdesc.is_defined proc_desc then let updated_files =
let file = (Procdesc.get_loc proc_desc).Location.file in if Procdesc.is_defined proc_desc then
if is_whitelisted file then files := SourceFile.Set.add file !files else () ) ; let file = (Procdesc.get_loc proc_desc).Location.file in
!files if is_whitelisted file then SourceFile.Set.add file files else files
else files
in
(updated_files, proc_desc :: pdescs) )
(SourceFile.Set.empty, [])
in in
SourceFile.Set.iter SourceFile.Set.iter
(fun file -> write_html_file linereader file (Cfg.get_all_procs cfg)) (fun file -> write_html_file linereader file pdescs_in_cfg)
source_files_in_cfg ) source_files_in_cfg )
exe_env exe_env

@ -94,9 +94,8 @@ let add_nonnull_to_fields fields tenv =
let analysis cfg tenv = let analysis cfg tenv =
let initial = FieldsAssignedInConstructors.empty in let initial = FieldsAssignedInConstructors.empty in
let f domain pdesc = let f proc_name pdesc domain =
let proc_name = Procdesc.get_proc_name pdesc in if Procdesc.is_defined pdesc && Typ.Procname.is_constructor proc_name then
if Typ.Procname.is_constructor proc_name then
match match
FieldsAssignedInConstructorsChecker.compute_post FieldsAssignedInConstructorsChecker.compute_post
(ProcData.make pdesc tenv (Ident.IdentHash.create 10)) (ProcData.make pdesc tenv (Ident.IdentHash.create 10))
@ -108,6 +107,5 @@ let analysis cfg tenv =
domain domain
else domain else domain
in in
let procs = Cfg.get_defined_procs cfg in let fields_assigned_in_constructor = Cfg.fold_proc_desc cfg f initial in
let fields_assigned_in_constructor = List.fold ~f ~init:initial procs in
add_nonnull_to_fields fields_assigned_in_constructor tenv add_nonnull_to_fields fields_assigned_in_constructor tenv

Loading…
Cancel
Save