[buck] java & clang combined capture

Summary:
A buck integration for capturing simultaneously clang and java targets.
Just like the java-specific `JavaGenruleCapture` integration, it relies on
dummy targets that depend on the flavoured clang versions.

For example, a `cxx_library` target named `//clang:hello` will have an associated target
called `//clang:hello_infer` that depends on `//clang:hello#infer-capture-all`,
and whose output is a text file containing the output path of the dependency.

Reviewed By: jvillard

Differential Revision: D21620458

fbshipit-source-id: 23919387b
master
Nikos Gorogiannis 5 years ago committed by Facebook GitHub Bot
parent 090ce4edb9
commit 2bbd25087c

@ -126,6 +126,10 @@ BUCK OPTIONS
Activates: Buck integration for clang-based targets Activates: Buck integration for clang-based targets
(C/C++/Objective-C/Objective-C++). (Conversely: --no-buck-clang) (C/C++/Objective-C/Objective-C++). (Conversely: --no-buck-clang)
--buck-combined
Activates: Buck integration for clang-based and Java targets.
(Conversely: --no-buck-combined)
--buck-compilation-database { no-deps | deps } --buck-compilation-database { no-deps | deps }
Buck integration using the compilation database, with or without Buck integration using the compilation database, with or without
dependencies. Only includes clang targets, as per Buck's dependencies. Only includes clang targets, as per Buck's

@ -143,6 +143,10 @@ OPTIONS
(C/C++/Objective-C/Objective-C++). (Conversely: --no-buck-clang) (C/C++/Objective-C/Objective-C++). (Conversely: --no-buck-clang)
See also infer-capture(1). See also infer-capture(1).
--buck-combined
Activates: Buck integration for clang-based and Java targets.
(Conversely: --no-buck-combined) See also infer-capture(1).
--buck-compilation-database { no-deps | deps } --buck-compilation-database { no-deps | deps }
Buck integration using the compilation database, with or without Buck integration using the compilation database, with or without
dependencies. Only includes clang targets, as per Buck's dependencies. Only includes clang targets, as per Buck's

@ -143,6 +143,10 @@ OPTIONS
(C/C++/Objective-C/Objective-C++). (Conversely: --no-buck-clang) (C/C++/Objective-C/Objective-C++). (Conversely: --no-buck-clang)
See also infer-capture(1). See also infer-capture(1).
--buck-combined
Activates: Buck integration for clang-based and Java targets.
(Conversely: --no-buck-combined) See also infer-capture(1).
--buck-compilation-database { no-deps | deps } --buck-compilation-database { no-deps | deps }
Buck integration using the compilation database, with or without Buck integration using the compilation database, with or without
dependencies. Only includes clang targets, as per Buck's dependencies. Only includes clang targets, as per Buck's

@ -20,10 +20,14 @@ let pp_clang_compilation_db_deps fmt = function
F.pp_print_string fmt "DepsAllDepths" F.pp_print_string fmt "DepsAllDepths"
type t = ClangFlavors | ClangCompilationDB of clang_compilation_db_deps | JavaGenruleMaster type t =
| CombinedGenrule
let is_java_genrule_master = function | ClangFlavors
| JavaGenruleMaster -> | ClangCompilationDB of clang_compilation_db_deps
| JavaGenruleMaster
let is_java_genrule_master_or_combined = function
| JavaGenruleMaster | CombinedGenrule ->
true true
| ClangFlavors | ClangCompilationDB _ -> | ClangFlavors | ClangCompilationDB _ ->
false false
@ -32,12 +36,12 @@ let is_java_genrule_master = function
let is_clang_compilation_db = function let is_clang_compilation_db = function
| ClangCompilationDB _ -> | ClangCompilationDB _ ->
true true
| ClangFlavors | JavaGenruleMaster -> | ClangFlavors | JavaGenruleMaster | CombinedGenrule ->
false false
let is_clang_flavors = function let is_clang_flavors = function
| ClangFlavors -> | ClangFlavors ->
true true
| ClangCompilationDB _ | JavaGenruleMaster -> | ClangCompilationDB _ | JavaGenruleMaster | CombinedGenrule ->
false false

@ -13,9 +13,13 @@ type clang_compilation_db_deps = NoDependencies | DepsUpToDepth of int | DepsAll
val pp_clang_compilation_db_deps : F.formatter -> clang_compilation_db_deps -> unit val pp_clang_compilation_db_deps : F.formatter -> clang_compilation_db_deps -> unit
type t = ClangFlavors | ClangCompilationDB of clang_compilation_db_deps | JavaGenruleMaster type t =
| CombinedGenrule
| ClangFlavors
| ClangCompilationDB of clang_compilation_db_deps
| JavaGenruleMaster
val is_java_genrule_master : t -> bool val is_java_genrule_master_or_combined : t -> bool
val is_clang_compilation_db : t -> bool val is_clang_compilation_db : t -> bool

@ -727,6 +727,11 @@ and buck_mode =
clang targets, as per Buck's $(i,#compilation-database) flavor." clang targets, as per Buck's $(i,#compilation-database) flavor."
~symbols:[("no-deps", `NoDeps); ("deps", `DepsTmp)] ~symbols:[("no-deps", `NoDeps); ("deps", `DepsTmp)]
|> ignore ; |> ignore ;
CLOpt.mk_bool ~long:"buck-combined"
~in_help:InferCommand.[(Capture, manual_buck)]
~f:(set_mode `CombinedGenrule)
"Buck integration for clang-based and Java targets."
|> ignore ;
buck_mode buck_mode
@ -2590,6 +2595,8 @@ and buck_mode : BuckMode.t option =
Some (ClangCompilationDB DepsAllDepths) Some (ClangCompilationDB DepsAllDepths)
| `ClangCompilationDB `DepsTmp, Some depth -> | `ClangCompilationDB `DepsTmp, Some depth ->
Some (ClangCompilationDB (DepsUpToDepth depth)) Some (ClangCompilationDB (DepsUpToDepth depth))
| `CombinedGenrule, _ ->
Some CombinedGenrule
and buck_targets_blacklist = !buck_targets_blacklist and buck_targets_blacklist = !buck_targets_blacklist

@ -81,7 +81,7 @@ module Target = struct
match (mode, command) with match (mode, command) with
| ClangCompilationDB _, _ -> | ClangCompilationDB _, _ ->
add_flavor_internal target "compilation-database" add_flavor_internal target "compilation-database"
| ClangFlavors, Compile | JavaGenruleMaster, _ -> | ClangFlavors, Compile | JavaGenruleMaster, _ | CombinedGenrule, _ ->
target target
| ClangFlavors, _ -> | ClangFlavors, _ ->
add_flavor_internal target "infer-capture-all" add_flavor_internal target "infer-capture-all"
@ -191,12 +191,14 @@ let parameters_with_argument =
let get_accepted_buck_kinds_pattern (mode : BuckMode.t) = let get_accepted_buck_kinds_pattern (mode : BuckMode.t) =
match mode with match mode with
| CombinedGenrule ->
"^(android|apple|cxx|java)_(binary|library)$"
| ClangCompilationDB _ -> | ClangCompilationDB _ ->
"^(apple|cxx)_(binary|library|test)$" "^(apple|cxx)_(binary|library|test)$"
| JavaGenruleMaster ->
"^(java|android)_library$"
| ClangFlavors -> | ClangFlavors ->
"^(apple|cxx)_(binary|library)$" "^(apple|cxx)_(binary|library)$"
| JavaGenruleMaster ->
"^(java|android)_library$"
let max_command_line_length = 50 let max_command_line_length = 50
@ -209,37 +211,46 @@ let infer_enabled_label = "infer_enabled"
(** for genrule_master_mode, this is the target name suffix for the capture genrules *) (** for genrule_master_mode, this is the target name suffix for the capture genrules *)
let genrule_suffix = "_infer" let genrule_suffix = "_infer"
let config buck_mode = let config =
let clang_path = let clang_path =
List.fold ["clang"; "install"; "bin"; "clang"] ~init:Config.fcp_dir ~f:Filename.concat List.fold ["clang"; "install"; "bin"; "clang"] ~init:Config.fcp_dir ~f:Filename.concat
in in
let args = let get_java_genrule_config () =
match (buck_mode : BuckMode.t) with ["infer.version=" ^ Version.versionString; "infer.mode=capture"]
| JavaGenruleMaster ->
["infer.version=" ^ Version.versionString; "infer.mode=capture"]
| ClangFlavors ->
[ "client.id=infer.clang"
; Printf.sprintf "*//infer.infer_bin=%s" Config.bin_dir
; Printf.sprintf "*//infer.clang_compiler=%s" clang_path
; Printf.sprintf "*//infer.clang_plugin=%s" Config.clang_plugin_path
; "*//cxx.pch_enabled=false"
; (* Infer doesn't support C++ modules yet (T35656509) *)
"*//cxx.modules_default=false"
; "*//cxx.modules=false" ]
@ ( match Config.xcode_developer_dir with
| Some d ->
[Printf.sprintf "apple.xcode_developer_dir=%s" d]
| None ->
[] )
@
if List.is_empty Config.buck_blacklist then []
else
[ Printf.sprintf "*//infer.blacklist_regex=(%s)"
(String.concat ~sep:")|(" Config.buck_blacklist) ]
| ClangCompilationDB _ ->
[]
in in
List.fold args ~init:[] ~f:(fun acc f -> "--config" :: f :: acc) let get_flavors_config () =
[ "client.id=infer.clang"
; Printf.sprintf "*//infer.infer_bin=%s" Config.bin_dir
; Printf.sprintf "*//infer.clang_compiler=%s" clang_path
; Printf.sprintf "*//infer.clang_plugin=%s" Config.clang_plugin_path
; "*//cxx.pch_enabled=false"
; (* Infer doesn't support C++ modules yet (T35656509) *)
"*//cxx.modules_default=false"
; "*//cxx.modules=false" ]
@ ( match Config.xcode_developer_dir with
| Some d ->
[Printf.sprintf "apple.xcode_developer_dir=%s" d]
| None ->
[] )
@
if List.is_empty Config.buck_blacklist then []
else
[ Printf.sprintf "*//infer.blacklist_regex=(%s)"
(String.concat ~sep:")|(" Config.buck_blacklist) ]
in
fun buck_mode ->
let args =
match (buck_mode : BuckMode.t) with
| JavaGenruleMaster ->
get_java_genrule_config ()
| ClangFlavors ->
get_flavors_config ()
| CombinedGenrule ->
get_java_genrule_config () @ get_flavors_config ()
| ClangCompilationDB _ ->
[]
in
List.fold args ~init:[] ~f:(fun acc f -> "--config" :: f :: acc)
let resolve_pattern_targets (buck_mode : BuckMode.t) ~filter_kind targets = let resolve_pattern_targets (buck_mode : BuckMode.t) ~filter_kind targets =
@ -247,17 +258,18 @@ let resolve_pattern_targets (buck_mode : BuckMode.t) ~filter_kind targets =
|> ( match buck_mode with |> ( match buck_mode with
| ClangFlavors | ClangCompilationDB NoDependencies -> | ClangFlavors | ClangCompilationDB NoDependencies ->
Fn.id Fn.id
| JavaGenruleMaster | ClangCompilationDB DepsAllDepths -> | CombinedGenrule | ClangCompilationDB DepsAllDepths | JavaGenruleMaster ->
Query.deps None Query.deps None
| ClangCompilationDB (DepsUpToDepth depth) -> | ClangCompilationDB (DepsUpToDepth depth) ->
Query.deps (Some depth) ) Query.deps (Some depth) )
|> (if filter_kind then Query.kind ~pattern:(get_accepted_buck_kinds_pattern buck_mode) else Fn.id) |> (if filter_kind then Query.kind ~pattern:(get_accepted_buck_kinds_pattern buck_mode) else Fn.id)
|> ( if BuckMode.is_java_genrule_master buck_mode then |> ( if BuckMode.is_java_genrule_master_or_combined buck_mode then
Query.label_filter ~label:infer_enabled_label Query.label_filter ~label:infer_enabled_label
else Fn.id ) else Fn.id )
|> Query.exec ~buck_config:(config buck_mode) |> Query.exec ~buck_config:(config buck_mode)
|> |>
if BuckMode.is_java_genrule_master buck_mode then List.rev_map ~f:(fun s -> s ^ genrule_suffix) if BuckMode.is_java_genrule_master_or_combined buck_mode then
List.rev_map ~f:(fun s -> s ^ genrule_suffix)
else Fn.id else Fn.id
@ -346,11 +358,12 @@ let parse_command_and_targets (buck_mode : BuckMode.t) ~filter_kind original_buc
let targets = let targets =
match (filter_kind, buck_mode, parsed_args) with match (filter_kind, buck_mode, parsed_args) with
| ( (`No | `Auto) | ( (`No | `Auto)
, (ClangFlavors | JavaGenruleMaster) , (ClangFlavors | JavaGenruleMaster | CombinedGenrule)
, {pattern_targets= []; alias_targets= []; normal_targets} ) -> , {pattern_targets= []; alias_targets= []; normal_targets} ) ->
normal_targets normal_targets
| `No, (ClangFlavors | JavaGenruleMaster), {pattern_targets= []; alias_targets; normal_targets} | ( `No
-> , (ClangFlavors | JavaGenruleMaster | CombinedGenrule)
, {pattern_targets= []; alias_targets; normal_targets} ) ->
alias_targets |> resolve_alias_targets |> List.rev_append normal_targets alias_targets |> resolve_alias_targets |> List.rev_append normal_targets
| (`Yes | `No | `Auto), _, {pattern_targets; alias_targets; normal_targets} -> | (`Yes | `No | `Auto), _, {pattern_targets; alias_targets; normal_targets} ->
let filter_kind = match filter_kind with `No -> false | `Yes | `Auto -> true in let filter_kind = match filter_kind with `No -> false | `Yes | `Auto -> true in

@ -42,7 +42,7 @@ module L = Logging
] ]
*) *)
(** Read the build report json file buck produced, and parse into a sorted list of pairs (** Read the build report json file buck produced, and parse into a list of pairs
[(target, output-path)]. NB contrary to what buck documentation says, the output path is always [(target, output-path)]. NB contrary to what buck documentation says, the output path is always
present even when the target is locally cached. *) present even when the target is locally cached. *)
let read_and_parse_report build_report = let read_and_parse_report build_report =
@ -78,9 +78,56 @@ let read_and_parse_report build_report =
| _ -> | _ ->
None None
in in
Yojson.Basic.from_file build_report Yojson.Basic.from_file build_report |> get_json_field "results" |> Option.bind ~f:parse_results
|> get_json_field "results" |> Option.bind ~f:parse_results
|> Option.map ~f:(List.stable_sort ~compare:[%compare: string * string])
(** Function for processing paths in a buck build report and generating an [infer-deps.txt] file.
Given a pair [(buck_target, output_path)],
- if [output_path] contains a capture DB, then generate the appropriate deps line;
- if [output_path] contains an [infer-deps.txt] file, expand and inline it;
- if [output_path] is a dummy target used in the combined genrule integration for clang targets,
read its contents, parse them as an output directory path and apply the above two tests to
that *)
let expand_target acc (target, target_path) =
let expand_dir acc (target, target_path) =
(* invariant: [target_path] is absolute *)
let db_file = ResultsDirEntryName.get_path ~results_dir:target_path CaptureDB in
match Sys.file_exists db_file with
| `Yes ->
(* there is a capture DB at this path, so terminate expansion and generate deps line *)
let line = Printf.sprintf "%s\t-\t%s" target target_path in
line :: acc
| `No | `Unknown -> (
(* no capture DB was found, so look for, and inline, an [infer-deps.txt] file *)
let infer_deps = ResultsDirEntryName.get_path ~results_dir:target_path BuckDependencies in
match Sys.file_exists infer_deps with
| `Yes ->
Utils.with_file_in infer_deps
~f:(In_channel.fold_lines ~init:acc ~f:(fun acc line -> line :: acc))
| `No | `Unknown ->
L.internal_error "No capture DB or infer-deps file in %s@." target_path ;
acc )
in
let target_path =
if Filename.is_absolute target_path then target_path else Config.project_root ^/ target_path
in
match Sys.is_directory target_path with
| `Yes ->
(* output path is directory, so should contain either a capture DB or an [infer-deps.txt] file *)
expand_dir acc (target, target_path)
| `No | `Unknown -> (
(* output path is not a directory, so assume it's an intermediate genrule output containing the
output path of the underlying capture target *)
match Utils.read_file target_path with
| Ok [new_target_path] ->
expand_dir acc (target, new_target_path)
| Ok _ ->
L.internal_error "Couldn't parse intermediate deps file %s@." target_path ;
acc
| Error error ->
L.internal_error "Error %s@\nCouldn't read intermediate deps file %s@." error target_path ;
acc )
let infer_deps_of_build_report build_report = let infer_deps_of_build_report build_report =
@ -88,12 +135,13 @@ let infer_deps_of_build_report build_report =
| None -> | None ->
L.die InternalError "Couldn't parse buck build report: %s@." build_report L.die InternalError "Couldn't parse buck build report: %s@." build_report
| Some target_path_list -> | Some target_path_list ->
let out_line out_channel (target, target_output_path) = let infer_deps_lines =
Printf.fprintf out_channel "%s\t-\t%s\n" target (Config.project_root ^/ target_output_path) List.fold target_path_list ~init:[] ~f:expand_target
|> List.dedup_and_sort ~compare:String.compare
in in
let infer_deps = ResultsDir.get_path BuckDependencies in let infer_deps = ResultsDir.get_path BuckDependencies in
Utils.with_file_out infer_deps ~f:(fun out_channel -> Utils.with_file_out infer_deps ~f:(fun out_channel ->
List.iter target_path_list ~f:(out_line out_channel) ) Out_channel.output_lines out_channel infer_deps_lines )
let run_buck_capture cmd = let run_buck_capture cmd =
@ -106,12 +154,12 @@ let run_buck_capture cmd =
Buck.wrap_buck_call ~extend_env ~label:"build" cmd |> ignore Buck.wrap_buck_call ~extend_env ~label:"build" cmd |> ignore
let capture build_cmd = let capture buck_mode build_cmd =
let prog, buck_cmd = (List.hd_exn build_cmd, List.tl_exn build_cmd) in let prog, buck_cmd = (List.hd_exn build_cmd, List.tl_exn build_cmd) in
L.progress "Querying buck for genrule capture targets...@." ; L.progress "Querying buck for genrule capture targets...@." ;
let time0 = Mtime_clock.counter () in let time0 = Mtime_clock.counter () in
let command, args, targets = let command, args, targets =
Buck.parse_command_and_targets JavaGenruleMaster ~filter_kind:`Yes buck_cmd Buck.parse_command_and_targets buck_mode ~filter_kind:`Yes buck_cmd
in in
L.progress "Found %d genrule capture targets in %a.@." (List.length targets) Mtime.Span.pp L.progress "Found %d genrule capture targets in %a.@." (List.length targets) Mtime.Span.pp
(Mtime_clock.count time0) ; (Mtime_clock.count time0) ;
@ -121,7 +169,7 @@ let capture build_cmd =
in in
let updated_buck_cmd = let updated_buck_cmd =
(* make buck tell us where in buck-out are the capture directories for merging *) (* make buck tell us where in buck-out are the capture directories for merging *)
(prog :: command :: "--build-report" :: build_report_file :: Buck.config JavaGenruleMaster) (prog :: command :: "--build-report" :: build_report_file :: Buck.config buck_mode)
@ List.rev_append Config.buck_build_args_no_inline (Buck.store_args_in_file all_args) @ List.rev_append Config.buck_build_args_no_inline (Buck.store_args_in_file all_args)
in in
L.(debug Capture Quiet) L.(debug Capture Quiet)

@ -7,5 +7,5 @@
open! IStd open! IStd
val capture : string list -> unit val capture : BuckMode.t -> string list -> unit
(** do genrule capture with the given buck command line *) (** do genrule capture with the given buck command line *)

@ -18,6 +18,7 @@ type mode =
| Analyze | Analyze
| Ant of {prog: string; args: string list} | Ant of {prog: string; args: string list}
| BuckClangFlavor of {build_cmd: string list} | BuckClangFlavor of {build_cmd: string list}
| BuckCombinedGenrule of {build_cmd: string list}
| BuckCompilationDB of {deps: BuckMode.clang_compilation_db_deps; prog: string; args: string list} | BuckCompilationDB of {deps: BuckMode.clang_compilation_db_deps; prog: string; args: string list}
| BuckGenrule of {prog: string} | BuckGenrule of {prog: string}
| BuckGenruleMaster of {build_cmd: string list} | BuckGenruleMaster of {build_cmd: string list}
@ -39,6 +40,8 @@ let pp_mode fmt = function
F.fprintf fmt "Ant driver mode:@\nprog = '%s'@\nargs = %a" prog Pp.cli_args args F.fprintf fmt "Ant driver mode:@\nprog = '%s'@\nargs = %a" prog Pp.cli_args args
| BuckClangFlavor {build_cmd} -> | BuckClangFlavor {build_cmd} ->
F.fprintf fmt "BuckClangFlavor driver mode: build_cmd = %a" Pp.cli_args build_cmd F.fprintf fmt "BuckClangFlavor driver mode: build_cmd = %a" Pp.cli_args build_cmd
| BuckCombinedGenrule {build_cmd} ->
F.fprintf fmt "BuckCombinedGenrule driver mode: build_cmd = %a" Pp.cli_args build_cmd
| BuckCompilationDB {deps; prog; args} -> | BuckCompilationDB {deps; prog; args} ->
F.fprintf fmt "BuckCompilationDB driver mode:@\nprog = '%s'@\nargs = %a@\ndeps = %a" prog F.fprintf fmt "BuckCompilationDB driver mode:@\nprog = '%s'@\nargs = %a@\ndeps = %a" prog
Pp.cli_args args BuckMode.pp_clang_compilation_db_deps deps Pp.cli_args args BuckMode.pp_clang_compilation_db_deps deps
@ -119,6 +122,9 @@ let capture ~changed_files = function
| BuckClangFlavor {build_cmd} -> | BuckClangFlavor {build_cmd} ->
L.progress "Capturing in buck mode...@." ; L.progress "Capturing in buck mode...@." ;
BuckFlavors.capture build_cmd BuckFlavors.capture build_cmd
| BuckCombinedGenrule {build_cmd} ->
L.progress "Capturing in buck combined genrule mode...@." ;
BuckGenrule.capture CombinedGenrule build_cmd
| BuckCompilationDB {deps; prog; args} -> | BuckCompilationDB {deps; prog; args} ->
L.progress "Capturing using Buck's compilation database...@." ; L.progress "Capturing using Buck's compilation database...@." ;
let json_cdb = let json_cdb =
@ -130,7 +136,7 @@ let capture ~changed_files = function
JMain.from_arguments prog JMain.from_arguments prog
| BuckGenruleMaster {build_cmd} -> | BuckGenruleMaster {build_cmd} ->
L.progress "Capturing for BuckGenruleMaster integration...@." ; L.progress "Capturing for BuckGenruleMaster integration...@." ;
BuckGenrule.capture build_cmd BuckGenrule.capture JavaGenruleMaster build_cmd
| Clang {compiler; prog; args} -> | Clang {compiler; prog; args} ->
if CLOpt.is_originator then L.progress "Capturing in make/cc mode...@." ; if CLOpt.is_originator then L.progress "Capturing in make/cc mode...@." ;
Clang.capture compiler ~prog ~args Clang.capture compiler ~prog ~args
@ -246,7 +252,7 @@ let analyze_and_report ?suppress_console_report ~changed_files mode =
&& InferCommand.equal Run Config.command -> && InferCommand.equal Run Config.command ->
(* if doing capture + analysis of buck with flavors, we always need to merge targets before the analysis phase *) (* if doing capture + analysis of buck with flavors, we always need to merge targets before the analysis phase *)
true true
| Analyze | BuckGenruleMaster _ -> | Analyze | BuckGenruleMaster _ | BuckCombinedGenrule _ ->
ResultsDir.RunState.get_merge_capture () ResultsDir.RunState.get_merge_capture ()
| _ -> | _ ->
false false
@ -285,6 +291,8 @@ let assert_supported_mode required_analyzer requested_mode_string =
match required_analyzer with match required_analyzer with
| `Clang -> | `Clang ->
Version.clang_enabled Version.clang_enabled
| `ClangJava ->
Version.clang_enabled && Version.java_enabled
| `Java -> | `Java ->
Version.java_enabled Version.java_enabled
| `Xcode -> | `Xcode ->
@ -295,6 +303,8 @@ let assert_supported_mode required_analyzer requested_mode_string =
match required_analyzer with match required_analyzer with
| `Clang -> | `Clang ->
"clang" "clang"
| `ClangJava ->
"clang & java"
| `Java -> | `Java ->
"java" "java"
| `Xcode -> | `Xcode ->
@ -326,6 +336,8 @@ let assert_supported_build_system build_system =
match Config.buck_mode with match Config.buck_mode with
| None -> | None ->
error_no_buck_mode_specified () error_no_buck_mode_specified ()
| Some CombinedGenrule ->
(`ClangJava, "buck combined genrule")
| Some ClangFlavors -> | Some ClangFlavors ->
(`Clang, "buck with flavors") (`Clang, "buck with flavors")
| Some (ClangCompilationDB _) -> | Some (ClangCompilationDB _) ->
@ -357,6 +369,8 @@ let mode_of_build_command build_cmd (buck_mode : BuckMode.t option) =
Ant {prog; args} Ant {prog; args}
| BBuck, None -> | BBuck, None ->
error_no_buck_mode_specified () error_no_buck_mode_specified ()
| BBuck, Some CombinedGenrule ->
BuckCombinedGenrule {build_cmd}
| BBuck, Some (ClangCompilationDB deps) -> | BBuck, Some (ClangCompilationDB deps) ->
BuckCompilationDB {deps; prog; args= List.append args (List.rev Config.buck_build_args)} BuckCompilationDB {deps; prog; args= List.append args (List.rev Config.buck_build_args)}
| BBuck, Some ClangFlavors when Config.is_checker_enabled Linters -> | BBuck, Some ClangFlavors when Config.is_checker_enabled Linters ->

@ -15,6 +15,7 @@ type mode =
| Analyze | Analyze
| Ant of {prog: string; args: string list} | Ant of {prog: string; args: string list}
| BuckClangFlavor of {build_cmd: string list} | BuckClangFlavor of {build_cmd: string list}
| BuckCombinedGenrule of {build_cmd: string list}
| BuckCompilationDB of {deps: BuckMode.clang_compilation_db_deps; prog: string; args: string list} | BuckCompilationDB of {deps: BuckMode.clang_compilation_db_deps; prog: string; args: string list}
| BuckGenrule of {prog: string} | BuckGenrule of {prog: string}
| BuckGenruleMaster of {build_cmd: string list} | BuckGenruleMaster of {build_cmd: string list}

@ -0,0 +1,2 @@
[buildfile]
includes = //DEFS

@ -0,0 +1,91 @@
import os
original_cxx_library = cxx_library
original_java_library = java_library
infer_clang_flavor = "infer-capture-all"
def _cxx_infer_capture_genrule(name):
cmd = "echo $(location :{}#{}) > $OUT".format(name, infer_clang_flavor)
genrule(
name = name + "_infer",
out = "dummy_out",
cmd = cmd,
)
def cxx_library(name, **kwargs):
_cxx_infer_capture_genrule(name)
new_kwargs = dict(kwargs, labels=kwargs.get("labels", []) + ["infer_enabled"])
original_cxx_library(
name=name,
**new_kwargs
)
def _get_project_root():
return "\$(git rev-parse --show-toplevel)/infer/tests/build_systems/buck_combined"
def _infer_capture_genrule(
name,
srcs
):
args = [
"--jobs",
"1",
"--genrule-mode",
"--quiet",
"--no-progress-bar",
"--results-dir",
"$OUT",
"--sourcepath",
"$SRCDIR",
"--project-root",
_get_project_root(),
"--classpath",
"$(classpath :{})".format(name),
"--generated-classes",
"$(location :{})".format(name),
"capture",
]
args_file = os.path.join("$TMP", "args.txt")
subcommands = [
"echo {} >> {}".format(arg, args_file)
for arg in args
] + [
"infer @" + args_file
]
genrule(
name = name + "_infer",
srcs = srcs,
cmd = " && ".join(subcommands),
out = "infer_out",
labels = ["infer_genrule"],
)
def _make_infer_capture_genrule(name, kwargs):
java_sources = [
f
for f in kwargs.get("srcs", [])
if f.endswith(".java")
]
if java_sources != []:
_infer_capture_genrule(name, java_sources)
kwargs["labels"] = kwargs.get("labels", []) + ["infer_enabled"]
return kwargs
def java_library(name, **kwargs):
new_kwargs = _make_infer_capture_genrule(name, kwargs)
original_java_library(
name=name,
**new_kwargs
)

@ -0,0 +1,26 @@
# Copyright (c) Facebook, Inc. and its affiliates.
#
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.
TESTS_DIR = ../..
ROOT_DIR = $(TESTS_DIR)/../..
BUCK_TARGET = //clang:hello //java:hello
SOURCES = clang/hello.c clang/hello2.c
OBJECTS = buck-out/gen/clang/hello\#compile-hello.c.o1f717d69,default/hello.c.o
INFER_OPTIONS = --report-custom-error --developer-mode --no-linters --buck-combined
INFERPRINT_OPTIONS = --issues-tests
CLEAN_EXTRA = buck-out
include $(TESTS_DIR)/infer.make
$(OBJECTS): $(SOURCES)
$(QUIET)$(call silent_on_success,Compiling Buck flavors tests,\
$(BUCK) build --no-cache $(BUCK_TARGET))
infer-out/report.json: $(CLANG_DEPS) $(SOURCES) $(MAKEFILE_LIST)
$(QUIET)$(REMOVE_DIR) buck-out && \
$(call silent_on_success,Testing infer-run Buck combined genrule integration,\
$(INFER_BIN) $(INFER_OPTIONS) run --results-dir $(CURDIR)/infer-out -- \
$(BUCK) build --no-cache $(BUCK_TARGET))

@ -0,0 +1,6 @@
cxx_library(
name = 'hello',
srcs = [
'hello.c', 'hello2.c',
],
)

@ -0,0 +1,13 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include <stdlib.h>
void test() {
int* s = NULL;
*s = 42;
}

@ -0,0 +1,13 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include <stdlib.h>
void test2() {
int* s = NULL;
*s = 42;
}

@ -0,0 +1,3 @@
clang/hello.c, test, 2, NULL_DEREFERENCE, no_bucket, ERROR, [start of procedure test()]
clang/hello2.c, test2, 2, NULL_DEREFERENCE, no_bucket, ERROR, [start of procedure test2()]
java/NullDeref.java, NullDeref.callToStringWithNullBad():java.lang.String, 1, NULL_DEREFERENCE, no_bucket, ERROR, [start of procedure callToStringWithNullBad(),start of procedure myToString(...),Skipping toString(): unknown method]

@ -0,0 +1,6 @@
java_library(
name='hello',
srcs=glob(["*.java"]),
deps=[],
visibility=['PUBLIC'],
)

@ -0,0 +1,16 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
public class NullDeref {
private static String myToString(Object foo) {
return foo.toString();
}
public String callToStringWithNullBad() {
return myToString(null);
}
}
Loading…
Cancel
Save