diff --git a/Makefile b/Makefile index 53af4e6d9..a39a204bf 100644 --- a/Makefile +++ b/Makefile @@ -182,7 +182,7 @@ endif ifneq ($(BUCK),no) -BUILD_SYSTEMS_TESTS += genrulecapture +BUILD_SYSTEMS_TESTS += genrulecapture buck_java_flavor endif ifneq ($(MVN),no) BUILD_SYSTEMS_TESTS += mvn diff --git a/infer/man/man1/infer-capture.txt b/infer/man/man1/infer-capture.txt index ada78ae1c..57d20ea01 100644 --- a/infer/man/man1/infer-capture.txt +++ b/infer/man/man1/infer-capture.txt @@ -143,6 +143,16 @@ BUCK OPTIONS Activates: Buck integration for Java targets. (Conversely: --no-buck-java) + --buck-java-flavor + Activates: Buck integration for Java which uses the buck flavor + #infer-java-capture instead of genrules like buck-java. + (Conversely: --no-buck-java-flavor) + + --buck-java-flavor-suppress-config + Activates: Suppress setting buck config values for the infer + binary and its version in the buck-java-flavor integration. + (Conversely: --no-buck-java-flavor-suppress-config) + --buck-merge-all-deps Activates: Find and merge all infer dependencies produced by buck. Use this flag if infer doesn't find any files to analyze after a diff --git a/infer/man/man1/infer-full.txt b/infer/man/man1/infer-full.txt index 3923a77bc..7778e21a9 100644 --- a/infer/man/man1/infer-full.txt +++ b/infer/man/man1/infer-full.txt @@ -158,6 +158,17 @@ OPTIONS Activates: Buck integration for Java targets. (Conversely: --no-buck-java) See also infer-capture(1). + --buck-java-flavor + Activates: Buck integration for Java which uses the buck flavor + #infer-java-capture instead of genrules like buck-java. + (Conversely: --no-buck-java-flavor) See also infer-capture(1). + + --buck-java-flavor-suppress-config + Activates: Suppress setting buck config values for the infer + binary and its version in the buck-java-flavor integration. + (Conversely: --no-buck-java-flavor-suppress-config) + See also infer-capture(1). + --buck-merge-all-deps Activates: Find and merge all infer dependencies produced by buck. Use this flag if infer doesn't find any files to analyze after a diff --git a/infer/man/man1/infer.txt b/infer/man/man1/infer.txt index 22f950e4f..ea8cf2a34 100644 --- a/infer/man/man1/infer.txt +++ b/infer/man/man1/infer.txt @@ -158,6 +158,17 @@ OPTIONS Activates: Buck integration for Java targets. (Conversely: --no-buck-java) See also infer-capture(1). + --buck-java-flavor + Activates: Buck integration for Java which uses the buck flavor + #infer-java-capture instead of genrules like buck-java. + (Conversely: --no-buck-java-flavor) See also infer-capture(1). + + --buck-java-flavor-suppress-config + Activates: Suppress setting buck config values for the infer + binary and its version in the buck-java-flavor integration. + (Conversely: --no-buck-java-flavor-suppress-config) + See also infer-capture(1). + --buck-merge-all-deps Activates: Find and merge all infer dependencies produced by buck. Use this flag if infer doesn't find any files to analyze after a diff --git a/infer/src/base/BuckMode.ml b/infer/src/base/BuckMode.ml index 48704932b..8a8d14193 100644 --- a/infer/src/base/BuckMode.ml +++ b/infer/src/base/BuckMode.ml @@ -24,24 +24,25 @@ type t = | CombinedGenrule | ClangFlavors | ClangCompilationDB of clang_compilation_db_deps + | JavaFlavor | JavaGenruleMaster let is_java_genrule_master_or_combined = function | JavaGenruleMaster | CombinedGenrule -> true - | ClangFlavors | ClangCompilationDB _ -> + | ClangFlavors | ClangCompilationDB _ | JavaFlavor -> false let is_clang_compilation_db = function | ClangCompilationDB _ -> true - | ClangFlavors | JavaGenruleMaster | CombinedGenrule -> + | ClangFlavors | JavaGenruleMaster | CombinedGenrule | JavaFlavor -> false let is_clang_flavors = function | ClangFlavors -> true - | ClangCompilationDB _ | JavaGenruleMaster | CombinedGenrule -> + | ClangCompilationDB _ | JavaGenruleMaster | CombinedGenrule | JavaFlavor -> false diff --git a/infer/src/base/BuckMode.mli b/infer/src/base/BuckMode.mli index cab10ce79..9e29b54cc 100644 --- a/infer/src/base/BuckMode.mli +++ b/infer/src/base/BuckMode.mli @@ -17,6 +17,7 @@ type t = | CombinedGenrule | ClangFlavors | ClangCompilationDB of clang_compilation_db_deps + | JavaFlavor | JavaGenruleMaster val is_java_genrule_master_or_combined : t -> bool diff --git a/infer/src/base/Config.ml b/infer/src/base/Config.ml index c410de766..6e3a158c4 100644 --- a/infer/src/base/Config.ml +++ b/infer/src/base/Config.ml @@ -703,6 +703,13 @@ and buck_compilation_database_depth = ~meta:"int" +and buck_java_flavor_suppress_config = + CLOpt.mk_bool ~long:"buck-java-flavor-suppress-config" ~default:false + ~in_help:InferCommand.[(Capture, manual_buck)] + "Suppress setting buck config values for the infer binary and its version in the \ + buck-java-flavor integration." + + and buck_merge_all_deps = CLOpt.mk_bool ~long:"buck-merge-all-deps" ~default:false ~in_help:InferCommand.[(Capture, manual_buck)] @@ -749,6 +756,12 @@ and buck_mode = ~f:(set_mode `CombinedGenrule) "Buck integration for clang-based and Java targets." |> ignore ; + CLOpt.mk_bool ~long:"buck-java-flavor" + ~in_help:InferCommand.[(Capture, manual_buck)] + ~f:(set_mode `JavaFlavor) + "Buck integration for Java which uses the buck flavor #infer-java-capture instead of genrules \ + like buck-java." + |> ignore ; buck_mode @@ -2638,6 +2651,8 @@ and buck_build_args_no_inline = !buck_build_args_no_inline and buck_cache_mode = (!buck || !genrule_mode) && not !debug +and buck_java_flavor_suppress_config = !buck_java_flavor_suppress_config + and buck_merge_all_deps = !buck_merge_all_deps and buck_mode : BuckMode.t option = @@ -2656,6 +2671,8 @@ and buck_mode : BuckMode.t option = Some (ClangCompilationDB (DepsUpToDepth depth)) | `CombinedGenrule, _ -> Some CombinedGenrule + | `JavaFlavor, _ -> + Some JavaFlavor and buck_targets_blacklist = !buck_targets_blacklist diff --git a/infer/src/base/Config.mli b/infer/src/base/Config.mli index 4b9bc8141..b08ebf7c0 100644 --- a/infer/src/base/Config.mli +++ b/infer/src/base/Config.mli @@ -53,6 +53,8 @@ val bin_dir : string val bound_error_allowed_in_procedure_call : bool +val buck_java_flavor_suppress_config : bool + val clang_exe_aliases : string list val clang_initializer_prefix : string diff --git a/infer/src/integration/Buck.ml b/infer/src/integration/Buck.ml index d876df126..15b26eb0b 100644 --- a/infer/src/integration/Buck.ml +++ b/infer/src/integration/Buck.ml @@ -83,6 +83,8 @@ module Target = struct add_flavor_internal target "compilation-database" | ClangFlavors, Compile | JavaGenruleMaster, _ | CombinedGenrule, _ -> target + | JavaFlavor, _ -> + add_flavor_internal target "infer-java-capture" | ClangFlavors, _ -> add_flavor_internal target "infer-capture-all" end @@ -197,7 +199,7 @@ let get_accepted_buck_kinds_pattern (mode : BuckMode.t) = "^(apple|cxx)_(binary|library|test)$" | ClangFlavors -> "^(apple|cxx)_(binary|library)$" - | JavaGenruleMaster -> + | JavaGenruleMaster | JavaFlavor -> "^(java|android)_library$" @@ -216,6 +218,12 @@ let config = let get_java_genrule_config () = ["infer.version=" ^ Version.versionString; "infer.mode=capture"] in + let get_java_flavor_config () = + if Config.buck_java_flavor_suppress_config then [] + else + [ "infer_java.version=" ^ Version.versionString + ; Printf.sprintf "infer_java.binary=%s/infer" Config.bin_dir ] + in let get_flavors_config () = [ "client.id=infer.clang" ; Printf.sprintf "*//infer.infer_bin=%s" Config.bin_dir @@ -241,6 +249,8 @@ let config = match (buck_mode : BuckMode.t) with | JavaGenruleMaster -> get_java_genrule_config () + | JavaFlavor -> + get_java_flavor_config () | ClangFlavors -> get_flavors_config () | CombinedGenrule -> @@ -256,7 +266,7 @@ let resolve_pattern_targets (buck_mode : BuckMode.t) targets = |> ( match buck_mode with | ClangFlavors | ClangCompilationDB NoDependencies -> Fn.id - | CombinedGenrule | ClangCompilationDB DepsAllDepths | JavaGenruleMaster -> + | CombinedGenrule | ClangCompilationDB DepsAllDepths | JavaGenruleMaster | JavaFlavor -> Query.deps None | ClangCompilationDB (DepsUpToDepth depth) -> Query.deps (Some depth) ) @@ -347,7 +357,7 @@ let parse_command_and_targets (buck_mode : BuckMode.t) original_buck_args = match (buck_mode, parsed_args) with | ClangFlavors, {pattern_targets= []; alias_targets= []; normal_targets} -> normal_targets - | ( (ClangFlavors | CombinedGenrule | JavaGenruleMaster | ClangCompilationDB _) + | ( (ClangFlavors | CombinedGenrule | JavaGenruleMaster | ClangCompilationDB _ | JavaFlavor) , {pattern_targets; alias_targets; normal_targets} ) -> pattern_targets |> List.rev_append alias_targets |> List.rev_append normal_targets |> resolve_pattern_targets buck_mode diff --git a/infer/src/integration/BuckGenrule.mli b/infer/src/integration/BuckGenrule.mli index e4dbc468c..12e6dace3 100644 --- a/infer/src/integration/BuckGenrule.mli +++ b/infer/src/integration/BuckGenrule.mli @@ -7,5 +7,8 @@ open! IStd +val infer_deps_of_build_report : string -> unit +(** parse a buck build report and construct resulting [infer-deps.txt] *) + val capture : BuckMode.t -> string list -> unit (** do genrule capture with the given buck command line *) diff --git a/infer/src/integration/BuckJavaFlavor.ml b/infer/src/integration/BuckJavaFlavor.ml new file mode 100644 index 000000000..cfff09fed --- /dev/null +++ b/infer/src/integration/BuckJavaFlavor.ml @@ -0,0 +1,39 @@ +(* + * 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. + *) + +open! IStd +module F = Format +module L = Logging + +let capture build_cmd = + let prog, buck_cmd = (List.hd_exn build_cmd, List.tl_exn build_cmd) in + L.progress "Querying buck for java flavor capture targets...@." ; + let time0 = Mtime_clock.counter () in + let BuckFlavors.{command; rev_not_targets; targets} = + BuckFlavors.add_flavors_to_buck_arguments JavaFlavor ~extra_flavors:[] buck_cmd + in + L.progress "Found %d java flavor capture targets in %a.@." (List.length targets) Mtime.Span.pp + (Mtime_clock.count time0) ; + let all_args = List.rev_append rev_not_targets targets in + let build_report_file = + Filename.temp_file ~in_dir:(ResultsDir.get_path Temporary) "buck_build_report" ".json" + in + let updated_buck_cmd = + (* make buck tell us where in buck-out are the capture directories for merging *) + (prog :: command :: "--build-report" :: build_report_file :: Buck.config JavaFlavor) + @ List.rev_append Config.buck_build_args_no_inline (Buck.store_args_in_file all_args) + in + L.(debug Capture Quiet) + "Processed buck command '%a'@." (Pp.seq F.pp_print_string) updated_buck_cmd ; + if List.is_empty targets then L.external_warning "WARNING: found no buck targets to analyze.@." + else + let time0 = Mtime_clock.counter () in + Buck.wrap_buck_call ~label:"build" updated_buck_cmd |> ignore ; + BuckGenrule.infer_deps_of_build_report build_report_file ; + L.progress "Java flavor capture took %a.@." Mtime.Span.pp (Mtime_clock.count time0) ; + ResultsDir.RunState.set_merge_capture true ; + () diff --git a/infer/src/integration/BuckJavaFlavor.mli b/infer/src/integration/BuckJavaFlavor.mli new file mode 100644 index 000000000..cbec97ef8 --- /dev/null +++ b/infer/src/integration/BuckJavaFlavor.mli @@ -0,0 +1,11 @@ +(* + * 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. + *) + +open! IStd + +val capture : string list -> unit +(** do java capture using flavors with the given buck command line *) diff --git a/infer/src/integration/Driver.ml b/infer/src/integration/Driver.ml index cdacbbfcb..c3808f0cf 100644 --- a/infer/src/integration/Driver.ml +++ b/infer/src/integration/Driver.ml @@ -22,6 +22,7 @@ type mode = | BuckCompilationDB of {deps: BuckMode.clang_compilation_db_deps; prog: string; args: string list} | BuckGenrule of {prog: string} | BuckGenruleMaster of {build_cmd: string list} + | BuckJavaFlavor of {build_cmd: string list} | Clang of {compiler: Clang.compiler; prog: string; args: string list} | ClangCompilationDB of {db_files: [`Escaped of string | `Raw of string] list} | Gradle of {prog: string; args: string list} @@ -49,6 +50,8 @@ let pp_mode fmt = function F.fprintf fmt "BuckGenRule driver mode:@\nprog = '%s'" prog | BuckGenruleMaster {build_cmd} -> F.fprintf fmt "BuckGenrule driver mode:@\nbuild command = %a" Pp.cli_args build_cmd + | BuckJavaFlavor {build_cmd} -> + F.fprintf fmt "BuckJavaFlavor driver mode:@\nbuild command = %a" Pp.cli_args build_cmd | Clang {prog; args} -> F.fprintf fmt "Clang driver mode:@\nprog = '%s'@\nargs = %a" prog Pp.cli_args args | ClangCompilationDB _ -> @@ -137,6 +140,9 @@ let capture ~changed_files = function | BuckGenruleMaster {build_cmd} -> L.progress "Capturing for BuckGenruleMaster integration...@." ; BuckGenrule.capture JavaGenruleMaster build_cmd + | BuckJavaFlavor {build_cmd} -> + L.progress "Capturing for BuckJavaFlavor integration...@." ; + BuckJavaFlavor.capture build_cmd | Clang {compiler; prog; args} -> if CLOpt.is_originator then L.progress "Capturing in make/cc mode...@." ; Clang.capture compiler ~prog ~args @@ -258,7 +264,7 @@ let analyze_and_report ?suppress_console_report ~changed_files mode = && InferCommand.equal Run Config.command -> (* if doing capture + analysis of buck with flavors, we always need to merge targets before the analysis phase *) true - | Analyze | BuckGenruleMaster _ | BuckCombinedGenrule _ -> + | Analyze | BuckGenruleMaster _ | BuckCombinedGenrule _ | BuckJavaFlavor _ -> ResultsDir.RunState.get_merge_capture () | _ -> false @@ -348,7 +354,7 @@ let assert_supported_build_system build_system = (`Clang, "buck with flavors") | Some (ClangCompilationDB _) -> (`Clang, "buck compilation database") - | Some JavaGenruleMaster -> + | Some (JavaGenruleMaster | JavaFlavor) -> (`Java, Config.string_of_build_system build_system) in assert_supported_mode analyzer build_string @@ -386,6 +392,8 @@ let mode_of_build_command build_cmd (buck_mode : BuckMode.t option) = BuckClangFlavor {build_cmd} | BBuck, Some JavaGenruleMaster -> BuckGenruleMaster {build_cmd} + | BBuck, Some JavaFlavor -> + BuckJavaFlavor {build_cmd} | BBuck, Some ClangFlavors -> BuckClangFlavor {build_cmd} | BClang, _ -> diff --git a/infer/src/integration/Driver.mli b/infer/src/integration/Driver.mli index 61dfaf8c6..a5c637cff 100644 --- a/infer/src/integration/Driver.mli +++ b/infer/src/integration/Driver.mli @@ -19,6 +19,7 @@ type mode = | BuckCompilationDB of {deps: BuckMode.clang_compilation_db_deps; prog: string; args: string list} | BuckGenrule of {prog: string} | BuckGenruleMaster of {build_cmd: string list} + | BuckJavaFlavor of {build_cmd: string list} | Clang of {compiler: Clang.compiler; prog: string; args: string list} | ClangCompilationDB of {db_files: [`Escaped of string | `Raw of string] list} | Gradle of {prog: string; args: string list} diff --git a/infer/tests/build_systems/buck_java_flavor/.buckconfig b/infer/tests/build_systems/buck_java_flavor/.buckconfig new file mode 100644 index 000000000..455b829d9 --- /dev/null +++ b/infer/tests/build_systems/buck_java_flavor/.buckconfig @@ -0,0 +1,6 @@ +[project] + ignore = .git, .ml, .mli + +[java] + source_level = 8 + target_level = 8 diff --git a/infer/tests/build_systems/buck_java_flavor/.buckversion b/infer/tests/build_systems/buck_java_flavor/.buckversion new file mode 120000 index 000000000..0a46cf46a --- /dev/null +++ b/infer/tests/build_systems/buck_java_flavor/.buckversion @@ -0,0 +1 @@ +../../../../.buckversion \ No newline at end of file diff --git a/infer/tests/build_systems/buck_java_flavor/Makefile b/infer/tests/build_systems/buck_java_flavor/Makefile new file mode 100644 index 000000000..c2180b29a --- /dev/null +++ b/infer/tests/build_systems/buck_java_flavor/Makefile @@ -0,0 +1,21 @@ +# 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 = //module2:module2 +CLEAN_EXTRA = buck-out +SOURCES = $(shell find . -name '*.java') + +INFERPRINT_OPTIONS = --issues-tests +INFER_OPTIONS = --buck-java-flavor --debug-exceptions + +include $(TESTS_DIR)/infer.make + +$(INFER_OUT)/report.json: $(MAKEFILE_LIST) $(SOURCES) + $(QUIET) $(REMOVE_DIR) buck-out && \ + $(call silent_on_success,Testing java flavor integration in $(TEST_REL_DIR),\ + $(INFER_BIN) --results-dir $(@D) $(INFER_OPTIONS) -- buck build --no-cache $(BUCK_TARGET)) diff --git a/infer/tests/build_systems/buck_java_flavor/annotations/BUCK b/infer/tests/build_systems/buck_java_flavor/annotations/BUCK new file mode 100644 index 000000000..013a1d88a --- /dev/null +++ b/infer/tests/build_systems/buck_java_flavor/annotations/BUCK @@ -0,0 +1,7 @@ +java_library( + name='annotations', + srcs=['ThreadSafe.java'], + visibility=[ + 'PUBLIC' + ], +) diff --git a/infer/tests/build_systems/buck_java_flavor/annotations/ThreadSafe.java b/infer/tests/build_systems/buck_java_flavor/annotations/ThreadSafe.java new file mode 100644 index 000000000..dd80d5ab2 --- /dev/null +++ b/infer/tests/build_systems/buck_java_flavor/annotations/ThreadSafe.java @@ -0,0 +1,9 @@ +/* + * 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. + */ +package genrulecapture.annotations; + +public @interface ThreadSafe {} diff --git a/infer/tests/build_systems/buck_java_flavor/issues.exp b/infer/tests/build_systems/buck_java_flavor/issues.exp new file mode 100644 index 000000000..da26ea8e4 --- /dev/null +++ b/infer/tests/build_systems/buck_java_flavor/issues.exp @@ -0,0 +1,2 @@ +module2/Class2.java, genrulecapture.module2.Class2.get():int, 22, THREAD_SAFETY_VIOLATION, no_bucket, WARNING, [,call to int Class1.get(),access to `this.c.x`,,call to void Class1.set(int),access to `this.c.x`] +module2/Class2.java, genrulecapture.module2.Class2.set(int):void, 18, THREAD_SAFETY_VIOLATION, no_bucket, WARNING, [call to void Class1.set(int),access to `this.c.x`] diff --git a/infer/tests/build_systems/buck_java_flavor/module1/BUCK b/infer/tests/build_systems/buck_java_flavor/module1/BUCK new file mode 100644 index 000000000..4ac82ec7d --- /dev/null +++ b/infer/tests/build_systems/buck_java_flavor/module1/BUCK @@ -0,0 +1,10 @@ +java_library( + name='module1', + srcs=glob(["*.java"]), + deps=[ + '//annotations:annotations', + ], + visibility=[ + 'PUBLIC' + ], +) diff --git a/infer/tests/build_systems/buck_java_flavor/module1/Class1.java b/infer/tests/build_systems/buck_java_flavor/module1/Class1.java new file mode 100644 index 000000000..0731dc5a2 --- /dev/null +++ b/infer/tests/build_systems/buck_java_flavor/module1/Class1.java @@ -0,0 +1,20 @@ +/* + * 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. + */ + +package genrulecapture.module1; + +public class Class1 { + int x; + + public void set(int d) { + x = d; + } + + public int get() { + return x; + } +} diff --git a/infer/tests/build_systems/buck_java_flavor/module2/BUCK b/infer/tests/build_systems/buck_java_flavor/module2/BUCK new file mode 100644 index 000000000..239ec0d9b --- /dev/null +++ b/infer/tests/build_systems/buck_java_flavor/module2/BUCK @@ -0,0 +1,9 @@ +java_library( + name='module2', + srcs=glob(["*.java"]), + deps=[ + '//module1:module1', + '//annotations:annotations', + '//module3:module3', + ] +) diff --git a/infer/tests/build_systems/buck_java_flavor/module2/Class2.java b/infer/tests/build_systems/buck_java_flavor/module2/Class2.java new file mode 100644 index 000000000..ea3e6658d --- /dev/null +++ b/infer/tests/build_systems/buck_java_flavor/module2/Class2.java @@ -0,0 +1,24 @@ +/* + * 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. + */ + +package genrulecapture.module2; + +import genrulecapture.annotations.ThreadSafe; +import genrulecapture.module1.Class1; + +@ThreadSafe +public class Class2 { + Class1 c; + + void set(int x) { + c.set(x); + } + + int get() { + return c.get(); + } +} diff --git a/infer/tests/build_systems/buck_java_flavor/module3/BUCK b/infer/tests/build_systems/buck_java_flavor/module3/BUCK new file mode 100644 index 000000000..7d613ba9b --- /dev/null +++ b/infer/tests/build_systems/buck_java_flavor/module3/BUCK @@ -0,0 +1,9 @@ +cxx_library( + name = 'module3', + visibility = [ + 'PUBLIC', + ], + srcs = [ + 'some_c_code.c', + ], +) diff --git a/infer/tests/build_systems/buck_java_flavor/module3/some_c_code.c b/infer/tests/build_systems/buck_java_flavor/module3/some_c_code.c new file mode 100644 index 000000000..11c462a9f --- /dev/null +++ b/infer/tests/build_systems/buck_java_flavor/module3/some_c_code.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 + +void some_c_func() { + int* s = NULL; + *s = 42; +}