diff --git a/infer/src/backend/InferAnalyze.re b/infer/src/backend/InferAnalyze.re index dec4bed8b..b5633198b 100644 --- a/infer/src/backend/InferAnalyze.re +++ b/infer/src/backend/InferAnalyze.re @@ -108,10 +108,25 @@ let print_legend () => { L.progress "@\n@?" }; -let cluster_should_be_analyzed cluster => { +let cluster_should_be_analyzed ::changed_files cluster => { let fname = DB.source_dir_to_string cluster; - let in_ondemand_config = - Option.map f::(fun dirs => String.Set.mem dirs fname) Ondemand.dirs_to_analyze; + /* whether [fname] is one of the [changed_files] */ + let is_changed_file = { + /* set of source dirs to analyze inside infer-out/captured/ */ + let source_dirs_to_analyze changed_files => + SourceFile.Set.fold + ( + fun source_file source_dir_set => { + let source_dir = DB.source_dir_from_source_file source_file; + String.Set.add source_dir_set (DB.source_dir_to_string source_dir) + } + ) + changed_files + String.Set.empty; + Option.map f::source_dirs_to_analyze changed_files |> ( + fun dirs_opt => Option.map dirs_opt f::(fun dirs => String.Set.mem dirs fname) + ) + }; let check_modified () => { let modified = DB.file_was_updated_after_start (DB.filename_from_string fname); if (modified && Config.developer_mode) { @@ -119,16 +134,14 @@ let cluster_should_be_analyzed cluster => { }; modified }; - switch in_ondemand_config { - | Some b => - /* ondemand config file is specified */ - b + switch is_changed_file { + | Some b => b | None when Config.reactive_mode => check_modified () | None => true } }; -let main makefile => { +let main ::changed_files ::makefile => { BuiltinDefn.init (); RegisterCheckers.register (); switch Config.modified_targets { @@ -145,13 +158,14 @@ let main makefile => { MergeCapture.merge_captured_targets () }; let all_clusters = DB.find_source_dirs (); - let clusters_to_analyze = List.filter f::cluster_should_be_analyzed all_clusters; + let clusters_to_analyze = + List.filter f::(cluster_should_be_analyzed ::changed_files) all_clusters; let n_clusters_to_analyze = List.length clusters_to_analyze; L.progress "Found %d%s source file%s to analyze in %s@." n_clusters_to_analyze ( - if (Config.reactive_mode || Option.is_some Ondemand.dirs_to_analyze) { + if (Config.reactive_mode || Option.is_some changed_files) { " (out of " ^ string_of_int (List.length all_clusters) ^ ")" } else { "" diff --git a/infer/src/backend/InferAnalyze.rei b/infer/src/backend/InferAnalyze.rei index b931e1823..9dda254c4 100644 --- a/infer/src/backend/InferAnalyze.rei +++ b/infer/src/backend/InferAnalyze.rei @@ -13,6 +13,6 @@ open! IStd; /** Main module for the analysis after the capture phase */ /** Given a name of the Makefile to use for multicore analysis, analyze the captured code */ -let main: string => unit; +let main: changed_files::option SourceFile.Set.t => makefile::string => unit; let register_perf_stats_report: unit => unit; diff --git a/infer/src/backend/infer.ml b/infer/src/backend/infer.ml index 172aba1d8..b946f3c79 100644 --- a/infer/src/backend/infer.ml +++ b/infer/src/backend/infer.ml @@ -243,13 +243,13 @@ let capture_with_compilation_database db_files = let compilation_database = CompilationDatabase.from_json_files db_files in CaptureCompilationDatabase.capture_files_in_database compilation_database -let capture = function +let capture ~changed_files = function | Analyze -> () | BuckCompilationDB (prog, args) -> L.progress "Capturing using Buck's compilation database...@."; let json_cdb = CaptureCompilationDatabase.get_compilation_database_files_buck ~prog ~args in - capture_with_compilation_database json_cdb + capture_with_compilation_database ~changed_files json_cdb | BuckGenrule path -> L.progress "Capturing for Buck genrule compatibility...@."; JMain.from_arguments path @@ -258,7 +258,7 @@ let capture = function Clang.capture compiler ~prog ~args | ClangCompilationDB db_files -> L.progress "Capturing using compilation database...@."; - capture_with_compilation_database db_files + capture_with_compilation_database ~changed_files db_files | Javac (compiler, prog, args) -> L.progress "Capturing in javac mode...@."; Javac.capture compiler ~prog ~args @@ -327,13 +327,13 @@ let capture = function check_xcpretty (); let json_cdb = CaptureCompilationDatabase.get_compilation_database_files_xcodebuild ~prog ~args in - capture_with_compilation_database json_cdb + capture_with_compilation_database ~changed_files json_cdb -let run_parallel_analysis () = +let run_parallel_analysis ~changed_files = let multicore_dir = Config.results_dir ^/ Config.multicore_dir_name in rmtree multicore_dir ; Unix.mkdir_p multicore_dir ; - InferAnalyze.main (multicore_dir ^/ "Makefile") ; + InferAnalyze.main ~changed_files ~makefile:(multicore_dir ^/ "Makefile") ; run_command ~prog:"make" ~args:( "-C" :: multicore_dir :: @@ -343,11 +343,11 @@ let run_parallel_analysis () = (if Config.debug_mode then [] else ["-s"]) ) (fun _ -> ()) -let execute_analyze () = +let execute_analyze ~changed_files = if Int.equal Config.jobs 1 || Config.cluster_cmdline <> None then - InferAnalyze.main "" + InferAnalyze.main ~changed_files ~makefile:"" else - run_parallel_analysis () + run_parallel_analysis ~changed_files let report () = let report_csv = @@ -378,7 +378,7 @@ let report () = "** Error running the reporting script:@\n** %s %s@\n** See error above@." prog (String.concat ~sep:" " args) -let analyze driver_mode = +let analyze driver_mode ~changed_files = let should_analyze, should_report = match driver_mode, Config.analyzer with | PythonCapture (BBuck, _), _ -> (* In Buck mode when compilation db is not used, analysis is invoked either from capture or @@ -398,7 +398,7 @@ let analyze driver_mode = check_captured_empty driver_mode) then ( L.user_error "There was nothing to analyze.@\n@." ; ) else if should_analyze then - execute_analyze (); + execute_analyze ~changed_files; if should_report && Config.report then report () (** as the Config.fail_on_bug flag mandates, exit with error when an issue is reported *) @@ -512,6 +512,17 @@ let get_driver_mode () = | None -> driver_mode_of_build_cmd (List.rev Config.rest) +let read_config_changed_files () = + match Config.changed_files_index with + | None -> + None + | Some index -> match Utils.read_file index with + | Ok lines -> + Some (SourceFile.changed_sources_from_changed_files lines) + | Error error -> + L.external_error "Error reading the changed files index '%s': %s@." index error ; + None + let infer_mode () = let driver_mode = get_driver_mode () in if not (equal_driver_mode driver_mode Analyze || @@ -528,8 +539,9 @@ let infer_mode () = Unix.unsetenv "MAKEFLAGS"; register_perf_stats_report () ; if not Config.buck_cache_mode then touch_start_file_unless_continue () ; - capture driver_mode ; - analyze driver_mode ; + let changed_files = read_config_changed_files () in + capture driver_mode ~changed_files ; + analyze driver_mode ~changed_files ; if CLOpt.is_originator then ( let in_buck_mode = match driver_mode with | PythonCapture (BBuck, _) -> true | _ -> false in StatsAggregator.generate_files () ; @@ -602,7 +614,7 @@ let () = | Some cluster -> F.fprintf fmt "of cluster %s" (Filename.basename cluster) in L.environment_info "Starting analysis %a" pp_cluster_opt Config.cluster_cmdline; InferAnalyze.register_perf_stats_report (); - analyze Analyze + analyze Analyze ~changed_files:(read_config_changed_files ()) | Clang -> let prog, args = match Array.to_list Sys.argv with | prog::args -> prog, args diff --git a/infer/src/backend/ondemand.ml b/infer/src/backend/ondemand.ml index 8294e23d9..16eab1679 100644 --- a/infer/src/backend/ondemand.ml +++ b/infer/src/backend/ondemand.ml @@ -15,18 +15,6 @@ open! PVariant module L = Logging module F = Format -(** Optional set of source dirs to analyze in on-demand mode. If None then all source dirs - will be analyzed *) -let dirs_to_analyze = - let process_changed_files changed_files = - SourceFile.Set.fold - (fun source_file source_dir_set -> - let source_dir = DB.source_dir_from_source_file source_file in - String.Set.add source_dir_set (DB.source_dir_to_string source_dir) - ) - changed_files String.Set.empty in - Option.map ~f:process_changed_files SourceFile.changed_files_set - type analyze_ondemand = Specs.summary -> Procdesc.t -> Specs.summary type get_proc_desc = Typ.Procname.t -> Procdesc.t option diff --git a/infer/src/backend/ondemand.mli b/infer/src/backend/ondemand.mli index 5d5913be6..e4ebe4084 100644 --- a/infer/src/backend/ondemand.mli +++ b/infer/src/backend/ondemand.mli @@ -11,10 +11,6 @@ open! IStd (** Module for on-demand analysis. *) -(** Optional set of source dirs to analyze in on-demand mode. If None then all source dirs - will be analyzed *) -val dirs_to_analyze : String.Set.t option - type analyze_ondemand = Specs.summary -> Procdesc.t -> Specs.summary type get_proc_desc = Typ.Procname.t -> Procdesc.t option diff --git a/infer/src/base/SourceFile.ml b/infer/src/base/SourceFile.ml index 500097b90..898a12279 100644 --- a/infer/src/base/SourceFile.ml +++ b/infer/src/base/SourceFile.ml @@ -135,23 +135,15 @@ let create ?(warn_on_error=true) path = else from_abs_path ~warn_on_error path -let changed_files_set = - match Config.changed_files_index with - | None -> - None - | Some index -> match Utils.read_file index with - | Ok lines -> - Some (List.fold lines ~init:Set.empty ~f:(fun changed_files line -> - let source_file = create line in - let changed_files' = Set.add source_file changed_files in - (* Add source corresponding to changed header if it exists *) - match of_header source_file with - | Some src -> Set.add src changed_files' - | None -> changed_files' - )) - | Error error -> - L.user_error "Error reading the changed files index '%s': %s@." index error ; - None +let changed_sources_from_changed_files changed_files = + List.fold changed_files ~init:Set.empty ~f:(fun changed_files_set line -> + let source_file = create line in + let changed_files' = Set.add source_file changed_files_set in + (* Add source corresponding to changed header if it exists *) + match of_header source_file with + | Some src -> Set.add src changed_files' + | None -> changed_files' + ) module UNSAFE = struct let from_string str = diff --git a/infer/src/base/SourceFile.mli b/infer/src/base/SourceFile.mli index 950e8f172..a74ed935c 100644 --- a/infer/src/base/SourceFile.mli +++ b/infer/src/base/SourceFile.mli @@ -30,7 +30,7 @@ val is_invalid : t -> bool (** Set of files read from --changed-files-index file, None if option not specified NOTE: it may include extra source_files if --changed-files-index contains paths to header files *) -val changed_files_set : Set.t option +val changed_sources_from_changed_files : string list -> Set.t (** Invalid source file *) val invalid : string -> t diff --git a/infer/src/integration/CaptureCompilationDatabase.ml b/infer/src/integration/CaptureCompilationDatabase.ml index a5da7db47..8fc3b525a 100644 --- a/infer/src/integration/CaptureCompilationDatabase.ml +++ b/infer/src/integration/CaptureCompilationDatabase.ml @@ -18,17 +18,6 @@ let capture_text = if Config.equal_analyzer Config.analyzer Config.Linters then "linting" else "translating" -(** Read the files to compile from the changed files index. *) -let should_capture_file_from_index () = - match SourceFile.changed_files_set with - | None -> - (match Config.changed_files_index with - | Some index -> - Process.print_error_and_exit "Error reading the changed files index %s.@\n%!" index - | None -> function _ -> true) - | Some files_set -> - function source_file -> SourceFile.Set.mem source_file files_set - let create_files_stack compilation_database should_capture_file = let stack = Stack.create () in let add_to_stack file _ = if should_capture_file file then @@ -140,8 +129,14 @@ let get_compilation_database_files_xcodebuild ~prog ~args = L.external_error "There was an error executing the build command"; exit 1 -let capture_files_in_database compilation_database = - run_compilation_database compilation_database (should_capture_file_from_index ()) +let capture_files_in_database ~changed_files compilation_database = + let filter_changed = match changed_files with + | None -> + fun _ -> true + | Some changed_files_set -> + fun source_file -> SourceFile.Set.mem source_file changed_files_set + in + run_compilation_database compilation_database filter_changed let capture_file_in_database compilation_database source_file = run_compilation_database compilation_database (SourceFile.equal source_file) diff --git a/infer/src/integration/CaptureCompilationDatabase.mli b/infer/src/integration/CaptureCompilationDatabase.mli index 0db2df81f..f7b5ee69b 100644 --- a/infer/src/integration/CaptureCompilationDatabase.mli +++ b/infer/src/integration/CaptureCompilationDatabase.mli @@ -9,10 +9,10 @@ open! IStd -(** capture_files_in_database file runs the capture of the files for which - we have compilation commands in the database. If the option changed-files-index - is passed, we only capture the files there *) -val capture_files_in_database : CompilationDatabase.t -> unit +(** Run the capture of the files for which we have compilation commands in the database and in + [changed_files], if specified. *) +val capture_files_in_database : changed_files:SourceFile.Set.t option -> + CompilationDatabase.t -> unit val capture_file_in_database : CompilationDatabase.t -> SourceFile.t -> unit