diff --git a/infer/src/IR/IssueLog.mli b/infer/src/IR/IssueLog.mli index cb1bf9487..c82455ec3 100644 --- a/infer/src/IR/IssueLog.mli +++ b/infer/src/IR/IssueLog.mli @@ -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 diff --git a/infer/src/backend/InferAnalyze.ml b/infer/src/backend/InferAnalyze.ml index 51be092aa..4bd72edbc 100644 --- a/infer/src/backend/InferAnalyze.ml +++ b/infer/src/backend/InferAnalyze.ml @@ -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 diff --git a/infer/src/backend/Summary.mli b/infer/src/backend/Summary.mli index 314f84b47..a31788781 100644 --- a/infer/src/backend/Summary.mli +++ b/infer/src/backend/Summary.mli @@ -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 diff --git a/infer/src/backend/callbacks.ml b/infer/src/backend/callbacks.ml index 360f18c85..4ad1c1039 100644 --- a/infer/src/backend/callbacks.ml +++ b/infer/src/backend/callbacks.ml @@ -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 diff --git a/infer/src/backend/callbacks.mli b/infer/src/backend/callbacks.mli index 4a9e28374..06ee08c7a 100644 --- a/infer/src/backend/callbacks.mli +++ b/infer/src/backend/callbacks.mli @@ -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 *) diff --git a/infer/src/backend/ondemand.ml b/infer/src/backend/ondemand.ml index a83b2c21d..d86c31f52 100644 --- a/infer/src/backend/ondemand.ml +++ b/infer/src/backend/ondemand.ml @@ -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) diff --git a/infer/src/backend/printer.ml b/infer/src/backend/printer.ml index dcf04ba27..40385a033 100644 --- a/infer/src/backend/printer.ml +++ b/infer/src/backend/printer.ml @@ -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 diff --git a/infer/src/backend/printer.mli b/infer/src/backend/printer.mli index 9b7a6094a..1dd3257df 100644 --- a/infer/src/backend/printer.mli +++ b/infer/src/backend/printer.mli @@ -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. *) diff --git a/infer/src/checkers/registerCheckers.ml b/infer/src/checkers/registerCheckers.ml index 41f6ae475..50d84c631 100644 --- a/infer/src/checkers/registerCheckers.ml +++ b/infer/src/checkers/registerCheckers.ml @@ -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 diff --git a/infer/src/concurrency/RacerD.ml b/infer/src/concurrency/RacerD.ml index b4f990262..1880b0e35 100644 --- a/infer/src/concurrency/RacerD.ml +++ b/infer/src/concurrency/RacerD.ml @@ -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 -> diff --git a/infer/src/concurrency/RacerD.mli b/infer/src/concurrency/RacerD.mli index 69d9a311b..f7be0cf6c 100644 --- a/infer/src/concurrency/RacerD.mli +++ b/infer/src/concurrency/RacerD.mli @@ -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 diff --git a/infer/src/concurrency/starvation.mli b/infer/src/concurrency/starvation.mli index 6b4b8d4d0..67b92d8e4 100644 --- a/infer/src/concurrency/starvation.mli +++ b/infer/src/concurrency/starvation.mli @@ -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