diff --git a/infer/src/IR/Cfg.ml b/infer/src/IR/Cfg.ml index f0f0ba3da..038b30e4d 100644 --- a/infer/src/IR/Cfg.ml +++ b/infer/src/IR/Cfg.ml @@ -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 fold_proc_desc cfg f init = Typ.Procname.Hash.fold f cfg init + let find_proc_desc_from_name cfg pname = 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 -(** 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 *) let check_cfg_connectedness cfg = let is_exit_node n = @@ -83,15 +82,13 @@ let check_cfg_connectedness cfg = (* if the if brances end with a return *) match succs with [n'] when is_exit_node n' -> false | _ -> Int.equal (List.length preds) 0 in - let do_pdesc pd = - let pname = Procdesc.get_proc_name pd in + let do_pdesc pname pd = let nodes = Procdesc.get_nodes pd in (* 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 L.(die InternalError) "Broken CFG on %a" Typ.Procname.pp pname in - let pdescs = get_all_procs cfg in - List.iter ~f:do_pdesc pdescs + iter_proc_desc cfg do_pdesc let get_load_statement = @@ -112,7 +109,7 @@ let load source = (** Save the .attr files for the procedures in the cfg. *) let save_attributes source_file cfg = - let save_proc pdesc = + let save_proc _ pdesc = let attributes = Procdesc.get_attributes pdesc in let loc = attributes.loc in let attributes' = @@ -121,7 +118,7 @@ let save_attributes source_file cfg = in Attributes.store attributes' in - List.iter ~f:save_proc (get_all_procs cfg) + iter_proc_desc cfg save_proc (** Inline a synthetic (access or bridge) method. *) diff --git a/infer/src/IR/Cfg.mli b/infer/src/IR/Cfg.mli index 0e80c209c..4e3a29e94 100644 --- a/infer/src/IR/Cfg.mli +++ b/infer/src/IR/Cfg.mli @@ -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 (** 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 (** 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 (** 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 : 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 - a) the block parameters are replaces with the closures - b) the parameters of the method are extended with parameters for the captured variables + a) the block parameters are replaces with the closures + b) the parameters of the method are extended with parameters for the captured variables in the closures *) val pp_proc_signatures : Format.formatter -> t -> unit diff --git a/infer/src/backend/callbacks.ml b/infer/src/backend/callbacks.ml index faa4a6d44..be26e57ac 100644 --- a/infer/src/backend/callbacks.ml +++ b/infer/src/backend/callbacks.ml @@ -55,7 +55,7 @@ let iterate_procedure_callbacks get_proc_desc exe_env summary proc_desc = let get_procs_in_file proc_name = match Exe_env.get_cfg exe_env proc_name with | 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 -> [] in diff --git a/infer/src/backend/printer.ml b/infer/src/backend/printer.ml index 40de117b9..f747e81fa 100644 --- a/infer/src/backend/printer.ml +++ b/infer/src/backend/printer.ml @@ -546,15 +546,19 @@ let write_all_html_files cluster = let linereader = LineReader.create () in Exe_env.iter_files (fun _ cfg -> - let source_files_in_cfg = - let files = ref SourceFile.Set.empty in - Cfg.iter_proc_desc cfg (fun _ proc_desc -> - if Procdesc.is_defined proc_desc then - let file = (Procdesc.get_loc proc_desc).Location.file in - if is_whitelisted file then files := SourceFile.Set.add file !files else () ) ; - !files + let source_files_in_cfg, pdescs_in_cfg = + Cfg.fold_proc_desc cfg + (fun _ proc_desc (files, pdescs) -> + let updated_files = + if Procdesc.is_defined proc_desc then + let file = (Procdesc.get_loc proc_desc).Location.file in + if is_whitelisted file then SourceFile.Set.add file files else files + else files + in + (updated_files, proc_desc :: pdescs) ) + (SourceFile.Set.empty, []) in 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 ) exe_env diff --git a/infer/src/checkers/NullabilityPreanalysis.ml b/infer/src/checkers/NullabilityPreanalysis.ml index c65c66e44..007ae8cf1 100644 --- a/infer/src/checkers/NullabilityPreanalysis.ml +++ b/infer/src/checkers/NullabilityPreanalysis.ml @@ -94,9 +94,8 @@ let add_nonnull_to_fields fields tenv = let analysis cfg tenv = let initial = FieldsAssignedInConstructors.empty in - let f domain pdesc = - let proc_name = Procdesc.get_proc_name pdesc in - if Typ.Procname.is_constructor proc_name then + let f proc_name pdesc domain = + if Procdesc.is_defined pdesc && Typ.Procname.is_constructor proc_name then match FieldsAssignedInConstructorsChecker.compute_post (ProcData.make pdesc tenv (Ident.IdentHash.create 10)) @@ -108,6 +107,5 @@ let analysis cfg tenv = domain else domain in - let procs = Cfg.get_defined_procs cfg in - let fields_assigned_in_constructor = List.fold ~f ~init:initial procs in + let fields_assigned_in_constructor = Cfg.fold_proc_desc cfg f initial in add_nonnull_to_fields fields_assigned_in_constructor tenv