[infer] refactor LintIssues for general use.

Summary:
One source of non-determinism is racing on procedure summaries when reporting.  In particular, the summary of a method may be computed and stored by one thread, but another may be trying to report on it (eg, in cluster checkers).

One solution (at least until everything is in sqlite) is to have separate files just for the reports, a la linters.  This diff improves the interface of LintIssues and generalises it ahead of using it in other analysers.

Reviewed By: jeremydubreil

Differential Revision: D7859973

fbshipit-source-id: 8672d3b
master
Nikos Gorogiannis 7 years ago committed by Facebook Github Bot
parent 96c6ff718b
commit 9a2c494454

@ -13,7 +13,9 @@ open! IStd
let errLogMap = ref Typ.Procname.Map.empty
let exists_issues () = not (Typ.Procname.Map.is_empty !errLogMap)
let exist_issues () = not (Typ.Procname.Map.is_empty !errLogMap)
let get_map () = !errLogMap
let get_err_log procname =
try Typ.Procname.Map.find procname !errLogMap with Caml.Not_found ->
@ -22,20 +24,19 @@ let get_err_log procname =
errlog
let lint_issues_serializer : Errlog.t Typ.Procname.Map.t Serialization.serializer =
Serialization.create_serializer Serialization.Key.lint_issues
let issues_serializer : Errlog.t Typ.Procname.Map.t Serialization.serializer =
Serialization.create_serializer Serialization.Key.issues
(** Save issues to a file *)
let store_issues filename errLogMap =
Serialization.write_to_file lint_issues_serializer filename ~data:errLogMap
let store filename = Serialization.write_to_file issues_serializer filename ~data:!errLogMap
(** Load issues from the given file *)
let load_issues issues_file = Serialization.read_from_file lint_issues_serializer issues_file
let load_issues issues_file = Serialization.read_from_file issues_serializer issues_file
(** Load all the lint issues in the given dir and update the issues map *)
let load_issues_to_errlog_map dir =
(** Load all the issues in the given dir and update the issues map *)
let load dir =
let () = errLogMap := Typ.Procname.Map.empty in
let issues_dir = Filename.concat Config.results_dir dir in
let children_opt = try Some (Sys.readdir issues_dir) with Sys_error _ -> None in
let load_issues_to_map issues_file =

@ -0,0 +1,27 @@
(*
* Copyright (c) 2016 - present Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*)
open! IStd
(** Module to store a map from procnames to error logs. Starts with an empty map. *)
val get_map : unit -> Errlog.t Typ.Procname.Map.t
val exist_issues : unit -> bool
val get_err_log : Typ.Procname.t -> Errlog.t
(** Get the error log for a given procname. If not present, then add the association from
procname to an empty error log and return the latter. *)
val store : DB.filename -> unit
(** Store map to a file *)
val load : string -> unit
(** Reset the issue map first, then walk the directory given as argument and merge all
maps stored in the found files into the current map. *)

@ -1,25 +0,0 @@
(*
* Copyright (c) 2016 - present Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*)
open! IStd
(** Module to store a set of issues per procedure *)
val errLogMap : Errlog.t Typ.Procname.Map.t ref
val exists_issues : unit -> bool
val get_err_log : Typ.Procname.t -> Errlog.t
(** Save issues to a file *)
val store_issues : DB.filename -> Errlog.t Typ.Procname.Map.t -> unit
(** Load issues from the given file *)
val load_issues_to_errlog_map : string -> unit
(** Load all the lint issues in the given dir and update the issues map *)

@ -967,10 +967,10 @@ let pp_summary_and_issues formats_by_report_kind issue_formats =
issue_formats )
(Issue.sort_filter_issues !all_issues) ;
if Config.precondition_stats then PreconditionStats.pp_stats () ;
LintIssues.load_issues_to_errlog_map Config.lint_issues_dir_name ;
IssueLog.load Config.lint_issues_dir_name ;
Typ.Procname.Map.iter
(pp_lint_issues filters formats_by_report_kind linereader)
!LintIssues.errLogMap ;
(IssueLog.get_map ()) ;
finalize_and_close_files formats_by_report_kind stats

@ -23,7 +23,7 @@ module Key = struct
(** Current keys for various serializable objects. The keys are computed using the [generate_keys]
function below *)
let tenv, summary, cluster, lint_issues = (425184201, 160179325, 579094948, 852343110)
let tenv, summary, cluster, issues = (425184201, 160179325, 579094948, 852343110)
end
(** version of the binary files, to be incremented for each change *)

@ -19,7 +19,7 @@ module Key : sig
val cluster : t
(** current key for a cluster *)
val lint_issues : t
val issues : t
(** current key for lint issues *)
val summary : t

@ -367,7 +367,7 @@ let store_issues source_file =
let lint_issues_file =
DB.filename_from_string (Filename.concat lint_issues_dir (abbrev_source_file ^ ".issue"))
in
LintIssues.store_issues lint_issues_file !LintIssues.errLogMap
IssueLog.store lint_issues_file
let find_linters_files () =
@ -407,7 +407,7 @@ let do_frontend_checks (trans_unit_ctx: CFrontend_config.translation_unit_contex
let active_map : Tableaux.context_linter_map = Tableaux.init_active_map () in
CFrontend_errors.invoke_set_of_checkers_on_node context (Ctl_parser_types.Decl ast) ;
List.iter ~f:(do_frontend_checks_decl context active_map) allowed_decls ;
if LintIssues.exists_issues () then store_issues source_file ;
if IssueLog.exist_issues () then store_issues source_file ;
L.(debug Linters Medium) "End linting file %a@\n" SourceFile.pp source_file ;
CTL.save_dotty_when_in_debug_mode trans_unit_ctx.CFrontend_config.source_file
(*if CFrontend_config.tableaux_evaluation then (

@ -445,7 +445,7 @@ let log_frontend_issue ~is_cpp method_decl_opt (node: Ctl_parser_types.ast_node)
| None ->
Typ.Procname.Linters_dummy_method
in
let errlog = LintIssues.get_err_log procname in
let errlog = IssueLog.get_err_log procname in
let err_desc =
Errdesc.explain_frontend_warning issue_desc.description issue_desc.suggestion issue_desc.loc
in

Loading…
Cancel
Save