Add base class fields to C++ classes

Summary: public Fix oversight where fields of base classes were
not exported.

Reviewed By: dulmarod

Differential Revision: D2652218

fb-gh-sync-id: 75b93ed
master
Andrzej Kotulski 9 years ago committed by facebook-github-bot-7
parent 10db97be1e
commit 55f9fb9d5e

@ -124,18 +124,21 @@ let get_class_methods tenv class_name namespace decl_list =
(* poor mans list_filter_map *)
IList.flatten_options (IList.map process_method_decl decl_list)
(** fetches list of superclasses for C++ classes *)
let get_superclass_list decl =
let get_superclass_decls decl =
match decl with
| Clang_ast_t.CXXRecordDecl (_, _, _, _, _, _, _, cxx_rec_info) ->
(* there is no concept of virtual inheritance in the backend right now *)
let base_ptr = cxx_rec_info.Clang_ast_t.xrdi_bases @ cxx_rec_info.Clang_ast_t.xrdi_vbases in
let base_decls = IList.map Ast_utils.get_decl_from_typ_ptr base_ptr in
let decl_to_mangled_name decl = Mangled.from_string (get_record_name decl) in
let get_super_field super_decl = (Sil.Class, decl_to_mangled_name super_decl) in
IList.map get_super_field base_decls
IList.map Ast_utils.get_decl_from_typ_ptr base_ptr
| _ -> []
(** fetches list of superclasses for C++ classes *)
let get_superclass_list decl =
let base_decls = get_superclass_decls decl in
let decl_to_mangled_name decl = Mangled.from_string (get_record_name decl) in
let get_super_field super_decl = (Sil.Class, decl_to_mangled_name super_decl) in
IList.map get_super_field base_decls
let add_struct_to_tenv tenv typ =
let csu = match typ with
| Sil.Tstruct(_, _, csu, _, _, _, _) -> csu
@ -144,8 +147,12 @@ let add_struct_to_tenv tenv typ =
let typename = Sil.TN_csu(csu, mangled) in
Sil.tenv_add tenv typename typ
let rec get_struct_fields tenv record_name namespace decl_list =
let rec get_struct_fields tenv namespace decl =
let open Clang_ast_t in
let decl_list = match decl with
| CXXRecordDecl (_, _, _, _, decl_list, _, _, _)
| RecordDecl (_, _, _, _, decl_list, _, _) -> decl_list
| _ -> [] in
let do_one_decl decl = match decl with
| FieldDecl (_, name_info, type_ptr, _) ->
let id = General_utils.mk_class_field_name name_info in
@ -158,7 +165,9 @@ let rec get_struct_fields tenv record_name namespace decl_list =
if not decl_info.Clang_ast_t.di_is_implicit then
ignore (add_types_from_decl_to_tenv tenv namespace decl); []
| _ -> [] in
IList.flatten (IList.map do_one_decl decl_list)
let base_decls = get_superclass_decls decl in
let base_class_fields = IList.map (get_struct_fields tenv namespace) base_decls in
IList.flatten (base_class_fields @ (IList.map do_one_decl decl_list))
(* For a record declaration it returns/constructs the type *)
and get_strct_cpp_class_declaration_type tenv namespace decl =
@ -174,7 +183,7 @@ and get_strct_cpp_class_declaration_type tenv namespace decl =
if not record_decl_info.Clang_ast_t.rdi_is_complete_definition then
Printing.log_err
" ...Warning, definition incomplete. The full definition will probably be later \n@.";
let non_static_fields = get_struct_fields tenv name namespace decl_list in
let non_static_fields = get_struct_fields tenv namespace decl in
let non_static_fields' = if CTrans_models.is_objc_memory_model_controlled name then
General_utils.append_no_duplicates_fields [Sil.objc_ref_counter_field] non_static_fields
else non_static_fields in

@ -0,0 +1,60 @@
/*
* Copyright (c) 2015 - 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 Base1 {
int b1;
};
struct Base2 {
int b2;
};
struct Sub : public Base1, public Base2 {
int s;
};
int div0_b1(Sub s) {
s.b1 = 0;
return 1 / s.b1;
}
int div0_b2(Sub s) {
s.b2 = 0;
return 1 / s.b2;
}
int div0_s(Sub s) {
s.s = 0;
return 1 / s.s;
}
int div0_cast(Sub *s) {
s->b1 = 0;
Base1 *b = s;
return 1 / b->b1;
}
int div0_cast_ref(Sub s) {
s.b1 = 0;
Base1 &b = s;
return 1 / b.b1;
}
int div1_b1(Sub s) {
s.b1 = 1;
return 1 / s.b1;
}
int div1_cast(Sub *s) {
s->b1 = 1;
Base1 *b = s;
return 1 / b->b1;
}

@ -0,0 +1,119 @@
digraph iCFG {
31 [label="31: BinaryOperatorStmt: Assign \n n$3=*&s:class Sub * [line 56]\n *n$3.b1:int =1 [line 56]\n REMOVE_TEMPS(n$3); [line 56]\n " shape="box"]
31 -> 30 ;
30 [label="30: DeclStmt \n n$2=*&s:class Sub * [line 57]\n *&b:struct Base1 *=n$2 [line 57]\n REMOVE_TEMPS(n$2); [line 57]\n NULLIFY(&s,false); [line 57]\n " shape="box"]
30 -> 29 ;
29 [label="29: Return Stmt \n n$0=*&b:struct Base1 * [line 58]\n n$1=*n$0.b1:int [line 58]\n *&return:int =(1 / n$1) [line 58]\n REMOVE_TEMPS(n$0,n$1); [line 58]\n NULLIFY(&b,false); [line 58]\n APPLY_ABSTRACTION; [line 58]\n " shape="box"]
29 -> 28 ;
28 [label="28: Exit div1_cast \n " color=yellow style=filled]
27 [label="27: Start div1_cast\nFormals: s:class Sub *\nLocals: b:struct Base1 * \n DECLARE_LOCALS(&return,&b); [line 55]\n NULLIFY(&b,false); [line 55]\n " color=yellow style=filled]
27 -> 31 ;
26 [label="26: BinaryOperatorStmt: Assign \n *&s.b1:int =1 [line 51]\n " shape="box"]
26 -> 25 ;
25 [label="25: Return Stmt \n n$0=*&s.b1:int [line 52]\n *&return:int =(1 / n$0) [line 52]\n REMOVE_TEMPS(n$0); [line 52]\n NULLIFY(&s,false); [line 52]\n APPLY_ABSTRACTION; [line 52]\n " shape="box"]
25 -> 24 ;
24 [label="24: Exit div1_b1 \n " color=yellow style=filled]
23 [label="23: Start div1_b1\nFormals: s:class Sub \nLocals: \n DECLARE_LOCALS(&return); [line 50]\n " color=yellow style=filled]
23 -> 26 ;
22 [label="22: BinaryOperatorStmt: Assign \n *&s.b1:int =0 [line 44]\n " shape="box"]
22 -> 21 ;
21 [label="21: DeclStmt \n *&b:struct Base1 &=&s [line 45]\n " shape="box"]
21 -> 20 ;
20 [label="20: Return Stmt \n n$0=*&b:struct Base1 & [line 46]\n n$1=*n$0.b1:int [line 46]\n *&return:int =(1 / n$1) [line 46]\n REMOVE_TEMPS(n$0,n$1); [line 46]\n NULLIFY(&b,false); [line 46]\n NULLIFY(&s,false); [line 46]\n APPLY_ABSTRACTION; [line 46]\n " shape="box"]
20 -> 19 ;
19 [label="19: Exit div0_cast_ref \n " color=yellow style=filled]
18 [label="18: Start div0_cast_ref\nFormals: s:class Sub \nLocals: b:struct Base1 & \n DECLARE_LOCALS(&return,&b); [line 43]\n NULLIFY(&b,false); [line 43]\n " color=yellow style=filled]
18 -> 22 ;
17 [label="17: BinaryOperatorStmt: Assign \n n$3=*&s:class Sub * [line 38]\n *n$3.b1:int =0 [line 38]\n REMOVE_TEMPS(n$3); [line 38]\n " shape="box"]
17 -> 16 ;
16 [label="16: DeclStmt \n n$2=*&s:class Sub * [line 39]\n *&b:struct Base1 *=n$2 [line 39]\n REMOVE_TEMPS(n$2); [line 39]\n NULLIFY(&s,false); [line 39]\n " shape="box"]
16 -> 15 ;
15 [label="15: Return Stmt \n n$0=*&b:struct Base1 * [line 40]\n n$1=*n$0.b1:int [line 40]\n *&return:int =(1 / n$1) [line 40]\n REMOVE_TEMPS(n$0,n$1); [line 40]\n NULLIFY(&b,false); [line 40]\n APPLY_ABSTRACTION; [line 40]\n " shape="box"]
15 -> 14 ;
14 [label="14: Exit div0_cast \n " color=yellow style=filled]
13 [label="13: Start div0_cast\nFormals: s:class Sub *\nLocals: b:struct Base1 * \n DECLARE_LOCALS(&return,&b); [line 37]\n NULLIFY(&b,false); [line 37]\n " color=yellow style=filled]
13 -> 17 ;
12 [label="12: BinaryOperatorStmt: Assign \n *&s.s:int =0 [line 33]\n " shape="box"]
12 -> 11 ;
11 [label="11: Return Stmt \n n$0=*&s.s:int [line 34]\n *&return:int =(1 / n$0) [line 34]\n REMOVE_TEMPS(n$0); [line 34]\n NULLIFY(&s,false); [line 34]\n APPLY_ABSTRACTION; [line 34]\n " shape="box"]
11 -> 10 ;
10 [label="10: Exit div0_s \n " color=yellow style=filled]
9 [label="9: Start div0_s\nFormals: s:class Sub \nLocals: \n DECLARE_LOCALS(&return); [line 32]\n " color=yellow style=filled]
9 -> 12 ;
8 [label="8: BinaryOperatorStmt: Assign \n *&s.b2:int =0 [line 28]\n " shape="box"]
8 -> 7 ;
7 [label="7: Return Stmt \n n$0=*&s.b2:int [line 29]\n *&return:int =(1 / n$0) [line 29]\n REMOVE_TEMPS(n$0); [line 29]\n NULLIFY(&s,false); [line 29]\n APPLY_ABSTRACTION; [line 29]\n " shape="box"]
7 -> 6 ;
6 [label="6: Exit div0_b2 \n " color=yellow style=filled]
5 [label="5: Start div0_b2\nFormals: s:class Sub \nLocals: \n DECLARE_LOCALS(&return); [line 27]\n " color=yellow style=filled]
5 -> 8 ;
4 [label="4: BinaryOperatorStmt: Assign \n *&s.b1:int =0 [line 23]\n " shape="box"]
4 -> 3 ;
3 [label="3: Return Stmt \n n$0=*&s.b1:int [line 24]\n *&return:int =(1 / n$0) [line 24]\n REMOVE_TEMPS(n$0); [line 24]\n NULLIFY(&s,false); [line 24]\n APPLY_ABSTRACTION; [line 24]\n " shape="box"]
3 -> 2 ;
2 [label="2: Exit div0_b1 \n " color=yellow style=filled]
1 [label="1: Start div0_b1\nFormals: s:class Sub \nLocals: \n DECLARE_LOCALS(&return); [line 22]\n " color=yellow style=filled]
1 -> 4 ;
}

@ -0,0 +1,67 @@
/*
* Copyright (c) 2015 - 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 InheritanceFieldTest {
public static final String FILE =
"infer/tests/codetoanalyze/cpp/frontend/types/inheritance_field.cpp";
private static ImmutableList<String> 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 = {
"div0_b1",
"div0_b2",
"div0_s",
"div0_cast",
"div0_cast_ref",
};
assertThat(
"Results should contain the expected divide by zero",
inferResults,
containsExactly(
DIVIDE_BY_ZERO,
FILE,
procedures
)
);
}
}

@ -20,14 +20,25 @@ import utils.ClangFrontendUtils;
public class InheritanceTest {
String basePath = "infer/tests/codetoanalyze/cpp/frontend/types/";
@Rule
public DebuggableTemporaryFolder folder = new DebuggableTemporaryFolder();
void frontendTest(String fileRelative) throws InterruptedException, IOException, InferException {
ClangFrontendUtils.createAndCompareCppDotFiles(folder, basePath + fileRelative);
}
@Test
public void testInheritanceDotFilesMatch()
throws InterruptedException, IOException, InferException {
frontendTest("inheritance.cpp");
}
@Test
public void whenCaptureRunCommaThenDotFilesAreTheSame()
public void testInheritanceFieldDotFilesMatch()
throws InterruptedException, IOException, InferException {
String src =
"infer/tests/codetoanalyze/cpp/frontend/types/inheritance.cpp";
ClangFrontendUtils.createAndCompareCppDotFiles(folder, src);
frontendTest("inheritance_field.cpp");
}
}

Loading…
Cancel
Save