[C++ frontend] Handle calling c++ methods

Summary:
Translate calling C++ methods. Code is pretty similar to C function calling,
but slightly simpler and has some modifications
master
Andrzej Kotulski 9 years ago
parent 7a839984da
commit 198c3c82e1

@ -524,7 +524,8 @@ struct
let function_type = CTypes_decl.get_type_from_expr_info expr_info context.tenv in
let procname = Cfg.Procdesc.get_proc_name context.procdesc in
let sil_loc = get_sil_location si pln context in
let fun_exp_stmt, params_stmt = (match stmt_list with (* First stmt is the function expr and the rest are params*)
(* First stmt is the function expr and the rest are params *)
let fun_exp_stmt, params_stmt = (match stmt_list with
| fe:: params -> fe, params
| _ -> assert false) in
let trans_state_pri = PriorityNode.try_claim_priority_node trans_state si in
@ -554,7 +555,8 @@ struct
(Procname.to_string pn) <> CFrontend_config.builtin_object_size
| _ -> true in
let params_stmt = if should_translate_args then
CTrans_utils.assign_default_params params_stmt callee_pname_opt else [] in
CTrans_utils.assign_default_params params_stmt callee_pname_opt ~is_cxx_method:false
else [] in
let res_trans_par =
let l = list_map (fun i -> exec_with_self_exception instruction trans_state_param i) params_stmt in
let rt = collect_res_trans (res_trans_callee :: l) in
@ -609,6 +611,70 @@ struct
| [ret_id'] -> { res_trans_to_parent with exps =[(Sil.Var ret_id', function_type)] }
| _ -> assert false) (* by construction of red_id, we cannot be in this case *)
and cxxMemberCallExpr_trans trans_state si stmt_list expr_info =
let pln = trans_state.parent_line_number in
let context = trans_state.context in
let function_type = CTypes_decl.get_type_from_expr_info expr_info context.tenv in
let procname = Cfg.Procdesc.get_proc_name context.procdesc in
let sil_loc = get_sil_location si pln context in
(* First stmt is the method+this expr and the rest are params *)
let fun_exp_stmt, params_stmt = (match stmt_list with
| fe:: params -> fe, params
| _ -> assert false) in
let trans_state_pri = PriorityNode.try_claim_priority_node trans_state si in
(* claim priority if no ancestors has claimed priority before *)
let line_number = get_line si pln in
let trans_state_callee = { trans_state_pri with
parent_line_number = line_number;
succ_nodes = [] } in
let result_trans_callee = instruction trans_state_callee fun_exp_stmt in
(* first for method address, second for 'this' expression *)
assert ((list_length result_trans_callee.exps) = 2);
let (sil_method, typ_method) = list_hd result_trans_callee.exps in
let callee_pname = match sil_method with
| Sil.Const (Sil.Cfun pn) -> pn
| _ -> assert false (* method pointer not implemented, this shouldn't happen *) in
let params_stmt = CTrans_utils.assign_default_params params_stmt (Some callee_pname) ~is_cxx_method:true in
(* As we may have nodes coming from different parameters we need to *)
(* call instruction for each parameter and collect the results *)
(* afterwards. The 'instructions' function does not do that *)
let trans_state_param =
{ trans_state_pri with parent_line_number = line_number; succ_nodes = [] } in
let result_trans_params =
let l = list_map (exec_with_self_exception instruction trans_state_param) params_stmt in
(* this function will automatically merge 'this' argument with rest of arguments in 'l'*)
let rt = collect_res_trans (result_trans_callee :: l) in
{ rt with exps = list_tl rt.exps } in
let actual_params = result_trans_params.exps in
let ret_id = if (Sil.typ_equal function_type Sil.Tvoid) then []
else [Ident.create_fresh Ident.knormal] in
let call_flags = {
Sil.cf_virtual = false (* TODO t7725350 *);
Sil.cf_noreturn = false;
Sil.cf_is_objc_block = false;
} in
let call_instr = Sil.Call (ret_id, sil_method, actual_params, sil_loc, call_flags) in
let ids = result_trans_params.ids @ ret_id in
let instrs = result_trans_params.instrs @ [call_instr] in
let res_trans_tmp = { result_trans_params with ids = ids; instrs = instrs; exps =[] } in
let nname = "Call " ^ (Sil.exp_to_string sil_method) in
let result_trans_to_parent =
PriorityNode.compute_results_to_parent trans_state_pri sil_loc nname si res_trans_tmp in
Cg.add_edge context.cg procname callee_pname;
(try
let callee_ms = CMethod_signature.find callee_pname in
ignore (CMethod_trans.create_local_procdesc context.cfg context.tenv callee_ms [] [] false)
with Not_found ->
CMethod_trans.create_external_procdesc context.cfg callee_pname false None);
match ret_id with
| [] -> { result_trans_to_parent with exps =[] }
| [ret_id'] -> { result_trans_to_parent with exps =[(Sil.Var ret_id', function_type)] }
| _ -> assert false (* by construction of red_id, we cannot be in this case *)
and objCMessageExpr_trans trans_state si obj_c_message_expr_info stmt_list expr_info =
Printing.log_out " priority node free = '%s'\n@."
(string_of_bool (PriorityNode.is_priority_free trans_state));
@ -1415,29 +1481,40 @@ struct
let field_name = match decl_ref.Clang_ast_t.dr_name with
| Some s -> s.Clang_ast_t.ni_name
| _ -> assert false in
let field_typ = match decl_ref.Clang_ast_t.dr_qual_type with
| Some t -> CTypes_decl.qual_type_to_sil_type trans_state.context.tenv t
let field_qt = match decl_ref.Clang_ast_t.dr_qual_type with
| Some t -> t
| _ -> assert false in
let field_typ = CTypes_decl.qual_type_to_sil_type trans_state.context.tenv field_qt in
Printing.log_out "!!!!! Dealing with field '%s' @." field_name;
let exp_stmt = extract_stmt_from_singleton stmt_list
"WARNING: in MemberExpr there must be only one stmt defining its expression.\n" in
let res_trans_exp_stmt = instruction trans_state exp_stmt in
let (e, class_typ) = extract_exp_from_list res_trans_exp_stmt.exps
let result_trans_exp_stmt = instruction trans_state exp_stmt in
let (obj_sil, class_typ) = extract_exp_from_list result_trans_exp_stmt.exps
"WARNING: in MemberExpr we expect the translation of the stmt to return an expression\n" in
let class_typ =
(match class_typ with
| Sil.Tptr (t, _) -> CTypes_decl.expand_structured_type trans_state.context.tenv t
| t -> t) in
let exp =
(match class_typ with
| Sil.Tvoid -> Sil.exp_minus_one
| _ ->
Printing.log_out "Type is '%s' @." (Sil.typ_to_string class_typ);
( match ObjcInterface_decl.find_field trans_state.context.tenv field_name (Some class_typ) false with
| Some (fn, _, _) -> Sil.Lfield (e, fn, class_typ)
| None -> assert false)) in
{ res_trans_exp_stmt with
exps = [(exp, field_typ)] }
match decl_ref.Clang_ast_t.dr_kind with
| `Field | `ObjCIvar ->
let exp = match class_typ with
| Sil.Tvoid -> Sil.exp_minus_one
| _ ->
Printing.log_out "Type is '%s' @." (Sil.typ_to_string class_typ);
(match ObjcInterface_decl.find_field trans_state.context.tenv field_name (Some class_typ) false with
| Some (fn, _, _) -> Sil.Lfield (obj_sil, fn, class_typ)
| None -> assert false) in
{ result_trans_exp_stmt with
exps = [(exp, field_typ)] }
| `CXXMethod ->
(* consider using context.CContext.is_callee_expression to deal with pointers to methods? *)
let raw_type = field_qt.Clang_ast_t.qt_raw in
let class_name = match class_typ with Sil.Tptr (t, _) | t -> CTypes.classname_of_type t in
let pname = mk_procname_from_cpp_method class_name field_name raw_type in
let method_exp = (Sil.Const (Sil.Cfun pname), field_typ) in
Cfg.set_procname_priority trans_state.context.cfg pname;
{ result_trans_exp_stmt with exps = [method_exp; (obj_sil, class_typ)] }
| _ -> assert false
and objCIvarRefExpr_trans trans_state stmt_info expr_info stmt_list obj_c_ivar_ref_expr_info =
let decl_ref = obj_c_ivar_ref_expr_info.Clang_ast_t.ovrei_decl_ref in
@ -1702,6 +1779,9 @@ struct
| None ->
callExpr_trans trans_state stmt_info stmt_list ei)
| CXXMemberCallExpr(stmt_info, stmt_list, ei) ->
cxxMemberCallExpr_trans trans_state stmt_info stmt_list ei
| ObjCMessageExpr(stmt_info, stmt_list, expr_info, obj_c_message_expr_info) ->
if is_block_enumerate_function obj_c_message_expr_info then
block_enumeration_trans trans_state stmt_info stmt_list expr_info

@ -678,13 +678,15 @@ let is_dispatch_function stmt_list =
| _ -> None))
| _ -> None
let assign_default_params params_stmt callee_pname_opt =
let assign_default_params params_stmt callee_pname_opt ~is_cxx_method =
match callee_pname_opt with
| None -> params_stmt
| Some callee_pname ->
try
let callee_ms = CMethod_signature.find callee_pname in
let args = CMethod_signature.ms_get_args callee_ms in
let args = if is_cxx_method then match args with _::tl -> tl | _ -> assert false
else args in
let params_args = list_combine params_stmt args in
let replace_default_arg param =
match param with

@ -203,6 +203,7 @@ val is_logical_negation_of_int : Sil.tenv -> Clang_ast_t.expr_info -> Clang_ast_
val is_dispatch_function : Clang_ast_t.stmt list -> int option
val assign_default_params : Clang_ast_t.stmt list -> Procname.t option -> Clang_ast_t.stmt list
val assign_default_params : Clang_ast_t.stmt list -> Procname.t option ->
is_cxx_method:bool -> Clang_ast_t.stmt list
val is_block_enumerate_function : Clang_ast_t.obj_c_message_expr_info -> bool

@ -16,6 +16,8 @@ struct A {
// inline definition
int def_in() { int c = 10; return c+1;}
// default parameters
int fun_default(int a, int b = 10, int c = 20) {return a+b+c;}
//static function
//static int get_fun() {return 1;}
};
@ -41,15 +43,27 @@ int A::add(const A& other) {
//return member1;
}
void test() {
// constructing objects
//A a;
//a.fun(1,2);
void call_method() {
// constructing objects
//A a;
//a.fun(1,2);
A *a_ptr;
// calling methods
// a_ptr->fun(10,20);
A *a_ptr;
// calling methods
a_ptr->fun(10,20);
a_ptr->fun_default(1,2,3);
}
void call_method_with_default_parameters() {
A *a_ptr;
a_ptr->fun_default(1,2);
a_ptr->fun_default(1);
}
//A::get_fun();
//a.get_fun();
/*
void call_static_method {
A *a_ptr;
A::get_fun();
a_ptr->get_fun();
}
*/

@ -1,51 +1,85 @@
digraph iCFG {
20 [label="20: Exit test \n " color=yellow style=filled]
29 [label="29: Call _fun_A_fun_default \n n$16=*&a_ptr:struct A * [line 59]\n n$17=_fun_A_fun_default(n$16:struct A ,1:int ,2:int ,20:int ) [line 59]\n REMOVE_TEMPS(n$16,n$17); [line 59]\n " shape="box"]
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]
29 -> 28 ;
28 [label="28: Call _fun_A_fun_default \n n$14=*&a_ptr:struct A * [line 60]\n n$15=_fun_A_fun_default(n$14:struct A ,1:int ,10:int ,20:int ) [line 60]\n REMOVE_TEMPS(n$14,n$15); [line 60]\n NULLIFY(&a_ptr,false); [line 60]\n APPLY_ABSTRACTION; [line 60]\n " shape="box"]
19 -> 20 ;
18 [label="18: Exit A_add \n " color=yellow style=filled]
28 -> 27 ;
27 [label="27: Exit call_method_with_default_parameters \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]
26 [label="26: Start call_method_with_default_parameters\nFormals: \nLocals: a_ptr:struct A * \n DECLARE_LOCALS(&return,&a_ptr); [line 57]\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"]
26 -> 29 ;
25 [label="25: Call _fun_A_fun \n n$12=*&a_ptr:struct A * [line 53]\n n$13=_fun_A_fun(n$12:struct A ,10:int ,20:int ) [line 53]\n REMOVE_TEMPS(n$12,n$13); [line 53]\n " shape="box"]
25 -> 24 ;
24 [label="24: Call _fun_A_fun_default \n n$10=*&a_ptr:struct A * [line 54]\n n$11=_fun_A_fun_default(n$10:struct A ,1:int ,2:int ,3:int ) [line 54]\n REMOVE_TEMPS(n$10,n$11); [line 54]\n NULLIFY(&a_ptr,false); [line 54]\n APPLY_ABSTRACTION; [line 54]\n " shape="box"]
24 -> 23 ;
23 [label="23: Exit call_method \n " color=yellow style=filled]
22 [label="22: Start call_method\nFormals: \nLocals: a_ptr:struct A * \n DECLARE_LOCALS(&return,&a_ptr); [line 46]\n " color=yellow style=filled]
22 -> 25 ;
21 [label="21: Exit A_add \n " color=yellow style=filled]
20 [label="20: Start A_add\nFormals: this:struct A other:struct A &\nLocals: \n DECLARE_LOCALS(&return); [line 41]\n NULLIFY(&this,false); [line 41]\n NULLIFY(&other,false); [line 41]\n " color=yellow style=filled]
20 -> 21 ;
19 [label="19: Return Stmt \n n$8=*&a:int [line 38]\n n$9=*&b:int [line 38]\n *&return:int =(n$8 + n$9) [line 38]\n REMOVE_TEMPS(n$8,n$9); [line 38]\n NULLIFY(&a,false); [line 38]\n NULLIFY(&b,false); [line 38]\n APPLY_ABSTRACTION; [line 38]\n " shape="box"]
19 -> 18 ;
18 [label="18: Exit A::AIn_fun \n " color=yellow style=filled]
17 [label="17: Start A::AIn_fun\nFormals: this:struct A::AIn a:int b:int \nLocals: \n DECLARE_LOCALS(&return); [line 37]\n NULLIFY(&this,false); [line 37]\n " color=yellow style=filled]
17 -> 19 ;
16 [label="16: DeclStmt \n n$6=*&a:int [line 31]\n n$7=*&b:int [line 31]\n *&c:int =((n$6 + n$7) + 1) [line 31]\n REMOVE_TEMPS(n$6,n$7); [line 31]\n NULLIFY(&a,false); [line 31]\n NULLIFY(&b,false); [line 31]\n " shape="box"]
16 -> 15 ;
15 [label="15: Exit A::AIn_fun \n " color=yellow style=filled]
15 [label="15: Return Stmt \n n$4=*&c:int [line 34]\n n$5=*&c:int [line 34]\n *&return:int =(n$4 * n$5) [line 34]\n REMOVE_TEMPS(n$4,n$5); [line 34]\n NULLIFY(&c,false); [line 34]\n APPLY_ABSTRACTION; [line 34]\n " shape="box"]
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]
15 -> 14 ;
14 [label="14: Exit A_fun \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 [label="13: Start A_fun\nFormals: this:struct A a:int b:int \nLocals: c:int \n DECLARE_LOCALS(&return,&c); [line 30]\n NULLIFY(&this,false); [line 30]\n NULLIFY(&c,false); [line 30]\n " color=yellow style=filled]
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"]
13 -> 16 ;
12 [label="12: Exit A_fun \n " color=yellow style=filled]
12 -> 11 ;
11 [label="11: Exit A_fun \n " color=yellow style=filled]
11 [label="11: Start A_fun\nFormals: this:struct A a:int b:int c:int \nLocals: \n DECLARE_LOCALS(&return); [line 25]\n NULLIFY(&this,false); [line 25]\n NULLIFY(&a,false); [line 25]\n NULLIFY(&b,false); [line 25]\n NULLIFY(&c,false); [line 25]\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]
11 -> 12 ;
10 [label="10: Return Stmt \n n$1=*&a:int [line 20]\n n$2=*&b:int [line 20]\n n$3=*&c:int [line 20]\n *&return:int =((n$1 + n$2) + n$3) [line 20]\n REMOVE_TEMPS(n$1,n$2,n$3); [line 20]\n NULLIFY(&a,false); [line 20]\n NULLIFY(&b,false); [line 20]\n NULLIFY(&c,false); [line 20]\n APPLY_ABSTRACTION; [line 20]\n " shape="box"]
10 -> 13 ;
9 [label="9: Exit A_fun \n " color=yellow style=filled]
10 -> 9 ;
9 [label="9: Exit A_fun_default \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 [label="8: Start A_fun_default\nFormals: this:struct A a:int b:int c:int \nLocals: \n DECLARE_LOCALS(&return); [line 20]\n NULLIFY(&this,false); [line 20]\n " color=yellow style=filled]
8 -> 9 ;
8 -> 10 ;
7 [label="7: DeclStmt \n *&c:int =10 [line 17]\n " shape="box"]

Loading…
Cancel
Save