diff --git a/infer/src/clang/cContext.ml b/infer/src/clang/cContext.ml index 1c5bdee29..0bc2ac8a8 100644 --- a/infer/src/clang/cContext.ml +++ b/infer/src/clang/cContext.ml @@ -30,19 +30,19 @@ type t = procdesc : Cfg.Procdesc.t; is_objc_method : bool; curr_class: curr_class; - has_return_param : bool; + return_param_typ : Sil.typ option; is_callee_expression : bool; outer_context : t option; (* in case of objc blocks, the context of the method containing the block *) mutable blocks_static_vars : ((Sil.pvar * Sil.typ) list) Procname.Map.t; } -let create_context tenv cg cfg procdesc curr_class ~has_return_param is_objc_method context_opt = +let create_context tenv cg cfg procdesc curr_class return_param_typ is_objc_method context_opt = { tenv = tenv; cg = cg; cfg = cfg; procdesc = procdesc; curr_class = curr_class; - has_return_param = has_return_param; + return_param_typ = return_param_typ; is_callee_expression = false; is_objc_method = is_objc_method; outer_context = context_opt; diff --git a/infer/src/clang/cContext.mli b/infer/src/clang/cContext.mli index 3eb8961ee..6ddd6c9a0 100644 --- a/infer/src/clang/cContext.mli +++ b/infer/src/clang/cContext.mli @@ -25,7 +25,7 @@ type t = procdesc : Cfg.Procdesc.t; is_objc_method : bool; curr_class: curr_class; - has_return_param : bool; + return_param_typ : Sil.typ option; is_callee_expression : bool; outer_context : t option; (* in case of objc blocks, the context of the method containing the block *) mutable blocks_static_vars : ((Sil.pvar * Sil.typ) list) Procname.Map.t; @@ -54,7 +54,7 @@ val is_objc_method : t -> bool val get_tenv : t -> Sil.tenv val create_context : Sil.tenv -> Cg.t -> Cfg.cfg -> Cfg.Procdesc.t -> - curr_class -> has_return_param : bool -> bool -> t option -> t + curr_class -> Sil.typ option -> bool -> t option -> t val create_curr_class : Sil.tenv -> string -> Csu.class_kind -> curr_class diff --git a/infer/src/clang/cMethod_decl.ml b/infer/src/clang/cMethod_decl.ml index 3bb016a34..f2a5fac1c 100644 --- a/infer/src/clang/cMethod_decl.ml +++ b/infer/src/clang/cMethod_decl.ml @@ -75,9 +75,9 @@ struct 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 - let has_return_param = CMethod_signature.ms_has_return_param ms in + let return_param_typ_opt = CMethod_signature.ms_get_return_param_typ ms in if CMethod_trans.create_local_procdesc cfg tenv ms [body] captured_vars false then - add_method tenv cg cfg CContext.ContextNoCls procname body has_return_param false + add_method tenv cg cfg CContext.ContextNoCls procname body return_param_typ_opt false captured_vars outer_context_opt extra_instrs | None -> () @@ -89,9 +89,9 @@ struct let is_instance = CMethod_signature.ms_is_instance ms in let procname = CMethod_signature.ms_get_name ms in let is_objc_inst_method = is_instance && is_objc in - let has_return_param = CMethod_signature.ms_has_return_param ms in + let return_param_typ_opt = CMethod_signature.ms_get_return_param_typ ms in if CMethod_trans.create_local_procdesc cfg tenv ms [body] [] is_objc_inst_method then - add_method tenv cg cfg curr_class procname body has_return_param is_objc [] + add_method tenv cg cfg curr_class procname body return_param_typ_opt is_objc [] None extra_instrs | None -> () diff --git a/infer/src/clang/cMethod_signature.ml b/infer/src/clang/cMethod_signature.ml index cf2ad35a5..5187df4ea 100644 --- a/infer/src/clang/cMethod_signature.ml +++ b/infer/src/clang/cMethod_signature.ml @@ -20,7 +20,7 @@ type method_signature = { language : CFrontend_config.lang; pointer_to_parent : Clang_ast_t.pointer option; pointer_to_property_opt : Clang_ast_t.pointer option; (* If set then method is a getter/setter *) - has_return_param : bool; + return_param_typ : Sil.typ option; } let ms_get_name { name } = @@ -53,8 +53,8 @@ let ms_get_pointer_to_parent { pointer_to_parent } = let ms_get_pointer_to_property_opt { pointer_to_property_opt } = pointer_to_property_opt -let ms_has_return_param { has_return_param } = - has_return_param +let ms_get_return_param_typ { return_param_typ } = + return_param_typ (* A method is a getter if it has a link to a property and *) (* it has 1 argument (this includes self) *) @@ -69,7 +69,7 @@ let ms_is_setter { pointer_to_property_opt; args } = IList.length args == 2 let make_ms name args ret_type attributes loc is_instance language pointer_to_parent - pointer_to_property_opt ~has_return_param = + pointer_to_property_opt return_param_typ = { name; args; @@ -80,7 +80,7 @@ let make_ms name args ret_type attributes loc is_instance language pointer_to_pa language; pointer_to_parent; pointer_to_property_opt; - has_return_param; + return_param_typ; } let replace_name_ms ms name = diff --git a/infer/src/clang/cMethod_signature.mli b/infer/src/clang/cMethod_signature.mli index 0ed35b7a0..91978cf31 100644 --- a/infer/src/clang/cMethod_signature.mli +++ b/infer/src/clang/cMethod_signature.mli @@ -33,7 +33,7 @@ val ms_get_pointer_to_parent : method_signature -> Clang_ast_t.pointer option val ms_get_pointer_to_property_opt : method_signature -> Clang_ast_t.pointer option -val ms_has_return_param : method_signature -> bool +val ms_get_return_param_typ : method_signature -> Sil.typ option val ms_is_getter : method_signature -> bool @@ -41,7 +41,7 @@ val ms_is_setter : method_signature -> bool val make_ms : Procname.t -> (string * Clang_ast_t.type_ptr) list -> Clang_ast_t.type_ptr -> Clang_ast_t.attribute list -> Clang_ast_t.source_range -> bool -> CFrontend_config.lang - -> Clang_ast_t.pointer option -> Clang_ast_t.pointer option -> has_return_param : bool + -> Clang_ast_t.pointer option -> Clang_ast_t.pointer option -> Sil.typ option -> method_signature val replace_name_ms : method_signature -> Procname.t -> method_signature diff --git a/infer/src/clang/cMethod_trans.ml b/infer/src/clang/cMethod_trans.ml index 6e22a0779..ebe3d3d44 100644 --- a/infer/src/clang/cMethod_trans.ml +++ b/infer/src/clang/cMethod_trans.ml @@ -109,26 +109,26 @@ let get_parameters tenv function_method_decl_info = 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_return_param tenv function_method_decl_info -(** get return type of the function and whether function has return parameter *) +(** get return type of the function and optionally type of function's return parameter *) 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 let is_objc_method = is_objc_method function_method_decl_info in if should_add_return_param return_typ is_objc_method then - Ast_expressions.create_void_type, true - else return_type_ptr, false + Ast_expressions.create_void_type, Some (Sil.Tptr (return_typ, Sil.Pk_pointer)) + else return_type_ptr, None 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, has_return_param = get_return_type tenv function_method_decl_info in + let tp, return_param_type_opt = 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 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 procname parameters tp attributes source_range is_instance_method lang parent_pointer - pointer_to_property_opt ~has_return_param + pointer_to_property_opt return_param_type_opt let get_assume_not_null_calls param_decls = let do_one_param decl = match decl with @@ -446,7 +446,7 @@ let get_method_for_frontend_checks cfg cg tenv class_name decl_info = | None -> let ms_type_ptr = Clang_ast_types.pointer_to_type_ptr (Ast_utils.get_invalid_pointer ()) in let ms = CMethod_signature.make_ms proc_name [] ms_type_ptr [] source_range false - CFrontend_config.OBJC None None false in + CFrontend_config.OBJC None None None in let body = [Clang_ast_t.CompoundStmt (stmt_info, [])] in ignore (create_local_procdesc cfg tenv ms body [] false); let pdesc = Option.get (Cfg.Procdesc.find_from_name cfg proc_name) in diff --git a/infer/src/clang/cTrans.ml b/infer/src/clang/cTrans.ml index 164505406..205b74e78 100644 --- a/infer/src/clang/cTrans.ml +++ b/infer/src/clang/cTrans.ml @@ -1750,16 +1750,16 @@ struct let trans_result = (match stmt_list with | [stmt] -> (* return exp; *) let procdesc = context.CContext.procdesc in - let ret_exp, var_instrs, var_ids = if context.CContext.has_return_param then - let name = CFrontend_config.return_param in - let procname = Cfg.Procdesc.get_proc_name procdesc in - let pvar = Sil.mk_pvar (Mangled.from_string name) procname in - let id = Ident.create_fresh Ident.knormal in - let ret_type_ptr = Sil.Tptr (Sil.Tvoid, Sil.Pk_pointer) in - let instr = Sil.Letderef (id, Sil.Lvar pvar, ret_type_ptr, sil_loc) in - Sil.Var id, [instr], [id] - else - Sil.Lvar (Cfg.Procdesc.get_ret_var procdesc), [], [] in + let ret_exp, var_instrs, var_ids = match context.CContext.return_param_typ with + | Some ret_param_typ -> + let name = CFrontend_config.return_param in + let procname = Cfg.Procdesc.get_proc_name procdesc in + let pvar = Sil.mk_pvar (Mangled.from_string name) procname in + let id = Ident.create_fresh Ident.knormal in + let instr = Sil.Letderef (id, Sil.Lvar pvar, ret_param_typ, sil_loc) in + Sil.Var id, [instr], [id] + | None -> + Sil.Lvar (Cfg.Procdesc.get_ret_var procdesc), [], [] in let ret_type = Cfg.Procdesc.get_ret_type procdesc in let trans_state' = { trans_state_pri with succ_nodes = []; var_exp = Some ret_exp} in let res_trans_stmt = exec_with_self_exception instruction trans_state' stmt in diff --git a/infer/src/clang/cTrans_models.ml b/infer/src/clang/cTrans_models.ml index 01fb51c77..167eb6d27 100644 --- a/infer/src/clang/cTrans_models.ml +++ b/infer/src/clang/cTrans_models.ml @@ -127,7 +127,7 @@ let get_predefined_ms_method condition class_name method_name method_kind mk_pro | Some procname -> procname | None -> mk_procname class_name method_name method_kind in let ms = CMethod_signature.make_ms procname arguments return_type attributes - (Ast_expressions.dummy_source_range ()) false lang None None false in + (Ast_expressions.dummy_source_range ()) false lang None None None in Some ms else None diff --git a/infer/tests/codetoanalyze/cpp/frontend/constructors/temp_object.cpp.dot b/infer/tests/codetoanalyze/cpp/frontend/constructors/temp_object.cpp.dot index c95a2f859..ee4c44fde 100644 --- a/infer/tests/codetoanalyze/cpp/frontend/constructors/temp_object.cpp.dot +++ b/infer/tests/codetoanalyze/cpp/frontend/constructors/temp_object.cpp.dot @@ -91,7 +91,7 @@ digraph iCFG { 19 -> 22 ; -18 [label="18: Return Stmt \n n$0=*&__return_param:void * [line 24]\n n$2=*&a:int [line 24]\n n$3=*&b:int [line 24]\n _fun_X_X(&SIL_materialize_temp__n$1:class X *,n$2:int ,n$3:int ) [line 24]\n _fun_X_X(n$0:class X *,&SIL_materialize_temp__n$1:class X &) [line 24]\n REMOVE_TEMPS(n$0,n$2,n$3); [line 24]\n NULLIFY(&__return_param,false); [line 24]\n NULLIFY(&a,false); [line 24]\n NULLIFY(&b,false); [line 24]\n NULLIFY(&SIL_materialize_temp__n$1,false); [line 24]\n APPLY_ABSTRACTION; [line 24]\n " shape="box"] +18 [label="18: Return Stmt \n n$0=*&__return_param:class X * [line 24]\n n$2=*&a:int [line 24]\n n$3=*&b:int [line 24]\n _fun_X_X(&SIL_materialize_temp__n$1:class X *,n$2:int ,n$3:int ) [line 24]\n _fun_X_X(n$0:class X *,&SIL_materialize_temp__n$1:class X &) [line 24]\n REMOVE_TEMPS(n$0,n$2,n$3); [line 24]\n NULLIFY(&__return_param,false); [line 24]\n NULLIFY(&a,false); [line 24]\n NULLIFY(&b,false); [line 24]\n NULLIFY(&SIL_materialize_temp__n$1,false); [line 24]\n APPLY_ABSTRACTION; [line 24]\n " shape="box"] 18 -> 17 ; diff --git a/infer/tests/codetoanalyze/cpp/frontend/methods/conversion_operator.cpp.dot b/infer/tests/codetoanalyze/cpp/frontend/methods/conversion_operator.cpp.dot index a7fe3fece..062517076 100644 --- a/infer/tests/codetoanalyze/cpp/frontend/methods/conversion_operator.cpp.dot +++ b/infer/tests/codetoanalyze/cpp/frontend/methods/conversion_operator.cpp.dot @@ -174,7 +174,7 @@ digraph iCFG { 18 -> 19 ; -17 [label="17: Return Stmt \n n$0=*&__return_param:void * [line 21]\n n$2=*&this:class Y * [line 21]\n n$3=*n$2.f:int [line 21]\n n$4=*&this:class Y * [line 21]\n n$5=*n$4.b:int [line 21]\n _fun_X_X(&SIL_materialize_temp__n$1:class X *,n$3:int ,n$5:_Bool ) [line 21]\n _fun_X_X(n$0:class X *,&SIL_materialize_temp__n$1:class X &) [line 21]\n REMOVE_TEMPS(n$0,n$2,n$3,n$4,n$5); [line 21]\n NULLIFY(&__return_param,false); [line 21]\n NULLIFY(&this,false); [line 21]\n NULLIFY(&SIL_materialize_temp__n$1,false); [line 21]\n APPLY_ABSTRACTION; [line 21]\n " shape="box"] +17 [label="17: Return Stmt \n n$0=*&__return_param:class X * [line 21]\n n$2=*&this:class Y * [line 21]\n n$3=*n$2.f:int [line 21]\n n$4=*&this:class Y * [line 21]\n n$5=*n$4.b:int [line 21]\n _fun_X_X(&SIL_materialize_temp__n$1:class X *,n$3:int ,n$5:_Bool ) [line 21]\n _fun_X_X(n$0:class X *,&SIL_materialize_temp__n$1:class X &) [line 21]\n REMOVE_TEMPS(n$0,n$2,n$3,n$4,n$5); [line 21]\n NULLIFY(&__return_param,false); [line 21]\n NULLIFY(&this,false); [line 21]\n NULLIFY(&SIL_materialize_temp__n$1,false); [line 21]\n APPLY_ABSTRACTION; [line 21]\n " shape="box"] 17 -> 16 ; diff --git a/infer/tests/codetoanalyze/cpp/frontend/methods/return_struct.cpp.dot b/infer/tests/codetoanalyze/cpp/frontend/methods/return_struct.cpp.dot index 01754a160..dd84cec66 100644 --- a/infer/tests/codetoanalyze/cpp/frontend/methods/return_struct.cpp.dot +++ b/infer/tests/codetoanalyze/cpp/frontend/methods/return_struct.cpp.dot @@ -18,7 +18,7 @@ digraph iCFG { 8 -> 7 ; -7 [label="7: Return Stmt \n n$0=*&__return_param:void * [line 17]\n _fun_X_X(n$0:class X *,&x:class X &) [line 17]\n REMOVE_TEMPS(n$0); [line 17]\n NULLIFY(&__return_param,false); [line 17]\n NULLIFY(&x,false); [line 17]\n APPLY_ABSTRACTION; [line 17]\n " shape="box"] +7 [label="7: Return Stmt \n n$0=*&__return_param:class X * [line 17]\n _fun_X_X(n$0:class X *,&x:class X &) [line 17]\n REMOVE_TEMPS(n$0); [line 17]\n NULLIFY(&__return_param,false); [line 17]\n NULLIFY(&x,false); [line 17]\n APPLY_ABSTRACTION; [line 17]\n " shape="box"] 7 -> 6 ; diff --git a/infer/tests/codetoanalyze/cpp/frontend/types/return_struct.cpp.dot b/infer/tests/codetoanalyze/cpp/frontend/types/return_struct.cpp.dot index fef73b1a6..f4fa886c0 100644 --- a/infer/tests/codetoanalyze/cpp/frontend/types/return_struct.cpp.dot +++ b/infer/tests/codetoanalyze/cpp/frontend/types/return_struct.cpp.dot @@ -85,7 +85,7 @@ digraph iCFG { 13 -> 12 ; -12 [label="12: Return Stmt \n n$0=*&__return_param:void * [line 23]\n _fun_X_X(n$0:class X *,&x:class X &) [line 23]\n REMOVE_TEMPS(n$0); [line 23]\n NULLIFY(&__return_param,false); [line 23]\n NULLIFY(&x,false); [line 23]\n APPLY_ABSTRACTION; [line 23]\n " shape="box"] +12 [label="12: Return Stmt \n n$0=*&__return_param:class X * [line 23]\n _fun_X_X(n$0:class X *,&x:class X &) [line 23]\n REMOVE_TEMPS(n$0); [line 23]\n NULLIFY(&__return_param,false); [line 23]\n NULLIFY(&x,false); [line 23]\n APPLY_ABSTRACTION; [line 23]\n " shape="box"] 12 -> 11 ;