Refactor PriorityNode.compute_results_to_parent to call collect_res_trans directly

Summary: public
Refactor compute_results_to_parent to call collect_res_trans directly there.
So the job of PriorityNode.compute_results_to_parent is the following:
Given list of [res_trans_1; res_trans_2; ... ; res_trans_n],
1. Connect nodes linearly (ie. res_trans_1 with res_trans_2, res_trans_2 with res_trans_3) etc.
   If res_trans_k has no nodes, try connecting res_trans_k-1 with res_trans_k+1 (this is what collect_res_trans always did)
2. Collect all ids, instrs and exps into one res_trans
3. Create node if needed and put there same ids and instrs as usual.
4. Connect new node with existing ones
4. Return new node structrue with exps = []

This will make function usable in more places so we don't have to create nodes over and over again

Reviewed By: ddino

Differential Revision: D2696351

fb-gh-sync-id: 9f4a9b4
master
Andrzej Kotulski 9 years ago committed by facebook-github-bot-7
parent 35bb8a9a26
commit 60b4f6e766

@ -171,6 +171,9 @@ struct
| e :: es' -> e :: f es' in
(f exps, !insts, !ids)
let collect_exprs res_trans_list =
IList.flatten (IList.map (fun res_trans -> res_trans.exps) res_trans_list)
(* If e is a block and the calling node has the priority then *)
(* we need to release the priority to allow*)
(* creation of nodes inside the block.*)
@ -698,11 +701,10 @@ struct
let params_stmt = if should_translate_args then
CTrans_utils.assign_default_params params_stmt fun_exp_stmt
else [] in
let res_trans_par =
let result_trans_subexprs =
let instruction' = exec_with_self_exception (exec_with_lvalue_as_reference instruction) in
let l = IList.map (instruction' trans_state_param) params_stmt in
let rt = collect_res_trans (res_trans_callee :: l) in
{ rt with exps = IList.tl rt.exps } in
let res_trans_p = IList.map (instruction' trans_state_param) params_stmt in
res_trans_callee :: res_trans_p in
let sil_fe, is_cf_retain_release = CTrans_models.builtin_predefined_model fun_exp_stmt sil_fe in
if CTrans_models.is_assert_log sil_fe then
if Config.report_assertion_failure then
@ -710,11 +712,13 @@ struct
else
CTrans_utils.trans_assume_false sil_loc context trans_state.succ_nodes
else
let act_params = if IList.length res_trans_par.exps = IList.length params_stmt then
res_trans_par.exps
let act_params =
let params = IList.tl (collect_exprs result_trans_subexprs) in
if IList.length params = IList.length params_stmt then
params
else (Printing.log_err
"WARNING: stmt_list and res_trans_par.exps must have same size. NEED TO BE FIXED\n\n";
fix_param_exps_mismatch params_stmt res_trans_par.exps) in
fix_param_exps_mismatch params_stmt params) in
let act_params = if is_cf_retain_release then
(Sil.Const (Sil.Cint Sil.Int.one), Sil.Tint Sil.IBool) :: act_params
else act_params in
@ -730,12 +734,12 @@ struct
let call_flags = { Sil.cf_virtual = false; Sil.cf_noreturn = false; Sil.cf_is_objc_block = is_call_to_block; } in
let call_instr = Sil.Call(ret_id, sil_fe, act_params, sil_loc, call_flags) in
ret_id, call_instr in
let ids = res_trans_par.ids@ret_id in
let instrs = res_trans_par.instrs @ [call_instr] in
let res_trans_call = { empty_res_trans with ids = ret_id; instrs = [call_instr] } in
let nname = "Call "^(Sil.exp_to_string sil_fe) in
let res_trans_tmp = { res_trans_par with ids = ids; instrs = instrs; exps =[]} in
let all_res_trans = result_trans_subexprs @ [res_trans_call] in
let res_trans_to_parent =
PriorityNode.compute_results_to_parent trans_state_pri sil_loc nname si res_trans_tmp in
PriorityNode.compute_results_to_parent trans_state_pri sil_loc nname si all_res_trans in
(match callee_pname_opt with
| Some callee_pname ->
let open CContext in
@ -769,14 +773,12 @@ struct
(* 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 instruction' = exec_with_lvalue_as_reference instruction in
let l = IList.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 = IList.tl rt.exps } in
let actual_params = result_trans_params.exps in
let result_trans_subexprs =
let instruction' = exec_with_self_exception (exec_with_lvalue_as_reference instruction) in
let res_trans_p = IList.map (instruction' trans_state_param) params_stmt in
result_trans_callee :: res_trans_p in
(* first expr is method address, rest are params including 'this' parameter *)
let actual_params = IList.tl (collect_exprs result_trans_subexprs) in
let ret_id = if (Sil.typ_equal function_type Sil.Tvoid) then []
else [Ident.create_fresh Ident.knormal] in
let call_flags = {
@ -785,12 +787,11 @@ struct
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 res_trans_call = { empty_res_trans with ids = ret_id; instrs = [call_instr] } in
let nname = "Call " ^ (Sil.exp_to_string sil_method) in
let all_res_trans = result_trans_subexprs @ [res_trans_call] in
let result_trans_to_parent =
PriorityNode.compute_results_to_parent trans_state_pri sil_loc nname si res_trans_tmp in
PriorityNode.compute_results_to_parent trans_state_pri sil_loc nname si all_res_trans in
Cg.add_edge context.CContext.cg procname callee_pname;
match ret_id with
| [] -> { result_trans_to_parent with exps = [] }
@ -871,8 +872,8 @@ struct
let instruction' =
exec_with_self_exception (exec_with_lvalue_as_reference instruction) in
let l = IList.map (instruction' trans_state_param) rest in
obj_c_message_expr_info, collect_res_trans (fst_res_trans :: l)
| [] -> obj_c_message_expr_info, empty_res_trans
obj_c_message_expr_info, fst_res_trans :: l
| [] -> obj_c_message_expr_info, [empty_res_trans]
and objCMessageExpr_trans trans_state si obj_c_message_expr_info stmt_list expr_info =
Printing.log_out " priority node free = '%s'\n@."
@ -886,22 +887,25 @@ struct
let trans_state_pri = PriorityNode.try_claim_priority_node trans_state si in
let trans_state_param =
{ trans_state_pri with parent_line_number = line_number; succ_nodes = [] } in
let obj_c_message_expr_info, res_trans_par =
let obj_c_message_expr_info, res_trans_subexpr_list =
objCMessageExpr_deal_with_static_self trans_state_param stmt_list obj_c_message_expr_info in
let subexpr_exprs = collect_exprs res_trans_subexpr_list in
match objCMessageExpr_trans_special_cases trans_state si obj_c_message_expr_info stmt_list
expr_info method_type trans_state_pri sil_loc res_trans_par.exps with
expr_info method_type trans_state_pri sil_loc subexpr_exprs with
| Some res -> res
| None ->
let procname = Cfg.Procdesc.get_proc_name context.CContext.procdesc in
let callee_name, method_call_type =
get_callee_objc_method context obj_c_message_expr_info res_trans_par.exps in
let res_trans_par = Self.add_self_parameter_for_super_instance context procname sil_loc
obj_c_message_expr_info res_trans_par in
get_callee_objc_method context obj_c_message_expr_info subexpr_exprs in
let res_trans_add_self = Self.add_self_parameter_for_super_instance context procname sil_loc
obj_c_message_expr_info in
let res_trans_subexpr_list = res_trans_add_self :: res_trans_subexpr_list in
let subexpr_exprs = collect_exprs res_trans_subexpr_list in
let is_virtual = method_call_type = CMethod_trans.MCVirtual in
Cg.add_edge context.CContext.cg procname callee_name;
let param_exps, instr_block_param, ids_block_param =
extract_block_from_tuple procname res_trans_par.exps sil_loc in
extract_block_from_tuple procname subexpr_exprs sil_loc in
let ret_id =
if Sil.typ_equal method_type Sil.Tvoid then []
@ -910,19 +914,17 @@ struct
Sil.cf_virtual = is_virtual;
Sil.cf_noreturn = false;
Sil.cf_is_objc_block = false; } in
let stmt_call =
Sil.Call (ret_id, (Sil.Const (Sil.Cfun callee_name)), param_exps, sil_loc, call_flags) in
let selector = obj_c_message_expr_info.Clang_ast_t.omei_selector in
let nname = "Message Call: "^selector in
let res_trans_tmp = {
res_trans_par with
ids = res_trans_par.ids @ ids_block_param @ ret_id;
instrs = res_trans_par.instrs @ instr_block_param @ [stmt_call];
exps = []
let res_trans_call = { empty_res_trans with
ids = ids_block_param @ ret_id;
instrs = instr_block_param @ [stmt_call];
} in
let res_trans_to_parent = (
PriorityNode.compute_results_to_parent trans_state_pri sil_loc nname si res_trans_tmp) in
let all_res_trans = res_trans_subexpr_list @ [res_trans_call] in
let res_trans_to_parent =
PriorityNode.compute_results_to_parent trans_state_pri sil_loc nname si all_res_trans in
match ret_id with
| [] -> { res_trans_to_parent with exps = [] }
| [ret_id'] -> { res_trans_to_parent with exps = [(Sil.Var ret_id', method_type)] }
@ -1445,33 +1447,21 @@ struct
"\nWARNING: Missing RHS operand in Compount Assign operator. Need Fixing.\n" in
let id_op, exp_op, instr_op = CArithmetic_trans.compound_assignment_binary_operation_instruction
binary_operator_info lhs_e sil_typ sil_e2 sil_loc in
let ids = res_trans_s1.ids@res_trans_s2.ids@id_op in
let instrs = res_trans_s1.instrs@res_trans_s2.instrs@instr_op in
let res_trans_tmp = { res_trans_s2 with ids = ids; instrs = instrs; exps =[]} in
let res_trans_to_parent =
PriorityNode.compute_results_to_parent trans_state_pri sil_loc "ComppoundAssignStmt" stmt_info res_trans_tmp in
let trans_s1_succs =
if res_trans_to_parent.root_nodes <> []
then res_trans_to_parent.root_nodes
else trans_state_pri.succ_nodes in
IList.iter
(fun n -> Cfg.Node.set_succs_exn n trans_s1_succs [])
res_trans_s1.leaf_nodes;
let instrs_to_parent', ids_to_parent', exp_to_parent' =
compute_instr_ids_exp_to_parent stmt_info res_trans_to_parent.instrs res_trans_to_parent.ids
[(exp_op, sil_typ)] lhs_e sil_typ sil_loc trans_state_pri.priority in
let root_nodes =
if res_trans_s1.root_nodes <> []
then res_trans_s1.root_nodes
else res_trans_to_parent.root_nodes in
{ root_nodes = root_nodes;
leaf_nodes = res_trans_to_parent.leaf_nodes;
ids = ids_to_parent';
instrs = instrs_to_parent';
exps = exp_to_parent' }
let extra_deref_instrs, extra_deref_ids, exp_to_parent =
if not (PriorityNode.own_priority_node trans_state_pri.priority stmt_info) &&
(* assignment operator result is lvalue in CPP, rvalue in C, hence the difference *)
not (General_utils.is_cpp_translation !CFrontend_config.language) then
let id = Ident.create_fresh Ident.knormal in
let instr = Sil.Letderef (id, lhs_e, sil_typ, sil_loc) in
[instr], [id], (Sil.Var id, sil_typ)
else [], [], (exp_op, sil_typ) in
let op_res_trans = { empty_res_trans with
ids = id_op @ extra_deref_ids;
instrs = instr_op @ extra_deref_instrs } in
let all_res_trans = [res_trans_s1; res_trans_s2; op_res_trans] in
let res_trans_to_parent = PriorityNode.compute_results_to_parent trans_state_pri
sil_loc "ComppoundAssignStmt" stmt_info all_res_trans in
{ res_trans_to_parent with exps = [exp_to_parent] }
| _ -> assert false) (* Compound assign statement should have two operands*)
and initListExpr_trans trans_state var_res_trans stmt_info expr_info stmts =
@ -1978,10 +1968,10 @@ struct
"WARNING: There should be one expression to delete. \n" in
(* function is void *)
let call_instr = Sil.Call ([], (Sil.Const (Sil.Cfun fname)), [exp], sil_loc, Sil.cf_default) in
let instrs = result_trans_param.instrs @ [call_instr] in
let res_trans_tmp = { result_trans_param with instrs = instrs} in
let res_trans =
PriorityNode.compute_results_to_parent trans_state_pri sil_loc "Call delete" stmt_info res_trans_tmp in
let call_res_trans = { empty_res_trans with instrs = [call_instr] } in
let all_res_trans = [ result_trans_param; call_res_trans] in
let res_trans = PriorityNode.compute_results_to_parent trans_state_pri sil_loc
"Call delete" stmt_info all_res_trans in
{ res_trans with exps = [] }
and materializeTemporaryExpr_trans trans_state stmt_info stmt_list expr_info =

@ -210,20 +210,22 @@ struct
| Busy p when p = stmt_info.Clang_ast_t.si_pointer -> true
| _ -> false
(* Used for function call and method call. It deals with creating or not *)
(* a cfg node depending of owning the priority_node and the nodes, ids, instrs returned *)
(* by the parameters of the call *)
let compute_results_to_parent trans_state loc nd_name stmt_info res_state_param =
let mk_node () =
let ids_node = ids_to_node trans_state.continuation res_state_param.ids in
(* Used by translation functions to handle potenatial cfg nodes. *)
(* It connects nodes returned by translation of stmt children and *)
(* deals with creating or not a cfg node depending of owning the *)
(* priority_node. It returns nodes, ids, instrs that should be passed to parent *)
let compute_results_to_parent trans_state loc nd_name stmt_info res_states_children =
let mk_node res_state =
let ids_node = ids_to_node trans_state.continuation res_state.ids in
let node_kind = Cfg.Node.Stmt_node (nd_name) in
Nodes.create_node node_kind ids_node res_state_param.instrs loc trans_state.context in
Nodes.create_node node_kind ids_node res_state.instrs loc trans_state.context in
(* Invariant: if leaf_nodes is empty then the params have not created a node.*)
let res_state_param = collect_res_trans res_states_children in
match res_state_param.leaf_nodes, own_priority_node trans_state.priority stmt_info with
| _, false -> (* The node is created by the parent. We just pass back nodes/leafs params *)
{ res_state_param with exps = []}
| [], true -> (* We need to create a node and params did not create a node.*)
let node' = mk_node () in
let node' = mk_node res_state_param in
let ids_parent = ids_to_parent trans_state.continuation res_state_param.ids in
Cfg.Node.set_succs_exn node' trans_state.succ_nodes [];
{ root_nodes =[node'];
@ -234,7 +236,7 @@ struct
| _, true ->
(* We need to create a node but params also created some,*)
(* so we need to pass back the nodes/leafs params*)
let node' = mk_node () in
let node' = mk_node res_state_param in
Cfg.Node.set_succs_exn node' trans_state.succ_nodes [];
let ids_parent = ids_to_parent trans_state.continuation res_state_param.ids in
IList.iter (fun n' -> Cfg.Node.set_succs_exn n' [node'] []) res_state_param.leaf_nodes;
@ -296,7 +298,8 @@ let alloc_trans trans_state loc stmt_info function_type is_cf_non_null_alloc =
let (function_type, ret_id, stmt_call, exp) = create_alloc_instrs trans_state.context loc function_type fname in
let res_trans_tmp = { empty_res_trans with ids =[ret_id]; instrs =[stmt_call]} in
let res_trans =
PriorityNode.compute_results_to_parent trans_state loc "Call alloc" stmt_info res_trans_tmp in
let nname = "Call alloc" in
PriorityNode.compute_results_to_parent trans_state loc nname stmt_info [res_trans_tmp] in
{ res_trans with exps =[(exp, function_type)]}
let objc_new_trans trans_state loc stmt_info cls_name function_type =
@ -314,7 +317,8 @@ let objc_new_trans trans_state loc stmt_info cls_name function_type =
let ids = [alloc_ret_id; init_ret_id] in
let res_trans_tmp = { empty_res_trans with ids = ids; instrs = instrs } in
let res_trans =
PriorityNode.compute_results_to_parent trans_state loc "Call objC new" stmt_info res_trans_tmp in
let nname = "Call objC new" in
PriorityNode.compute_results_to_parent trans_state loc nname stmt_info [res_trans_tmp] in
{ res_trans with exps = [(Sil.Var init_ret_id, alloc_ret_type)]}
let new_or_alloc_trans trans_state loc stmt_info type_ptr class_name_opt selector =
@ -335,7 +339,8 @@ let cpp_new_trans trans_state sil_loc stmt_info function_type =
let (function_type, ret_id, stmt_call, exp) = create_alloc_instrs trans_state.context sil_loc function_type fname in
let res_trans_tmp = { empty_res_trans with ids =[ret_id]; instrs =[stmt_call]} in
let res_trans =
PriorityNode.compute_results_to_parent trans_state sil_loc "Call C++ new" stmt_info res_trans_tmp in
let nname = "Call C++ new" in
PriorityNode.compute_results_to_parent trans_state sil_loc nname stmt_info [res_trans_tmp] in
{ res_trans with exps = [(exp, function_type)] }
let create_cast_instrs context exp cast_from_typ cast_to_typ sil_loc =
@ -446,27 +451,6 @@ let define_condition_side_effects context e_cond instrs_cond sil_loc =
[Sil.Letderef (id, Sil.Lvar pvar, typ, sil_loc)]
| _ -> [(e', typ)], instrs_cond
(* Given a list of instuctions, ids, an expression, lhs of an compound *)
(* assignment its type and loc it computes which instructions, ids, and *)
(* expression need to be returned to the AST's parent node. This function *)
(* is used by a compount assignment. The expression e is the result of *)
(* translating the rhs of the assignment *)
let compute_instr_ids_exp_to_parent stmt_info instr ids e lhs typ loc pri =
if PriorityNode.own_priority_node pri stmt_info then(
(* The current AST element has created a node then instr and ids have *)
(* been already included in the node. *)
[], [], e
) else if General_utils.is_cpp_translation !CFrontend_config.language then (
(* assignment operator result is lvalue in CPP, rvalue in C, hence the difference *)
instr, ids, e
) else (
(* The node will be created by the parent. We pass the instr and ids. *)
(* For the expression we need to save the constend of the lhs in a new *)
(* temp so that can be used by the parent node (for example: x=(y=10)) *)
let id = Ident.create_fresh Ident.knormal in
let res_instr = [Sil.Letderef (id, lhs, typ, loc)] in
instr@res_instr, ids @ [id], [(Sil.Var id, typ)])
let fix_param_exps_mismatch params_stmt exps_param =
let diff = IList.length params_stmt - IList.length exps_param in
let args = if diff >0 then Array.make diff dummy_exp
@ -548,7 +532,7 @@ struct
exception SelfClassException of string
let add_self_parameter_for_super_instance context procname loc mei trans_result =
let add_self_parameter_for_super_instance context procname loc mei =
if is_superinstance mei then
let typ, self_expr, id, ins =
let t' = CTypes.add_pointer_to_typ
@ -556,11 +540,11 @@ struct
let e = Sil.Lvar (Sil.mk_pvar (Mangled.from_string CFrontend_config.self) procname) in
let id = Ident.create_fresh Ident.knormal in
t', Sil.Var id, [id], [Sil.Letderef (id, e, t', loc)] in
{ trans_result with
exps = (self_expr, typ):: trans_result.exps;
ids = id@trans_result.ids;
instrs = ins@trans_result.instrs }
else trans_result
{ empty_res_trans with
exps = [(self_expr, typ)];
ids = id;
instrs = ins }
else empty_res_trans
let is_var_self pvar is_objc_method =
let is_self = Mangled.to_string (Sil.pvar_get_name pvar) = CFrontend_config.self in

@ -37,9 +37,6 @@ type trans_result = {
val empty_res_trans: trans_result
(** Collect the results of translating a list of instructions, and link up the nodes created. *)
val collect_res_trans: trans_result list -> trans_result
val is_return_temp: continuation option -> bool
val ids_to_parent: continuation option -> Ident.t list -> Ident.t list
@ -64,11 +61,6 @@ val extract_stmt_from_singleton : Clang_ast_t.stmt list -> string -> Clang_ast_t
val is_null_stmt : Clang_ast_t.stmt -> bool
val compute_instr_ids_exp_to_parent :
Clang_ast_t.stmt_info -> Sil.instr list -> Ident.t list -> (Sil.exp * Sil.typ) list ->
Sil.exp -> Sil.typ -> Location.t -> priority_node ->
Sil.instr list * Ident.t list * (Sil.exp * Sil.typ) list
val is_enumeration_constant : Clang_ast_t.stmt -> bool
val is_member_exp : Clang_ast_t.stmt -> bool
@ -162,11 +154,12 @@ sig
val own_priority_node : t -> Clang_ast_t.stmt_info -> bool
(* Used for function call and method call. It deals with creating or not *)
(* a cfg node depending of owning the priority_node and the nodes returned *)
(* by the parameters of the call *)
val compute_results_to_parent :
trans_state -> Location.t -> string -> Clang_ast_t.stmt_info -> trans_result -> trans_result
(* Used by translation functions to handle potenatial cfg nodes. *)
(* It connects nodes returned by translation of stmt children and *)
(* deals with creating or not a cfg node depending of owning the *)
(* priority_node. It returns nodes, ids, instrs that should be passed to parent *)
val compute_results_to_parent : trans_state -> Location.t -> string -> Clang_ast_t.stmt_info ->
trans_result list -> trans_result
end
@ -206,7 +199,7 @@ sig
val add_self_parameter_for_super_instance :
CContext.t -> Procname.t -> Location.t -> Clang_ast_t.obj_c_message_expr_info ->
trans_result -> trans_result
trans_result
val is_var_self : Sil.pvar -> bool -> bool
end

Loading…
Cancel
Save