diff --git a/infer/src/clang/cFrontend_config.ml b/infer/src/clang/cFrontend_config.ml index 3d4a68dfc..1fa637b7c 100644 --- a/infer/src/clang/cFrontend_config.ml +++ b/infer/src/clang/cFrontend_config.ml @@ -33,6 +33,8 @@ let self = "self" let this = "this" +let return_param = "__return_param" + let alloc = "alloc" let malloc = "malloc" diff --git a/infer/src/clang/cFrontend_config.mli b/infer/src/clang/cFrontend_config.mli index b5589ee04..b229ad534 100644 --- a/infer/src/clang/cFrontend_config.mli +++ b/infer/src/clang/cFrontend_config.mli @@ -53,6 +53,8 @@ val self : string val this : string +val return_param : string + val nsstring_cl : string val nsobject_cl : string diff --git a/infer/src/clang/cMethod_decl.ml b/infer/src/clang/cMethod_decl.ml index 6117d7dd8..d7dfda84e 100644 --- a/infer/src/clang/cMethod_decl.ml +++ b/infer/src/clang/cMethod_decl.ml @@ -71,7 +71,7 @@ struct | Some (outer_context, _, _, captured_vars) -> captured_vars, Some outer_context | None -> [], None in let ms, body_opt, extra_instrs = - CMethod_trans.method_signature_of_decl func_decl block_data_opt in + CMethod_trans.method_signature_of_decl tenv func_decl block_data_opt in match body_opt with | Some body -> (* Only in the case the function declaration has a defined body we create a procdesc *) let procname = CMethod_signature.ms_get_name ms in @@ -82,7 +82,7 @@ struct let process_method_decl tenv cg cfg curr_class meth_decl ~is_objc = let ms, body_opt, extra_instrs = - CMethod_trans.method_signature_of_decl meth_decl None in + CMethod_trans.method_signature_of_decl tenv meth_decl None in match body_opt with | Some body -> let is_instance = CMethod_signature.ms_is_instance ms in diff --git a/infer/src/clang/cMethod_trans.ml b/infer/src/clang/cMethod_trans.ml index baf968497..1dece3624 100644 --- a/infer/src/clang/cMethod_trans.ml +++ b/infer/src/clang/cMethod_trans.ml @@ -41,6 +41,13 @@ let is_instance_method function_method_decl_info = | ObjC_Meth_decl_info (method_decl_info, _) -> method_decl_info.Clang_ast_t.omdi_is_instance_method +let get_original_return_type function_method_decl_info = + match function_method_decl_info with + | Func_decl_info (_, typ, _) + | Cpp_Meth_decl_info (_, _, _, typ) + | Block_decl_info (_, typ, _) -> CTypes.return_type_of_function_type typ + | ObjC_Meth_decl_info (method_decl_info, _) -> method_decl_info.Clang_ast_t.omdi_result_type + let get_class_param function_method_decl_info = if (is_instance_method function_method_decl_info) then match function_method_decl_info with @@ -53,6 +60,19 @@ let get_class_param function_method_decl_info = | _ -> [] else [] +let should_add_return_param return_type = + match return_type with + | Sil.Tstruct _ -> false (* will return true once everything is in place *) + | _ -> false + +let get_return_param tenv function_method_decl_info = + let return_type_ptr = get_original_return_type function_method_decl_info in + let return_typ = CTypes_decl.type_ptr_to_sil_type tenv return_type_ptr in + if should_add_return_param return_typ then + [(CFrontend_config.return_param, Ast_expressions.create_pointer_type return_type_ptr)] + else + [] + let get_param_decls function_method_decl_info = match function_method_decl_info with | Func_decl_info (function_decl_info, _, _) @@ -68,30 +88,33 @@ let get_language function_method_decl_info = | ObjC_Meth_decl_info _ -> CFrontend_config.OBJC | Block_decl_info _ -> CFrontend_config.OBJC -let get_parameters function_method_decl_info = +(** Returns parameters of a function/method. They will have following order: + 1. self/this parameter (optional, only for methods) + 2. normal parameters + 3. return parameter (optional) *) +let get_parameters tenv function_method_decl_info = let par_to_ms_par par = match par with | Clang_ast_t.ParmVarDecl (decl_info, name_info, type_ptr, var_decl_info) -> let name = name_info.Clang_ast_t.ni_name in (name, type_ptr) | _ -> assert false in - let pars = IList.map par_to_ms_par (get_param_decls function_method_decl_info) in - get_class_param function_method_decl_info @ pars + get_class_param function_method_decl_info @ pars @ get_return_param tenv function_method_decl_info -let get_return_type function_method_decl_info = - match function_method_decl_info with - | Func_decl_info (_, typ, _) - | Cpp_Meth_decl_info (_, _, _, typ) - | Block_decl_info (_, typ, _) -> CTypes.return_type_of_function_type typ - | ObjC_Meth_decl_info (method_decl_info, _) -> method_decl_info.Clang_ast_t.omdi_result_type +let get_return_type tenv function_method_decl_info = + let return_type_ptr = get_original_return_type function_method_decl_info in + let return_typ = CTypes_decl.type_ptr_to_sil_type tenv return_type_ptr in + if should_add_return_param return_typ then + Ast_expressions.create_void_type + else return_type_ptr -let build_method_signature decl_info procname function_method_decl_info is_anonym_block +let build_method_signature tenv decl_info procname function_method_decl_info is_anonym_block parent_pointer pointer_to_property_opt = let source_range = decl_info.Clang_ast_t.di_source_range in - let tp = get_return_type function_method_decl_info in + let tp = get_return_type tenv function_method_decl_info in let is_instance_method = is_instance_method function_method_decl_info in - let parameters = get_parameters function_method_decl_info in + let parameters = get_parameters tenv function_method_decl_info in let attributes = decl_info.Clang_ast_t.di_attributes in let lang = get_language function_method_decl_info in CMethod_signature.make_ms @@ -111,7 +134,7 @@ let get_init_list_instrs method_decl_info = let create_custom_instr construct_instr = `CXXConstructorInit construct_instr in IList.map create_custom_instr method_decl_info.Clang_ast_t.xmdi_cxx_ctor_initializers -let method_signature_of_decl meth_decl block_data_opt = +let method_signature_of_decl tenv meth_decl block_data_opt = let open Clang_ast_t in match meth_decl, block_data_opt with | FunctionDecl (decl_info, name_info, tp, fdi), _ -> @@ -120,7 +143,7 @@ let method_signature_of_decl meth_decl block_data_opt = let func_decl = Func_decl_info (fdi, tp, language) in 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 None None in + let ms = build_method_signature tenv decl_info procname func_decl false None None in let extra_instrs = get_assume_not_null_calls fdi.Clang_ast_t.fdi_parameters in ms, fdi.Clang_ast_t.fdi_body, extra_instrs | CXXMethodDecl (decl_info, name_info, tp, fdi, mdi), _ @@ -131,7 +154,7 @@ let method_signature_of_decl meth_decl block_data_opt = let procname = General_utils.mk_procname_from_cpp_method class_name method_name tp in let method_decl = Cpp_Meth_decl_info (fdi, mdi, class_name, tp) in let parent_pointer = decl_info.Clang_ast_t.di_parent_pointer in - let ms = build_method_signature decl_info procname method_decl false parent_pointer + let ms = build_method_signature tenv decl_info procname method_decl false parent_pointer None in let non_null_instrs = get_assume_not_null_calls fdi.Clang_ast_t.fdi_parameters in let init_list_instrs = get_init_list_instrs mdi in (* it will be empty for methods *) @@ -148,22 +171,22 @@ let method_signature_of_decl meth_decl block_data_opt = match mdi.Clang_ast_t.omdi_property_decl with | Some decl_ref -> Some decl_ref.Clang_ast_t.dr_decl_pointer | None -> None in - let ms = build_method_signature decl_info procname method_decl false + let ms = build_method_signature tenv decl_info procname method_decl false parent_pointer pointer_to_property_opt in let extra_instrs = get_assume_not_null_calls mdi.omdi_parameters in ms, mdi.omdi_body, extra_instrs | BlockDecl (decl_info, bdi), Some (outer_context, tp, procname, _) -> let func_decl = Block_decl_info (bdi, tp, outer_context) in - let ms = build_method_signature decl_info procname func_decl true None None in + let ms = build_method_signature tenv decl_info procname func_decl true None None in let extra_instrs = get_assume_not_null_calls bdi.bdi_parameters in ms, bdi.bdi_body, extra_instrs | _ -> raise Invalid_declaration -let method_signature_of_pointer pointer = +let method_signature_of_pointer tenv pointer = try match Ast_utils.get_decl pointer with | Some meth_decl -> - let ms, _, _ = method_signature_of_decl meth_decl None in + let ms, _, _ = method_signature_of_decl tenv meth_decl None in Some ms | None -> None with Invalid_declaration -> None @@ -207,10 +230,10 @@ let get_superclass_curr_class context = | CContext.ContextProtocol _ -> assert false (* Gets the class name from a method signature found by clang, if search is successful *) -let get_class_name_method_call_from_clang obj_c_message_expr_info = +let get_class_name_method_call_from_clang tenv obj_c_message_expr_info = match obj_c_message_expr_info.Clang_ast_t.omei_decl_pointer with | Some pointer -> - (match method_signature_of_pointer pointer with + (match method_signature_of_pointer tenv pointer with | Some ms -> let class_name = Procname.c_get_class (CMethod_signature.ms_get_name ms) in Some class_name @@ -385,7 +408,7 @@ let create_external_procdesc cfg proc_name is_objc_inst_method type_opt = let create_procdesc_with_pointer context pointer class_name_opt name tp = let open CContext in - match method_signature_of_pointer pointer with + match method_signature_of_pointer context.tenv pointer with | Some callee_ms -> ignore (create_local_procdesc context.cfg context.tenv callee_ms [] [] false); CMethod_signature.ms_get_name callee_ms diff --git a/infer/src/clang/cMethod_trans.mli b/infer/src/clang/cMethod_trans.mli index fae46a803..91d104d5e 100644 --- a/infer/src/clang/cMethod_trans.mli +++ b/infer/src/clang/cMethod_trans.mli @@ -20,6 +20,8 @@ type method_call_type = | MCNoVirtual | MCStatic +val should_add_return_param : Sil.typ -> bool + val create_local_procdesc : Cfg.cfg -> Sil.tenv -> CMethod_signature.method_signature -> Clang_ast_t.stmt list -> (Sil.pvar * Sil.typ) list -> bool -> bool @@ -31,12 +33,14 @@ val get_objc_method_data : Clang_ast_t.obj_c_message_expr_info -> val get_class_name_method_call_from_receiver_kind : CContext.t -> Clang_ast_t.obj_c_message_expr_info -> (Sil.exp * Sil.typ) list -> string -val get_class_name_method_call_from_clang : Clang_ast_t.obj_c_message_expr_info -> string option +val get_class_name_method_call_from_clang : Sil.tenv -> Clang_ast_t.obj_c_message_expr_info -> + string option -val method_signature_of_decl : Clang_ast_t.decl -> CModule_type.block_data option -> +val method_signature_of_decl : Sil.tenv -> Clang_ast_t.decl -> CModule_type.block_data option -> CMethod_signature.method_signature * Clang_ast_t.stmt option * CModule_type.instr_type list -val method_signature_of_pointer : Clang_ast_t.pointer -> CMethod_signature.method_signature option +val method_signature_of_pointer : Sil.tenv -> Clang_ast_t.pointer -> + CMethod_signature.method_signature option val get_method_name_from_clang : Sil.tenv -> CMethod_signature.method_signature option -> CMethod_signature.method_signature option diff --git a/infer/src/clang/cTrans.ml b/infer/src/clang/cTrans.ml index 9cf511678..4cf6016c9 100644 --- a/infer/src/clang/cTrans.ml +++ b/infer/src/clang/cTrans.ml @@ -43,7 +43,7 @@ struct let method_kind = Procname.objc_method_kind_of_bool is_instance in let ms_opt = match method_pointer_opt with - | Some pointer -> CMethod_trans.method_signature_of_pointer pointer + | Some pointer -> CMethod_trans.method_signature_of_pointer context.tenv pointer | None -> None in let procname = match CMethod_trans.get_method_name_from_clang context.tenv ms_opt with @@ -418,7 +418,7 @@ struct Printing.log_out "!!!!! Dealing with method '%s' @." method_name; let method_typ = CTypes_decl.type_ptr_to_sil_type context.tenv type_ptr in let is_instance_method = - match CMethod_trans.method_signature_of_pointer decl_ptr with + match CMethod_trans.method_signature_of_pointer context.tenv decl_ptr with | Some ms -> CMethod_signature.ms_is_instance ms | _ -> true in (* might happen for methods that are not exported yet (some templates). *) let extra_exps = if is_instance_method then ( @@ -833,8 +833,8 @@ struct else if (selector = CFrontend_config.alloc) || (selector = CFrontend_config.new_str) then match receiver_kind with | `Class type_ptr -> - let class_opt = - CMethod_trans.get_class_name_method_call_from_clang obj_c_message_expr_info in + let class_opt = CMethod_trans.get_class_name_method_call_from_clang context.tenv + obj_c_message_expr_info in Some (new_or_alloc_trans trans_state_pri sil_loc si type_ptr class_opt selector) | _ -> None (* assertions *)