Add documentation and better naming around checker callbacks

Summary:
1. Some invariants are tricky enough to be documented. This is especially
important for cases related with error reporting. Lets document it.
2. Cluster callback -> File callback rename.

Reviewed By: ngorogiannis

Differential Revision: D20093932

fbshipit-source-id: e716f1f5b
master
Mitya Lyubarskiy 5 years ago committed by Facebook Github Bot
parent d50039b495
commit d94b365b65

@ -7,7 +7,9 @@
open! IStd
(** Module for maps from procnames to error logs. *)
(** Module for storing issues detected outside of per-procedure analysis (and hence not serialized
as a part of procedure summary). Normally those are issues detected at the file-level analysis
step. Individual checkers are responsible for storing their own list of such issues. *)
type t
val empty : t

@ -60,8 +60,8 @@ let analyze_target : (SchedulerTypes.target, Procname.t) Tasks.doer =
analyze_source_file exe_env source_file
let output_json_makefile_stats clusters =
let num_files = List.length clusters in
let output_json_makefile_stats files =
let num_files = List.length files in
let num_procs = 0 in
(* can't compute it at this stage *)
let num_lines = 0 in
@ -144,7 +144,7 @@ let analyze source_files_to_analyze =
else (
L.environment_info "Parallel jobs: %d@." Config.jobs ;
let build_tasks_generator () = tasks_generator_builder_for source_files_to_analyze in
(* Prepare tasks one cluster at a time while executing in parallel *)
(* Prepare tasks one file at a time while executing in parallel *)
RestartScheduler.setup () ;
let runner =
Tasks.Runner.create ~jobs:Config.jobs ~f:analyze_target ~child_epilogue:BackendStats.get

@ -47,6 +47,10 @@ type t =
; status: Status.t
; proc_desc: Procdesc.t
; err_log: Errlog.t
(** Those are issues that are detected for this procedure after per-procedure analysis. In
addition to that there can be errors detected after file-level analysis (next stage
after per-procedure analysis). This latter category of errors should NOT be written
here, use [IssueLog] and its serialization capabilities instead. *)
; mutable callee_pnames: Procname.Set.t }
val poly_fields : t PolyFields.t

@ -7,37 +7,35 @@
open! IStd
(** Module to register and invoke callbacks *)
type proc_callback_args =
{get_procs_in_file: Procname.t -> Procname.t list; summary: Summary.t; exe_env: Exe_env.t}
type proc_callback_t = proc_callback_args -> Summary.t
type cluster_callback_args =
type file_callback_args =
{procedures: Procname.t list; source_file: SourceFile.t; exe_env: Exe_env.t}
type cluster_callback_t = cluster_callback_args -> unit
type file_callback_t = file_callback_args -> unit
type procedure_callback =
{name: string; dynamic_dispatch: bool; language: Language.t; callback: proc_callback_t}
{checker_name: string; dynamic_dispatch: bool; language: Language.t; callback: proc_callback_t}
type cluster_callback = {name: string; language: Language.t; callback: cluster_callback_t}
type file_callback = {checker_name: string; language: Language.t; callback: file_callback_t}
let procedure_callbacks = ref []
let cluster_callbacks = ref []
let file_callbacks = ref []
let register_procedure_callback ~name ?(dynamic_dispatch = false) language
let register_procedure_callback ~checker_name ?(dynamic_dispatch = false) language
(callback : proc_callback_t) =
procedure_callbacks := {name; dynamic_dispatch; language; callback} :: !procedure_callbacks
procedure_callbacks :=
{checker_name; dynamic_dispatch; language; callback} :: !procedure_callbacks
let register_cluster_callback ~name language (callback : cluster_callback_t) =
cluster_callbacks := {name; language; callback} :: !cluster_callbacks
let register_file_callback ~checker_name language (callback : file_callback_t) =
file_callbacks := {checker_name; language; callback} :: !file_callbacks
(** Invoke all registered procedure callbacks on the given procedure. *)
let iterate_procedure_callbacks exe_env summary =
let proc_desc = Summary.get_proc_desc summary in
let proc_name = Procdesc.get_proc_name proc_desc in
@ -55,11 +53,11 @@ let iterate_procedure_callbacks exe_env summary =
in
let is_specialized = Procdesc.is_specialized proc_desc in
List.fold ~init:summary
~f:(fun summary {name; dynamic_dispatch; language; callback} ->
~f:(fun summary {checker_name; dynamic_dispatch; language; callback} ->
if Language.equal language procedure_language && (dynamic_dispatch || not is_specialized) then (
PerfEvent.(
log (fun logger ->
log_begin_event logger ~name ~categories:["backend"]
log_begin_event logger ~name:checker_name ~categories:["backend"]
~arguments:[("proc", `String (Procname.to_string proc_name))]
() )) ;
let summary = callback {get_procs_in_file; summary; exe_env} in
@ -69,9 +67,8 @@ let iterate_procedure_callbacks exe_env summary =
!procedure_callbacks
(** Invoke all registered cluster callbacks on a cluster of procedures. *)
let iterate_cluster_callbacks procedures exe_env source_file =
if not (List.is_empty !cluster_callbacks) then
let iterate_file_callbacks procedures exe_env source_file =
if not (List.is_empty !file_callbacks) then
let environment = {procedures; source_file; exe_env} in
let language_matches language =
match procedures with
@ -85,4 +82,4 @@ let iterate_cluster_callbacks procedures exe_env source_file =
if language_matches language then (
Language.curr_language := language ;
callback environment ) )
!cluster_callbacks
!file_callbacks

@ -7,7 +7,18 @@
open! IStd
(** Module to register and invoke callbacks *)
(** Module to register and invoke checkers' callbacks. *)
(* There are two types of callbacks:
1) Procedure level callback.
The checker is responsible for updating checker-specific summary artifacts for that procedure, including
writing errors that were detected during per-procedure analysis.
2) File level callback. Guaranteed to be invoked after all procedure-level callbacks for this files are invoked,
and generated summaries are serialized.
The checker is responsible for doing any additional work, but SHALL NOT modify summaries at this point, including updating
summaries' error log.
Additional errors can be issued at this stage using capabilities of [IssueLog].
*)
type proc_callback_args =
{get_procs_in_file: Procname.t -> Procname.t list; summary: Summary.t; exe_env: Exe_env.t}
@ -20,20 +31,21 @@ type proc_callback_args =
- Procedure for the callback to act on. *)
type proc_callback_t = proc_callback_args -> Summary.t
type cluster_callback_args =
type file_callback_args =
{procedures: Procname.t list; source_file: SourceFile.t; exe_env: Exe_env.t}
type cluster_callback_t = cluster_callback_args -> unit
type file_callback_t = file_callback_args -> unit
val register_procedure_callback :
name:string -> ?dynamic_dispatch:bool -> Language.t -> proc_callback_t -> unit
(** register a procedure callback *)
checker_name:string -> ?dynamic_dispatch:bool -> Language.t -> proc_callback_t -> unit
(** Register a procedure callback (see details above) *)
val register_cluster_callback : name:string -> Language.t -> cluster_callback_t -> unit
(** register a cluster callback *)
val register_file_callback : checker_name:string -> Language.t -> file_callback_t -> unit
(** Register a file callback (see details above) *)
val iterate_procedure_callbacks : Exe_env.t -> Summary.t -> Summary.t
(** Invoke all registered procedure callbacks on the given procedure. *)
val iterate_cluster_callbacks : Procname.t list -> Exe_env.t -> SourceFile.t -> unit
(** Invoke all registered cluster callbacks on a cluster of procedures. *)
val iterate_file_callbacks : Procname.t list -> Exe_env.t -> SourceFile.t -> unit
(** Invoke all registered file callbacks on a file. Guaranteed to be called after all
procedure-level callbacks are invoked *)

@ -381,13 +381,13 @@ let analyze_procedures exe_env procs_to_analyze source_file_opt =
Option.iter source_file_opt ~f:(fun source_file ->
if Config.dump_duplicate_symbols then dump_duplicate_procs source_file procs_to_analyze ) ;
Option.iter source_file_opt ~f:(fun source_file ->
Callbacks.iterate_cluster_callbacks procs_to_analyze exe_env source_file ;
Callbacks.iterate_file_callbacks procs_to_analyze exe_env source_file ;
create_perf_stats_report source_file ) ;
unset_exe_env () ;
Language.curr_language := saved_language
(** Invoke all procedure and cluster callbacks on a given environment. *)
(** Invoke all procedure-level and file-level callbacks on a given environment. *)
let analyze_file (exe_env : Exe_env.t) source_file =
let procs_to_analyze = SourceFiles.proc_names_of_source source_file in
analyze_procedures exe_env procs_to_analyze (Some source_file)

@ -236,7 +236,6 @@ end = struct
Errlog.update global_err_log (Summary.get_err_log summary)
(** Create filename.ext.html. *)
let write_html_file filename procs =
let fname_encoding = DB.source_file_encoding filename in
let fd, fmt = Io_infer.Html.create filename [".."; fname_encoding] in

@ -38,4 +38,5 @@ val write_proc_html : Procdesc.t -> unit
(** Write html file for the procedure. *)
val write_all_html_files : SourceFile.t -> unit
(** Create filename.ext.html for each file in the cluster. *)
(** Group procedures used in the file by their corresponding source files, and create
filename.ext.html for each such a file. *)

@ -21,7 +21,7 @@ let () =
type callback_fun =
| Procedure of Callbacks.proc_callback_t
| DynamicDispatch of Callbacks.proc_callback_t
| Cluster of Callbacks.cluster_callback_t
| File of Callbacks.file_callback_t
type callback = callback_fun * Language.t
@ -101,8 +101,8 @@ let all_checkers =
; callbacks=
[ (Procedure RacerD.analyze_procedure, Language.Clang)
; (Procedure RacerD.analyze_procedure, Language.Java)
; (Cluster RacerD.file_analysis, Language.Clang)
; (Cluster RacerD.file_analysis, Language.Java) ] }
; (File RacerD.file_analysis, Language.Clang)
; (File RacerD.file_analysis, Language.Java) ] }
(* toy resource analysis to use in the infer lab, see the lab/ directory *)
; { name= "resource leak"
; active= Config.resource_leak
@ -131,9 +131,9 @@ let all_checkers =
; active= Config.starvation
; callbacks=
[ (Procedure Starvation.analyze_procedure, Language.Java)
; (Cluster Starvation.reporting, Language.Java)
; (File Starvation.reporting, Language.Java)
; (Procedure Starvation.analyze_procedure, Language.Clang)
; (Cluster Starvation.reporting, Language.Clang) ] }
; (File Starvation.reporting, Language.Clang) ] }
; { name= "purity"
; active= Config.purity || Config.loop_hoisting
; callbacks=
@ -156,11 +156,12 @@ let register checkers =
let register_callback (callback, language) =
match callback with
| Procedure procedure_cb ->
Callbacks.register_procedure_callback ~name language procedure_cb
Callbacks.register_procedure_callback ~checker_name:name language procedure_cb
| DynamicDispatch procedure_cb ->
Callbacks.register_procedure_callback ~name ~dynamic_dispatch:true language procedure_cb
| Cluster cluster_cb ->
Callbacks.register_cluster_callback ~name language cluster_cb
Callbacks.register_procedure_callback ~checker_name:name ~dynamic_dispatch:true language
procedure_cb
| File file_cb ->
Callbacks.register_file_callback ~checker_name:name language file_cb
in
List.iter ~f:register_callback callbacks
in

@ -1151,7 +1151,7 @@ let aggregate_by_class exe_env procedures =
(* 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 ({procedures; source_file; exe_env} : Callbacks.cluster_callback_args) =
let file_analysis ({procedures; source_file; exe_env} : Callbacks.file_callback_args) =
let class_map = aggregate_by_class exe_env procedures in
Typ.Name.Map.fold
(fun classname methods issue_log ->

@ -7,6 +7,6 @@
open! IStd
val file_analysis : Callbacks.cluster_callback_t
val file_analysis : Callbacks.file_callback_t
val analyze_procedure : Callbacks.proc_callback_t

@ -9,6 +9,6 @@ open! IStd
val analyze_procedure : Callbacks.proc_callback_t
val reporting : Callbacks.cluster_callback_t
val reporting : Callbacks.file_callback_t
val whole_program_analysis : unit -> unit

Loading…
Cancel
Save