diff --git a/infer/src/clang/cMethod_signature.ml b/infer/src/clang/cMethod_signature.ml index ac27f18f7..10ef607dc 100644 --- a/infer/src/clang/cMethod_signature.ml +++ b/infer/src/clang/cMethod_signature.ml @@ -20,7 +20,7 @@ type method_signature = { _is_generated : bool; _language : CFrontend_config.lang; _pointer_to_parent : Clang_ast_t.pointer option; - mutable _objc_accessor : ProcAttributes.objc_accessor_type option; + _pointer_to_property_opt : Clang_ast_t.pointer option; (* If set then method is a getter/setter *) } let ms_get_name ms = @@ -53,13 +53,17 @@ let ms_get_lang ms = let ms_get_pointer_to_parent ms = ms._pointer_to_parent -let ms_objc_accessor ms = - ms._objc_accessor +let ms_get_pointer_to_property_opt ms = + ms._pointer_to_property_opt -let ms_set_objc_accessor ms objc_accessor = - ms._objc_accessor <- objc_accessor +(* A method is a getter if it has a link to a property and *) +(* it has 1 argument (this includes self) *) +let ms_is_getter ms = + Option.is_some ms._pointer_to_property_opt && + IList.length ms._args == 1 -let make_ms procname args ret_type attributes loc is_instance is_generated lang pointer_to_parent = +let make_ms procname args ret_type attributes loc is_instance is_generated lang pointer_to_parent + pointer_to_property_opt = let meth_signature = { _name = procname; _args = args; @@ -70,7 +74,7 @@ let make_ms procname args ret_type attributes loc is_instance is_generated lang _is_generated = is_generated; _language = lang; _pointer_to_parent = pointer_to_parent; - _objc_accessor = None + _pointer_to_property_opt = pointer_to_property_opt; } in meth_signature diff --git a/infer/src/clang/cMethod_signature.mli b/infer/src/clang/cMethod_signature.mli index 94d6e4c23..7700413a0 100644 --- a/infer/src/clang/cMethod_signature.mli +++ b/infer/src/clang/cMethod_signature.mli @@ -31,16 +31,16 @@ val ms_get_lang : method_signature -> CFrontend_config.lang 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_is_getter : 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 -> bool -> CFrontend_config.lang - -> Clang_ast_t.pointer option -> method_signature + -> Clang_ast_t.pointer option -> Clang_ast_t.pointer option -> method_signature val replace_name_ms : method_signature -> Procname.t -> method_signature val ms_to_string : method_signature -> string val ms_is_generated : method_signature -> bool - -val ms_objc_accessor : method_signature -> ProcAttributes.objc_accessor_type option - -val ms_set_objc_accessor : method_signature -> ProcAttributes.objc_accessor_type option -> unit diff --git a/infer/src/clang/cMethod_trans.ml b/infer/src/clang/cMethod_trans.ml index 0169c2576..c030c4527 100644 --- a/infer/src/clang/cMethod_trans.ml +++ b/infer/src/clang/cMethod_trans.ml @@ -87,7 +87,7 @@ let get_return_type function_method_decl_info = | ObjC_Meth_decl_info (method_decl_info, _) -> method_decl_info.Clang_ast_t.omdi_result_type let build_method_signature decl_info procname function_method_decl_info is_anonym_block - is_generated parent_pointer = + is_generated 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 is_instance_method = is_instance_method function_method_decl_info in @@ -96,7 +96,7 @@ let build_method_signature decl_info procname function_method_decl_info is_anony let lang = get_language function_method_decl_info in CMethod_signature.make_ms procname parameters tp attributes source_range is_instance_method is_generated - lang parent_pointer + lang parent_pointer pointer_to_property_opt let get_assume_not_null_calls param_decls = let do_one_param decl = match decl with @@ -120,7 +120,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 false None in + let ms = build_method_signature decl_info procname func_decl false 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), _ @@ -130,7 +130,8 @@ 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 false parent_pointer in + let ms = build_method_signature decl_info procname method_decl false 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 *) ms, fdi.Clang_ast_t.fdi_body, (init_list_instrs @ non_null_instrs) @@ -143,13 +144,17 @@ let method_signature_of_decl 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 parent_pointer = decl_info.Clang_ast_t.di_parent_pointer in - let ms = - build_method_signature decl_info procname method_decl false is_generated parent_pointer in + let pointer_to_property_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 is_generated + 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 false None in + let ms = build_method_signature decl_info procname func_decl true false None None in let extra_instrs = get_assume_not_null_calls bdi.bdi_parameters in ms, bdi.bdi_body, extra_instrs | _ -> raise Invalid_declaration @@ -235,6 +240,18 @@ let get_objc_method_data obj_c_message_expr_info = | `Class _ | `SuperClass -> (selector, pointer, MCStatic) +let get_objc_property_accessor ms = + let open Clang_ast_t in + let pointer_to_property_opt = CMethod_signature.ms_get_pointer_to_property_opt ms in + match Ast_utils.get_decl_opt pointer_to_property_opt with + | Some ObjCPropertyDecl (decl_info, named_decl_info, obj_c_property_decl_info) -> + let field_name_str = Ast_utils.generated_ivar_name named_decl_info in + let field_name = General_utils.mk_class_field_name field_name_str in + if CMethod_signature.ms_is_getter ms then + Some (ProcAttributes.Objc_getter field_name) + else None (* Setter TODO *) + | _ -> None + let get_formal_parameters tenv ms = let rec defined_parameters pl = match pl with @@ -324,7 +341,7 @@ let create_local_procdesc cfg tenv ms fbody captured is_objc_inst_method = let proc_attributes = { (ProcAttributes.default proc_name Config.C_CPP) with ProcAttributes.captured = captured'; - ProcAttributes.objc_accessor = CMethod_signature.ms_objc_accessor ms; + ProcAttributes.objc_accessor = get_objc_property_accessor ms; formals; func_attributes = attributes; is_defined = defined; @@ -407,7 +424,7 @@ let get_method_for_frontend_checks cfg cg tenv class_name decl_info = | Some pdesc -> pdesc | None -> let ms = CMethod_signature.make_ms proc_name [] (Clang_ast_types.pointer_to_type_ptr "-1") - [] source_range false false CFrontend_config.OBJC None in + [] source_range false false CFrontend_config.OBJC 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 fb81649ee..146c95d5e 100644 --- a/infer/src/clang/cTrans.ml +++ b/infer/src/clang/cTrans.ml @@ -35,7 +35,7 @@ struct (* 1. method is a predefined model *) (* 2. method is found by clang's resolution*) (* 3. Method is found by our resolution *) - let get_callee_objc_method context obj_c_message_expr_info act_params property_accessor_opt = + let get_callee_objc_method context obj_c_message_expr_info act_params = let open CContext in let (selector, method_pointer_opt, mc_type) = CMethod_trans.get_objc_method_data obj_c_message_expr_info in @@ -62,10 +62,9 @@ struct CMethod_signature.ms_get_name ms, CMethod_trans.MCNoVirtual | None, Some ms -> if not (M.process_getter_setter context procname) then - (CMethod_signature.ms_set_objc_accessor ms property_accessor_opt; - ignore (CMethod_trans.create_local_procdesc context.cfg context.tenv + (ignore (CMethod_trans.create_local_procdesc context.cfg context.tenv ms [] [] is_instance)); - if Option.is_some property_accessor_opt then + if CMethod_signature.ms_is_getter ms then procname, CMethod_trans.MCNoVirtual else procname, mc_type @@ -833,8 +832,7 @@ struct 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 - property_accessor_opt = + and objCMessageExpr_trans trans_state si obj_c_message_expr_info stmt_list expr_info = Printing.log_out " priority node free = '%s'\n@." (string_of_bool (PriorityNode.is_priority_free trans_state)); let context = trans_state.context in @@ -854,7 +852,7 @@ struct | 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 - subexpr_exprs property_accessor_opt in + 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 @@ -1603,20 +1601,6 @@ struct | stmt :: _ -> instruction trans_state' stmt | _ -> assert false in match stmt_list with - | [ObjCPropertyRefExpr (_, _, _, oprei); _; - ObjCMessageExpr (si, stmts, info, ocmei)] -> - let property_accessor_opt = - match oprei.Clang_ast_t.oprei_kind with - | `PropertyRef decl_ref -> - (let create_field_name property_name = - General_utils.mk_class_field_name (Ast_utils.generated_ivar_name property_name) in - let field_name_opt = Option.map create_field_name decl_ref.Clang_ast_t.dr_name in - match field_name_opt with - | Some field_name when oprei.Clang_ast_t.oprei_is_messaging_getter -> - Some (ProcAttributes.Objc_getter field_name) - | _ -> None) - | _ -> None in - objCMessageExpr_trans trans_state si ocmei stmts info property_accessor_opt | syntactic_form :: semantic_form -> do_semantic_elements semantic_form | _ -> assert false @@ -1911,7 +1895,6 @@ struct block_enumeration_trans trans_state stmt_info stmt_list expr_info else objCMessageExpr_trans trans_state stmt_info obj_c_message_expr_info stmt_list expr_info - None | CompoundStmt (stmt_info, stmt_list) -> (* No node for this statement. We just collect its statement list*) diff --git a/infer/src/clang/cTrans_models.ml b/infer/src/clang/cTrans_models.ml index ea1e9d036..10059072b 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 false lang None in + (Ast_expressions.dummy_source_range ()) false false lang None None in Some ms else None diff --git a/infer/tests/codetoanalyze/objc/frontend/exceptions/ExceptionExample.dot b/infer/tests/codetoanalyze/objc/frontend/exceptions/ExceptionExample.dot index f69765457..10b92b0fa 100644 --- a/infer/tests/codetoanalyze/objc/frontend/exceptions/ExceptionExample.dot +++ b/infer/tests/codetoanalyze/objc/frontend/exceptions/ExceptionExample.dot @@ -31,7 +31,7 @@ digraph iCFG { 4 -> 3 ; -3 [label="3: Message Call: description \n n$0=*&self:class ExceptionExample * [line 26]\n n$1=_fun_ExceptionExample_description(n$0:class ExceptionExample *) virtual [line 26]\n REMOVE_TEMPS(n$0,n$1); [line 26]\n NULLIFY(&self,false); [line 26]\n APPLY_ABSTRACTION; [line 26]\n " shape="box"] +3 [label="3: Message Call: description \n n$0=*&self:class ExceptionExample * [line 26]\n n$1=_fun_ExceptionExample_description(n$0:class ExceptionExample *) [line 26]\n REMOVE_TEMPS(n$0,n$1); [line 26]\n NULLIFY(&self,false); [line 26]\n APPLY_ABSTRACTION; [line 26]\n " shape="box"] 3 -> 2 ; diff --git a/infer/tests/codetoanalyze/objc/frontend/fast_enumeration/Fast_enumeration.dot b/infer/tests/codetoanalyze/objc/frontend/fast_enumeration/Fast_enumeration.dot index d5af0af65..358652826 100644 --- a/infer/tests/codetoanalyze/objc/frontend/fast_enumeration/Fast_enumeration.dot +++ b/infer/tests/codetoanalyze/objc/frontend/fast_enumeration/Fast_enumeration.dot @@ -7,7 +7,7 @@ digraph iCFG { 20 -> 15 ; -19 [label="19: BinaryOperatorStmt: AddAssign \n n$13=*&item:class NSArray * [line 29]\n n$14=_fun_NSArray_count(n$13:class NSArray *) virtual [line 29]\n n$15=*&size:int [line 29]\n *&size:int =(n$15 + n$14) [line 29]\n REMOVE_TEMPS(n$13,n$14,n$15); [line 29]\n NULLIFY(&item,false); [line 29]\n APPLY_ABSTRACTION; [line 29]\n " shape="box"] +19 [label="19: BinaryOperatorStmt: AddAssign \n n$13=*&item:class NSArray * [line 29]\n n$14=_fun_NSArray_count(n$13:class NSArray *) [line 29]\n n$15=*&size:int [line 29]\n *&size:int =(n$15 + n$14) [line 29]\n REMOVE_TEMPS(n$13,n$14,n$15); [line 29]\n NULLIFY(&item,false); [line 29]\n APPLY_ABSTRACTION; [line 29]\n " shape="box"] 19 -> 15 ; @@ -47,7 +47,7 @@ digraph iCFG { 10 -> 4 ; -9 [label="9: BinaryOperatorStmt: AddAssign \n n$4=*&item:class NSArray * [line 20]\n n$5=_fun_NSArray_count(n$4:class NSArray *) virtual [line 20]\n n$6=*&size:int [line 20]\n *&size:int =(n$6 + n$5) [line 20]\n REMOVE_TEMPS(n$4,n$5,n$6); [line 20]\n NULLIFY(&item,false); [line 20]\n " shape="box"] +9 [label="9: BinaryOperatorStmt: AddAssign \n n$4=*&item:class NSArray * [line 20]\n n$5=_fun_NSArray_count(n$4:class NSArray *) [line 20]\n n$6=*&size:int [line 20]\n *&size:int =(n$6 + n$5) [line 20]\n REMOVE_TEMPS(n$4,n$5,n$6); [line 20]\n NULLIFY(&item,false); [line 20]\n " shape="box"] 9 -> 8 ;