diff --git a/infer/src/backend/infer.ml b/infer/src/backend/infer.ml index 451210fe3..f8fecb4d6 100644 --- a/infer/src/backend/infer.ml +++ b/infer/src/backend/infer.ml @@ -62,6 +62,8 @@ let () = | args when buck -> IList.map (fun arg -> ["--Xbuck"; "'" ^ arg ^ "'"]) args |> IList.flatten | _ -> []) @ + (if not Config.continue_capture then [] else + ["--continue"]) @ (if not Config.debug_mode then [] else ["--debug"]) @ (if not Config.debug_exceptions then [] else @@ -73,6 +75,8 @@ let () = (match Config.infer_cache with None -> [] | Some s -> ["--infer_cache"; s]) @ "--multicore" :: (string_of_int Config.jobs) :: + (if not Config.reactive_mode then [] else + ["--reactive"]) @ "--out" :: Config.results_dir :: (match Config.project_root with None -> [] | Some pr -> ["--project_root"; pr]) @ diff --git a/infer/tests/build_systems/build_integration_tests.py b/infer/tests/build_systems/build_integration_tests.py index e671fa76f..49ec20e7a 100755 --- a/infer/tests/build_systems/build_integration_tests.py +++ b/infer/tests/build_systems/build_integration_tests.py @@ -45,8 +45,6 @@ CLANG_BIN = os.path.join(ROOT_DIR, 'facebook-clang-plugins', 'clang', REPORT_JSON = 'report.json' -INFER_EXECUTABLE = 'infer' - RECORD_ENV = 'INFER_RECORD_INTEGRATION_TESTS' REPORT_FIELDS = [ @@ -68,10 +66,11 @@ ALL_TESTS = [ 'locale', 'make', 'multiclang', + 'ndk-build', + 'reactive', 'unknown_ext', 'utf8_in_pwd', 'waf', - 'ndk-build', ] to_test = ALL_TESTS @@ -113,14 +112,20 @@ def save_report(reports, filename): separators=(',', ': '), sort_keys=True) -def run_analysis(clean_cmds, build_cmds, analyzer, env=None): +def run_analysis(clean_cmds, build_cmds, env=None): for clean_cmd in clean_cmds: subprocess.check_call(clean_cmd, env=env) + temp_out_dir = tempfile.mkdtemp(suffix='_out', prefix='infer_') for build_cmd in build_cmds: - temp_out_dir = tempfile.mkdtemp(suffix='_out', prefix='infer_') - infer_cmd = (['infer', '-a', analyzer, '-o', temp_out_dir, '--'] + - build_cmd) + extra_args = (build_cmd['infer_args'] + if 'infer_args' in build_cmd + else []) + infer_cmd = (['infer', '-o', temp_out_dir] + + extra_args + + ['--'] + + build_cmd['compile']) + print(str(infer_cmd)) # Only record the output of the last build command. We record # all of them but each command overwrites the output of the # previous one. @@ -273,7 +278,6 @@ def test(name, errors = run_analysis( clean_commands, compile_commands, - INFER_EXECUTABLE, env=env) original = os.path.join(EXPECTED_OUTPUTS_DIR, report_fname) do_test(postprocess(errors), original) @@ -284,7 +288,7 @@ class BuildIntegrationTest(unittest.TestCase): def test_ant_integration(self): test('ant', 'Ant', os.path.join(SCRIPT_DIR, os.pardir), - [['ant', 'compile']], + [{'compile': ['ant', 'compile']}], clean_commands=[['ant', 'clean']], available=lambda: is_tool_available(['ant', '-version'])) @@ -295,7 +299,7 @@ class BuildIntegrationTest(unittest.TestCase): report_fname='javac_report.json'): test('javac', 'javac', root, - [['javac', 'Hello.java']], + [{'compile': ['javac', 'Hello.java']}], enabled=enabled, report_fname=report_fname) @@ -311,7 +315,7 @@ class BuildIntegrationTest(unittest.TestCase): ) test('gradle', 'Gradle', root, - [['gradle', 'build']], + [{'compile': ['gradle', 'build']}], enabled=enabled, report_fname=report_fname, env=env) @@ -319,7 +323,7 @@ class BuildIntegrationTest(unittest.TestCase): def test_buck_integration(self): test('buck', 'Buck', ROOT_DIR, - [['buck', 'build', 'infer']], + [{'compile': ['buck', 'build', 'infer']}], clean_commands=[['buck', 'clean']], available=lambda: is_tool_available(['buck', '--version'])) @@ -330,7 +334,7 @@ class BuildIntegrationTest(unittest.TestCase): report_fname='make_report.json'): test('make', 'make', root, - [['make', 'all']], + [{'compile': ['make', 'all']}], clean_commands=[['make', 'clean']], enabled=enabled, report_fname=report_fname) @@ -348,7 +352,8 @@ class BuildIntegrationTest(unittest.TestCase): env['PATH'] = '{}:{}'.format(os.getenv('PATH'), ndk_dir) if test('ndk-build', 'ndk-build', root, - [['ndk-build', '-B', 'NDK_LIBS_OUT=./libs', 'NDK_OUT=./obj']], + [{'compile': ['ndk-build', '-B', + 'NDK_LIBS_OUT=./libs', 'NDK_OUT=./obj']}], clean_commands=[['ndk-build', 'clean']], available=lambda: is_tool_available([ os.path.join(ndk_dir, 'ndk-build'), '-v']), @@ -362,14 +367,14 @@ class BuildIntegrationTest(unittest.TestCase): env['LC_ALL'] = 'C' test('locale', 'wonky locale', os.path.join(CODETOANALYZE_DIR, 'make'), - [['clang', '-c', 'utf8_in_function_names.c'], - ['clang', '-c', 'utf8_in_function_names.c']], + [{'compile': ['clang', '-c', 'utf8_in_function_names.c']}, + {'compile': ['clang', '-c', 'utf8_in_function_names.c']}], env=env) def test_waf_integration(self): test('waf', 'waf', os.path.join(CODETOANALYZE_DIR, 'make'), - [['./waf', 'build']], + [{'compile': ['./waf', 'build']}], clean_commands=[['make', 'clean']]) def test_cmake_integration( @@ -380,7 +385,8 @@ class BuildIntegrationTest(unittest.TestCase): build_root = os.path.join(root, 'build') if test('cmake', 'CMake', build_root, - [['cmake', '..'], ['make', 'clean', 'all']], + [{'compile': ['cmake', '..']}, + {'compile': ['make', 'clean', 'all']}], available=lambda: is_tool_available(['cmake', '--version']), enabled=enabled, # remove build/ directory just in case @@ -427,12 +433,22 @@ class BuildIntegrationTest(unittest.TestCase): def test_unknown_extension(self): test('unknown_ext', 'unknown extension', CODETOANALYZE_DIR, - [['clang', '-x', 'c', '-c', 'hello.unknown_ext']]) + [{'compile': ['clang', '-x', 'c', '-c', 'hello.unknown_ext']}]) def test_clang_multiple_source_files(self): test('multiclang', 'clang multiple source files', CODETOANALYZE_DIR, - [['clang', '-c', 'hello.c', 'hello2.c']]) + [{'compile': ['clang', '-c', 'hello.c', 'hello2.c']}]) + + def test_reactive_multiple_capture(self): + reactive_args = ['-a', 'capture', '--reactive', '--continue'] + test('reactive', 'reactive with multiple capture', + CODETOANALYZE_DIR, + [{'compile': ['clang', '-c', 'hello.c'], + 'infer_args': reactive_args}, + {'compile': ['clang', '-c', 'hello2.c'], + 'infer_args': reactive_args}, + {'compile': ['analyze']}]) def test_clang_cc1(self): def preprocess(): @@ -445,10 +461,10 @@ class BuildIntegrationTest(unittest.TestCase): cc1_line = filter(lambda s: s.find('"-cc1"') != -1, hashhashhash.splitlines())[0] # [cc1_line] usually looks like ' "/foo/clang" "bar" "baz"'. - # return [['clang', 'bar', 'baz']] + # return ['clang', 'bar', 'baz'] cmd = [s.strip('"') for s in cc1_line.strip().split('" "')] cmd[0] = 'clang' - return [cmd] + return [{'compile': cmd}] test('cc1', 'clang -cc1', CODETOANALYZE_DIR, [], diff --git a/infer/tests/build_systems/expected_outputs/reactive_report.json b/infer/tests/build_systems/expected_outputs/reactive_report.json new file mode 100644 index 000000000..2fd39e4b3 --- /dev/null +++ b/infer/tests/build_systems/expected_outputs/reactive_report.json @@ -0,0 +1,12 @@ +[ + { + "bug_type": "NULL_DEREFERENCE", + "file": "hello.c", + "procedure": "test" + }, + { + "bug_type": "NULL_DEREFERENCE", + "file": "hello2.c", + "procedure": "test2" + } +] \ No newline at end of file