Create generic way of generating extra instructions

Summary: @​public
Refactor exising code that handles __nonnull annotations.
Create extendable way to add extra stuff to be translated before
rest of statements get translated.
This will make handling of constructor initializer list simpler

Reviewed By: @dulmarod

Differential Revision: D2521659

fb-gh-sync-id: ba613e7
master
Andrzej Kotulski 9 years ago committed by facebook-github-bot-1
parent f63582893f
commit aa1951cad4

@ -37,21 +37,9 @@ struct
let model_exists procname = let model_exists procname =
Specs.summary_exists_in_models procname && not !CFrontend_config.models_mode Specs.summary_exists_in_models procname && not !CFrontend_config.models_mode
let rec add_assume_not_null_calls param_decls attributes =
match param_decls with
| [] -> []
| decl:: rest ->
let rest_assume_calls = add_assume_not_null_calls rest attributes in
(match decl with
| Clang_ast_t.ParmVarDecl (decl_info, name, tp, var_decl_info)
when CFrontend_utils.Ast_utils.is_type_nonnull tp attributes ->
let assume_call = Ast_expressions.create_assume_not_null_call decl_info name tp in
assume_call:: rest_assume_calls
| _ -> rest_assume_calls)
(* Translates the method/function's body into nodes of the cfg. *) (* Translates the method/function's body into nodes of the cfg. *)
let add_method tenv cg cfg class_decl_opt procname namespace instrs is_objc_method is_instance let add_method tenv cg cfg class_decl_opt procname namespace instrs is_objc_method is_instance
captured_vars is_anonym_block param_decls attributes = captured_vars is_anonym_block extra_instrs =
Printing.log_out Printing.log_out
"\n\n>>---------- ADDING METHOD: '%s' ---------<<\n@." (Procname.to_string procname); "\n\n>>---------- ADDING METHOD: '%s' ---------<<\n@." (Procname.to_string procname);
try try
@ -70,9 +58,7 @@ struct
Printing.log_out Printing.log_out
"\n\n>>---------- Start translating body of function: '%s' ---------<<\n@." "\n\n>>---------- Start translating body of function: '%s' ---------<<\n@."
(Procname.to_string procname); (Procname.to_string procname);
let nonnull_assume_calls = add_assume_not_null_calls param_decls in let meth_body_nodes = T.instructions_trans context instrs extra_instrs exit_node in
let instrs' = instrs@nonnull_assume_calls attributes in
let meth_body_nodes = T.instructions_trans context instrs' exit_node in
if (not is_anonym_block) then CContext.LocalVars.reset_block (); if (not is_anonym_block) then CContext.LocalVars.reset_block ();
Cfg.Node.set_succs_exn start_node meth_body_nodes []; Cfg.Node.set_succs_exn start_node meth_body_nodes [];
Cg.add_node (CContext.get_cg context) (Cfg.Procdesc.get_proc_name procdesc)) Cg.add_node (CContext.get_cg context) (Cfg.Procdesc.get_proc_name procdesc))
@ -99,7 +85,7 @@ struct
| None -> false, [], CContext.ContextNoCls in | None -> false, [], CContext.ContextNoCls in
let class_name = let class_name =
if curr_class = CContext.ContextNoCls then None else Some (CContext.get_curr_class_name curr_class) in if curr_class = CContext.ContextNoCls then None else Some (CContext.get_curr_class_name curr_class) in
let ms, body_opt, param_decls = let ms, body_opt, extra_instrs =
CMethod_trans.method_signature_of_decl class_name func_decl block_data_opt in CMethod_trans.method_signature_of_decl class_name func_decl block_data_opt in
match method_body_to_translate ms body_opt with match method_body_to_translate ms body_opt with
| Some body -> (* Only in the case the function declaration has a defined body we create a procdesc *) | Some body -> (* Only in the case the function declaration has a defined body we create a procdesc *)
@ -107,23 +93,21 @@ struct
if CMethod_trans.create_local_procdesc cfg tenv ms [body] captured_vars false then if CMethod_trans.create_local_procdesc cfg tenv ms [body] captured_vars false then
let is_instance = CMethod_signature.ms_is_instance ms in let is_instance = CMethod_signature.ms_is_instance ms in
let is_objc_method = is_anonym_block in let is_objc_method = is_anonym_block in
let attributes = CMethod_signature.ms_get_attributes ms in
add_method tenv cg cfg curr_class procname namespace [body] is_objc_method is_instance add_method tenv cg cfg curr_class procname namespace [body] is_objc_method is_instance
captured_vars is_anonym_block param_decls attributes captured_vars is_anonym_block extra_instrs
| None -> () | None -> ()
let process_method_decl tenv cg cfg namespace curr_class meth_decl ~is_objc = let process_method_decl tenv cg cfg namespace curr_class meth_decl ~is_objc =
let class_name = Some (CContext.get_curr_class_name curr_class) in let class_name = Some (CContext.get_curr_class_name curr_class) in
let ms, body_opt, param_decls = let ms, body_opt, extra_instrs =
CMethod_trans.method_signature_of_decl class_name meth_decl None in CMethod_trans.method_signature_of_decl class_name meth_decl None in
match method_body_to_translate ms body_opt with match method_body_to_translate ms body_opt with
| Some body -> | Some body ->
let is_instance = CMethod_signature.ms_is_instance ms in let is_instance = CMethod_signature.ms_is_instance ms in
let attributes = CMethod_signature.ms_get_attributes ms in
let procname = CMethod_signature.ms_get_name ms in let procname = CMethod_signature.ms_get_name ms in
if CMethod_trans.create_local_procdesc cfg tenv ms [body] [] is_instance then if CMethod_trans.create_local_procdesc cfg tenv ms [body] [] is_instance then
add_method tenv cg cfg curr_class procname namespace [body] is_objc is_instance [] false add_method tenv cg cfg curr_class procname namespace [body] is_objc is_instance [] false
param_decls attributes extra_instrs
| None -> () | None -> ()
let rec process_one_method_decl tenv cg cfg curr_class namespace dec = let rec process_one_method_decl tenv cg cfg curr_class namespace dec =

@ -95,6 +95,16 @@ let build_method_signature decl_info procname function_method_decl_info is_anony
CMethod_signature.make_ms procname parameters tp attributes source_range is_instance_method CMethod_signature.make_ms procname parameters tp attributes source_range is_instance_method
is_generated lang is_generated lang
let get_assume_not_null_calls ms param_decls =
let attributes = CMethod_signature.ms_get_attributes ms in
let do_one_param decl = match decl with
| Clang_ast_t.ParmVarDecl (decl_info, name, tp, var_decl_info)
when CFrontend_utils.Ast_utils.is_type_nonnull tp attributes ->
let assume_call = Ast_expressions.create_assume_not_null_call decl_info name tp in
[(`ClangStmt assume_call)]
| _ -> [] in
list_flatten (list_map do_one_param param_decls)
let method_signature_of_decl class_name_opt meth_decl block_data_opt = let method_signature_of_decl class_name_opt meth_decl block_data_opt =
let open Clang_ast_t in let open Clang_ast_t in
match meth_decl, block_data_opt, class_name_opt with match meth_decl, block_data_opt, class_name_opt with
@ -105,13 +115,15 @@ let method_signature_of_decl class_name_opt meth_decl block_data_opt =
let function_info = Some (decl_info, fdi) in let function_info = Some (decl_info, fdi) in
let procname = General_utils.mk_procname_from_function name function_info tp language in let procname = General_utils.mk_procname_from_function name function_info tp language in
let ms = build_method_signature decl_info procname func_decl false false in let ms = build_method_signature decl_info procname func_decl false false in
ms, fdi.Clang_ast_t.fdi_body, fdi.Clang_ast_t.fdi_parameters let extra_instrs = get_assume_not_null_calls ms fdi.Clang_ast_t.fdi_parameters in
ms, fdi.Clang_ast_t.fdi_body, extra_instrs
| CXXMethodDecl (decl_info, name_info, tp, fdi, _), _, Some class_name -> | CXXMethodDecl (decl_info, name_info, tp, fdi, _), _, Some class_name ->
let method_name = name_info.Clang_ast_t.ni_name in let method_name = name_info.Clang_ast_t.ni_name in
let procname = General_utils.mk_procname_from_cpp_method class_name method_name tp in let procname = General_utils.mk_procname_from_cpp_method class_name method_name tp in
let method_decl = Cpp_Meth_decl_info (fdi, class_name, tp) in let method_decl = Cpp_Meth_decl_info (fdi, class_name, tp) in
let ms = build_method_signature decl_info procname method_decl false false in let ms = build_method_signature decl_info procname method_decl false false in
ms, fdi.Clang_ast_t.fdi_body, fdi.Clang_ast_t.fdi_parameters let extra_instrs = get_assume_not_null_calls ms fdi.Clang_ast_t.fdi_parameters in
ms, fdi.Clang_ast_t.fdi_body, extra_instrs
| ObjCMethodDecl (decl_info, name_info, mdi), _, Some class_name -> | ObjCMethodDecl (decl_info, name_info, mdi), _, Some class_name ->
let method_name = name_info.ni_name in let method_name = name_info.ni_name in
let is_instance = mdi.omdi_is_instance_method in let is_instance = mdi.omdi_is_instance_method in
@ -120,12 +132,14 @@ let method_signature_of_decl class_name_opt meth_decl block_data_opt =
let method_decl = ObjC_Meth_decl_info (mdi, class_name) in let method_decl = ObjC_Meth_decl_info (mdi, class_name) in
let is_generated = Ast_utils.is_generated name_info in let is_generated = Ast_utils.is_generated name_info in
let ms = build_method_signature decl_info procname method_decl false is_generated in let ms = build_method_signature decl_info procname method_decl false is_generated in
ms, mdi.omdi_body, mdi.omdi_parameters let extra_instrs = get_assume_not_null_calls ms mdi.omdi_parameters in
ms, mdi.omdi_body, extra_instrs
| BlockDecl (decl_info, decl_list, decl_context_info, bdi), | BlockDecl (decl_info, decl_list, decl_context_info, bdi),
Some (context, tp, procname, _), _ -> Some (context, tp, procname, _), _ ->
let func_decl = Block_decl_info (bdi, tp, context) in let func_decl = Block_decl_info (bdi, tp, context) in
let ms = build_method_signature decl_info procname func_decl true false in let ms = build_method_signature decl_info procname func_decl true false in
ms, bdi.bdi_body, bdi.bdi_parameters let extra_instrs = get_assume_not_null_calls ms bdi.bdi_parameters in
ms, bdi.bdi_body, extra_instrs
| _ -> raise Invalid_declaration | _ -> raise Invalid_declaration
let method_signature_of_pointer class_name_opt pointer = let method_signature_of_pointer class_name_opt pointer =

@ -33,7 +33,7 @@ val get_class_selector_instance : CContext.t -> Clang_ast_t.obj_c_message_expr_i
val should_create_procdesc : Cfg.cfg -> Procname.t -> bool -> bool -> bool val should_create_procdesc : Cfg.cfg -> Procname.t -> bool -> bool -> bool
val method_signature_of_decl : string option -> Clang_ast_t.decl -> CModule_type.block_data option -> val method_signature_of_decl : string option -> Clang_ast_t.decl -> CModule_type.block_data option ->
CMethod_signature.method_signature * Clang_ast_t.stmt option * Clang_ast_t.decl list CMethod_signature.method_signature * Clang_ast_t.stmt option * CModule_type.instr_type list
val method_signature_of_pointer : string option -> Clang_ast_t.pointer -> CMethod_signature.method_signature option val method_signature_of_pointer : string option -> Clang_ast_t.pointer -> CMethod_signature.method_signature option

@ -9,9 +9,12 @@
type block_data = CContext.t * Clang_ast_t.type_ptr * Procname.t * (Mangled.t * Sil.typ * bool) list type block_data = CContext.t * Clang_ast_t.type_ptr * Procname.t * (Mangled.t * Sil.typ * bool) list
type instr_type = [ `ClangStmt of Clang_ast_t.stmt ]
module type CTranslation = module type CTranslation =
sig sig
val instructions_trans : CContext.t -> Clang_ast_t.stmt list -> Cfg.Node.t -> Cfg.Node.t list val instructions_trans : CContext.t -> Clang_ast_t.stmt list -> instr_type list ->
Cfg.Node.t -> Cfg.Node.t list
end end
module type CMethod_declaration = module type CMethod_declaration =

@ -19,9 +19,11 @@ module L = Logging
module type CTrans = sig module type CTrans = sig
(** Translates instructions: (statements and expressions) from the ast into sil *) (** Translates instructions: (statements and expressions) from the ast into sil *)
(** It receives the context, a list of statements and the exit node and it returns a list of cfg nodes *) (** It receives the context, a list of statements from clang ast, list of custom statments *)
(** to be added before clang statements and the exit node and it returns a list of cfg nodes *)
(** that reporesent the translation of the stmts into sil. *) (** that reporesent the translation of the stmts into sil. *)
val instructions_trans : CContext.t -> Clang_ast_t.stmt list -> Cfg.Node.t -> Cfg.Node.t list val instructions_trans : CContext.t -> Clang_ast_t.stmt list -> CModule_type.instr_type list ->
Cfg.Node.t -> Cfg.Node.t list
(** It receives the context and a statement and a warning string and returns the translated sil expression *) (** It receives the context and a statement and a warning string and returns the translated sil expression *)
(** that represents the translation of the stmts into sil. *) (** that represents the translation of the stmts into sil. *)
@ -2019,32 +2021,52 @@ struct
(Ast_utils.string_of_stmt s); (Ast_utils.string_of_stmt s);
assert false) assert false)
(* Given a translation state, this function traslates a list of clang statements. *) (** Given a translation state and list of translation functions it executes translation *)
and instructions trans_state clang_stmt_list = and exec_trans_instrs trans_state trans_stmt_fun_list =
(* Printing.log_err "\n instruction list %i" (List.length clang_stmt_list); *) match trans_stmt_fun_list with
match clang_stmt_list with
| [] -> { empty_res_trans with root_nodes = trans_state.succ_nodes } | [] -> { empty_res_trans with root_nodes = trans_state.succ_nodes }
| s :: clang_stmt_list' -> | trans_stmt_fun :: trans_stmt_fun_list' ->
let res_trans_s = instruction trans_state s in let res_trans_s = trans_stmt_fun trans_state in
let trans_state' = let trans_state' =
if res_trans_s.root_nodes <> [] if res_trans_s.root_nodes <> []
then { trans_state with succ_nodes = res_trans_s.root_nodes } then { trans_state with succ_nodes = res_trans_s.root_nodes }
else trans_state in else trans_state in
let res_trans_tail = instructions trans_state' clang_stmt_list' in let res_trans_tail = exec_trans_instrs trans_state' trans_stmt_fun_list' in
{ root_nodes = res_trans_tail.root_nodes; { root_nodes = res_trans_tail.root_nodes;
leaf_nodes =[]; leaf_nodes = [];
ids = res_trans_s.ids @ res_trans_tail.ids; ids = res_trans_s.ids @ res_trans_tail.ids;
instrs = res_trans_s.instrs @ res_trans_tail.instrs; instrs = res_trans_s.instrs @ res_trans_tail.instrs;
exps = res_trans_s.exps @ res_trans_tail.exps } exps = res_trans_s.exps @ res_trans_tail.exps }
and get_clang_stmt_trans stmt_list =
let instruction' = fun stmt -> fun trans_state -> instruction trans_state stmt in
list_map instruction' stmt_list
and get_custom_stmt_trans custom_stmts =
let do_one_stmt stmt = match stmt with
| `ClangStmt stmt -> get_clang_stmt_trans [stmt] in
list_flatten (list_map do_one_stmt custom_stmts)
(** Given a translation state, this function translates a list of clang statements. *)
and instructions trans_state stmt_list =
exec_trans_instrs trans_state (get_clang_stmt_trans stmt_list)
let expression_trans context stmt warning = let expression_trans context stmt warning =
let trans_state = { context = context; succ_nodes =[]; continuation = None; parent_line_number = -1; priority = Free } in let trans_state = { context = context; succ_nodes =[]; continuation = None; parent_line_number = -1; priority = Free } in
let res_trans_stmt = instruction trans_state stmt in let res_trans_stmt = instruction trans_state stmt in
fst (CTrans_utils.extract_exp_from_list res_trans_stmt.exps warning) fst (CTrans_utils.extract_exp_from_list res_trans_stmt.exps warning)
let instructions_trans context clang_stmt_list exit_node = let instructions_trans context clang_stmt_list extra_instrs exit_node =
let trans_state = { context = context; succ_nodes =[exit_node]; continuation = None; parent_line_number = -1; priority = Free } in let trans_state = {
let res_trans = instructions trans_state clang_stmt_list in context = context;
succ_nodes = [exit_node];
continuation = None;
parent_line_number = -1;
priority = Free;
} in
let clang_ast_trans = get_clang_stmt_trans clang_stmt_list in
let extra_stmt_trans = get_custom_stmt_trans extra_instrs in
let res_trans = exec_trans_instrs trans_state (clang_ast_trans @ extra_stmt_trans) in
res_trans.root_nodes res_trans.root_nodes
end end

@ -10,9 +10,11 @@
module type CTrans = sig module type CTrans = sig
(** Translates instructions: (statements and expressions) from the ast into sil *) (** Translates instructions: (statements and expressions) from the ast into sil *)
(** It receives the context, a list of statements and the exit node and it returns a list of cfg nodes *) (** It receives the context, a list of statements from clang ast, list of custom statments *)
(** to be added before clang statements and the exit node and it returns a list of cfg nodes *)
(** that reporesent the translation of the stmts into sil. *) (** that reporesent the translation of the stmts into sil. *)
val instructions_trans : CContext.t -> Clang_ast_t.stmt list -> Cfg.Node.t -> Cfg.Node.t list val instructions_trans : CContext.t -> Clang_ast_t.stmt list -> CModule_type.instr_type list ->
Cfg.Node.t -> Cfg.Node.t list
(** It receives the context and a statement and a warning string and returns the translated sil expression *) (** It receives the context and a statement and a warning string and returns the translated sil expression *)
(** that represents the translation of the stmts into sil. *) (** that represents the translation of the stmts into sil. *)

Loading…
Cancel
Save