[C++] Add inheritance information for C++ classes

Summary:
Pass inheritance information to the backend
It also changes some functions in cTypes_decl and we are using type and decl maps to resolve these types
master
Andrzej Kotulski 9 years ago
parent 0b4fc3a979
commit bc050c4188

@ -83,8 +83,8 @@ let rec translate_one_declaration tenv cg cfg namespace parent_dec dec =
| Some ptr -> Ast_utils.get_decl ptr
| None -> Some parent_dec in
(match class_decl with
| Some CXXRecordDecl(_, name_info, opt_type, _, _, _, _, _) ->
let class_name = CTypes_decl.get_record_name opt_type name_info in
| Some (CXXRecordDecl _ as d)->
let class_name = CTypes_decl.get_record_name d in
let curr_class = CContext.ContextCls(class_name, None, []) in
if !CFrontend_config.testing_mode then
CMethod_declImpl.process_methods tenv cg cfg curr_class namespace [dec]

@ -273,6 +273,32 @@ struct
CFrontend_config.sil_types_map :=
Clang_ast_main.PointerMap.add type_ptr sil_type !CFrontend_config.sil_types_map
let get_type type_ptr =
try
Some (Clang_ast_main.PointerMap.find type_ptr !CFrontend_config.pointer_type_index)
with Not_found -> Printing.log_stats "type with pointer %s not found\n" type_ptr; None
let get_desugared_type type_ptr =
let typ_opt = get_type type_ptr in
match typ_opt with
| Some typ ->
let type_info = Clang_ast_proj.get_type_tuple typ in
(match type_info.Clang_ast_t.ti_desugared_type with
| Some ptr -> get_type ptr
| _ -> typ_opt)
| _ -> typ_opt
let get_decl_from_typ_ptr typ_ptr =
let typ_opt = get_desugared_type typ_ptr in
let typ = match typ_opt with Some t -> t | _ -> assert false in
let get_decl_or_fail decl_ptr = match get_decl decl_ptr with
| Some d -> d
| None -> assert false in
(* it needs extending to handle objC types *)
match typ with
| Clang_ast_t.RecordType (ti, decl_ptr) -> get_decl_or_fail decl_ptr
| _ -> assert false
end
(* Global counter for anonymous block*)

@ -82,6 +82,14 @@ sig
(** creates a string to append to a name from a list of qualifiers to a name *)
val get_qualifier_string : Clang_ast_t.named_decl_info -> string
val get_type : Clang_ast_t.pointer -> Clang_ast_t.c_type option
val get_desugared_type : Clang_ast_t.pointer -> Clang_ast_t.c_type option
(** returns declaration of the type for certain types and crashes for others
NOTE: this function needs extending to handle objC types *)
val get_decl_from_typ_ptr : Clang_ast_t.type_ptr -> Clang_ast_t.decl
end
module General_utils :

@ -116,8 +116,8 @@ and sil_type_of_c_type translate_decl tenv c_type =
| AttributedType type_info ->
(match type_info.Clang_ast_t.ti_desugared_type with
| Some type_ptr ->
(match Clang_ast_main.PointerMap.find type_ptr !CFrontend_config.pointer_type_index with
| ObjCObjectPointerType (type_info', type_ptr') ->
(match Ast_utils.get_type type_ptr with
| Some ObjCObjectPointerType (type_info', type_ptr') ->
let typ = qual_type_ptr_to_sil_type translate_decl tenv type_ptr' in
CTypes.sil_type_of_attr_pointer_type typ type_info.Clang_ast_t.ti_raw
| _ -> qual_type_ptr_to_sil_type translate_decl tenv type_ptr)
@ -152,15 +152,12 @@ and qual_type_ptr_to_sil_type translate_decl tenv type_ptr =
try
Clang_ast_main.PointerMap.find type_ptr !CFrontend_config.sil_types_map
with Not_found ->
try
let c_type = Clang_ast_main.PointerMap.find type_ptr !CFrontend_config.pointer_type_index in
let sil_type = sil_type_of_c_type translate_decl tenv c_type in
Ast_utils.update_sil_types_map type_ptr sil_type;
sil_type
with Not_found ->
Printing.log_err "Warning: Type pointer %s not found."
(Clang_ast_j.string_of_pointer type_ptr);
Sil.Tvoid
match Ast_utils.get_type type_ptr with
| Some c_type ->
let sil_type = sil_type_of_c_type translate_decl tenv c_type in
Ast_utils.update_sil_types_map type_ptr sil_type;
sil_type
| _ -> Sil.Tvoid
and qual_type_to_sil_type translate_decl tenv qt =
let type_ptr = qt.Clang_ast_t.qt_type_ptr in

@ -198,22 +198,20 @@ let sil_type_of_attr_pointer_type typ raw_type =
let rec return_type_of_function_type_ptr type_ptr =
let open Clang_ast_t in
try
let c_type = Clang_ast_main.PointerMap.find type_ptr !CFrontend_config.pointer_type_index in
match c_type with
| FunctionProtoType (type_info, function_type_info, _)
| FunctionNoProtoType (type_info, function_type_info) ->
function_type_info.Clang_ast_t.fti_return_type
| BlockPointerType (type_info, in_type_ptr) ->
return_type_of_function_type_ptr in_type_ptr
| _ ->
Printing.log_err "Warning: Type pointer %s is not a function type."
(Clang_ast_j.string_of_pointer type_ptr);
""
with Not_found ->
Printing.log_err "Warning: Type pointer %s not found."
(Clang_ast_j.string_of_pointer type_ptr);
""
match Ast_utils.get_type type_ptr with
| Some FunctionProtoType (type_info, function_type_info, _)
| Some FunctionNoProtoType (type_info, function_type_info) ->
function_type_info.Clang_ast_t.fti_return_type
| Some BlockPointerType (type_info, in_type_ptr) ->
return_type_of_function_type_ptr in_type_ptr
| Some _ ->
Printing.log_err "Warning: Type pointer %s is not a function type."
(Clang_ast_j.string_of_pointer type_ptr);
""
| None ->
Printing.log_err "Warning: Type pointer %s not found."
(Clang_ast_j.string_of_pointer type_ptr);
""
let return_type_of_function_type qt =
return_type_of_function_type_ptr qt.Clang_ast_t.qt_type_ptr

@ -86,8 +86,11 @@ let get_record_name_csu opt_type name_info =
if (String.length name_str = 0) then prefix ^ type_name else prefix ^ name_str in
csu, name
let get_record_name opt_type name_info =
let get_record_name decl =
let name_info, opt_type = match decl with
| Clang_ast_t.RecordDecl (_, name_info, opt_type, _, _, _, _)
| Clang_ast_t.CXXRecordDecl (_, name_info, opt_type, _, _, _, _, _) -> name_info, opt_type
| _ -> assert false in
snd (get_record_name_csu opt_type name_info)
let get_method_decls parent decl_list =
@ -112,6 +115,18 @@ let get_class_methods tenv class_name namespace decl_list =
(* poor mans list_filter_map *)
list_flatten_options (list_map process_method_decl decl_list)
(** fetches list of superclasses for C++ classes *)
let get_superclass_list 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 = list_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
list_map get_super_field base_decls
| _ -> []
let add_struct_to_tenv tenv typ =
let csu = match typ with
| Sil.Tstruct(_, _, csu, _, _, _, _) -> csu
@ -155,7 +170,7 @@ and get_declaration_type tenv namespace decl =
let sorted_non_static_fields = CFrontend_utils.General_utils.sort_fields non_static_fields' in
let static_fields = [] in (* Warning for the moment we do not treat static field. *)
let methods = get_class_methods tenv name namespace decl_list in (* C++ methods only *)
let superclasses = [] in
let superclasses = get_superclass_list decl in
let item_annotation = Sil.item_annotation_empty in (* No annotations for struts *)
let sil_type = Sil.Tstruct (sorted_non_static_fields, static_fields, csu, Some mangled_name,
superclasses, methods, item_annotation) in

@ -13,7 +13,7 @@ val get_declaration_type : Sil.tenv -> string option -> Clang_ast_t.decl -> Sil.
val add_struct_to_tenv : Sil.tenv -> Sil.typ -> unit
val get_record_name : Clang_ast_t.opt_type -> Clang_ast_t.named_decl_info -> string
val get_record_name : Clang_ast_t.decl -> string
val get_method_decls : Clang_ast_t.decl -> Clang_ast_t.decl list -> (Clang_ast_t.decl * Clang_ast_t.decl) list

@ -0,0 +1,33 @@
/*
* 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.
*/
class Base {
public:
int fun() { return 1;}
int fun_redefine() { return 10; } // note that they are not virtual
};
class Sub : public Base {
public:
int fun_redefine() { return 20; }
};
void call_static_methods() {
Base *b = new Base;
Base *s1 = new Sub; // note the type of s1
Sub *s2 = new Sub;
b->fun();
s1->fun();
s2->fun();
b->fun_redefine();
s1->fun_redefine(); // will call Base::fun_redefine
s2->fun_redefine(); // will call Sub::fun_redefine
}

@ -0,0 +1,78 @@
digraph iCFG {
20 [label="20: DeclStmt \n n$14=_fun___new(sizeof(class Base ):unsigned long ) [line 22]\n *&b:class Base *=n$14 [line 22]\n REMOVE_TEMPS(n$14); [line 22]\n " shape="box"]
20 -> 19 ;
19 [label="19: DeclStmt \n n$13=_fun___new(sizeof(class Sub ):unsigned long ) [line 23]\n *&s1:class Base *=n$13 [line 23]\n REMOVE_TEMPS(n$13); [line 23]\n " shape="box"]
19 -> 18 ;
18 [label="18: DeclStmt \n n$12=_fun___new(sizeof(class Sub ):unsigned long ) [line 24]\n *&s2:class Sub *=n$12 [line 24]\n REMOVE_TEMPS(n$12); [line 24]\n " shape="box"]
18 -> 17 ;
17 [label="17: Call _fun_Base_fun \n n$10=*&b:class Base * [line 26]\n n$11=_fun_Base_fun(n$10:class Base ) [line 26]\n REMOVE_TEMPS(n$10,n$11); [line 26]\n " shape="box"]
17 -> 16 ;
16 [label="16: Call _fun_Base_fun \n n$8=*&s1:class Base * [line 27]\n n$9=_fun_Base_fun(n$8:class Base ) [line 27]\n REMOVE_TEMPS(n$8,n$9); [line 27]\n " shape="box"]
16 -> 15 ;
15 [label="15: Call _fun_Base_fun \n n$6=*&s2:class Sub * [line 28]\n n$7=_fun_Base_fun(n$6:class Base ) [line 28]\n REMOVE_TEMPS(n$6,n$7); [line 28]\n " shape="box"]
15 -> 14 ;
14 [label="14: Call _fun_Base_fun_redefine \n n$4=*&b:class Base * [line 30]\n n$5=_fun_Base_fun_redefine(n$4:class Base ) [line 30]\n REMOVE_TEMPS(n$4,n$5); [line 30]\n NULLIFY(&b,false); [line 30]\n " shape="box"]
14 -> 13 ;
13 [label="13: Call _fun_Base_fun_redefine \n n$2=*&s1:class Base * [line 31]\n n$3=_fun_Base_fun_redefine(n$2:class Base ) [line 31]\n REMOVE_TEMPS(n$2,n$3); [line 31]\n NULLIFY(&s1,false); [line 31]\n " shape="box"]
13 -> 12 ;
12 [label="12: Call _fun_Sub_fun_redefine \n n$0=*&s2:class Sub * [line 32]\n n$1=_fun_Sub_fun_redefine(n$0:class Sub ) [line 32]\n REMOVE_TEMPS(n$0,n$1); [line 32]\n NULLIFY(&s2,false); [line 32]\n APPLY_ABSTRACTION; [line 32]\n " shape="box"]
12 -> 11 ;
11 [label="11: Exit call_static_methods \n " color=yellow style=filled]
10 [label="10: Start call_static_methods\nFormals: \nLocals: b:class Base * s1:class Base * s2:class Sub * \n DECLARE_LOCALS(&return,&b,&s1,&s2); [line 21]\n NULLIFY(&b,false); [line 21]\n NULLIFY(&s1,false); [line 21]\n NULLIFY(&s2,false); [line 21]\n " color=yellow style=filled]
10 -> 20 ;
9 [label="9: Return Stmt \n *&return:int =20 [line 18]\n APPLY_ABSTRACTION; [line 18]\n " shape="box"]
9 -> 8 ;
8 [label="8: Exit Sub_fun_redefine \n " color=yellow style=filled]
7 [label="7: Start Sub_fun_redefine\nFormals: this:struct Sub \nLocals: \n DECLARE_LOCALS(&return); [line 18]\n NULLIFY(&this,false); [line 18]\n " color=yellow style=filled]
7 -> 9 ;
6 [label="6: Return Stmt \n *&return:int =10 [line 13]\n APPLY_ABSTRACTION; [line 13]\n " shape="box"]
6 -> 5 ;
5 [label="5: Exit Base_fun_redefine \n " color=yellow style=filled]
4 [label="4: Start Base_fun_redefine\nFormals: this:struct Base \nLocals: \n DECLARE_LOCALS(&return); [line 13]\n NULLIFY(&this,false); [line 13]\n " color=yellow style=filled]
4 -> 6 ;
3 [label="3: Return Stmt \n *&return:int =1 [line 12]\n APPLY_ABSTRACTION; [line 12]\n " shape="box"]
3 -> 2 ;
2 [label="2: Exit Base_fun \n " color=yellow style=filled]
1 [label="1: Start Base_fun\nFormals: this:struct Base \nLocals: \n DECLARE_LOCALS(&return); [line 12]\n NULLIFY(&this,false); [line 12]\n " color=yellow style=filled]
1 -> 3 ;
}

@ -0,0 +1,51 @@
/*
* Copyright (c) 2013 - 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 static org.hamcrest.MatcherAssert.assertThat;
import static utils.matchers.DotFilesEqual.dotFileEqualTo;
import com.google.common.collect.ImmutableList;
import org.junit.Rule;
import org.junit.Test;
import java.io.File;
import java.io.IOException;
import utils.DebuggableTemporaryFolder;
import utils.InferException;
import utils.InferRunner;
public class InheritanceTest {
@Rule
public DebuggableTemporaryFolder folder = new DebuggableTemporaryFolder();
@Test
public void whenCaptureRunCommaThenDotFilesAreTheSame()
throws InterruptedException, IOException, InferException {
String src =
"infer/tests/codetoanalyze/cpp/frontend/types/inheritance.cpp";
String dotty =
"infer/tests/codetoanalyze/cpp/frontend/types/inheritance.dot";
ImmutableList<String> inferCmd =
InferRunner.createCPPInferCommandFrontend(
folder,
src);
File newDotFile = InferRunner.runInferFrontend(inferCmd);
assertThat(
"In the capture of " + src +
" the dotty files should be the same.",
newDotFile, dotFileEqualTo(dotty));
}
}
Loading…
Cancel
Save