diff --git a/infer/src/clang/cField_decl.ml b/infer/src/clang/cField_decl.ml index 4897798e5..6f7ad2627 100644 --- a/infer/src/clang/cField_decl.ml +++ b/infer/src/clang/cField_decl.ml @@ -106,21 +106,3 @@ let is_ivar_atomic ivar fields = with Not_found -> ( Printing.log_out "NOT Found field ivar = '%s' " (Ident.fieldname_to_string ivar); false) - -let get_property_corresponding_ivar tenv type_ptr_to_sil_type class_name property_decl = - let open Clang_ast_t in - match property_decl with - | ObjCPropertyDecl (_, named_decl_info, obj_c_property_decl_info) -> - (let ivar_decl_ref = obj_c_property_decl_info.Clang_ast_t.opdi_ivar_decl in - match Ast_utils.get_decl_opt_with_decl_ref ivar_decl_ref with - | Some ObjCIvarDecl (_, named_decl_info, _, _, _) -> - General_utils.mk_class_field_name named_decl_info - | _ -> (* Ivar is not known, so add a default one to the tenv *) - let type_ptr = obj_c_property_decl_info.Clang_ast_t.opdi_type_ptr in - let field_name_str = Ast_utils.generated_ivar_name named_decl_info in - let prop_attributes = obj_c_property_decl_info.Clang_ast_t.opdi_property_attributes in - let field_name, typ, attr = build_sil_field type_ptr_to_sil_type tenv - field_name_str type_ptr prop_attributes in - ignore (add_missing_fields tenv class_name Csu.Objc [(field_name, typ, attr)]); - field_name) - | _ -> assert false diff --git a/infer/src/clang/cField_decl.mli b/infer/src/clang/cField_decl.mli index d5e69e45e..ee94940a0 100644 --- a/infer/src/clang/cField_decl.mli +++ b/infer/src/clang/cField_decl.mli @@ -26,6 +26,3 @@ val build_sil_field : Ast_utils.type_ptr_to_sil_type -> Tenv.t -> Clang_ast_t.na val add_missing_fields : Tenv.t -> string -> Csu.class_kind -> field_type list -> unit val is_ivar_atomic : Ident.fieldname -> Sil.struct_fields -> bool - -val get_property_corresponding_ivar : Tenv.t -> Ast_utils.type_ptr_to_sil_type -> string -> - Clang_ast_t.decl -> Ident.fieldname diff --git a/infer/src/clang/cFrontend_decl.ml b/infer/src/clang/cFrontend_decl.ml index 6508223d9..2a03594fe 100644 --- a/infer/src/clang/cFrontend_decl.ml +++ b/infer/src/clang/cFrontend_decl.ml @@ -92,6 +92,36 @@ struct None extra_instrs | None -> () + let process_property_implementation obj_c_property_impl_decl_info = + let property_decl_opt = obj_c_property_impl_decl_info.Clang_ast_t.opidi_property_decl in + match Ast_utils.get_decl_opt_with_decl_ref property_decl_opt with + | Some ObjCPropertyDecl (_, _, obj_c_property_decl_info) -> + let ivar_decl_ref = obj_c_property_decl_info.Clang_ast_t.opdi_ivar_decl in + (match Ast_utils.get_decl_opt_with_decl_ref ivar_decl_ref with + | Some ObjCIvarDecl (_, named_decl_info, _, _, _) -> + let field_name = General_utils.mk_class_field_name named_decl_info in + let process_accessor pointer ~getter = + (match Ast_utils.get_decl_opt_with_decl_ref pointer with + | Some ObjCMethodDecl (decl_info, name_info, mdi) -> + let source_range = decl_info.Clang_ast_t.di_source_range in + let loc = CLocation.get_sil_location_from_range source_range true in + let property_accessor = + if getter then + Some (ProcAttributes.Objc_getter field_name) + else + Some (ProcAttributes.Objc_setter field_name) in + let class_name = Ast_utils.get_class_name_from_member name_info in + let procname = CMethod_trans.get_objc_method_name name_info mdi class_name in + let attrs = { (ProcAttributes.default procname Config.Clang) with + loc = loc; + objc_accessor = property_accessor; } in + AttributesTable.store_attributes attrs + | _ -> ()) in + process_accessor obj_c_property_decl_info.Clang_ast_t.opdi_getter_method ~getter:true; + process_accessor obj_c_property_decl_info.Clang_ast_t.opdi_setter_method ~getter:false + | _ -> ()) + | _ -> () + let process_one_method_decl tenv cg cfg curr_class dec = let open Clang_ast_t in match dec with @@ -99,7 +129,9 @@ struct process_method_decl tenv cg cfg curr_class dec ~is_objc:false | ObjCMethodDecl _ -> process_method_decl tenv cg cfg curr_class dec ~is_objc:true - | ObjCPropertyImplDecl _ | EmptyDecl _ + | ObjCPropertyImplDecl (_, obj_c_property_impl_decl_info) -> + process_property_implementation obj_c_property_impl_decl_info + | EmptyDecl _ | ObjCIvarDecl _ | ObjCPropertyDecl _ -> () | _ -> Printing.log_stats diff --git a/infer/src/clang/cMethod_trans.ml b/infer/src/clang/cMethod_trans.ml index eefffea4e..b71d0be71 100644 --- a/infer/src/clang/cMethod_trans.ml +++ b/infer/src/clang/cMethod_trans.ml @@ -150,6 +150,12 @@ 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 get_objc_method_name name_info mdi class_name = + let method_name = name_info.Clang_ast_t.ni_name in + let is_instance = mdi.Clang_ast_t.omdi_is_instance_method in + let method_kind = Procname.objc_method_kind_of_bool is_instance in + General_utils.mk_procname_from_objc_method class_name method_name method_kind + let method_signature_of_decl tenv meth_decl block_data_opt = let open Clang_ast_t in match meth_decl, block_data_opt with @@ -176,11 +182,8 @@ let method_signature_of_decl tenv meth_decl block_data_opt = 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) | ObjCMethodDecl (decl_info, name_info, mdi), _ -> - let method_name = name_info.ni_name in let class_name = Ast_utils.get_class_name_from_member name_info in - let is_instance = mdi.omdi_is_instance_method in - let method_kind = Procname.objc_method_kind_of_bool is_instance in - let procname = General_utils.mk_procname_from_objc_method class_name method_name method_kind in + let procname = get_objc_method_name name_info mdi class_name in let method_decl = ObjC_Meth_decl_info (mdi, class_name) in let parent_pointer = decl_info.Clang_ast_t.di_parent_pointer in let pointer_to_property_opt = @@ -284,20 +287,12 @@ let get_objc_method_data obj_c_message_expr_info = | `Class _ | `SuperClass -> (selector, pointer, MCStatic) -let get_objc_property_accessor tenv ms = +let skip_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, CMethod_signature.ms_get_name ms with - | Some (ObjCPropertyDecl _ as d), Procname.ObjC_Cpp objc_cpp -> - let class_name = Procname.objc_cpp_get_class_name objc_cpp in - let field_name = CField_decl.get_property_corresponding_ivar tenv - CTypes_decl.type_ptr_to_sil_type class_name d in - if CMethod_signature.ms_is_getter ms then - Some (ProcAttributes.Objc_getter field_name) - else if CMethod_signature.ms_is_setter ms then - Some (ProcAttributes.Objc_setter field_name) - else None - | _ -> None + match Ast_utils.get_decl_opt pointer_to_property_opt with + | Some (ObjCPropertyDecl _ as d) -> true + | _ -> false let get_formal_parameters tenv ms = let rec defined_parameters pl = @@ -379,30 +374,31 @@ let create_local_procdesc cfg tenv ms fbody captured is_objc_inst_method = let loc_exit = CLocation.get_sil_location_from_range source_range false in let ret_type = get_return_type tenv ms in let captured' = IList.map (fun (var, t) -> (Pvar.get_name var, t)) captured in - let procdesc = - let proc_attributes = - { (ProcAttributes.default proc_name Config.Clang) with - ProcAttributes.captured = captured'; - ProcAttributes.objc_accessor = get_objc_property_accessor tenv ms; - formals; - func_attributes = attributes; - is_defined = defined; - is_objc_instance_method = is_objc_inst_method; - is_cpp_instance_method = is_cpp_inst_method; - loc = loc_start; - method_annotation; - ret_type; - } in - Cfg.Procdesc.create cfg proc_attributes in - if defined then - (if !Config.arc_mode then - Cfg.Procdesc.set_flag procdesc Mleak_buckets.objc_arc_flag "true"; - let start_kind = Cfg.Node.Start_node procdesc in - let start_node = Cfg.Node.create cfg loc_start start_kind [] procdesc in - let exit_kind = Cfg.Node.Exit_node procdesc in - let exit_node = Cfg.Node.create cfg loc_exit exit_kind [] procdesc in - Cfg.Procdesc.set_start_node procdesc start_node; - Cfg.Procdesc.set_exit_node procdesc exit_node) in + if skip_property_accessor ms then () + else + let procdesc = + let proc_attributes = + { (ProcAttributes.default proc_name Config.Clang) with + ProcAttributes.captured = captured'; + formals; + func_attributes = attributes; + is_defined = defined; + is_objc_instance_method = is_objc_inst_method; + is_cpp_instance_method = is_cpp_inst_method; + loc = loc_start; + method_annotation; + ret_type; + } in + Cfg.Procdesc.create cfg proc_attributes in + if defined then + (if !Config.arc_mode then + Cfg.Procdesc.set_flag procdesc Mleak_buckets.objc_arc_flag "true"; + let start_kind = Cfg.Node.Start_node procdesc in + let start_node = Cfg.Node.create cfg loc_start start_kind [] procdesc in + let exit_kind = Cfg.Node.Exit_node procdesc in + let exit_node = Cfg.Node.create cfg loc_exit exit_kind [] procdesc in + Cfg.Procdesc.set_start_node procdesc start_node; + Cfg.Procdesc.set_exit_node procdesc exit_node) in if should_create_procdesc cfg proc_name defined then (create_new_procdesc (); true) else false diff --git a/infer/src/clang/cMethod_trans.mli b/infer/src/clang/cMethod_trans.mli index 84aa8b448..f69645f64 100644 --- a/infer/src/clang/cMethod_trans.mli +++ b/infer/src/clang/cMethod_trans.mli @@ -55,3 +55,6 @@ val get_method_for_frontend_checks : Cfg.cfg -> Cg.t -> Location.t -> Cfg.Procde val add_default_method_for_class : string -> Clang_ast_t.decl_info -> unit val get_procname_from_cpp_lambda : CContext.t -> Clang_ast_t.decl -> Procname.t + +val get_objc_method_name : Clang_ast_t.named_decl_info -> Clang_ast_t.obj_c_method_decl_info -> + string -> Procname.t diff --git a/infer/tests/codetoanalyze/objc/errors/memory_leaks_benchmark/retain_cycle.m b/infer/tests/codetoanalyze/objc/errors/memory_leaks_benchmark/retain_cycle.m index 6beb8f8c7..343e37041 100644 --- a/infer/tests/codetoanalyze/objc/errors/memory_leaks_benchmark/retain_cycle.m +++ b/infer/tests/codetoanalyze/objc/errors/memory_leaks_benchmark/retain_cycle.m @@ -17,26 +17,41 @@ @property(nonatomic, strong) BB* b; @end +@implementation AA +@end + @interface BBStrong : NSObject @property(nonatomic, strong) AA* a; @end +@implementation BBStrong +@end + @interface BBUnsafeUnretained : NSObject @property(nonatomic, unsafe_unretained) AA* a; @end +@implementation BBUnsafeUnretained +@end + @interface BBWeak : NSObject @property(nonatomic, weak) AA* a; @end +@implementation BBWeak +@end + @interface BBAssign : NSObject @property(nonatomic, assign) AA* a; @end +@implementation BBAssign +@end + int strongcycle() { AA* a_obj = [AA alloc]; diff --git a/infer/tests/endtoend/objc/GetterBuiltinTest.java b/infer/tests/endtoend/objc/GetterBuiltinTest.java index bb8765163..9efcab5f0 100644 --- a/infer/tests/endtoend/objc/GetterBuiltinTest.java +++ b/infer/tests/endtoend/objc/GetterBuiltinTest.java @@ -57,7 +57,6 @@ public class GetterBuiltinTest { DIVIDE_BY_ZERO, FILE, new String[]{ - "should_have_div0", } ) );