diff --git a/infer/src/base/Config.ml b/infer/src/base/Config.ml index 254ef3545..e35f61631 100644 --- a/infer/src/base/Config.ml +++ b/infer/src/base/Config.ml @@ -651,6 +651,13 @@ and clang_include_to_override_regex = location of internal compiler headers. This option should specify regular expression with \ the path to those headers so that infer can use its own clang internal headers instead." +and clang_ignore_regex = + CLOpt.mk_string_opt ~long:"clang-ignore-regex" + ~meta:"dir OCaml regex" + "The files in this regex will be ignored in the compilation process and \ + an empty file will be passed to clang instead. This is to be used with the buck flavour \ + infer-capture-all to work around missing generated files." + and classpath = CLOpt.mk_string_opt ~long:"classpath" "Specify the Java classpath" @@ -1629,6 +1636,7 @@ and dump_duplicate_symbols = !dump_duplicate_symbols and checkers = !checkers and checkers_repeated_calls = !checkers_repeated_calls and clang_biniou_file = !clang_biniou_file +and clang_ignore_regex = !clang_ignore_regex and clang_include_to_override_regex = !clang_include_to_override_regex and classpath = !classpath and cluster_cmdline = !cluster diff --git a/infer/src/base/Config.mli b/infer/src/base/Config.mli index 6d92f0229..293ddad71 100644 --- a/infer/src/base/Config.mli +++ b/infer/src/base/Config.mli @@ -197,6 +197,7 @@ val clang_biniou_file : string option val clang_frontend_action_string : string val clang_frontend_do_capture : bool val clang_frontend_do_lint : bool +val clang_ignore_regex : string option val clang_include_to_override_regex : string option val cluster_cmdline : string option val compute_analytics : bool diff --git a/infer/src/clang/ClangWrapper.re b/infer/src/clang/ClangWrapper.re index c6752a0cf..318c4f2e7 100644 --- a/infer/src/clang/ClangWrapper.re +++ b/infer/src/clang/ClangWrapper.re @@ -17,6 +17,41 @@ type action_item = | ClangError string | ClangWarning string; +let clang_ignore_regex = Option.map f::Str.regexp Config.clang_ignore_regex; + +let check_for_existing_file args => + if (Option.is_some clang_ignore_regex && Option.is_none Config.buck_compilation_database) { + let (arg_files, args_list) = List.partition_tf f::(String.is_prefix prefix::"@") args; + let read_arg_files args_list arg_file_at => { + let file = String.slice arg_file_at 1 (String.length arg_file_at); + let args_list_file = In_channel.read_lines file; + List.append args_list args_list_file + }; + let all_args_ = List.fold_left f::read_arg_files init::args_list arg_files; + let all_args = List.map f::String.strip all_args_; + let rec check_for_existing_file_arg args => + switch args { + | [] => () + | [option, ...rest] => + if (String.equal option "-c") { + /* infer-capture-all flavour of buck produces path to generated file that doesn't exist. + Create empty file empty file and pass that to clang. This is to enable compilation to continue */ + switch (clang_ignore_regex, List.hd rest) { + | (Some regexp, Some arg) => + if (Str.string_match regexp arg 0 && Sys.file_exists arg != `Yes) { + Unix.mkdir_p (Filename.dirname arg); + let file = Unix.openfile mode::[Unix.O_CREAT, Unix.O_RDONLY] arg; + Unix.close file + } + | _ => () + } + } else { + check_for_existing_file_arg rest + } + }; + check_for_existing_file_arg all_args + }; + /** Given a list of arguments for clang [args], return a list of new commands to run according to the results of `clang -### [args]`. */ @@ -100,6 +135,7 @@ let exe ::prog ::args => { let xx_suffix = String.is_suffix suffix::"++" prog ? "++" : ""; /* use clang in facebook-clang-plugins */ let clang_xx = CFrontend_config.clang_bin xx_suffix; + check_for_existing_file args; let commands = normalize prog::clang_xx ::args; /* xcodebuild projects may require the object files to be generated by the Apple compiler, eg to generate precompiled headers compatible with Apple's clang. */