From f703d780da9882be1f96d83dd0f2b82c1dc55813 Mon Sep 17 00:00:00 2001 From: Andrzej Kotulski Date: Wed, 17 Feb 2016 03:22:46 -0800 Subject: [PATCH] Translate headers located inside analyzed project Summary:public Translate headers every time they are included provided that they are located inside project_root directory. While this is suboptimal (we might end up translating same header many times), doing it exactly once is hard due to parallel compilation and template instantiations Reviewed By: dulmarod Differential Revision: D2916799 fb-gh-sync-id: 93b72c4 shipit-source-id: 93b72c4 --- infer/src/clang/cLocation.ml | 15 +- infer/src/clang/cMain.ml | 5 +- .../cpp/frontend/include_header/header.h | 22 +++ .../include_header/include_no_templ.cpp.dot | 46 ++++++ .../frontend/include_header/include_only.cpp | 10 ++ .../include_header/include_only.cpp.dot | 24 ++++ .../frontend/include_header/include_templ.cpp | 29 ++++ .../include_header/include_templ.cpp.dot | 134 ++++++++++++++++++ .../cpp/frontend/namespace/namespace.cpp | 2 +- .../cpp/IncludeHeaderNoTemplTest.java | 66 +++++++++ .../endtoend/cpp/IncludeHeaderTemplTest.java | 70 +++++++++ .../tests/frontend/cpp/IncludeHeaderTest.java | 44 ++++++ 12 files changed, 461 insertions(+), 6 deletions(-) create mode 100644 infer/tests/codetoanalyze/cpp/frontend/include_header/header.h create mode 100644 infer/tests/codetoanalyze/cpp/frontend/include_header/include_no_templ.cpp.dot create mode 100644 infer/tests/codetoanalyze/cpp/frontend/include_header/include_only.cpp create mode 100644 infer/tests/codetoanalyze/cpp/frontend/include_header/include_only.cpp.dot create mode 100644 infer/tests/codetoanalyze/cpp/frontend/include_header/include_templ.cpp create mode 100644 infer/tests/codetoanalyze/cpp/frontend/include_header/include_templ.cpp.dot create mode 100644 infer/tests/endtoend/cpp/IncludeHeaderNoTemplTest.java create mode 100644 infer/tests/endtoend/cpp/IncludeHeaderTemplTest.java create mode 100644 infer/tests/frontend/cpp/IncludeHeaderTest.java diff --git a/infer/src/clang/cLocation.ml b/infer/src/clang/cLocation.ml index de69937b1..bb68a5df9 100644 --- a/infer/src/clang/cLocation.ml +++ b/infer/src/clang/cLocation.ml @@ -75,17 +75,28 @@ let clang_to_sil_location clang_loc procdesc_opt = Location.{line; col; file; nLOC} let should_translate (loc_start, loc_end) = - let map_file_of pred loc = + let map_path_of pred loc = match loc.Clang_ast_t.sl_file with - | Some f -> pred (source_file_from_path f) + | Some f -> pred f | None -> false in + let map_file_of pred loc = + let path_pred path = pred (source_file_from_path path) in + map_path_of path_pred loc + in let equal_current_source file = DB.source_file_equal file !DB.current_source in + let file_in_project file = match !Config.project_root with + | Some root -> Utils.string_is_prefix root file + | None -> false + in + let file_in_project = map_path_of file_in_project loc_end + || map_path_of file_in_project loc_start in equal_current_source !curr_file || map_file_of equal_current_source loc_end || map_file_of equal_current_source loc_start + || (!CFrontend_config.testing_mode && file_in_project) let should_translate_lib source_range = not !CFrontend_config.no_translate_libs diff --git a/infer/src/clang/cMain.ml b/infer/src/clang/cMain.ml index cefa73d91..b78e492cf 100644 --- a/infer/src/clang/cMain.ml +++ b/infer/src/clang/cMain.ml @@ -16,7 +16,6 @@ module L = Logging open CFrontend_utils let arg_desc = - Config.dotty_cfg_libs := false; (* default behavior for this frontend *) let desc = (Utils.arg_desc_filter ["-results_dir"] Utils.base_arg_desc) @ [ @@ -35,8 +34,8 @@ let arg_desc = Some "file", "AST file for the translation" ; - "-dotty_cfg_libs", - Arg.Unit (fun _ -> Config.dotty_cfg_libs := true), + "-dotty_no_cfg_libs", + Arg.Unit (fun _ -> Config.dotty_cfg_libs := false), None, "Prints the cfg of the code coming from the libraries" ; diff --git a/infer/tests/codetoanalyze/cpp/frontend/include_header/header.h b/infer/tests/codetoanalyze/cpp/frontend/include_header/header.h new file mode 100644 index 000000000..5754b2a41 --- /dev/null +++ b/infer/tests/codetoanalyze/cpp/frontend/include_header/header.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2016 - present Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +struct A { + int div0() { return 1 / 0; } +}; + +template +struct B { + int div0() { return 1 / 0; } +}; + +int div0_fun() { return 1 / 0; } + +template +int div0_templ() { return 1 / 0; } diff --git a/infer/tests/codetoanalyze/cpp/frontend/include_header/include_no_templ.cpp.dot b/infer/tests/codetoanalyze/cpp/frontend/include_header/include_no_templ.cpp.dot new file mode 100644 index 000000000..7a3dad2e2 --- /dev/null +++ b/infer/tests/codetoanalyze/cpp/frontend/include_header/include_no_templ.cpp.dot @@ -0,0 +1,46 @@ +digraph iCFG { +12 [label="12: DeclStmt \n _fun_A_A(&a:class A *) [line 13]\n " shape="box"] + + + 12 -> 11 ; +11 [label="11: Return Stmt \n n$0=_fun_A_get0(&a:class A &) [line 14]\n *&return:int =(1 / n$0) [line 14]\n REMOVE_TEMPS(n$0); [line 14]\n NULLIFY(&a,false); [line 14]\n APPLY_ABSTRACTION; [line 14]\n " shape="box"] + + + 11 -> 10 ; +10 [label="10: Exit div0_a \n " color=yellow style=filled] + + +9 [label="9: Start div0_a\nFormals: \nLocals: a:class A \n DECLARE_LOCALS(&return,&a); [line 12]\n " color=yellow style=filled] + + + 9 -> 12 ; +8 [label="8: Return Stmt \n *&return:int =(1 / 0) [line 19]\n APPLY_ABSTRACTION; [line 19]\n " shape="box"] + + + 8 -> 7 ; +7 [label="7: Exit div0_fun \n " color=yellow style=filled] + + +6 [label="6: Start div0_fun\nFormals: \nLocals: \n DECLARE_LOCALS(&return); [line 19]\n " color=yellow style=filled] + + + 6 -> 8 ; +5 [label="5: Exit A_A \n " color=yellow style=filled] + + +4 [label="4: Start A_A\nFormals: this:class A *\nLocals: \n DECLARE_LOCALS(&return); [line 10]\n NULLIFY(&this,false); [line 10]\n " color=yellow style=filled] + + + 4 -> 5 ; +3 [label="3: Return Stmt \n *&return:int =0 [line 11]\n APPLY_ABSTRACTION; [line 11]\n " shape="box"] + + + 3 -> 2 ; +2 [label="2: Exit A_get0 \n " color=yellow style=filled] + + +1 [label="1: Start A_get0\nFormals: this:class A *\nLocals: \n DECLARE_LOCALS(&return); [line 11]\n NULLIFY(&this,false); [line 11]\n " color=yellow style=filled] + + + 1 -> 3 ; +} diff --git a/infer/tests/codetoanalyze/cpp/frontend/include_header/include_only.cpp b/infer/tests/codetoanalyze/cpp/frontend/include_header/include_only.cpp new file mode 100644 index 000000000..457901dce --- /dev/null +++ b/infer/tests/codetoanalyze/cpp/frontend/include_header/include_only.cpp @@ -0,0 +1,10 @@ +/* + * Copyright (c) 2016 - present Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#include "header.h" diff --git a/infer/tests/codetoanalyze/cpp/frontend/include_header/include_only.cpp.dot b/infer/tests/codetoanalyze/cpp/frontend/include_header/include_only.cpp.dot new file mode 100644 index 000000000..43c38a01b --- /dev/null +++ b/infer/tests/codetoanalyze/cpp/frontend/include_header/include_only.cpp.dot @@ -0,0 +1,24 @@ +digraph iCFG { +6 [label="6: Return Stmt \n *&return:int =(1 / 0) [line 19]\n APPLY_ABSTRACTION; [line 19]\n " shape="box"] + + + 6 -> 5 ; +5 [label="5: Exit div0_fun \n " color=yellow style=filled] + + +4 [label="4: Start div0_fun\nFormals: \nLocals: \n DECLARE_LOCALS(&return); [line 19]\n " color=yellow style=filled] + + + 4 -> 6 ; +3 [label="3: Return Stmt \n *&return:int =(1 / 0) [line 11]\n APPLY_ABSTRACTION; [line 11]\n " shape="box"] + + + 3 -> 2 ; +2 [label="2: Exit A_div0 \n " color=yellow style=filled] + + +1 [label="1: Start A_div0\nFormals: this:class A *\nLocals: \n DECLARE_LOCALS(&return); [line 11]\n NULLIFY(&this,false); [line 11]\n " color=yellow style=filled] + + + 1 -> 3 ; +} diff --git a/infer/tests/codetoanalyze/cpp/frontend/include_header/include_templ.cpp b/infer/tests/codetoanalyze/cpp/frontend/include_header/include_templ.cpp new file mode 100644 index 000000000..e2ca0d271 --- /dev/null +++ b/infer/tests/codetoanalyze/cpp/frontend/include_header/include_templ.cpp @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2016 - present Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#include "header.h" + +// instantiate templates to produce bug reports for them +void div0_B_int() { + B b; + b.div0(); +} + +void div0_B_A() { + B b; + b.div0(); +} + +void div0_templ_int() { + div0_templ(); +} + +int div0_templ_A() { + div0_templ(); +} diff --git a/infer/tests/codetoanalyze/cpp/frontend/include_header/include_templ.cpp.dot b/infer/tests/codetoanalyze/cpp/frontend/include_header/include_templ.cpp.dot new file mode 100644 index 000000000..065e7afde --- /dev/null +++ b/infer/tests/codetoanalyze/cpp/frontend/include_header/include_templ.cpp.dot @@ -0,0 +1,134 @@ +digraph iCFG { +36 [label="36: Call _fun_div0_templ \n n$0=_fun_div0_templ() [line 28]\n REMOVE_TEMPS(n$0); [line 28]\n APPLY_ABSTRACTION; [line 28]\n " shape="box"] + + + 36 -> 35 ; +35 [label="35: Exit div0_templ_A \n " color=yellow style=filled] + + +34 [label="34: Start div0_templ_A\nFormals: \nLocals: \n DECLARE_LOCALS(&return); [line 27]\n " color=yellow style=filled] + + + 34 -> 36 ; +33 [label="33: Call _fun_div0_templ \n n$0=_fun_div0_templ() [line 24]\n REMOVE_TEMPS(n$0); [line 24]\n APPLY_ABSTRACTION; [line 24]\n " shape="box"] + + + 33 -> 32 ; +32 [label="32: Exit div0_templ_int \n " color=yellow style=filled] + + +31 [label="31: Start div0_templ_int\nFormals: \nLocals: \n DECLARE_LOCALS(&return); [line 23]\n " color=yellow style=filled] + + + 31 -> 33 ; +30 [label="30: DeclStmt \n _fun_B_B(&b:class B *) [line 19]\n " shape="box"] + + + 30 -> 29 ; +29 [label="29: Call _fun_B_div0 \n n$0=_fun_B_div0(&b:class B &) [line 20]\n REMOVE_TEMPS(n$0); [line 20]\n NULLIFY(&b,false); [line 20]\n APPLY_ABSTRACTION; [line 20]\n " shape="box"] + + + 29 -> 28 ; +28 [label="28: Exit div0_B_A \n " color=yellow style=filled] + + +27 [label="27: Start div0_B_A\nFormals: \nLocals: b:class B \n DECLARE_LOCALS(&return,&b); [line 18]\n " color=yellow style=filled] + + + 27 -> 30 ; +26 [label="26: DeclStmt \n _fun_B_B(&b:class B *) [line 14]\n " shape="box"] + + + 26 -> 25 ; +25 [label="25: Call _fun_B_div0 \n n$0=_fun_B_div0(&b:class B &) [line 15]\n REMOVE_TEMPS(n$0); [line 15]\n NULLIFY(&b,false); [line 15]\n APPLY_ABSTRACTION; [line 15]\n " shape="box"] + + + 25 -> 24 ; +24 [label="24: Exit div0_B_int \n " color=yellow style=filled] + + +23 [label="23: Start div0_B_int\nFormals: \nLocals: b:class B \n DECLARE_LOCALS(&return,&b); [line 13]\n " color=yellow style=filled] + + + 23 -> 26 ; +22 [label="22: Return Stmt \n *&return:int =(1 / 0) [line 22]\n APPLY_ABSTRACTION; [line 22]\n " shape="box"] + + + 22 -> 21 ; +21 [label="21: Exit div0_templ \n " color=yellow style=filled] + + +20 [label="20: Start div0_templ\nFormals: \nLocals: \n DECLARE_LOCALS(&return); [line 22]\n " color=yellow style=filled] + + + 20 -> 22 ; +19 [label="19: Return Stmt \n *&return:int =(1 / 0) [line 22]\n APPLY_ABSTRACTION; [line 22]\n " shape="box"] + + + 19 -> 18 ; +18 [label="18: Exit div0_templ \n " color=yellow style=filled] + + +17 [label="17: Start div0_templ\nFormals: \nLocals: \n DECLARE_LOCALS(&return); [line 22]\n " color=yellow style=filled] + + + 17 -> 19 ; +16 [label="16: Return Stmt \n *&return:int =(1 / 0) [line 19]\n APPLY_ABSTRACTION; [line 19]\n " shape="box"] + + + 16 -> 15 ; +15 [label="15: Exit div0_fun \n " color=yellow style=filled] + + +14 [label="14: Start div0_fun\nFormals: \nLocals: \n DECLARE_LOCALS(&return); [line 19]\n " color=yellow style=filled] + + + 14 -> 16 ; +13 [label="13: Exit B_B \n " color=yellow style=filled] + + +12 [label="12: Start B_B\nFormals: this:class B *\nLocals: \n DECLARE_LOCALS(&return); [line 15]\n NULLIFY(&this,false); [line 15]\n " color=yellow style=filled] + + + 12 -> 13 ; +11 [label="11: Return Stmt \n *&return:int =(1 / 0) [line 16]\n APPLY_ABSTRACTION; [line 16]\n " shape="box"] + + + 11 -> 10 ; +10 [label="10: Exit B_div0 \n " color=yellow style=filled] + + +9 [label="9: Start B_div0\nFormals: this:class B *\nLocals: \n DECLARE_LOCALS(&return); [line 16]\n NULLIFY(&this,false); [line 16]\n " color=yellow style=filled] + + + 9 -> 11 ; +8 [label="8: Exit B_B \n " color=yellow style=filled] + + +7 [label="7: Start B_B\nFormals: this:class B *\nLocals: \n DECLARE_LOCALS(&return); [line 15]\n NULLIFY(&this,false); [line 15]\n " color=yellow style=filled] + + + 7 -> 8 ; +6 [label="6: Return Stmt \n *&return:int =(1 / 0) [line 16]\n APPLY_ABSTRACTION; [line 16]\n " shape="box"] + + + 6 -> 5 ; +5 [label="5: Exit B_div0 \n " color=yellow style=filled] + + +4 [label="4: Start B_div0\nFormals: this:class B *\nLocals: \n DECLARE_LOCALS(&return); [line 16]\n NULLIFY(&this,false); [line 16]\n " color=yellow style=filled] + + + 4 -> 6 ; +3 [label="3: Return Stmt \n *&return:int =(1 / 0) [line 11]\n APPLY_ABSTRACTION; [line 11]\n " shape="box"] + + + 3 -> 2 ; +2 [label="2: Exit A_div0 \n " color=yellow style=filled] + + +1 [label="1: Start A_div0\nFormals: this:class A *\nLocals: \n DECLARE_LOCALS(&return); [line 11]\n NULLIFY(&this,false); [line 11]\n " color=yellow style=filled] + + + 1 -> 3 ; +} diff --git a/infer/tests/codetoanalyze/cpp/frontend/namespace/namespace.cpp b/infer/tests/codetoanalyze/cpp/frontend/namespace/namespace.cpp index 0ba4f165e..3564a02e3 100644 --- a/infer/tests/codetoanalyze/cpp/frontend/namespace/namespace.cpp +++ b/infer/tests/codetoanalyze/cpp/frontend/namespace/namespace.cpp @@ -7,7 +7,7 @@ * of patent rights can be found in the PATENTS file in the same directory. */ -#include + using namespace std; namespace foo diff --git a/infer/tests/endtoend/cpp/IncludeHeaderNoTemplTest.java b/infer/tests/endtoend/cpp/IncludeHeaderNoTemplTest.java new file mode 100644 index 000000000..ca3700695 --- /dev/null +++ b/infer/tests/endtoend/cpp/IncludeHeaderNoTemplTest.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2016 - present Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +package endtoend.cpp; + +import static org.hamcrest.MatcherAssert.assertThat; +import static utils.matchers.ResultContainsExactly.containsExactly; + +import com.google.common.collect.ImmutableList; + +import org.junit.BeforeClass; +import org.junit.ClassRule; +import org.junit.Test; + +import java.io.IOException; + +import utils.DebuggableTemporaryFolder; +import utils.InferException; +import utils.InferResults; +import utils.InferRunner; + +public class IncludeHeaderNoTemplTest { + + public static final String FILE = + "infer/tests/codetoanalyze/cpp/frontend/include_header/include_only.cpp"; + public static final String HEADER = + "infer/tests/codetoanalyze/cpp/frontend/include_header/header.h"; + + private static ImmutableList inferCmd; + + public static final String DIVIDE_BY_ZERO = "DIVIDE_BY_ZERO"; + + @ClassRule + public static DebuggableTemporaryFolder folder = + new DebuggableTemporaryFolder(); + + @BeforeClass + public static void runInfer() throws InterruptedException, IOException { + inferCmd = InferRunner.createCPPInferCommand(folder, FILE); + } + + @Test + public void whenInferRunsOnDiv0MethodsErrorIsFound() + throws InterruptedException, IOException, InferException { + InferResults inferResults = InferRunner.runInferCPP(inferCmd); + String[] procedures = { + "A_div0", + "div0_fun", + }; + assertThat( + "Results should contain the expected divide by zero", + inferResults, + containsExactly( + DIVIDE_BY_ZERO, + HEADER, + procedures + ) + ); + } +} diff --git a/infer/tests/endtoend/cpp/IncludeHeaderTemplTest.java b/infer/tests/endtoend/cpp/IncludeHeaderTemplTest.java new file mode 100644 index 000000000..0939216d3 --- /dev/null +++ b/infer/tests/endtoend/cpp/IncludeHeaderTemplTest.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2016 - present Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +package endtoend.cpp; + +import static org.hamcrest.MatcherAssert.assertThat; +import static utils.matchers.ResultContainsExactly.containsExactly; + +import com.google.common.collect.ImmutableList; + +import org.junit.BeforeClass; +import org.junit.ClassRule; +import org.junit.Test; + +import java.io.IOException; + +import utils.DebuggableTemporaryFolder; +import utils.InferException; +import utils.InferResults; +import utils.InferRunner; + +public class IncludeHeaderTemplTest { + + public static final String FILE = + "infer/tests/codetoanalyze/cpp/frontend/include_header/include_templ.cpp"; + public static final String HEADER = + "infer/tests/codetoanalyze/cpp/frontend/include_header/header.h"; + + private static ImmutableList inferCmd; + + public static final String DIVIDE_BY_ZERO = "DIVIDE_BY_ZERO"; + + @ClassRule + public static DebuggableTemporaryFolder folder = + new DebuggableTemporaryFolder(); + + @BeforeClass + public static void runInfer() throws InterruptedException, IOException { + inferCmd = InferRunner.createCPPInferCommand(folder, FILE); + } + + @Test + public void whenInferRunsOnDiv0MethodsErrorIsFound() + throws InterruptedException, IOException, InferException { + InferResults inferResults = InferRunner.runInferCPP(inferCmd); + String[] procedures = { + "A_div0", + "B_div0", + "B_div0", + "div0_fun", + "div0_templ", + "div0_templ", + }; + assertThat( + "Results should contain the expected divide by zero", + inferResults, + containsExactly( + DIVIDE_BY_ZERO, + HEADER, + procedures + ) + ); + } +} diff --git a/infer/tests/frontend/cpp/IncludeHeaderTest.java b/infer/tests/frontend/cpp/IncludeHeaderTest.java new file mode 100644 index 000000000..5070aa4f9 --- /dev/null +++ b/infer/tests/frontend/cpp/IncludeHeaderTest.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2016 - present Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +package frontend.cpp; + +import org.junit.Rule; +import org.junit.Test; + +import java.io.IOException; + +import utils.DebuggableTemporaryFolder; +import utils.InferException; +import utils.ClangFrontendUtils; + +public class IncludeHeaderTest { + + String basePath = "infer/tests/codetoanalyze/cpp/frontend/include_header/"; + + @Rule + public DebuggableTemporaryFolder folder = new DebuggableTemporaryFolder(); + + void frontendTest(String fileRelative) throws InterruptedException, IOException, InferException { + ClangFrontendUtils.createAndCompareCppDotFiles(folder, basePath + fileRelative); + } + + @Test + public void testIncludeOnlyDotFilesMatch() + throws InterruptedException, IOException, InferException { + frontendTest("include_only.cpp"); + } + + @Test + public void testIncludeTemplDotFilesMatch() + throws InterruptedException, IOException, InferException { + frontendTest("include_templ.cpp"); + } + +}