diff --git a/infer/src/clang/cGeneral_utils.ml b/infer/src/clang/cGeneral_utils.ml index e623b5a1c..4de382e29 100644 --- a/infer/src/clang/cGeneral_utils.ml +++ b/infer/src/clang/cGeneral_utils.ml @@ -30,6 +30,10 @@ let append_no_duplicates_annotations = Staged.unstage (IList.append_no_duplicates ~cmp) +let append_no_duplicates_methods = + Staged.unstage (IList.append_no_duplicates ~cmp:Typ.Procname.compare) + + let add_no_duplicates_fields field_tuple l = let rec replace_field field_tuple l found = match (field_tuple, l) with diff --git a/infer/src/clang/cGeneral_utils.mli b/infer/src/clang/cGeneral_utils.mli index f8db8e62e..dc843a41d 100644 --- a/infer/src/clang/cGeneral_utils.mli +++ b/infer/src/clang/cGeneral_utils.mli @@ -18,6 +18,9 @@ val add_no_duplicates_fields : Typ.Struct.field -> Typ.Struct.field list -> Typ. val append_no_duplicates_fields : Typ.Struct.field list -> Typ.Struct.field list -> Typ.Struct.field list +val append_no_duplicates_methods : + Typ.Procname.t list -> Typ.Procname.t list -> Typ.Procname.t list + val swap_elements_list : 'a list -> 'a list val list_range : int -> int -> int list diff --git a/infer/src/clang/objcCategory_decl.ml b/infer/src/clang/objcCategory_decl.ml index ea19d7262..b75bf866e 100644 --- a/infer/src/clang/objcCategory_decl.ml +++ b/infer/src/clang/objcCategory_decl.ml @@ -63,19 +63,21 @@ let get_base_class_name_from_category decl = None -(* Add potential extra fields defined only in the category *) +(* Add potential extra fields and methods defined only in the category *) (* to the corresponding class. Update the tenv accordingly.*) let process_category qual_type_to_sil_type tenv class_name decl_info decl_list = let class_tn_name = Typ.Name.Objc.from_qual_name class_name in let decl_fields = CField_decl.get_fields qual_type_to_sil_type tenv class_tn_name decl_list in + let decl_methods = ObjcMethod_decl.get_methods class_tn_name decl_list in let class_tn_desc = Typ.Tstruct class_tn_name in let decl_key = Clang_ast_extend.DeclPtr decl_info.Clang_ast_t.di_pointer in CAst_utils.update_sil_types_map decl_key class_tn_desc ; ( match Tenv.lookup tenv class_tn_name with - | Some ({fields} as struct_typ) -> + | Some ({fields; methods} as struct_typ) -> let new_fields = CGeneral_utils.append_no_duplicates_fields decl_fields fields in + let new_methods = CGeneral_utils.append_no_duplicates_methods decl_methods methods in ignore - (Tenv.mk_struct tenv ~default:struct_typ ~fields:new_fields ~statics:[] ~methods:[] + (Tenv.mk_struct tenv ~default:struct_typ ~fields:new_fields ~methods:new_methods class_tn_name) ; L.(debug Capture Verbose) " Updating info for class '%a' in tenv@\n" QualifiedCppName.pp class_name diff --git a/infer/src/clang/objcInterface_decl.ml b/infer/src/clang/objcInterface_decl.ml index e7b35c249..cc6861c32 100644 --- a/infer/src/clang/objcInterface_decl.ml +++ b/infer/src/clang/objcInterface_decl.ml @@ -91,52 +91,37 @@ let append_no_duplicates_typ_name = (* Adds pairs (interface name, interface_type_info) to the global environment. *) let add_class_to_tenv qual_type_to_sil_type tenv decl_info name_info decl_list ocidi = let class_name = CAst_utils.get_qualified_name name_info in - L.(debug Capture Verbose) "ADDING: ObjCInterfaceDecl for '%a'@\n" QualifiedCppName.pp class_name ; let interface_name = Typ.Name.Objc.from_qual_name class_name in let interface_desc = Typ.Tstruct interface_name in let decl_key = Clang_ast_extend.DeclPtr decl_info.Clang_ast_t.di_pointer in CAst_utils.update_sil_types_map decl_key interface_desc ; + (* We don't need to add the methods of the superclass *) let decl_supers, decl_fields = create_supers_fields qual_type_to_sil_type tenv interface_name decl_list ocidi.Clang_ast_t.otdi_super ocidi.Clang_ast_t.otdi_protocols in let fields_sc = CField_decl.fields_superclass tenv ocidi in - List.iter - ~f:(fun (fn, ft, _) -> - L.(debug Capture Verbose) "----->SuperClass field: '%s' " (Typ.Fieldname.to_string fn) ; - L.(debug Capture Verbose) "type: '%s'@\n" (Typ.to_string ft) ) - fields_sc ; (*In case we found categories, or partial definition of this class earlier and they are already in the tenv *) - let fields, (supers: Typ.Name.t list) = + let fields, (supers: Typ.Name.t list), methods = match Tenv.lookup tenv interface_name with - | Some {fields; supers} -> + | Some {fields; supers; methods} -> ( CGeneral_utils.append_no_duplicates_fields decl_fields fields - , append_no_duplicates_typ_name decl_supers supers ) + , append_no_duplicates_typ_name decl_supers supers + , methods ) | _ -> - (decl_fields, decl_supers) + (decl_fields, decl_supers, []) in let fields = CGeneral_utils.append_no_duplicates_fields fields fields_sc in let modelled_fields = CField_decl.modelled_field name_info in let all_fields = CGeneral_utils.append_no_duplicates_fields modelled_fields fields in - L.(debug Capture Verbose) "Class %a field:@\n" QualifiedCppName.pp class_name ; - List.iter - ~f:(fun (fn, _, _) -> - L.(debug Capture Verbose) "-----> field: '%s'@\n" (Typ.Fieldname.to_string fn) ) - all_fields ; + let methods = + CGeneral_utils.append_no_duplicates_methods + (ObjcMethod_decl.get_methods interface_name decl_list) + methods + in ignore - (Tenv.mk_struct tenv ~fields:all_fields ~supers ~methods:[] ~annots:Annot.Class.objc + (Tenv.mk_struct tenv ~fields:all_fields ~supers ~methods ~annots:Annot.Class.objc interface_name) ; - L.(debug Capture Verbose) - " >>>Verifying that Typename '%s' is in tenv@\n" - (Typ.Name.to_string interface_name) ; - ( match Tenv.lookup tenv interface_name with - | Some st -> - L.(debug Capture Verbose) - " >>>OK. Found typ='%a'@\n" - (Typ.Struct.pp Pp.text interface_name) - st - | None -> - L.(debug Capture Verbose) " >>>NOT Found!!@\n" ) ; interface_desc @@ -162,12 +147,15 @@ let interface_impl_declaration qual_type_to_sil_type tenv decl = match decl with | ObjCImplementationDecl (decl_info, name_info, decl_list, _, idi) -> let class_name = CAst_utils.get_qualified_name name_info in + let interface_name = Typ.Name.Objc.from_qual_name class_name in L.(debug Capture Verbose) "ADDING: ObjCImplementationDecl for class '%a'@\n" QualifiedCppName.pp class_name ; let _ = add_class_decl qual_type_to_sil_type tenv idi in let class_tn_name = Typ.Name.Objc.from_qual_name class_name in let fields = CField_decl.get_fields qual_type_to_sil_type tenv class_tn_name decl_list in CField_decl.add_missing_fields tenv class_name fields ; + let methods = ObjcMethod_decl.get_methods interface_name decl_list in + ObjcMethod_decl.add_missing_methods tenv class_tn_name methods ; let decl_key = Clang_ast_extend.DeclPtr decl_info.Clang_ast_t.di_pointer in let class_desc = Typ.Tstruct class_tn_name in CAst_utils.update_sil_types_map decl_key class_desc ; diff --git a/infer/src/clang/objcMethod_decl.ml b/infer/src/clang/objcMethod_decl.ml new file mode 100644 index 000000000..6140797dd --- /dev/null +++ b/infer/src/clang/objcMethod_decl.ml @@ -0,0 +1,38 @@ +(* + * 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. + *) +(* Given a list of declarations in an interface returns list of methods *) + +open! IStd + +let get_methods class_typename decl_list = + let open Clang_ast_t in + let get_method list_methods decl = + match decl with + | Clang_ast_t.ObjCMethodDecl (_, ndi, mdi) -> + let method_kind = + Typ.Procname.ObjC_Cpp.objc_method_kind_of_bool mdi.omdi_is_instance_method + in + let method_name = + Typ.Procname.ObjC_Cpp + (Typ.Procname.ObjC_Cpp.make class_typename ndi.ni_name method_kind Typ.NoTemplate) + in + method_name :: list_methods + | _ -> + list_methods + in + List.fold_left ~f:get_method decl_list ~init:[] + + +let add_missing_methods tenv class_tn_name missing_methods = + match Tenv.lookup tenv class_tn_name with + | Some ({methods} as struct_typ) -> + let new_methods = CGeneral_utils.append_no_duplicates_methods methods missing_methods in + ignore (Tenv.mk_struct tenv ~default:struct_typ ~methods:new_methods class_tn_name) + | _ -> + () diff --git a/infer/src/clang/objcMethod_decl.mli b/infer/src/clang/objcMethod_decl.mli new file mode 100644 index 000000000..c4e8acc3f --- /dev/null +++ b/infer/src/clang/objcMethod_decl.mli @@ -0,0 +1,12 @@ +(* + * 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. + *) + +val get_methods : Typ.name -> Clang_ast_t.decl list -> Typ.Procname.t list + +val add_missing_methods : Tenv.t -> Typ.name -> Typ.Procname.t list -> unit