[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 7 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 *)

@ -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) ->
let updated_files =
if Procdesc.is_defined proc_desc then if Procdesc.is_defined proc_desc then
let file = (Procdesc.get_loc proc_desc).Location.file in let file = (Procdesc.get_loc proc_desc).Location.file in
if is_whitelisted file then files := SourceFile.Set.add file !files else () ) ; if is_whitelisted file then SourceFile.Set.add file files else files
!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