diff --git a/infer/lib/python/inferlib/capture/ant.py b/infer/lib/python/inferlib/capture/ant.py deleted file mode 100644 index 464f71a75..000000000 --- a/infer/lib/python/inferlib/capture/ant.py +++ /dev/null @@ -1,84 +0,0 @@ -# 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. - -import logging -import os - -from . import util -from inferlib import jwlib - -MODULE_NAME = __name__ -MODULE_DESCRIPTION = '''Run analysis of code built with a command like: -ant [options] [target] - -Analysis examples: -infer -- ant compile''' -LANG = ['java'] - - -def gen_instance(*args): - return AntCapture(*args) - - -# This creates an empty argparser for the module, which provides only -# description/usage information and no arguments. -create_argparser = util.base_argparser(MODULE_DESCRIPTION, MODULE_NAME) - - -class AntCapture: - - def __init__(self, args, cmd): - self.args = args - util.log_java_version() - logging.info(util.run_cmd_ignore_fail([cmd[0], '-version'])) - # TODO: make the extraction of targets smarter - self.build_cmd = [cmd[0], '-verbose'] + cmd[1:] - - def is_interesting(self, content): - return self.is_quoted(content) or content.endswith('.java') - - def is_quoted(self, argument): - quote = '\'' - return len(argument) > 2 and argument[0] == quote\ - and argument[-1] == quote - - def remove_quotes(self, argument): - if self.is_quoted(argument): - return argument[1:-1] - else: - return argument - - def get_infer_commands(self, verbose_output): - javac_pattern = '[javac]' - argument_start_pattern = 'Compilation arguments' - calls = [] - javac_arguments = [] - collect = False - for line in verbose_output.split('\n'): - if javac_pattern in line: - if argument_start_pattern in line: - collect = True - if javac_arguments != []: - capture = jwlib.create_infer_command(javac_arguments) - calls.append(capture) - javac_arguments = [] - if collect: - pos = line.index(javac_pattern) + len(javac_pattern) - content = line[pos:].strip() - if self.is_interesting(content): - arg = self.remove_quotes(content) - javac_arguments.append(arg) - if javac_arguments != []: - capture = jwlib.create_infer_command(javac_arguments) - calls.append(capture) - javac_arguments = [] - return calls - - def capture(self): - (code, (verbose_out, _)) = util.get_build_output(self.build_cmd) - if code != os.EX_OK: - return code - cmds = self.get_infer_commands(verbose_out) - return util.run_compilation_commands(cmds) diff --git a/infer/src/integration/Ant.ml b/infer/src/integration/Ant.ml new file mode 100644 index 000000000..836ea931f --- /dev/null +++ b/infer/src/integration/Ant.ml @@ -0,0 +1,73 @@ +(* + * 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 L = Logging + +let javac_pattern = "[javac]" + +let arg_start_pattern = "Compilation arguments" + +let extract_javac_args line = + let is_quoted s = + String.length s > 2 && String.is_prefix s ~prefix:"'" && String.is_suffix s ~suffix:"'" + in + let remove_quotes s = if is_quoted s then String.sub s ~pos:1 ~len:(String.length s - 2) else s in + let is_interesting s = String.is_suffix s ~suffix:".java" || is_quoted s in + Option.map (String.substr_index line ~pattern:javac_pattern) ~f:(fun pos -> + let content = String.drop_prefix line (pos + String.length javac_pattern) |> String.strip in + if is_interesting content then Some (remove_quotes content) else None ) + |> Option.join + + +let do_javac_capture rev_javac_args = + let prog = Config.bin_dir ^/ "infer" in + let args = + "capture" :: "--continue" :: "--" :: "javac" + :: List.rev_filter_map rev_javac_args ~f:(fun arg -> + if String.equal "-Werror" arg then None + else if String.is_substring arg ~substring:"-g:" then Some "-g" + else Some arg ) + in + L.debug Capture Verbose "%s %s@." prog (String.concat ~sep:" " args) ; + Process.create_process_and_wait ~prog ~args + + +type fold_state = {collecting: bool; rev_javac_args: string list} + +let capture ~prog ~args = + let _, java_version = + Process.create_process_and_wait_with_output ~prog:"java" ~args:["-version"] + in + let _, javac_version = + Process.create_process_and_wait_with_output ~prog:"javac" ~args:["-version"] + in + let ant_version, _ = Process.create_process_and_wait_with_output ~prog ~args:["-version"] in + L.environment_info "%s %s %s@." java_version javac_version ant_version ; + L.debug Capture Verbose "%s %s@." prog @@ String.concat ~sep:" " args ; + let ant_out, _ = Process.create_process_and_wait_with_output ~prog ~args:("-verbose" :: args) in + L.debug Capture Verbose "%s" ant_out ; + let res = + List.fold (String.split_lines ant_out) ~init:{collecting= false; rev_javac_args= []} + ~f:(fun {collecting; rev_javac_args} line -> + let is_line_interesting = String.is_substring line ~substring:javac_pattern in + if is_line_interesting then + let start_collecting = String.is_substring line ~substring:arg_start_pattern in + let collecting = collecting || start_collecting in + let rev_javac_args = + if start_collecting && not (List.is_empty rev_javac_args) then ( + do_javac_capture rev_javac_args ; [] ) + else rev_javac_args + in + let rev_javac_args = + if collecting then + Option.fold (extract_javac_args line) ~init:rev_javac_args ~f:(Fn.flip List.cons) + else rev_javac_args + in + {collecting; rev_javac_args} + else {collecting; rev_javac_args} ) + in + if not (List.is_empty res.rev_javac_args) then do_javac_capture res.rev_javac_args diff --git a/infer/src/integration/Ant.mli b/infer/src/integration/Ant.mli new file mode 100644 index 000000000..8cd80138a --- /dev/null +++ b/infer/src/integration/Ant.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 : prog:string -> args:string list -> unit +(** do an ant capture with the given prog (i.e. ant) and args *) diff --git a/infer/src/integration/Driver.ml b/infer/src/integration/Driver.ml index ecfe1e3b1..8364d97f9 100644 --- a/infer/src/integration/Driver.ml +++ b/infer/src/integration/Driver.ml @@ -16,7 +16,8 @@ module F = Format (* based on the build_system and options passed to infer, we run in different driver modes *) type mode = | Analyze - | BuckClangFlavor of string list + | Ant of {prog: string; args: string list} + | BuckClangFlavor of {build_cmd: string list} | BuckCompilationDB of BuckMode.clang_compilation_db_deps * string * string list | BuckGenrule of string | BuckGenruleMaster of string list @@ -24,9 +25,9 @@ type mode = | ClangCompilationDB of [`Escaped of string | `Raw of string] list | Javac of Javac.compiler * string * string list | Maven of string * string list - | NdkBuild of string list + | NdkBuild of {build_cmd: string list} | PythonCapture of Config.build_system * string list - | XcodeBuild of string * string list + | XcodeBuild of {prog: string; args: string list} | XcodeXcpretty of string * string list let is_analyze_mode = function Analyze -> true | _ -> false @@ -34,8 +35,10 @@ let is_analyze_mode = function Analyze -> true | _ -> false let pp_mode fmt = function | Analyze -> F.fprintf fmt "Analyze driver mode" - | BuckClangFlavor args -> - F.fprintf fmt "BuckClangFlavor driver mode: args = %a" Pp.cli_args args + | Ant {prog; args} -> + F.fprintf fmt "Ant driver mode:@\nprog = '%s'@\nargs = %a" prog Pp.cli_args args + | BuckClangFlavor {build_cmd} -> + F.fprintf fmt "BuckClangFlavor driver mode: build_cmd = %a" Pp.cli_args build_cmd | BuckGenrule prog -> F.fprintf fmt "BuckGenRule driver mode:@\nprog = '%s'" prog | BuckGenruleMaster build_cmd -> @@ -49,7 +52,7 @@ let pp_mode fmt = function F.fprintf fmt "PythonCapture driver mode:@\nbuild system = '%s'@\nargs = %a" (Config.string_of_build_system bs) Pp.cli_args args - | XcodeBuild (prog, args) -> + | XcodeBuild {prog; args} -> F.fprintf fmt "XcodeBuild driver mode:@\nprog = '%s'@\nargs = %a" prog Pp.cli_args args | XcodeXcpretty (prog, args) -> F.fprintf fmt "XcodeXcpretty driver mode:@\nprog = '%s'@\nargs = %a" prog Pp.cli_args args @@ -57,8 +60,8 @@ let pp_mode fmt = function F.fprintf fmt "Javac driver mode:@\nprog = '%s'@\nargs = %a" prog Pp.cli_args args | Maven (prog, args) -> F.fprintf fmt "Maven driver mode:@\nprog = '%s'@\nargs = %a" prog Pp.cli_args args - | NdkBuild args -> - F.fprintf fmt "NdkBuild driver mode: args = %a" Pp.cli_args args + | NdkBuild {build_cmd} -> + F.fprintf fmt "NdkBuild driver mode: build_cmd = %a" Pp.cli_args build_cmd | Clang (_, prog, args) -> F.fprintf fmt "Clang driver mode:@\nprog = '%s'@\nargs = %a" prog Pp.cli_args args @@ -266,7 +269,10 @@ let python_capture build_system build_cmd = let capture ~changed_files = function | Analyze -> () - | BuckClangFlavor build_cmd -> + | Ant {prog; args} -> + L.progress "Capturing in ant mode...@." ; + Ant.capture ~prog ~args + | BuckClangFlavor {build_cmd} -> buck_capture build_cmd | BuckCompilationDB (deps, prog, args) -> L.progress "Capturing using Buck's compilation database...@." ; @@ -292,12 +298,12 @@ let capture ~changed_files = function | Maven (prog, args) -> L.progress "Capturing in maven mode...@." ; Maven.capture ~prog ~args - | NdkBuild build_cmd -> + | NdkBuild {build_cmd} -> L.progress "Capturing in ndk-build mode...@." ; NdkBuild.capture ~build_cmd | PythonCapture (build_system, build_cmd) -> python_capture build_system build_cmd - | XcodeBuild (prog, args) -> + | XcodeBuild {prog; args} -> L.progress "Capturing in xcodebuild mode...@." ; XcodeBuild.capture ~prog ~args | XcodeXcpretty (prog, args) -> @@ -526,7 +532,7 @@ let mode_of_build_command build_cmd (buck_mode : BuckMode.t option) = L.user_warning "WARNING: the linters require --buck-compilation-database to be set.@ Alternatively, \ set --no-linters to disable them and this warning.@." ; - BuckClangFlavor build_cmd + BuckClangFlavor {build_cmd} | BBuck, Some JavaGenruleMaster -> BuckGenruleMaster build_cmd | BClang, _ -> @@ -542,12 +548,14 @@ let mode_of_build_command build_cmd (buck_mode : BuckMode.t option) = | BXcode, _ when Config.xcpretty -> XcodeXcpretty (prog, args) | BXcode, _ -> - XcodeBuild (prog, args) + XcodeBuild {prog; args} | BBuck, Some ClangFlavors -> - BuckClangFlavor build_cmd + BuckClangFlavor {build_cmd} | BNdk, _ -> - NdkBuild build_cmd - | ((BAnt | BGradle) as build_system), _ -> + NdkBuild {build_cmd} + | BAnt, _ -> + Ant {prog; args} + | (BGradle as build_system), _ -> PythonCapture (build_system, build_cmd) ) diff --git a/infer/src/integration/Driver.mli b/infer/src/integration/Driver.mli index 392a37ffc..5f7740f60 100644 --- a/infer/src/integration/Driver.mli +++ b/infer/src/integration/Driver.mli @@ -13,7 +13,8 @@ open! IStd (** based on the build_system and options passed to infer, we run in different driver modes *) type mode = | Analyze - | BuckClangFlavor of string list + | Ant of {prog: string; args: string list} + | BuckClangFlavor of {build_cmd: string list} | BuckCompilationDB of BuckMode.clang_compilation_db_deps * string * string list | BuckGenrule of string | BuckGenruleMaster of string list @@ -21,9 +22,9 @@ type mode = | ClangCompilationDB of [`Escaped of string | `Raw of string] list | Javac of Javac.compiler * string * string list | Maven of string * string list - | NdkBuild of string list + | NdkBuild of {build_cmd: string list} | PythonCapture of Config.build_system * string list - | XcodeBuild of string * string list + | XcodeBuild of {prog: string; args: string list} | XcodeXcpretty of string * string list val is_analyze_mode : mode -> bool diff --git a/infer/src/integration/NdkBuild.mli b/infer/src/integration/NdkBuild.mli index 53d5d6b97..b7472b3b3 100644 --- a/infer/src/integration/NdkBuild.mli +++ b/infer/src/integration/NdkBuild.mli @@ -8,3 +8,4 @@ open! IStd val capture : build_cmd:string list -> unit +(** do an ndk-build capture with the given the build commands *) diff --git a/infer/src/integration/XcodeBuild.mli b/infer/src/integration/XcodeBuild.mli index 9b11361af..f98b9cdf3 100644 --- a/infer/src/integration/XcodeBuild.mli +++ b/infer/src/integration/XcodeBuild.mli @@ -8,3 +8,4 @@ open! IStd val capture : prog:string -> args:string list -> unit +(** do an xcodebuild capture with the given prog (i.e. xcodebuild) and args *)