From 0914fee2ccc3cfcf8e1214d9da3dc37141452b35 Mon Sep 17 00:00:00 2001 From: Jules Villard Date: Wed, 20 Jun 2018 07:28:16 -0700 Subject: [PATCH] [backend] remove source file from exe_env Summary: The execution environment is really just a cache. It happens to point to a particular source file which is where the analysis was started from, but that is not relevant, and in fact is confusing because it suggests that it is somewhat tied to that file. In reality, exe_env caches information about any procedure and source file encountered by the analysis. This will make it easier to make further changes but I think it also brings a bit more clarity to the code. Reviewed By: jeremydubreil Differential Revision: D8513735 fbshipit-source-id: f4b38ce --- infer/src/backend/InferAnalyze.ml | 4 ++-- infer/src/backend/callbacks.ml | 24 ++++++++++++------------ infer/src/backend/callbacks.mli | 5 +++-- infer/src/backend/exe_env.ml | 23 ++++++++--------------- infer/src/backend/exe_env.mli | 19 ++++++++----------- infer/src/backend/printer.ml | 6 ++---- infer/src/concurrency/RacerD.ml | 5 ++--- infer/src/concurrency/starvation.ml | 5 ++--- 8 files changed, 39 insertions(+), 52 deletions(-) diff --git a/infer/src/backend/InferAnalyze.ml b/infer/src/backend/InferAnalyze.ml index 3441b0634..38daee123 100644 --- a/infer/src/backend/InferAnalyze.ml +++ b/infer/src/backend/InferAnalyze.ml @@ -17,13 +17,13 @@ let create_exe_env_tasks source_file exe_env : Tasks.t = Typ.Procname.SQLite.clear_cache () ; Random.self_init () ; [ (fun () -> - Callbacks.iterate_callbacks exe_env ; + Callbacks.analyze_file exe_env source_file ; if Config.write_html then Printer.write_all_html_files source_file ) ] (** Create tasks to analyze a cluster *) let create_source_file_tasks (source_file: SourceFile.t) : Tasks.t = - let exe_env = Exe_env.mk source_file in + let exe_env = Exe_env.mk () in L.(debug Analysis Medium) "@\nProcessing '%a'@." SourceFile.pp source_file ; create_exe_env_tasks source_file exe_env diff --git a/infer/src/backend/callbacks.ml b/infer/src/backend/callbacks.ml index be4c6d267..494590b1b 100644 --- a/infer/src/backend/callbacks.ml +++ b/infer/src/backend/callbacks.ml @@ -22,6 +22,7 @@ type proc_callback_t = proc_callback_args -> Summary.t type cluster_callback_args = { procedures: (Tenv.t * Procdesc.t) list + ; source_file: SourceFile.t ; get_proc_desc: Typ.Procname.t -> Procdesc.t option ; exe_env: Exe_env.t } @@ -75,10 +76,10 @@ let iterate_procedure_callbacks get_proc_desc exe_env summary proc_desc = (** Invoke all registered cluster callbacks on a cluster of procedures. *) -let iterate_cluster_callbacks all_procs exe_env get_proc_desc = +let iterate_cluster_callbacks all_procs exe_env source_file get_proc_desc = if !cluster_callbacks <> [] then let procedures = List.filter_map ~f:(get_procedure_definition exe_env) all_procs in - let environment = {procedures; get_proc_desc; exe_env} in + let environment = {procedures; source_file; get_proc_desc; exe_env} in let language_matches language = match procedures with | (_, pdesc) :: _ -> @@ -91,7 +92,7 @@ let iterate_cluster_callbacks all_procs exe_env get_proc_desc = !cluster_callbacks -let dump_duplicate_procs (exe_env: Exe_env.t) procs = +let dump_duplicate_procs (exe_env: Exe_env.t) source_file procs = let duplicate_procs = List.filter_map procs ~f:(fun pname -> match Exe_env.get_proc_desc exe_env pname with @@ -99,9 +100,9 @@ let dump_duplicate_procs (exe_env: Exe_env.t) procs = match Attributes.load pname with | Some {translation_unit; loc} when (* defined in another file *) - not (SourceFile.equal exe_env.source_file translation_unit) + not (SourceFile.equal source_file translation_unit) && (* really defined in the current file and not in an include *) - SourceFile.equal exe_env.source_file loc.file -> + SourceFile.equal source_file loc.file -> Some (pname, translation_unit) | _ -> None ) @@ -114,8 +115,7 @@ let dump_duplicate_procs (exe_env: Exe_env.t) procs = let fmt = F.formatter_of_out_channel outc in List.iter duplicate_procs ~f:(fun (pname, source_captured) -> F.fprintf fmt "@.DUPLICATE_SYMBOLS source:%a source_captured:%a pname:%a@." - SourceFile.pp exe_env.source_file SourceFile.pp source_captured Typ.Procname.pp pname - ) ) + SourceFile.pp source_file SourceFile.pp source_captured Typ.Procname.pp pname ) ) in if not (List.is_empty duplicate_procs) then output_to_file duplicate_procs @@ -126,7 +126,7 @@ let create_perf_stats_report source_file = (** Invoke all procedure and cluster callbacks on a given environment. *) -let iterate_callbacks (exe_env: Exe_env.t) = +let analyze_file (exe_env: Exe_env.t) source_file = let saved_language = !Language.curr_language in let get_proc_desc proc_name = match Exe_env.get_proc_desc exe_env proc_name with @@ -142,15 +142,15 @@ let iterate_callbacks (exe_env: Exe_env.t) = (* Invoke procedure callbacks using on-demand analysis schedulling *) let procs_to_analyze = (* analyze all the currently defined procedures *) - SourceFiles.proc_names_of_source exe_env.source_file + SourceFiles.proc_names_of_source source_file in - if Config.dump_duplicate_symbols then dump_duplicate_procs exe_env procs_to_analyze ; + if Config.dump_duplicate_symbols then dump_duplicate_procs exe_env source_file procs_to_analyze ; let analyze_proc_name pname = ignore (Ondemand.analyze_proc_name pname : Summary.t option) in List.iter ~f:analyze_proc_name procs_to_analyze ; (* Invoke cluster callbacks. *) - iterate_cluster_callbacks procs_to_analyze exe_env get_proc_desc ; + iterate_cluster_callbacks procs_to_analyze exe_env source_file get_proc_desc ; (* Perf logging needs to remain at the end - after analysis work is complete *) - create_perf_stats_report exe_env.source_file ; + create_perf_stats_report source_file ; (* Unregister callbacks *) Ondemand.unset_callbacks () ; Language.curr_language := saved_language diff --git a/infer/src/backend/callbacks.mli b/infer/src/backend/callbacks.mli index ba80511b4..5b679fe74 100644 --- a/infer/src/backend/callbacks.mli +++ b/infer/src/backend/callbacks.mli @@ -26,6 +26,7 @@ type proc_callback_t = proc_callback_args -> Summary.t type cluster_callback_args = { procedures: (Tenv.t * Procdesc.t) list + ; source_file: SourceFile.t ; get_proc_desc: Typ.Procname.t -> Procdesc.t option ; exe_env: Exe_env.t } @@ -37,5 +38,5 @@ val register_procedure_callback : ?dynamic_dispatch:bool -> Language.t -> proc_c val register_cluster_callback : Language.t -> cluster_callback_t -> unit (** register a cluster callback *) -val iterate_callbacks : Exe_env.t -> unit -(** Invoke all the registered callbacks. *) +val analyze_file : Exe_env.t -> SourceFile.t -> unit +(** Invoke all the registered callbacks on the given file. *) diff --git a/infer/src/backend/exe_env.ml b/infer/src/backend/exe_env.ml index 7f574ce36..4e810db5a 100644 --- a/infer/src/backend/exe_env.ml +++ b/infer/src/backend/exe_env.ml @@ -8,7 +8,8 @@ open! IStd -(** Support for Execution environments *) +(** Execution environments: basically a cache of where procedures are and what is their CFG and type + environment *) module L = Logging @@ -36,8 +37,7 @@ let create_file_data table source = type t = { proc_map: file_data Typ.Procname.Hash.t (** map from procedure name to file data *) - ; file_map: file_data SourceFile.Hash.t (** map from source files to file data *) - ; source_file: SourceFile.t (** source file being analyzed *) } + ; file_map: file_data SourceFile.Hash.t (** map from source files to file data *) } let get_file_data exe_env pname = try Some (Typ.Procname.Hash.find exe_env.proc_map pname) with Caml.Not_found -> @@ -91,13 +91,14 @@ let get_tenv exe_env proc_name = | Some tenv -> tenv | None -> + let loc = State.get_loc () in L.(die InternalError) - "get_tenv: tenv not found for %a in file '%a'" Typ.Procname.pp proc_name SourceFile.pp - exe_env.source_file ) + "get_tenv: tenv not found for %a in file '%a' at %a" Typ.Procname.pp proc_name + SourceFile.pp loc.Location.file Location.pp loc ) | None -> let loc = State.get_loc () in L.(die InternalError) - "get_tenv: file_data not found for %a in file %a at %a" Typ.Procname.pp proc_name + "get_tenv: file_data not found for %a in file '%a' at %a" Typ.Procname.pp proc_name SourceFile.pp loc.Location.file Location.pp loc @@ -119,12 +120,4 @@ let get_proc_desc exe_env pname = None -let mk source_file = - {proc_map= Typ.Procname.Hash.create 17; file_map= SourceFile.Hash.create 1; source_file} - - -(** [iter_files f exe_env] applies [f] to the filename and tenv and cfg for each file in [exe_env] *) -let iter_files f exe_env = - let source = exe_env.source_file in - let cfg = Cfg.load source in - Option.iter ~f:(f source) cfg +let mk () = {proc_map= Typ.Procname.Hash.create 17; file_map= SourceFile.Hash.create 1} diff --git a/infer/src/backend/exe_env.mli b/infer/src/backend/exe_env.mli index 22a237814..819dc8655 100644 --- a/infer/src/backend/exe_env.mli +++ b/infer/src/backend/exe_env.mli @@ -8,26 +8,23 @@ open! IStd -(** Support for Execution environments *) +(** Execution environments: basically a cache of where procedures are and what is their CFG and type + environment *) type file_data type t = private { proc_map: file_data Typ.Procname.Hash.t (** map from procedure name to file data *) - ; file_map: file_data SourceFile.Hash.t (** map from source files to file data *) - ; source_file: SourceFile.t (** source file being analyzed *) } + ; file_map: file_data SourceFile.Hash.t (** map from source files to file data *) } -val mk : SourceFile.t -> t -(** Create an exe_env from a source file *) +val mk : unit -> t +(** Create a new cache *) val get_tenv : t -> Typ.Procname.t -> Tenv.t -(** return the type environment associated to the procedure *) +(** return the type environment associated with the procedure *) val get_cfg : t -> Typ.Procname.t -> Cfg.t option -(** return the cfg associated to the procedure *) +(** return the cfg associated with the procedure *) val get_proc_desc : t -> Typ.Procname.t -> Procdesc.t option -(** return the proc desc associated to the procedure *) - -val iter_files : (SourceFile.t -> Cfg.t -> unit) -> t -> unit -(** [iter_files f exe_env] applies [f] to the source file and tenv and cfg for each file in [exe_env] *) +(** return the proc desc associated with the procedure *) diff --git a/infer/src/backend/printer.ml b/infer/src/backend/printer.ml index e3186f3d3..b328aa685 100644 --- a/infer/src/backend/printer.ml +++ b/infer/src/backend/printer.ml @@ -366,7 +366,6 @@ let write_html_file linereader filename procs = (** Create filename.ext.html for each file in the cluster. *) let write_all_html_files cluster = - let exe_env = Exe_env.mk cluster in let opt_whitelist_regex = match Config.write_html_whitelist_regex with | [] -> @@ -380,8 +379,8 @@ let write_all_html_files cluster = Str.string_match regex fname 0 ) in let linereader = LineReader.create () in - Exe_env.iter_files - (fun _ cfg -> + let cfg = Cfg.load cluster in + Option.iter cfg ~f:(fun cfg -> let source_files_in_cfg, pdescs_in_cfg = Typ.Procname.Hash.fold (fun _ proc_desc (files, pdescs) -> @@ -397,4 +396,3 @@ let write_all_html_files cluster = SourceFile.Set.iter (fun file -> write_html_file linereader file pdescs_in_cfg) source_files_in_cfg ) - exe_env diff --git a/infer/src/concurrency/RacerD.ml b/infer/src/concurrency/RacerD.ml index 16e89bf96..8caeaa9e6 100644 --- a/infer/src/concurrency/RacerD.ml +++ b/infer/src/concurrency/RacerD.ml @@ -1483,7 +1483,7 @@ let aggregate_by_class file_env = (* Gathers results by analyzing all the methods in a file, then post-processes the results to check an (approximation of) thread safety *) -let file_analysis {Callbacks.procedures; exe_env} = +let file_analysis {Callbacks.procedures; source_file} = String.Map.iter ~f:(fun class_env -> let tenv = fst (List.hd_exn class_env) in @@ -1493,5 +1493,4 @@ let file_analysis {Callbacks.procedures; exe_env} = else (module MayAliasQuotientedAccessListMap) ) class_env) ) (aggregate_by_class procedures) ; - let sourcefile = exe_env.Exe_env.source_file in - IssueLog.store Config.racerd_issues_dir_name sourcefile + IssueLog.store Config.racerd_issues_dir_name source_file diff --git a/infer/src/concurrency/starvation.ml b/infer/src/concurrency/starvation.ml index 0b018f19c..e3e088824 100644 --- a/infer/src/concurrency/starvation.ml +++ b/infer/src/concurrency/starvation.ml @@ -436,7 +436,7 @@ let report_starvation env get_proc_desc {StarvationDomain.events; ui} report_map EventDomain.fold (report_on_current_elem ui_explain) events report_map' -let reporting {Callbacks.procedures; get_proc_desc; exe_env} = +let reporting {Callbacks.procedures; source_file; get_proc_desc} = let report_procedure ((_, proc_desc) as env) = die_if_not_java proc_desc ; if should_report proc_desc then @@ -446,5 +446,4 @@ let reporting {Callbacks.procedures; get_proc_desc; exe_env} = |> report_starvation env get_proc_desc summary |> ReportMap.log ) in List.iter procedures ~f:report_procedure ; - let sourcefile = exe_env.Exe_env.source_file in - IssueLog.store Config.starvation_issues_dir_name sourcefile + IssueLog.store Config.starvation_issues_dir_name source_file