From af8c57e07f7ade8c20255c88a609add041489968 Mon Sep 17 00:00:00 2001 From: Phoebe Nichols Date: Wed, 17 Jul 2019 08:50:20 -0700 Subject: [PATCH] Write function to load specfiles Summary: Write a function to read in the summaries from the `.specs` folder This is needed so the reverse analysis call graph can be constructed from the summaries Reviewed By: ngorogiannis Differential Revision: D16282333 fbshipit-source-id: 101ce2c5b --- infer/src/backend/InferPrint.ml | 51 +------------------------ infer/src/backend/SpecsFiles.ml | 65 ++++++++++++++++++++++++++++++++ infer/src/backend/SpecsFiles.mli | 18 +++++++++ 3 files changed, 84 insertions(+), 50 deletions(-) create mode 100644 infer/src/backend/SpecsFiles.ml create mode 100644 infer/src/backend/SpecsFiles.mli diff --git a/infer/src/backend/InferPrint.ml b/infer/src/backend/InferPrint.ml index ad974f738..dec2ab8b3 100644 --- a/infer/src/backend/InferPrint.ml +++ b/infer/src/backend/InferPrint.ml @@ -6,30 +6,10 @@ * LICENSE file in the root directory of this source tree. *) open! IStd -module CLOpt = CommandLineOption module Hashtbl = Caml.Hashtbl module L = Logging module F = Format -let print_usage_exit err_s = - L.user_error "Load Error: %s@\n@." err_s ; - Config.print_usage_exit () - - -(** return the list of the .specs files in the results dir and libs, if they're defined *) -let load_specfiles () = - let specs_files_in_dir dir = - let is_specs_file fname = - Sys.is_directory fname <> `Yes && Filename.check_suffix fname Config.specs_files_suffix - in - let all_filenames = try Array.to_list (Sys.readdir dir) with Sys_error _ -> [] in - let all_filepaths = List.map ~f:(fun fname -> Filename.concat dir fname) all_filenames in - List.filter ~f:is_specs_file all_filepaths - in - let result_specs_dir = DB.filename_to_string DB.Results_dir.specs_dir in - specs_files_in_dir result_specs_dir - - let error_desc_to_plain_string error_desc = let pp fmt = Localise.pp_error_desc fmt error_desc in let s = F.asprintf "%t" pp in @@ -1089,34 +1069,6 @@ let process_summary filters formats_by_report_kind linereader stats summary issu issues_acc' -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)) && 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 get_summary_iterator () = - let sorted_spec_files = List.sort ~compare:String.compare (spec_files_from_cmdline ()) in - let do_spec f fname = - match Summary.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 - - (** Although the out_file is an Option type, the None option is strictly meant for the logs format_kind, and all other formats should contain an outfile value. *) let mk_format format_kind fname = @@ -1205,9 +1157,8 @@ let pp_summary_and_issues formats_by_report_kind issue_formats = let stats = Stats.create () in let linereader = Printer.LineReader.create () in let filters = Inferconfig.create_filters () in - let iterate_summaries = get_summary_iterator () in let all_issues = ref [] in - iterate_summaries (fun summary -> + SpecsFiles.iter_from_config ~f:(fun summary -> all_issues := process_summary filters formats_by_report_kind linereader stats summary !all_issues ) ; all_issues := Issue.sort_filter_issues !all_issues ; diff --git a/infer/src/backend/SpecsFiles.ml b/infer/src/backend/SpecsFiles.ml new file mode 100644 index 000000000..aa672032b --- /dev/null +++ b/infer/src/backend/SpecsFiles.ml @@ -0,0 +1,65 @@ +(* + * 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 L = Logging +module CLOpt = CommandLineOption + +(** return the list of the .specs files in the results dir and libs, if they're defined *) +let load_specfiles () = + let specs_files_in_dir dir = + let is_specs_file fname = + Sys.is_directory fname <> `Yes && Filename.check_suffix fname Config.specs_files_suffix + in + match Sys.readdir dir with + | exception Sys_error _ -> + [] + | files -> + Array.fold files ~init:[] ~f:(fun acc fname -> + let path = Filename.concat dir fname in + 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 + specs_files_in_dir 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)) && 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.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 diff --git a/infer/src/backend/SpecsFiles.mli b/infer/src/backend/SpecsFiles.mli new file mode 100644 index 000000000..3339bc5e7 --- /dev/null +++ b/infer/src/backend/SpecsFiles.mli @@ -0,0 +1,18 @@ +(* + * 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 + +(* Suppress unused value warning because this method is intended for incremental analysis, which is + not yet finished *) +val iter : f:(Summary.t -> unit) -> unit + [@@warning "-32"] +(** 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 *)