diff --git a/infer/src/clang/cMethod_decl.ml b/infer/src/clang/cMethod_decl.ml index 337194e4a..7fb2a77e7 100644 --- a/infer/src/clang/cMethod_decl.ml +++ b/infer/src/clang/cMethod_decl.ml @@ -37,21 +37,9 @@ struct let model_exists procname = 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. *) 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 "\n\n>>---------- ADDING METHOD: '%s' ---------<<\n@." (Procname.to_string procname); try @@ -70,9 +58,7 @@ struct Printing.log_out "\n\n>>---------- Start translating body of function: '%s' ---------<<\n@." (Procname.to_string procname); - let nonnull_assume_calls = add_assume_not_null_calls param_decls in - let instrs' = instrs@nonnull_assume_calls attributes in - let meth_body_nodes = T.instructions_trans context instrs' exit_node in + let meth_body_nodes = T.instructions_trans context instrs extra_instrs exit_node in if (not is_anonym_block) then CContext.LocalVars.reset_block (); Cfg.Node.set_succs_exn start_node meth_body_nodes []; Cg.add_node (CContext.get_cg context) (Cfg.Procdesc.get_proc_name procdesc)) @@ -99,7 +85,7 @@ struct | None -> false, [], CContext.ContextNoCls in let class_name = 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 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 *) @@ -107,23 +93,21 @@ struct 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_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 - captured_vars is_anonym_block param_decls attributes + captured_vars is_anonym_block extra_instrs | None -> () 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 ms, body_opt, param_decls = + let ms, body_opt, extra_instrs = CMethod_trans.method_signature_of_decl class_name meth_decl None in match method_body_to_translate ms body_opt with | Some body -> 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 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 - param_decls attributes + extra_instrs | None -> () let rec process_one_method_decl tenv cg cfg curr_class namespace dec = diff --git a/infer/src/clang/cMethod_trans.ml b/infer/src/clang/cMethod_trans.ml index bed00cd49..f426327a3 100644 --- a/infer/src/clang/cMethod_trans.ml +++ b/infer/src/clang/cMethod_trans.ml @@ -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 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 open Clang_ast_t in 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 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 - 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 -> 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 method_decl = Cpp_Meth_decl_info (fdi, class_name, tp) 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 -> let method_name = name_info.ni_name 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 is_generated = Ast_utils.is_generated name_info 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), Some (context, tp, procname, _), _ -> let func_decl = Block_decl_info (bdi, tp, context) 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 let method_signature_of_pointer class_name_opt pointer = diff --git a/infer/src/clang/cMethod_trans.mli b/infer/src/clang/cMethod_trans.mli index c5ac523f6..72f2907fc 100644 --- a/infer/src/clang/cMethod_trans.mli +++ b/infer/src/clang/cMethod_trans.mli @@ -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 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 diff --git a/infer/src/clang/cModule_type.ml b/infer/src/clang/cModule_type.ml index e0c2401ce..53549400c 100644 --- a/infer/src/clang/cModule_type.ml +++ b/infer/src/clang/cModule_type.ml @@ -9,9 +9,12 @@ 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 = 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 module type CMethod_declaration = diff --git a/infer/src/clang/cTrans.ml b/infer/src/clang/cTrans.ml index d6773b263..ed83ef264 100644 --- a/infer/src/clang/cTrans.ml +++ b/infer/src/clang/cTrans.ml @@ -19,9 +19,11 @@ module L = Logging module type CTrans = sig (** 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. *) - 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 *) (** that represents the translation of the stmts into sil. *) @@ -2019,32 +2021,52 @@ struct (Ast_utils.string_of_stmt s); assert false) - (* Given a translation state, this function traslates a list of clang statements. *) - and instructions trans_state clang_stmt_list = - (* Printing.log_err "\n instruction list %i" (List.length clang_stmt_list); *) - match clang_stmt_list with + (** Given a translation state and list of translation functions it executes translation *) + and exec_trans_instrs trans_state trans_stmt_fun_list = + match trans_stmt_fun_list with | [] -> { empty_res_trans with root_nodes = trans_state.succ_nodes } - | s :: clang_stmt_list' -> - let res_trans_s = instruction trans_state s in + | trans_stmt_fun :: trans_stmt_fun_list' -> + let res_trans_s = trans_stmt_fun trans_state in let trans_state' = if res_trans_s.root_nodes <> [] then { trans_state with succ_nodes = res_trans_s.root_nodes } 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; - leaf_nodes =[]; + leaf_nodes = []; ids = res_trans_s.ids @ res_trans_tail.ids; instrs = res_trans_s.instrs @ res_trans_tail.instrs; 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 trans_state = { context = context; succ_nodes =[]; continuation = None; parent_line_number = -1; priority = Free } in let res_trans_stmt = instruction trans_state stmt in fst (CTrans_utils.extract_exp_from_list res_trans_stmt.exps warning) - let instructions_trans context clang_stmt_list exit_node = - let trans_state = { context = context; succ_nodes =[exit_node]; continuation = None; parent_line_number = -1; priority = Free } in - let res_trans = instructions trans_state clang_stmt_list in + 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 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 end diff --git a/infer/src/clang/cTrans.mli b/infer/src/clang/cTrans.mli index 8c29a8d84..3a2e2c003 100644 --- a/infer/src/clang/cTrans.mli +++ b/infer/src/clang/cTrans.mli @@ -10,9 +10,11 @@ module type CTrans = sig (** 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. *) - 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 *) (** that represents the translation of the stmts into sil. *)