From fe617afa49048af5553566ce595fe72bbafa0a52 Mon Sep 17 00:00:00 2001 From: Nikos Gorogiannis Date: Wed, 5 Aug 2020 09:39:31 -0700 Subject: [PATCH] [specs] move specs file functionality into summary Summary: As per title. Eases next diffs by making Summary the only source of truth for how spec files are accessed/stored. Reviewed By: ezgicicek Differential Revision: D22794742 fbshipit-source-id: 0ee20ec1c --- infer/src/backend/InferAnalyze.ml | 3 +- infer/src/backend/ReverseAnalysisCallGraph.ml | 2 +- infer/src/backend/SpecsFiles.ml | 71 ------------------- infer/src/backend/SpecsFiles.mli | 21 ------ infer/src/backend/StarvationGlobalAnalysis.ml | 2 +- infer/src/backend/Summary.ml | 65 +++++++++++++++++ infer/src/backend/Summary.mli | 23 +++--- infer/src/infer.ml | 2 +- infer/src/integration/JsonReports.ml | 2 +- 9 files changed, 84 insertions(+), 107 deletions(-) delete mode 100644 infer/src/backend/SpecsFiles.ml delete mode 100644 infer/src/backend/SpecsFiles.mli diff --git a/infer/src/backend/InferAnalyze.ml b/infer/src/backend/InferAnalyze.ml index f5ad78f01..15122d726 100644 --- a/infer/src/backend/InferAnalyze.ml +++ b/infer/src/backend/InferAnalyze.ml @@ -201,7 +201,8 @@ let invalidate_changed_procedures changed_files = let invalidated_nodes = CallGraph.fold_flagged reverse_callgraph ~f:(fun node acc -> - SpecsFiles.delete node.pname ; + Ondemand.LocalCache.remove node.pname ; + Summary.OnDisk.delete node.pname ; acc + 1 ) 0 in diff --git a/infer/src/backend/ReverseAnalysisCallGraph.ml b/infer/src/backend/ReverseAnalysisCallGraph.ml index 0b012b201..a930e4f83 100644 --- a/infer/src/backend/ReverseAnalysisCallGraph.ml +++ b/infer/src/backend/ReverseAnalysisCallGraph.ml @@ -14,4 +14,4 @@ let register_summary graph summary = callee_pnames -let build graph = SpecsFiles.iter ~f:(register_summary graph) +let build graph = Summary.OnDisk.iter_specs ~f:(register_summary graph) diff --git a/infer/src/backend/SpecsFiles.ml b/infer/src/backend/SpecsFiles.ml deleted file mode 100644 index 4f3dd87fc..000000000 --- a/infer/src/backend/SpecsFiles.ml +++ /dev/null @@ -1,71 +0,0 @@ -(* - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - *) - -open! IStd -module F = Format -module L = Logging -module CLOpt = CommandLineOption - -(** return the list of the .specs files in the results dir *) -let load_specfiles () = - let is_specs_file fname = Filename.check_suffix fname Config.specs_files_suffix in - let do_file acc path = if is_specs_file path then path :: acc else acc in - let result_specs_dir = DB.filename_to_string DB.Results_dir.specs_dir in - Utils.directory_fold do_file [] result_specs_dir - - -let print_usage_exit err_s = - L.user_error "Load Error: %s@\n@." err_s ; - Config.print_usage_exit () - - -let spec_files_from_cmdline () = - if CLOpt.is_originator then ( - (* Find spec files specified by command-line arguments. Not run at init time since the specs - files may be generated between init and report time. *) - List.iter - ~f:(fun arg -> - if (not (Filename.check_suffix arg Config.specs_files_suffix)) && not (String.equal arg ".") - then print_usage_exit ("file " ^ arg ^ ": arguments must be .specs files") ) - Config.anon_args ; - if Config.test_filtering then ( - Inferconfig.test () ; - L.exit 0 ) ; - if List.is_empty Config.anon_args then load_specfiles () else List.rev Config.anon_args ) - else load_specfiles () - - -(** Create an iterator which loads spec files one at a time *) -let summary_iterator spec_files = - let sorted_spec_files = List.sort ~compare:String.compare (spec_files ()) in - let do_spec f fname = - match Summary.OnDisk.load_from_file (DB.filename_from_string fname) with - | None -> - L.(die UserError) "Error: cannot open file %s@." fname - | Some summary -> - f summary - in - let iterate f = List.iter ~f:(do_spec f) sorted_spec_files in - iterate - - -let iter_from_config ~f = summary_iterator spec_files_from_cmdline f - -let iter ~f = summary_iterator load_specfiles f - -let delete pname = - let filename = Summary.OnDisk.specs_filename_of_procname pname |> DB.filename_to_string in - (* Unix_error is raised if the file isn't present so do nothing in this case *) - (try Unix.unlink filename with Unix.Unix_error _ -> ()) ; - Ondemand.LocalCache.remove pname ; - Summary.OnDisk.remove_from_cache pname - - -let pp_from_config fmt = - iter_from_config ~f:(fun summary -> - F.fprintf fmt "Procedure: %a@\n%a@." Procname.pp (Summary.get_proc_name summary) - Summary.pp_text summary ) diff --git a/infer/src/backend/SpecsFiles.mli b/infer/src/backend/SpecsFiles.mli deleted file mode 100644 index eae8453ca..000000000 --- a/infer/src/backend/SpecsFiles.mli +++ /dev/null @@ -1,21 +0,0 @@ -(* - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - *) - -open! IStd - -val iter : f:(Summary.t -> unit) -> unit -(** Iterates over all summaries from the .specs files *) - -val iter_from_config : f:(Summary.t -> unit) -> unit -(** Iterates over all sumaries from the .specs files unless a list of specs files has been passed on - the command line *) - -val delete : Procname.t -> unit -(** Delete the .specs file associated with a summary and remove the summary from the caches in - Summary.ml and ondemand.ml *) - -val pp_from_config : Format.formatter -> unit diff --git a/infer/src/backend/StarvationGlobalAnalysis.ml b/infer/src/backend/StarvationGlobalAnalysis.ml index 9da0bbcf0..066cbabb4 100644 --- a/infer/src/backend/StarvationGlobalAnalysis.ml +++ b/infer/src/backend/StarvationGlobalAnalysis.ml @@ -95,7 +95,7 @@ let whole_program_analysis () = let work_set = WorkHashSet.create 1 in let exe_env = Exe_env.mk () in L.progress "Processing on-disk summaries...@." ; - SpecsFiles.iter ~f:(iter_summary exe_env ~f:(WorkHashSet.add_pairs work_set)) ; + Summary.OnDisk.iter_specs ~f:(iter_summary exe_env ~f:(WorkHashSet.add_pairs work_set)) ; L.progress "Loaded %d pairs@." (WorkHashSet.length work_set) ; L.progress "Reporting on processed summaries...@." ; report exe_env work_set diff --git a/infer/src/backend/Summary.ml b/infer/src/backend/Summary.ml index bbaa9383e..7ed018c8b 100644 --- a/infer/src/backend/Summary.ml +++ b/infer/src/backend/Summary.ml @@ -8,6 +8,8 @@ open! IStd module F = Format +module L = Logging +module CLOpt = CommandLineOption module Stats = struct type t = @@ -123,6 +125,8 @@ module OnDisk = struct let clear_cache () = Procname.Hash.clear cache + (** Remove an element from the cache of summaries. Contrast to reset which re-initializes a + summary keeping the same Procdesc and updates the cache accordingly. *) let remove_from_cache pname = Procname.Hash.remove cache pname (** Add the summary to the table for the given function *) @@ -238,4 +242,65 @@ module OnDisk = struct Serialization.write_to_file summary_serializer filename ~data:blank_summary ) in Procedures.get_all ~filter () |> List.iter ~f:reset + + + let delete pname = + let filename = specs_filename_of_procname pname |> DB.filename_to_string in + (* Unix_error is raised if the file isn't present so do nothing in this case *) + (try Unix.unlink filename with Unix.Unix_error _ -> ()) ; + remove_from_cache pname + + + (** return the list of the .specs files in the results dir *) + let load_specfiles () = + let is_specs_file fname = Filename.check_suffix fname Config.specs_files_suffix in + let do_file acc path = if is_specs_file path then path :: acc else acc in + let result_specs_dir = DB.filename_to_string DB.Results_dir.specs_dir in + Utils.directory_fold do_file [] result_specs_dir + + + let print_usage_exit err_s = + L.user_error "Load Error: %s@\n@." err_s ; + Config.print_usage_exit () + + + let spec_files_from_cmdline () = + if CLOpt.is_originator then ( + (* Find spec files specified by command-line arguments. Not run at init time since the specs + files may be generated between init and report time. *) + List.iter + ~f:(fun arg -> + if + (not (Filename.check_suffix arg Config.specs_files_suffix)) + && not (String.equal arg ".") + then print_usage_exit ("file " ^ arg ^ ": arguments must be .specs files") ) + Config.anon_args ; + if Config.test_filtering then ( + Inferconfig.test () ; + L.exit 0 ) ; + if List.is_empty Config.anon_args then load_specfiles () else List.rev Config.anon_args ) + else load_specfiles () + + + (** Create an iterator which loads spec files one at a time *) + let summary_iterator spec_files = + let sorted_spec_files = List.sort ~compare:String.compare (spec_files ()) in + let do_spec f fname = + match load_from_file (DB.filename_from_string fname) with + | None -> + L.(die UserError) "Error: cannot open file %s@." fname + | Some summary -> + f summary + in + let iterate f = List.iter ~f:(do_spec f) sorted_spec_files in + iterate + + + let iter_specs_from_config ~f = summary_iterator spec_files_from_cmdline f + + let iter_specs ~f = summary_iterator load_specfiles f + + let pp_specs_from_config fmt = + iter_specs_from_config ~f:(fun summary -> + F.fprintf fmt "Procedure: %a@\n%a@." Procname.pp (get_proc_name summary) pp_text summary ) end diff --git a/infer/src/backend/Summary.mli b/infer/src/backend/Summary.mli index 6e8e28fac..b39596bbd 100644 --- a/infer/src/backend/Summary.mli +++ b/infer/src/backend/Summary.mli @@ -65,22 +65,12 @@ module OnDisk : sig val clear_cache : unit -> unit (** Remove all the elements from the cache of summaries *) - val remove_from_cache : Procname.t -> unit - (** Remove an element from the cache of summaries. Contrast to reset which re-initializes a - summary keeping the same Procdesc and updates the cache accordingly. *) - val get : Procname.t -> t option (** Return the summary option for the procedure name *) val reset : Procdesc.t -> t (** Reset a summary rebuilding the dependents and preserving the proc attributes if present. *) - val specs_filename_of_procname : Procname.t -> DB.filename - (** Return the path to the .specs file for the given procedure in the current results directory *) - - val load_from_file : DB.filename -> t option - (** Load procedure summary from the given file *) - val proc_resolve_attributes : Procname.t -> ProcAttributes.t option (** Try to find the attributes for a defined proc. First look at specs (to get attributes computed by analysis) then look at the attributes table. If no attributes can be found, return None. *) @@ -89,4 +79,17 @@ module OnDisk : sig (** Save summary for the procedure into the spec database *) val reset_all : filter:Filtering.procedures_filter -> unit -> unit + + val delete : Procname.t -> unit + (** Delete the .specs file corresponding to the procname and remove its summary from the Summary + cache *) + + val iter_specs : f:(t -> unit) -> unit + (** Iterates over all summaries from the .specs files *) + + val iter_specs_from_config : f:(t -> unit) -> unit + (** Iterates over all sumaries from the .specs files unless a list of specs files has been passed + on the command line *) + + val pp_specs_from_config : Format.formatter -> unit end diff --git a/infer/src/infer.ml b/infer/src/infer.ml index 6c604aec8..12678effd 100644 --- a/infer/src/infer.ml +++ b/infer/src/infer.ml @@ -191,7 +191,7 @@ let () = in match (Config.issues_tests, Config.cost_issues_tests) with | None, None -> - if not Config.quiet then L.result "%t" SpecsFiles.pp_from_config + if not Config.quiet then L.result "%t" Summary.OnDisk.pp_specs_from_config | Some out_path, Some cost_out_path -> write_from_json out_path ; write_from_cost_json cost_out_path diff --git a/infer/src/integration/JsonReports.ml b/infer/src/integration/JsonReports.ml index b9bba6be1..613855dae 100644 --- a/infer/src/integration/JsonReports.ml +++ b/infer/src/integration/JsonReports.ml @@ -314,7 +314,7 @@ let process_all_summaries_and_issues ~issues_outf ~costs_outf = let linereader = LineReader.create () in let filters = Inferconfig.create_filters () in let all_issues = ref [] in - SpecsFiles.iter_from_config ~f:(fun summary -> + Summary.OnDisk.iter_specs_from_config ~f:(fun summary -> all_issues := process_summary ~costs_outf summary !all_issues ) ; all_issues := Issue.sort_filter_issues !all_issues ; List.iter