From 9f343853ec7c17e779fc43b2db6822c1ddbd8244 Mon Sep 17 00:00:00 2001 From: Dulma Churchill Date: Fri, 2 Mar 2018 05:52:18 -0800 Subject: [PATCH] [clang] Find fields from the properties corresponding to the property implementations. Summary: When a property was defined in a protocol, we were not translating its attributes which leads to retain cycles false positives. This diff fixes it. It also refactors the code for translating fields a bit. Reviewed By: mbouaziz Differential Revision: D7136355 fbshipit-source-id: b5e7445 --- infer/src/clang/cField_decl.ml | 53 +++++++++++-------- infer/src/clang/cGeneral_utils.mli | 5 +- .../tests/codetoanalyze/objc/errors/Makefile | 1 + .../RetainCyclePropertyInProtocol.m | 46 ++++++++++++++++ 4 files changed, 80 insertions(+), 25 deletions(-) create mode 100644 infer/tests/codetoanalyze/objc/errors/memory_leaks_benchmark/RetainCyclePropertyInProtocol.m diff --git a/infer/src/clang/cField_decl.ml b/infer/src/clang/cField_decl.ml index 75a823457..9257c2808 100644 --- a/infer/src/clang/cField_decl.ml +++ b/infer/src/clang/cField_decl.ml @@ -66,31 +66,38 @@ let build_sil_field qual_type_to_sil_type tenv class_tname field_name qual_type (* Given a list of declarations in an interface returns a list of fields *) -let rec get_fields qual_type_to_sil_type tenv class_tname decl_list = +let get_fields qual_type_to_sil_type tenv class_tname decl_list = let open Clang_ast_t in - let add_field name_info (qt: qual_type) attributes decl_list' = - let fields = get_fields qual_type_to_sil_type tenv class_tname decl_list' in - let field_tuple = - build_sil_field qual_type_to_sil_type tenv class_tname name_info qt attributes - in - CGeneral_utils.append_no_duplicates_fields [field_tuple] fields + let get_sil_field name_info (qt: qual_type) property_attributes = + build_sil_field qual_type_to_sil_type tenv class_tname name_info qt property_attributes in - match decl_list with - | [] -> - [] - | (ObjCPropertyDecl (_, _, obj_c_property_decl_info)) :: decl_list' - -> ( - let ivar_decl_ref = obj_c_property_decl_info.Clang_ast_t.opdi_ivar_decl in - match CAst_utils.get_decl_opt_with_decl_ref ivar_decl_ref with - | Some ObjCIvarDecl (_, name_info, qual_type, _, _) -> - let attributes = obj_c_property_decl_info.Clang_ast_t.opdi_property_attributes in - add_field name_info qual_type attributes decl_list' - | _ -> - get_fields qual_type_to_sil_type tenv class_tname decl_list' ) - | (ObjCIvarDecl (_, name_info, qual_type, _, _)) :: decl_list' -> - add_field name_info qual_type [] decl_list' - | _ :: decl_list' -> - get_fields qual_type_to_sil_type tenv class_tname decl_list' + let rec get_field fields decl = + match decl with + | ObjCPropertyDecl (_, _, obj_c_property_decl_info) + -> ( + let ivar_decl_ref = obj_c_property_decl_info.Clang_ast_t.opdi_ivar_decl in + let property_attributes = obj_c_property_decl_info.Clang_ast_t.opdi_property_attributes in + match CAst_utils.get_decl_opt_with_decl_ref ivar_decl_ref with + | Some ObjCIvarDecl (_, name_info, qual_type, _, _) -> + let field = get_sil_field name_info qual_type property_attributes in + CGeneral_utils.add_no_duplicates_fields field fields + | _ -> + fields ) + | ObjCPropertyImplDecl (_, obj_c_property_impl_decl_info) + -> ( + let property_decl_opt = obj_c_property_impl_decl_info.Clang_ast_t.opidi_property_decl in + match CAst_utils.get_decl_opt_with_decl_ref property_decl_opt with + | Some decl -> + get_field fields decl + | None -> + fields ) + | ObjCIvarDecl (_, name_info, qual_type, _, _) -> + let field = get_sil_field name_info qual_type [] in + CGeneral_utils.add_no_duplicates_fields field fields + | _ -> + fields + in + List.fold ~f:get_field ~init:[] decl_list (* Add potential extra fields defined only in the implementation of the class *) diff --git a/infer/src/clang/cGeneral_utils.mli b/infer/src/clang/cGeneral_utils.mli index 9a5b2904c..f8db8e62e 100644 --- a/infer/src/clang/cGeneral_utils.mli +++ b/infer/src/clang/cGeneral_utils.mli @@ -13,9 +13,10 @@ open! IStd type var_info = Clang_ast_t.decl_info * Clang_ast_t.qual_type * Clang_ast_t.var_decl_info * bool +val add_no_duplicates_fields : Typ.Struct.field -> Typ.Struct.field list -> Typ.Struct.field list + val append_no_duplicates_fields : - (Typ.Fieldname.t * Typ.t * Annot.Item.t) list -> (Typ.Fieldname.t * Typ.t * Annot.Item.t) list - -> (Typ.Fieldname.t * Typ.t * Annot.Item.t) list + Typ.Struct.field list -> Typ.Struct.field list -> Typ.Struct.field list val swap_elements_list : 'a list -> 'a list diff --git a/infer/tests/codetoanalyze/objc/errors/Makefile b/infer/tests/codetoanalyze/objc/errors/Makefile index e8ae66d34..be38247d6 100644 --- a/infer/tests/codetoanalyze/objc/errors/Makefile +++ b/infer/tests/codetoanalyze/objc/errors/Makefile @@ -94,6 +94,7 @@ SOURCES_ARC = \ memory_leaks_benchmark/retain_cycle.m \ memory_leaks_benchmark/retain_cycle2.m \ memory_leaks_benchmark/RetainCycleBlocks.m \ + memory_leaks_benchmark/RetainCyclePropertyInProtocol.m \ npe/BoxedNumberExample.m \ npe/ObjCMethodCallInCondition.m \ npe/UpdateDict.m \ diff --git a/infer/tests/codetoanalyze/objc/errors/memory_leaks_benchmark/RetainCyclePropertyInProtocol.m b/infer/tests/codetoanalyze/objc/errors/memory_leaks_benchmark/RetainCyclePropertyInProtocol.m new file mode 100644 index 000000000..dfe756b17 --- /dev/null +++ b/infer/tests/codetoanalyze/objc/errors/memory_leaks_benchmark/RetainCyclePropertyInProtocol.m @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2018 - present Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ +#import + +@protocol Delegate +@property(nonatomic, weak, readwrite) id delegate; +@end + +@interface MyCustomView : NSObject +- (instancetype)initWithDelegate:(id)delegate; +@end + +@implementation MyCustomView +@synthesize delegate = _delegate; + +- (instancetype)initWithDelegate:(id)delegate { + _delegate = delegate; + return self; +} + +@end + +@interface MyCustomViewController : NSObject +@property(nonatomic, strong, readwrite) id view; +@end + +@implementation MyCustomViewController + +- (void)loadView { + MyCustomView* _myView = [[MyCustomView alloc] initWithDelegate:self]; + self.view = _myView; +} + +@end + +int main_good() { + MyCustomViewController* controller = [MyCustomViewController new]; + [controller loadView]; + return 0; +}