[C++] Add cpp methods signatures and implementations

Summary:
Handle C++ method declarations and create cfgs for them.

Doesn't do:
Method calls (CXXMethodCall)
Using `this` expression in methods (including implicit ones)
master
Andrzej Kotulski 10 years ago
parent 352b8edff9
commit 7a839984da

@ -242,19 +242,21 @@ and decl_process_locs loc_composer decl =
let decl1 = Clang_ast_proj.update_decl_tuple update decl in
let decl_list' = list_map (decl_process_locs loc_composer) decl_list in
decl_set_sub_decls decl1 decl_list' in
let get_updated_fun_decl (decl_info', name, qt, fdecl_info) =
let fdi_decls_in_prototype_scope' =
list_map (decl_process_locs loc_composer) fdecl_info.fdi_decls_in_prototype_scope in
let fdi_parameters' =
list_map (decl_process_locs loc_composer) fdecl_info.fdi_parameters in
let body' = Option.map (stmt_process_locs loc_composer) fdecl_info.fdi_body in
let fdecl_info' =
{ fdecl_info with
fdi_body = body';
fdi_parameters = fdi_parameters';
fdi_decls_in_prototype_scope = fdi_decls_in_prototype_scope'; } in
(decl_info', name, qt, fdecl_info') in
match decl' with
| FunctionDecl (decl_info', name, qt, fdecl_info) ->
let fdi_decls_in_prototype_scope' =
list_map (decl_process_locs loc_composer) fdecl_info.fdi_decls_in_prototype_scope in
let fdi_parameters' =
list_map (decl_process_locs loc_composer) fdecl_info.fdi_parameters in
let body' = Option.map (stmt_process_locs loc_composer) fdecl_info.fdi_body in
let fdecl_info' =
{ fdecl_info with
fdi_body = body';
fdi_parameters = fdi_parameters';
fdi_decls_in_prototype_scope = fdi_decls_in_prototype_scope'; } in
FunctionDecl (decl_info', name, qt, fdecl_info')
| FunctionDecl fun_info -> FunctionDecl (get_updated_fun_decl fun_info)
| CXXMethodDecl fun_info -> CXXMethodDecl (get_updated_fun_decl fun_info)
| ObjCMethodDecl (decl_info', name, obj_c_method_decl_info) ->
let body' =
Option.map (stmt_process_locs loc_composer) obj_c_method_decl_info.omdi_body in

@ -21,7 +21,7 @@ open CGen_trans
open Clang_ast_t
(* Translate one global declaration *)
let rec translate_one_declaration tenv cg cfg namespace dec =
let rec translate_one_declaration tenv cg cfg namespace parent_dec dec =
let ns_suffix = Ast_utils.namespace_to_string namespace in
let info = Clang_ast_proj.get_decl_tuple dec in
CLocation.update_curr_file info;
@ -39,7 +39,11 @@ let rec translate_one_declaration tenv cg cfg namespace dec =
| RecordDecl (decl_info, name_info, opt_type, _, decl_list, decl_context_info, record_decl_info) ->
let record_name = name_info.Clang_ast_t.ni_name in
CTypes_decl.do_record_declaration tenv namespace
decl_info record_name opt_type decl_list decl_context_info record_decl_info
decl_info record_name opt_type decl_list decl_context_info record_decl_info;
let method_decls = CTypes_decl.get_method_decls dec decl_list in
let tranlate_method (parent, decl) =
translate_one_declaration tenv cg cfg namespace parent decl in
list_iter tranlate_method method_decls
| VarDecl(decl_info, name_info, t, _) ->
let name = name_info.Clang_ast_t.ni_name in
@ -73,6 +77,20 @@ let rec translate_one_declaration tenv cg cfg namespace dec =
let curr_class =
ObjcInterface_decl.interface_impl_declaration tenv name decl_list idi in
CMethod_declImpl.process_methods tenv cg cfg curr_class namespace decl_list
| CXXMethodDecl(decl_info, name_info, qual_type, function_decl_info) ->
(* di_parent_pointer has pointer to lexical context such as class.*)
(* If it's not defined, then it's the same as parent in AST *)
let class_decl = match decl_info.Clang_ast_t.di_parent_pointer with
| Some ptr -> Ast_utils.get_decl ptr
| None -> Some parent_dec in
(match class_decl with
| Some CXXRecordDecl(_, _, opt_type, _, _, _, _, _) ->
let class_name = CTypes_decl.get_record_name opt_type 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]
| Some dec -> Printing.log_stats "Methods of %s skipped\n" (Ast_utils.string_of_decl dec)
| None -> ())
| EnumDecl(decl_info, name_info, opt_type, _, decl_list, decl_context_info, enum_decl_info)
when should_translate_enum ->
@ -81,10 +99,10 @@ let rec translate_one_declaration tenv cg cfg namespace dec =
| LinkageSpecDecl(decl_info, decl_list, decl_context_info) ->
Printing.log_out "ADDING: LinkageSpecDecl decl list\n";
list_iter (translate_one_declaration tenv cg cfg namespace) decl_list
list_iter (translate_one_declaration tenv cg cfg namespace dec) decl_list
| NamespaceDecl(decl_info, name_info, decl_list, decl_context_info, _) ->
let name = ns_suffix^name_info.Clang_ast_t.ni_name in
list_iter (translate_one_declaration tenv cg cfg (Some name)) decl_list
list_iter (translate_one_declaration tenv cg cfg (Some name) dec) decl_list
| EmptyDecl _ ->
Printing.log_out "Passing from EmptyDecl. Treated as skip\n";
| dec ->
@ -98,7 +116,7 @@ let compute_icfg tenv source_file ast =
Printing.log_out "\n Start creating icfg\n";
let cg = Cg.create () in
let cfg = Cfg.Node.create_cfg () in
list_iter (translate_one_declaration tenv cg cfg None) decl_list;
list_iter (translate_one_declaration tenv cg cfg None ast) decl_list;
Printing.log_out "\n Finished creating icfg\n";
(cg, cfg)
| _ -> assert false (* NOTE: Assumes that an AST alsways starts with a TranslationUnitDecl *)

@ -33,6 +33,8 @@ let id_cl = "id"
let self = "self"
let this = "this"
let alloc = "alloc"
let malloc = "malloc"

@ -49,6 +49,8 @@ val id_cl : string
val self : string
val this : string
val nsstring_cl : string
val nsobject_cl : string

@ -258,6 +258,11 @@ struct
| generated:: rest -> generated = CFrontend_config.generated_suffix
| _ -> false
let get_decl decl_ptr =
try
Some (Clang_ast_main.PointerMap.find decl_ptr !CFrontend_config.pointer_decl_index)
with Not_found -> Printing.log_stats "decl with pointer %s not found\n" decl_ptr; None
end
(* Global counter for anonymous block*)
@ -379,6 +384,18 @@ struct
let mk_class_field_name class_name field_name =
Ident.create_fieldname (Mangled.mangled field_name (class_name^"_"^field_name)) 0
let mk_procname_from_function name type_name =
let type_name_crc = CRC.crc16 type_name in
Procname.mangled_c_fun name type_name_crc
let mk_procname_from_method class_name method_name method_kind =
let mangled = Procname.mangled_of_objc_method_kind method_kind in
Procname.mangled_c_method class_name method_name mangled
let mk_procname_from_cpp_method class_name method_name type_name =
let type_name_crc = Some (CRC.crc16 type_name) in
Procname.mangled_c_method class_name method_name type_name_crc
end

@ -76,6 +76,8 @@ sig
val is_generated : Clang_ast_t.named_decl_info -> bool
val get_decl : Clang_ast_t.pointer -> Clang_ast_t.decl option
end
module General_utils :
@ -116,6 +118,12 @@ sig
val replicate: int -> 'a -> 'a list
val mk_procname_from_method : string -> string -> Procname.objc_method_kind -> Procname.t
val mk_procname_from_function : string -> string -> Procname.t
val mk_procname_from_cpp_method : string -> string -> string -> Procname.t
val mk_class_field_name : string -> string -> Ident.fieldname

@ -37,7 +37,6 @@ struct
then None else Some body
| None -> body
let model_exists procname =
Specs.summary_exists_in_models procname && not !CFrontend_config.models_mode
@ -115,7 +114,7 @@ struct
captured_vars is_anonym_block param_decls attributes
| None -> CMethod_signature.add ms
let process_objc_method_decl tenv cg cfg namespace curr_class meth_decl =
let process_method_decl tenv cg cfg namespace curr_class meth_decl ~is_objc =
let ms, body_opt, param_decls =
CMethod_trans.method_signature_of_decl curr_class meth_decl None in
CMethod_signature.add ms;
@ -125,14 +124,16 @@ struct
let attributes = CMethod_signature.ms_get_attributes ms in
let procname = CMethod_signature.ms_get_name ms in
if CMethod_trans.create_local_procdesc cfg tenv ms [body] [] is_instance then
add_method tenv cg cfg curr_class procname namespace [body] true is_instance [] false
add_method tenv cg cfg curr_class procname namespace [body] is_objc is_instance [] false
param_decls attributes
| None -> ()
let rec process_one_method_decl tenv cg cfg curr_class namespace dec =
match dec with
| ObjCMethodDecl (decl_info, name_info, method_decl_info) ->
process_objc_method_decl tenv cg cfg namespace curr_class dec
| CXXMethodDecl _ ->
process_method_decl tenv cg cfg namespace curr_class dec ~is_objc:false
| ObjCMethodDecl _ ->
process_method_decl tenv cg cfg namespace curr_class dec ~is_objc:true
| ObjCPropertyImplDecl (decl_info, property_impl_decl_info) ->
let pname = Ast_utils.property_name property_impl_decl_info in
Printing.log_out "ADDING: ObjCPropertyImplDecl for property '%s' " pname;

@ -17,15 +17,6 @@ open Clang_ast_t
module L = Logging
let mk_procname_from_function name type_name =
let type_name_crc = CRC.crc16 type_name in
Procname.mangled_c_fun name type_name_crc
let mk_procname_from_method class_name method_name method_kind =
let mangled = Procname.mangled_of_objc_method_kind method_kind in
Procname.mangled_c_method class_name method_name mangled
(** When the methoc call is MCStatic, means that it is a class method. *)
(** When it is MCVirtual, it means that it is an instance method and that *)
(** the method to be called will be determined at runtime. If it is MCNoVirtual *)
@ -38,16 +29,33 @@ type method_call_type =
type function_method_decl_info =
| Func_decl_info of Clang_ast_t.function_decl_info * string
| Cpp_Meth_decl_info of Clang_ast_t.function_decl_info * string (* class_name *) * string (* ret_type *)
| Meth_decl_info of Clang_ast_t.obj_c_method_decl_info * string
| Block_decl_info of Clang_ast_t.block_decl_info * string
let is_instance_method function_method_decl_info is_instance =
match function_method_decl_info with
| Func_decl_info (function_decl_info, _) -> false
| Cpp_Meth_decl_info _ -> true
| Meth_decl_info (method_decl_info, _) ->
method_decl_info.Clang_ast_t.omdi_is_instance_method
| Block_decl_info (block_decl_info, _) -> is_instance
let get_class_param function_method_decl_info =
if (is_instance_method function_method_decl_info false) then
match function_method_decl_info with
| Cpp_Meth_decl_info (_, class_name, _) -> [(CFrontend_config.this, class_name, None)]
| Meth_decl_info (_, class_name) -> [(CFrontend_config.self, class_name, None)]
| _ -> []
else []
let get_param_decls function_method_decl_info =
match function_method_decl_info with
| Func_decl_info (function_decl_info, _)
| Cpp_Meth_decl_info (function_decl_info, _, _) -> function_decl_info.Clang_ast_t.fdi_parameters
| Meth_decl_info (method_decl_info, _) -> method_decl_info.Clang_ast_t.omdi_parameters
| Block_decl_info (block_decl_info, _) -> block_decl_info.Clang_ast_t.bdi_parameters
let get_parameters function_method_decl_info =
let par_to_ms_par par =
match par with
@ -57,24 +65,18 @@ let get_parameters function_method_decl_info =
Printing.log_out "with pointer %s@." decl_info.Clang_ast_t.di_pointer;
(name, CTypes.get_type qtype, var_decl_info.vdi_init_expr)
| _ -> assert false in
match function_method_decl_info with
| Func_decl_info (function_decl_info, _) ->
list_map par_to_ms_par function_decl_info.Clang_ast_t.fdi_parameters
| Meth_decl_info (method_decl_info, class_name) ->
let pars = list_map par_to_ms_par method_decl_info.Clang_ast_t.omdi_parameters in
if (is_instance_method function_method_decl_info false) then
("self", class_name, None):: pars
else pars
| Block_decl_info (block_decl_info, _) ->
list_map par_to_ms_par block_decl_info.Clang_ast_t.bdi_parameters
let pars = list_map par_to_ms_par (get_param_decls function_method_decl_info) in
get_class_param function_method_decl_info @ pars
let get_return_type function_method_decl_info =
match function_method_decl_info with
| Func_decl_info (_, qt) -> qt
| Func_decl_info (_, typ)
| Cpp_Meth_decl_info (_, _, typ)
| Block_decl_info (_, typ) -> typ
| Meth_decl_info (method_decl_info, _) ->
let qt = method_decl_info.Clang_ast_t.omdi_result_type in
CTypes.get_type qt
| Block_decl_info (_, qt) -> qt
let build_method_signature decl_info procname function_method_decl_info is_instance is_anonym_block is_generated =
let source_range = decl_info.Clang_ast_t.di_source_range in
@ -84,21 +86,28 @@ let build_method_signature decl_info procname function_method_decl_info is_insta
let attributes = decl_info.Clang_ast_t.di_attributes in
CMethod_signature.make_ms procname parameters qt attributes source_range is_instance_method is_generated
let method_signature_of_decl curr_class meth_decl block_data_opt =
match meth_decl, block_data_opt with
| FunctionDecl(decl_info, name_info, qt, fdi), _ ->
let name = name_info.Clang_ast_t.ni_name in
let func_decl = Func_decl_info (fdi, CTypes.get_type qt) in
let procname = mk_procname_from_function name (CTypes.get_type qt) in
let procname = General_utils.mk_procname_from_function name (CTypes.get_type qt) in
let ms = build_method_signature decl_info procname func_decl false false false in
ms, fdi.Clang_ast_t.fdi_body, fdi.Clang_ast_t.fdi_parameters
| CXXMethodDecl(decl_info, name_info, qt, fdi), _ ->
let class_name = CContext.get_curr_class_name curr_class in
let method_name = name_info.Clang_ast_t.ni_name in
let typ = CTypes.get_type qt in
let procname = General_utils.mk_procname_from_cpp_method class_name method_name typ in
let method_decl = Cpp_Meth_decl_info (fdi, class_name, typ) in
let ms = build_method_signature decl_info procname method_decl false false false in
ms, fdi.Clang_ast_t.fdi_body, fdi.Clang_ast_t.fdi_parameters
| ObjCMethodDecl(decl_info, name_info, mdi), _ ->
let class_name = CContext.get_curr_class_name curr_class in
let method_name = name_info.Clang_ast_t.ni_name in
let is_instance = mdi.Clang_ast_t.omdi_is_instance_method in
let method_kind = Procname.objc_method_kind_of_bool is_instance in
let procname = mk_procname_from_method class_name method_name method_kind in
let procname = General_utils.mk_procname_from_method class_name method_name method_kind in
let method_decl = Meth_decl_info (mdi, class_name) in
let is_generated = Ast_utils.is_generated name_info in
let ms = build_method_signature decl_info procname method_decl false false is_generated in
@ -109,7 +118,6 @@ let method_signature_of_decl curr_class meth_decl block_data_opt =
ms, bdi.Clang_ast_t.bdi_body, bdi.Clang_ast_t.bdi_parameters
|_ -> assert false
let get_superclass_curr_class context =
let retrive_super cname super_opt =
let iname = Sil.TN_csu (Sil.Class, Mangled.from_string cname) in

@ -27,10 +27,6 @@ val create_external_procdesc : Cfg.cfg -> Procname.t -> bool -> (Sil.typ * Sil.t
val captured_vars_from_block_info : CContext.t -> Clang_ast_t.block_captured_variable list -> (Mangled.t * Sil.typ * bool) list
val mk_procname_from_method : string -> string -> Procname.objc_method_kind -> Procname.t
val mk_procname_from_function : string -> string -> Procname.t
val get_class_selector_instance : CContext.t -> Clang_ast_t.obj_c_message_expr_info -> (Sil.exp * Sil.typ) list
-> (string * string * method_call_type)

@ -45,19 +45,19 @@ struct
let is_instance = mc_type != CMethod_trans.MCStatic in
let method_kind = Procname.objc_method_kind_of_bool is_instance in
match CTrans_models.get_predefined_model_method_signature class_name method_name
CMethod_trans.mk_procname_from_method with
General_utils.mk_procname_from_method with
| Some ms ->
ignore (CMethod_trans.create_local_procdesc context.cfg context.tenv ms [] [] is_instance);
CMethod_signature.ms_get_name ms, CMethod_trans.MCNoVirtual
| None ->
let procname = CMethod_trans.mk_procname_from_method class_name method_name method_kind in
let procname = General_utils.mk_procname_from_method class_name method_name method_kind in
try
let callee_ms = CMethod_signature.find procname in
if not (M.process_getter_setter context procname) then
(ignore (CMethod_trans.create_local_procdesc context.cfg context.tenv callee_ms [] [] is_instance));
procname, mc_type
with Not_found ->
let callee_pn = CMethod_trans.mk_procname_from_method class_name method_name method_kind in
let callee_pn = General_utils.mk_procname_from_method class_name method_name method_kind in
CMethod_trans.create_external_procdesc context.cfg callee_pn is_instance None;
callee_pn, mc_type
@ -317,7 +317,7 @@ struct
let pname, type_opt =
match qt with
| Some v ->
CMethod_trans.mk_procname_from_function name v, CTypes_decl.parse_func_type name v
mk_procname_from_function name v, CTypes_decl.parse_func_type name v
| None -> Procname.from_string_c_fun name, None in
let address_of_function = not context.CContext.is_callee_expression in
(* If we are not translating a callee expression, then the address of the function is being taken.*)

@ -305,7 +305,7 @@ let objc_new_trans trans_state loc stmt_info cls_name function_type =
let init_ret_id = Ident.create_fresh Ident.knormal in
let is_instance = true in
let call_flags = { Sil.cf_virtual = is_instance; Sil.cf_noreturn = false; Sil.cf_is_objc_block = false; } in
let pname = CMethod_trans.mk_procname_from_method cls_name CFrontend_config.init Procname.Instance_objc_method in
let pname = General_utils.mk_procname_from_method cls_name CFrontend_config.init Procname.Instance_objc_method in
CMethod_trans.create_external_procdesc trans_state.context.cfg pname is_instance None;
let args = [(Sil.Var alloc_ret_id, alloc_ret_type)] in
let init_stmt_call = Sil.Call([init_ret_id], (Sil.Const (Sil.Cfun pname)), args, loc, call_flags) in

@ -132,6 +132,22 @@ let parse_func_type name func_type =
Printing.log_stats "\nXXXXXXX PARSE ERROR for string '%s'." func_type;
None)
(* We need to take the name out of the type as the struct can be anonymous*)
let get_record_name opt_type = match opt_type with
| `Type n' -> CTypes.cut_struct_union n'
| `NoType -> assert false
let get_method_decls parent decl_list =
let rec traverse_decl parent decl = match decl with
| CXXMethodDecl _ -> [(parent, decl)]
| CXXRecordDecl (_, _, _, _, decl_list', _, _, _)
| RecordDecl (_, _, _, _, decl_list', _, _) -> traverse_decl_list decl decl_list'
| _ -> []
and traverse_decl_list parent decl_list = list_flatten (list_map (traverse_decl parent) decl_list) in
traverse_decl_list parent decl_list
(*In case of typedef like *)
(* typedef struct { f1; f2; ... } s; *)
(* the AST-dump splits the typedef definition from the struct definition. *)
@ -197,6 +213,17 @@ and get_struct_fields tenv record_name namespace decl_list =
get_struct_fields tenv record_name namespace decl_list'
| _ :: decl_list' -> get_struct_fields tenv record_name namespace decl_list'
and get_class_methods tenv class_name namespace decl_list =
let process_method_decl = function
| CXXMethodDecl (decl_info, name_info, qual_type, function_decl_info) ->
let method_name = name_info.ni_name in
Printing.log_out " ...Declaring method '%s'.\n" method_name;
let method_proc = mk_procname_from_cpp_method class_name method_name (CTypes.get_type qual_type) in
Some method_proc
| _ -> None in
(* poor mans list_filter_map *)
list_flatten_options (list_map process_method_decl decl_list)
and do_record_declaration tenv namespace decl_info name opt_type decl_list decl_context_info record_decl_info =
Printing.log_out "ADDING: RecordDecl for '%s'" name;
Printing.log_out " pointer= '%s'\n" decl_info.Clang_ast_t.di_pointer;
@ -206,11 +233,6 @@ and do_record_declaration tenv namespace decl_info name opt_type decl_list decl_
let typ = expand_structured_type tenv typ in
add_struct_to_tenv tenv typ
(* We need to take the name out of the type as the struct can be anonymous*)
and get_record_name opt_type = match opt_type with
| `Type n' -> CTypes.cut_struct_union n'
| `NoType -> assert false
(* For a record declaration it returns/constructs the type *)
and get_declaration_type tenv namespace decl_info n opt_type decl_list decl_context_info record_decl_info =
let ns_suffix = Ast_utils.namespace_to_string namespace in
@ -230,8 +252,8 @@ and get_declaration_type tenv namespace decl_info n opt_type decl_list decl_cont
| Sil.Tvar (Sil.TN_csu (csu, _)) -> csu
| _ -> Sil.Struct) in
let name = Some (Mangled.from_string name_str) in
let methods_list = get_class_methods tenv name_str namespace decl_list in (* C++ methods only *)
let superclass_list = [] in (* No super class for structs *)
let methods_list = [] in (* No methods list for structs *)
let item_annotation = Sil.item_annotation_empty in (* No annotations for struts *)
Sil.Tstruct
(non_static_fields, static_fields, csu, name, superclass_list, methods_list, item_annotation)

@ -15,6 +15,10 @@ val get_declaration_type : Sil.tenv -> string option -> Clang_ast_t.decl_info ->
val add_struct_to_tenv : Sil.tenv -> Sil.typ -> unit
val get_record_name : Clang_ast_t.opt_type -> string
val get_method_decls : Clang_ast_t.decl -> Clang_ast_t.decl list -> (Clang_ast_t.decl * Clang_ast_t.decl) list
val do_typedef_declaration : Sil.tenv -> string option -> Clang_ast_t.decl_info -> string ->
Clang_ast_t.opt_type -> Clang_ast_t.typedef_decl_info -> unit

@ -370,7 +370,7 @@ let get_methods curr_class decl_list =
let method_name = name_info.Clang_ast_t.ni_name in
Printing.log_out " ...Adding Method '%s' \n" (class_name^"_"^method_name);
let _ = check_for_property curr_class method_name d method_decl_info.Clang_ast_t.omdi_body in
let meth_name = CMethod_trans.mk_procname_from_method class_name method_name method_kind in
let meth_name = General_utils.mk_procname_from_method class_name method_name method_kind in
meth_name:: list_methods
| _ -> list_methods in
list_fold_right get_method decl_list []

@ -0,0 +1,55 @@
// commented out parts are not done yet
struct A {
public:
int member1;
float member2;
public:
int fun(int a, int b);
// overloading
int fun(int a, int b, int c);
int add(const A& other);
struct AIn {
int fun1() { return 1;}
int fun(int a, int b);
};
// inline definition
int def_in() { int c = 10; return c+1;}
//static function
//static int get_fun() {return 1;}
};
int A::fun(int a, int b, int c) {
//using class members
//fun(a,b);
}
int A::fun(int a, int b) {
int c = a + b + 1;
//using class members
//member1 = c;
return c*c;
}
int A::AIn::fun(int a, int b) {
return a+b;
}
int A::add(const A& other) {
//member1 += other.member1;
//return member1;
}
void test() {
// constructing objects
//A a;
//a.fun(1,2);
A *a_ptr;
// calling methods
// a_ptr->fun(10,20);
//A::get_fun();
//a.get_fun();
}

@ -0,0 +1,75 @@
digraph iCFG {
20 [label="20: Exit test \n " color=yellow style=filled]
19 [label="19: Start test\nFormals: \nLocals: a_ptr:struct A * \n DECLARE_LOCALS(&return,&a_ptr); [line 44]\n NULLIFY(&a_ptr,false); [line 44]\n " color=yellow style=filled]
19 -> 20 ;
18 [label="18: Exit A_add \n " color=yellow style=filled]
17 [label="17: Start A_add\nFormals: this:struct A other:struct A &\nLocals: \n DECLARE_LOCALS(&return); [line 39]\n NULLIFY(&this,false); [line 39]\n NULLIFY(&other,false); [line 39]\n " color=yellow style=filled]
17 -> 18 ;
16 [label="16: Return Stmt \n n$5=*&a:int [line 36]\n n$6=*&b:int [line 36]\n *&return:int =(n$5 + n$6) [line 36]\n REMOVE_TEMPS(n$5,n$6); [line 36]\n NULLIFY(&a,false); [line 36]\n NULLIFY(&b,false); [line 36]\n APPLY_ABSTRACTION; [line 36]\n " shape="box"]
16 -> 15 ;
15 [label="15: Exit A::AIn_fun \n " color=yellow style=filled]
14 [label="14: Start A::AIn_fun\nFormals: this:struct A::AIn a:int b:int \nLocals: \n DECLARE_LOCALS(&return); [line 35]\n NULLIFY(&this,false); [line 35]\n " color=yellow style=filled]
14 -> 16 ;
13 [label="13: DeclStmt \n n$3=*&a:int [line 29]\n n$4=*&b:int [line 29]\n *&c:int =((n$3 + n$4) + 1) [line 29]\n REMOVE_TEMPS(n$3,n$4); [line 29]\n NULLIFY(&a,false); [line 29]\n NULLIFY(&b,false); [line 29]\n " shape="box"]
13 -> 12 ;
12 [label="12: Return Stmt \n n$1=*&c:int [line 32]\n n$2=*&c:int [line 32]\n *&return:int =(n$1 * n$2) [line 32]\n REMOVE_TEMPS(n$1,n$2); [line 32]\n NULLIFY(&c,false); [line 32]\n APPLY_ABSTRACTION; [line 32]\n " shape="box"]
12 -> 11 ;
11 [label="11: Exit A_fun \n " color=yellow style=filled]
10 [label="10: Start A_fun\nFormals: this:struct A a:int b:int \nLocals: c:int \n DECLARE_LOCALS(&return,&c); [line 28]\n NULLIFY(&this,false); [line 28]\n NULLIFY(&c,false); [line 28]\n " color=yellow style=filled]
10 -> 13 ;
9 [label="9: Exit A_fun \n " color=yellow style=filled]
8 [label="8: Start A_fun\nFormals: this:struct A a:int b:int c:int \nLocals: \n DECLARE_LOCALS(&return); [line 23]\n NULLIFY(&this,false); [line 23]\n NULLIFY(&a,false); [line 23]\n NULLIFY(&b,false); [line 23]\n NULLIFY(&c,false); [line 23]\n " color=yellow style=filled]
8 -> 9 ;
7 [label="7: DeclStmt \n *&c:int =10 [line 17]\n " shape="box"]
7 -> 6 ;
6 [label="6: Return Stmt \n n$0=*&c:int [line 17]\n *&return:int =(n$0 + 1) [line 17]\n REMOVE_TEMPS(n$0); [line 17]\n NULLIFY(&c,false); [line 17]\n APPLY_ABSTRACTION; [line 17]\n " shape="box"]
6 -> 5 ;
5 [label="5: Exit A_def_in \n " color=yellow style=filled]
4 [label="4: Start A_def_in\nFormals: this:struct A \nLocals: c:int \n DECLARE_LOCALS(&return,&c); [line 17]\n NULLIFY(&this,false); [line 17]\n NULLIFY(&c,false); [line 17]\n " color=yellow style=filled]
4 -> 7 ;
3 [label="3: Return Stmt \n *&return:int =1 [line 13]\n APPLY_ABSTRACTION; [line 13]\n " shape="box"]
3 -> 2 ;
2 [label="2: Exit A::AIn_fun1 \n " color=yellow style=filled]
1 [label="1: Start A::AIn_fun1\nFormals: this:struct A::AIn \nLocals: \n DECLARE_LOCALS(&return); [line 13]\n NULLIFY(&this,false); [line 13]\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 MethodsTest {
@Rule
public DebuggableTemporaryFolder folder = new DebuggableTemporaryFolder();
@Test
public void whenCaptureRunCommaThenDotFilesAreTheSame()
throws InterruptedException, IOException, InferException {
String literal_src =
"infer/tests/codetoanalyze/cpp/frontend/types/methods.cpp";
String literal_dotty =
"infer/tests/codetoanalyze/cpp/frontend/types/methods.dot";
ImmutableList<String> inferCmd =
InferRunner.createCPPInferCommandFrontend(
folder,
literal_src);
File newDotFile = InferRunner.runInferFrontend(inferCmd);
assertThat(
"In the capture of " + literal_src +
" the dotty files should be the same.",
newDotFile, dotFileEqualTo(literal_dotty));
}
}
Loading…
Cancel
Save