From 742cb4146e99d913fbf418ebe42179c5786a2f2a Mon Sep 17 00:00:00 2001 From: Dulma Rodriguez Date: Tue, 15 Dec 2015 06:56:36 -0800 Subject: [PATCH] Remove property of maps Summary: public Remove property of maps and make sure that we add to the tenv the property attributes by folowing the link between the property and the corresponding ivar. Reviewed By: ddino Differential Revision: D2755887 fb-gh-sync-id: beeecaf --- infer/src/clang/cField_decl.ml | 54 ++----- infer/src/clang/cField_decl.mli | 4 - infer/src/clang/cFrontend.ml | 1 - infer/src/clang/cFrontend_utils.ml | 69 +++++--- infer/src/clang/cFrontend_utils.mli | 2 + infer/src/clang/objcProperty_decl.ml | 225 -------------------------- infer/src/clang/objcProperty_decl.mli | 51 ------ 7 files changed, 63 insertions(+), 343 deletions(-) diff --git a/infer/src/clang/cField_decl.ml b/infer/src/clang/cField_decl.ml index cbe1a9777..2b7f85ed4 100644 --- a/infer/src/clang/cField_decl.ml +++ b/infer/src/clang/cField_decl.ml @@ -52,50 +52,26 @@ let build_sil_field type_ptr_to_sil_type tenv field_name type_ptr prop_attribute [({ Sil.class_name = Config.property_attributes; Sil.parameters = prop_atts }, true)] in fname, typ, item_annotations -(* From an ivar look for its property and if it finds it returns its attributes *) -let ivar_property curr_class ivar = - Printing.log_out "Checking if a property is defined for the ivar: '%s'@." - ivar.Clang_ast_t.ni_name; - match ObjcProperty_decl.Property.find_property_name_from_ivar curr_class ivar with - | Some pname' -> - (Printing.log_out "Found property name from ivar: '%s'" pname'.Clang_ast_t.ni_name; - try - let _, atts, _, _, _, _ = ObjcProperty_decl.Property.find_property curr_class pname' in - atts - with Not_found -> - Printing.log_out "Didn't find property for pname '%s'" pname'.Clang_ast_t.ni_name; - []) - | None -> Printing.log_out "No property found for ivar '%s'@." ivar.Clang_ast_t.ni_name; - [] - -let build_sil_field_property type_ptr_to_sil_type curr_class tenv field_name type_ptr att_opt = - let prop_attributes = - match att_opt with - | Some prop_attributes -> prop_attributes - | None -> ivar_property curr_class field_name in - build_sil_field type_ptr_to_sil_type tenv field_name type_ptr prop_attributes - (* Given a list of declarations in an interface returns a list of fields *) let rec get_fields type_ptr_to_sil_type tenv curr_class decl_list = let open Clang_ast_t in + let add_field name_info type_ptr attributes decl_list' = + let fields = get_fields type_ptr_to_sil_type tenv curr_class decl_list' in + let field_tuple = build_sil_field type_ptr_to_sil_type tenv name_info type_ptr attributes in + General_utils.append_no_duplicates_fields [field_tuple] fields in match decl_list with | [] -> [] - | ObjCIvarDecl (decl_info, name_info, type_ptr, field_decl_info, obj_c_ivar_decl_info) :: decl_list' -> - let fields = get_fields type_ptr_to_sil_type tenv curr_class decl_list' in - (* Doing a post visit here. Adding Ivar after all the declaration have been visited so that *) - (* ivar names will be added in the property list. *) - Printing.log_out " ...Adding Instance Variable '%s' @." name_info.Clang_ast_t.ni_name; - let (fname, typ, ia) = - build_sil_field_property type_ptr_to_sil_type curr_class tenv name_info type_ptr None in - Printing.log_out " ...Resulting sil field: (%s) with attributes:@." ((Ident.fieldname_to_string fname) ^":"^(Sil.typ_to_string typ)); - IList.iter (fun (ia', _) -> - IList.iter (fun a -> Printing.log_out " '%s'@." a) ia'.Sil.parameters) ia; - (fname, typ, ia):: fields - | ObjCPropertyImplDecl (decl_info, property_impl_decl_info):: decl_list' -> - let property_fields_decl = - ObjcProperty_decl.prepare_dynamic_property curr_class decl_info property_impl_decl_info in - get_fields type_ptr_to_sil_type tenv curr_class (property_fields_decl @ decl_list') - | _ :: decl_list' -> get_fields type_ptr_to_sil_type tenv curr_class decl_list' + | ObjCPropertyDecl (_, named_decl_info, obj_c_property_decl_info) :: decl_list' -> + (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 (_, name_info, type_ptr, _, _)) -> + let attributes = obj_c_property_decl_info.Clang_ast_t.opdi_property_attributes in + add_field name_info type_ptr attributes decl_list' + | _ -> get_fields type_ptr_to_sil_type tenv curr_class decl_list') + | ObjCIvarDecl (_, name_info, type_ptr, _, _) :: decl_list' -> + add_field name_info type_ptr [] decl_list' + | decl :: decl_list' -> + get_fields type_ptr_to_sil_type tenv curr_class decl_list' (* Add potential extra fields defined only in the implementation of the class *) (* to the info given in the interface. Update the tenv accordingly. *) diff --git a/infer/src/clang/cField_decl.mli b/infer/src/clang/cField_decl.mli index 4c9616f19..df7e5255b 100644 --- a/infer/src/clang/cField_decl.mli +++ b/infer/src/clang/cField_decl.mli @@ -23,10 +23,6 @@ val fields_superclass : Sil.tenv -> Clang_ast_t.obj_c_interface_decl_info -> fie val build_sil_field : Ast_utils.type_ptr_to_sil_type -> Sil.tenv -> Clang_ast_t.named_decl_info -> Clang_ast_t.type_ptr -> Clang_ast_t.property_attribute list -> field_type -val build_sil_field_property : Ast_utils.type_ptr_to_sil_type -> CContext.curr_class -> Sil.tenv -> - Clang_ast_t.named_decl_info -> Clang_ast_t.type_ptr -> Clang_ast_t.property_attribute list option - -> field_type - val add_missing_fields : Sil.tenv -> string -> field_type list -> unit val is_ivar_atomic : Ident.fieldname -> Sil.struct_fields -> bool diff --git a/infer/src/clang/cFrontend.ml b/infer/src/clang/cFrontend.ml index 7229dd495..2d7d4fe7c 100644 --- a/infer/src/clang/cFrontend.ml +++ b/infer/src/clang/cFrontend.ml @@ -134,7 +134,6 @@ let init_global_state source_file = DB.Results_dir.init (); Ident.NameGenerator.reset (); CFrontend_config.global_translation_unit_decls := []; - ObjcProperty_decl.reset_property_table (); CFrontend_utils.General_utils.reset_block_counter () let do_source_file source_file ast = diff --git a/infer/src/clang/cFrontend_utils.ml b/infer/src/clang/cFrontend_utils.ml index 9eb44dce6..b3fddfd2b 100644 --- a/infer/src/clang/cFrontend_utils.ml +++ b/infer/src/clang/cFrontend_utils.ml @@ -25,6 +25,15 @@ struct let pp = if !CFrontend_config.debug_mode then Format.fprintf else Format.ifprintf in pp Format.err_formatter fmt + + let annotation_to_string (annotation, _) = + "< " ^ annotation.Sil.class_name ^ " : " ^ + (IList.to_string (fun x -> x) annotation.Sil.parameters) ^ " >" + + let field_to_string (fieldname, typ, annotation) = + (Ident.fieldname_to_string fieldname) ^ " " ^ + (Sil.typ_to_string typ) ^ (IList.to_string annotation_to_string annotation) + let log_stats fmt = let pp = if !CFrontend_config.stats_mode || !CFrontend_config.debug_mode @@ -35,23 +44,18 @@ struct Sil.tenv_iter (fun typname typ -> match typname with | Sil.TN_csu (Sil.Class, _) | Sil.TN_csu (Sil.Protocol, _) -> - (match typ with (Sil.Tstruct (fields, static_fields, _, cls, super_classes, methods, iann)) -> - (print_endline ( - (Sil.typename_to_string typname)^"\n"^ - "---> superclass and protocols "^(IList.to_string (fun (csu, x) -> - let nsu = Sil.TN_csu (csu, x) in - "\t"^(Sil.typename_to_string nsu)^"\n") super_classes)^ - "---> methods "^(IList.to_string (fun x ->"\t"^(Procname.to_string x)^"\n") methods)^" "^ - "\t---> static fields "^(IList.to_string (fun (fieldname, typ, _) -> - "\t "^(Ident.fieldname_to_string fieldname)^" "^ - (Sil.typ_to_string typ)^"\n") static_fields)^ - "\t---> fields "^(IList.to_string (fun (fieldname, typ, _) -> - "\t "^(Ident.fieldname_to_string fieldname)^" "^ - (Sil.typ_to_string typ)^"\n") fields - ) - ) - ) - | _ -> ()) + (match typ with + | Sil.Tstruct (fields, _, _, cls, super_classes, methods, iann) -> + print_endline ( + (Sil.typename_to_string typname) ^ "\n"^ + "---> superclass and protocols " ^ (IList.to_string (fun (csu, x) -> + let nsu = Sil.TN_csu (csu, x) in + "\t" ^ (Sil.typename_to_string nsu) ^ "\n") super_classes) ^ + "---> methods " ^ + (IList.to_string (fun x ->"\t" ^ (Procname.to_string x) ^ "\n") methods) + ^ " " ^ + "\t---> fields " ^ (IList.to_string field_to_string fields) ^ "\n") + | _ -> ()) | _ -> () ) tenv @@ -442,12 +446,31 @@ struct let eq (e1, t1) (e2, t2) = (Sil.exp_equal e1 e2) && (Sil.typ_equal t1 t2) in append_no_duplicates eq list1 list2 - let append_no_duplicates_fields list1 list2 = - let field_eq (n1, t1, a1) (n2, t2, a2) = - match Ident.fieldname_equal n1 n2, Sil.typ_equal t1 t2, Sil.item_annotation_compare a1 a2 with - | true, true, _ -> true - | _, _, _ -> false in - append_no_duplicates field_eq list1 list2 + + let append_no_duplicates_annotations list1 list2 = + let eq (annot1, _) (annot2, _) = annot1.Sil.class_name = annot2.Sil.class_name in + append_no_duplicates eq list1 list2 + + let add_no_duplicates_fields field_tuple l = + let rec replace_field field_tuple l found = + match field_tuple, l with + | (field, typ, annot), ((old_field, old_typ, old_annot) as old_field_tuple :: rest) -> + let ret_list, ret_found = replace_field field_tuple rest found in + if Ident.fieldname_equal field old_field && Sil.typ_equal typ old_typ then + let annotations = append_no_duplicates_annotations annot old_annot in + (field, typ, annotations) :: ret_list, true + else old_field_tuple :: ret_list, ret_found + | _, [] -> [], found in + let new_list, found = replace_field field_tuple l false in + if found then new_list + else field_tuple :: l + + let rec append_no_duplicates_fields list1 list2 = + match list1 with + | field_tuple :: rest -> + let updated_list2 = append_no_duplicates_fields rest list2 in + add_no_duplicates_fields field_tuple updated_list2 + | [] -> list2 let sort_fields fields = let compare (name1, _, _) (name2, _, _) = diff --git a/infer/src/clang/cFrontend_utils.mli b/infer/src/clang/cFrontend_utils.mli index 5d92d2a39..d2f0bcf5f 100644 --- a/infer/src/clang/cFrontend_utils.mli +++ b/infer/src/clang/cFrontend_utils.mli @@ -30,6 +30,8 @@ sig val print_nodes : Cfg.Node.t list -> unit val instrs_to_string : Sil.instr list -> string + + val field_to_string : Ident.fieldname * Sil.typ * Sil.item_annotation -> string end module Ast_utils : diff --git a/infer/src/clang/objcProperty_decl.ml b/infer/src/clang/objcProperty_decl.ml index 882ff6de3..409b9b4d3 100644 --- a/infer/src/clang/objcProperty_decl.ml +++ b/infer/src/clang/objcProperty_decl.ml @@ -18,239 +18,15 @@ open Utils open CFrontend_utils -module L = Logging - -open CContext - -type prop_getter_setter = string * (Clang_ast_t.decl * bool) option - -(** For each property, we save the getter and the setter method declarations (no implementation). *) -(** A property type is a tuple: *) -(** (type_ptr, property attributes, decl_info, (getter_name, getter), (setter_name, setter), ivar name) *) -type property_type = Clang_ast_t.type_ptr * Clang_ast_t.property_attribute list * - Clang_ast_t.decl_info * prop_getter_setter * prop_getter_setter * - Clang_ast_t.named_decl_info option - -(** A table that record the property defined in the interface and its getter/setter. *) -(** This info used later on in the implementation if the getter/setter need to automatically *) -(** synthesized*) -module type PropertySig = -sig - - type t - - type property_key = (CContext.curr_class * Clang_ast_t.named_decl_info) - - val property_key_to_string : property_key -> string - - val reset_property_table: unit -> unit - - val find_property : CContext.curr_class -> Clang_ast_t.named_decl_info -> property_type - - val find_properties_class : CContext.curr_class -> - (Clang_ast_t.named_decl_info * property_type) list - - val is_mem_property : property_key -> bool - - val replace_property : property_key -> property_type -> unit - - val add_property : property_key -> Clang_ast_t.type_ptr -> Clang_ast_t.obj_c_property_decl_info -> - Clang_ast_t.decl_info -> unit - - val print_property_table : unit -> unit - - val find_property_name_from_ivar : CContext.curr_class -> Clang_ast_t.named_decl_info -> - Clang_ast_t.named_decl_info option -end -module Property: PropertySig = -struct - - type property_key = (CContext.curr_class * Clang_ast_t.named_decl_info) - - let property_key_to_string (curr_class, property_name) = - ((CContext.curr_class_to_string curr_class) ^ "-" ^ property_name.Clang_ast_t.ni_name) - - (** Hash table to implement error logs *) - module PropertyTableHash = Hashtbl.Make (struct - - type t = property_key - - let hash (curr_class, pname) = (CContext.curr_class_hash curr_class) + Hashtbl.hash pname - - let equal (curr_class1, property_name1) (curr_class2, property_name2) = - CContext.curr_class_equal curr_class1 curr_class2 && - (String.compare property_name1.Clang_ast_t.ni_name property_name2.Clang_ast_t.ni_name = 0) - - end) - - type t = property_type PropertyTableHash.t - - let property_table : t = PropertyTableHash.create 100 - - let reset_property_table () = - PropertyTableHash.reset property_table - - let rec find_property curr_class property_name = - try PropertyTableHash.find property_table (curr_class, property_name) - with Not_found -> - match curr_class with - | ContextCls (name, _, protocols) -> - let res_opt = IList.fold_right - (fun protocol found_procname_opt -> - match found_procname_opt with - | Some found_procname -> Some found_procname - | None -> - Some (find_property (ContextProtocol protocol) property_name)) protocols None in - (match res_opt with - | Some res -> res - | None -> raise Not_found) - | _ -> raise Not_found - - let find_property_name_from_ivar curr_class ivar = - let res = ref None in - PropertyTableHash.iter (fun (cl, pname) (_, _, _, _, _, ivar') -> - match ivar' with - | Some s when (CContext.curr_class_equal curr_class cl) && s = ivar -> res:= Some pname - | _ -> ()) property_table; - !res - - let is_mem_property property = - PropertyTableHash.mem property_table property - - let replace_property property = - PropertyTableHash.replace property_table property - - let print_property_table () = - let print_item key (tp, attributes, decl_info, getter, setter, ivar) = - let getter_str = - match getter with - | getter_name, Some (Clang_ast_t.ObjCMethodDecl _, defined1) -> - getter_name - | _ -> "" in - let setter_str = match setter with - | setter_name, Some (Clang_ast_t.ObjCMethodDecl _, defined2) -> - setter_name - | _ -> "" in - Logging.out "Property item %s accessors %s and %s \n" - (property_key_to_string key) getter_str setter_str in - PropertyTableHash.iter print_item property_table - - let find_properties_class curr_class = - let find_properties (curr_class', property_name) property_type properties = - if (CContext.curr_class_equal curr_class' curr_class) then - (property_name, property_type):: properties - else properties in - PropertyTableHash.fold find_properties property_table [] - - let add_property (curr_class, property_name) tp ocpdi decl_info = - let key = (curr_class, property_name) in - let attributes = ocpdi.Clang_ast_t.opdi_property_attributes in - let getter = Ast_utils.get_decl_opt_with_decl_ref ocpdi.Clang_ast_t.opdi_getter_method in - let setter = Ast_utils.get_decl_opt_with_decl_ref ocpdi.Clang_ast_t.opdi_setter_method in - let getter_decl = - match getter with - | Some (Clang_ast_t.ObjCMethodDecl (_, getter_name, getter_ocmdi) as getter_d) -> - getter_name.Clang_ast_t.ni_name, Some (getter_d, false) - | _ -> "", None in (* TODO refactor property map so that this is not needed t9330897 *) - let setter_decl = - match setter with - | Some (Clang_ast_t.ObjCMethodDecl (_, setter_name, setter_ocmdi) as setter_d) -> - setter_name.Clang_ast_t.ni_name, Some (setter_d, false) - | _ -> "", None in (* TODO refactor property map so that this is not needed t9330897 *) - PropertyTableHash.add property_table key - (tp, attributes, decl_info, getter_decl, setter_decl, None) -end - -let reset_property_table = Property.reset_property_table - -let print_property_table () = Property.print_property_table () - -let find_properties_class = Property.find_properties_class - -let upgrade_property_accessor property_key property_type meth_decl new_defined is_getter = - let is_defined meth_decl = - match meth_decl with - | Some (method_decl, was_defined) -> new_defined || was_defined - | None -> new_defined in - match property_type with - | tp, attributes, decl_info, (gname, getter), (sname, setter), ivar -> - if is_getter then - let defined = is_defined getter in - Property.replace_property property_key - (tp, attributes, decl_info, (gname, Some (meth_decl, defined)), (sname, setter), ivar) - else let defined = is_defined setter in - Property.replace_property property_key - (tp, attributes, decl_info, (gname, getter), (sname, Some (meth_decl, defined)), ivar) - -let check_for_property curr_class method_name meth_decl body = - let defined = Option.is_some body in - let properties_class = find_properties_class curr_class in - let check_property_accessor curr_class method_name is_getter = - let method_is_getter (property_name, property_type) = - match property_type with (_, _, _, (getter_name, _), (setter_name, _), _) -> - let found = - if is_getter then (method_name = getter_name) - else (method_name = setter_name) in - if found then - (Printing.log_out " Found property '%s' defined in property table\n" - (Property.property_key_to_string (curr_class, property_name)); - upgrade_property_accessor - (curr_class, property_name) property_type meth_decl defined is_getter) in - IList.iter method_is_getter properties_class in - check_property_accessor curr_class method_name true; - check_property_accessor curr_class method_name false - let is_strong_property obj_c_property_decl_info = let attrs = obj_c_property_decl_info.Clang_ast_t.opdi_property_attributes in IList.exists (fun a -> match a with | `Strong -> true | _ -> false) attrs -let prepare_dynamic_property curr_class decl_info property_impl_decl_info = - let pname = Ast_utils.property_name property_impl_decl_info in - let prop_name = pname.Clang_ast_t.ni_name in - let res = (try - let tp', atts, di, getter, setter, _ = Property.find_property curr_class pname in - let ivar = (match property_impl_decl_info.Clang_ast_t.opidi_ivar_decl with - | Some dr -> (match dr.Clang_ast_t.dr_name with - | Some name_info -> name_info - | None -> assert false) - | None -> Ast_utils.generated_ivar_name pname) in - (* update property info with proper ivar name *) - Property.replace_property (curr_class, pname) (tp', atts, di, getter, setter, Some ivar); - Printing.log_out "Updated property table by adding ivar name for property '%s'\n" - prop_name; - Some (tp', ivar) - with Not_found -> - L.err "Property '%s' not found in the table. Ivar not updated.@." prop_name; - None) in - match property_impl_decl_info.Clang_ast_t.opidi_implementation, res with - | `Dynamic, Some (tp, ivar) -> - (* For Dynamic property we need to create the ObjCIvarDecl which specifies*) - (* the field of the property. In case of Dynamic this is not in the AST.*) - (* Once created the ObjCIvarDecl then we treat the property as synthesized *) - [Ast_expressions.make_objc_ivar_decl decl_info tp property_impl_decl_info ivar] - | _ -> - (* No names of fields/method to collect from ObjCPropertyImplDecl when Synthesized *) - [] - -let add_properties_to_table curr_class decl_list = - let add_property_to_table dec = - match dec with - | Clang_ast_t.ObjCPropertyDecl(decl_info, name_info, pdi) -> - (* Property declaration register the property on the property table to be *) - let pname = name_info.Clang_ast_t.ni_name in - Printing.log_out "ADDING: ObjCPropertyDecl for property '%s' " pname; - Printing.log_out " pointer= '%s' \n" decl_info.Clang_ast_t.di_pointer; - Property.add_property (curr_class, name_info) pdi.Clang_ast_t.opdi_type_ptr - pdi decl_info; - | _ -> () in - IList.iter add_property_to_table decl_list - (* Given a list of declarations in an interface returns list of methods *) let get_methods curr_class decl_list = let class_name = CContext.get_curr_class_name curr_class in - add_properties_to_table curr_class decl_list; let get_method decl list_methods = match decl with | Clang_ast_t.ObjCMethodDecl (decl_info, name_info, method_decl_info) -> @@ -258,7 +34,6 @@ let get_methods curr_class decl_list = let method_kind = Procname.objc_method_kind_of_bool is_instance in let method_name = name_info.Clang_ast_t.ni_name in Printing.log_out " ...Adding Method '%s' \n" (class_name^"_"^method_name); - let _ = check_for_property curr_class method_name decl method_decl_info.Clang_ast_t.omdi_body in let meth_name = General_utils.mk_procname_from_objc_method class_name method_name method_kind in meth_name:: list_methods | _ -> list_methods in diff --git a/infer/src/clang/objcProperty_decl.mli b/infer/src/clang/objcProperty_decl.mli index d34e4feaf..bc2b60264 100644 --- a/infer/src/clang/objcProperty_decl.mli +++ b/infer/src/clang/objcProperty_decl.mli @@ -7,61 +7,10 @@ * of patent rights can be found in the PATENTS file in the same directory. *) -type prop_getter_setter = string * (Clang_ast_t.decl * bool) option - -(** For each property, we save the getter and the setter method declarations (no implementation). *) -(** A property type is a tuple: *) -(** (type_ptr, property attributes, decl_info, (getter_name, getter), (setter_name, setter), ivar name ) *) -type property_type = Clang_ast_t.type_ptr * Clang_ast_t.property_attribute list * - Clang_ast_t.decl_info * prop_getter_setter * prop_getter_setter * - Clang_ast_t.named_decl_info option - -module type PropertySig = -sig - - type t - - type property_key = (CContext.curr_class * Clang_ast_t.named_decl_info) - - val property_key_to_string : property_key -> string - - val reset_property_table: unit -> unit - - val find_property : CContext.curr_class -> Clang_ast_t.named_decl_info -> property_type - - val find_properties_class : CContext.curr_class -> - (Clang_ast_t.named_decl_info * property_type) list - - val is_mem_property : property_key -> bool - - val replace_property : property_key -> property_type -> unit - - val add_property : property_key -> Clang_ast_t.type_ptr -> Clang_ast_t.obj_c_property_decl_info -> - Clang_ast_t.decl_info -> unit - - val print_property_table : unit -> unit - - val find_property_name_from_ivar : CContext.curr_class -> Clang_ast_t.named_decl_info -> - Clang_ast_t.named_decl_info option - -end - -module Property: PropertySig - (** Process properties by creating their getters and setters in the case that they need to be syntethized *) (** or in the case of dynamic. *) -val prepare_dynamic_property : CContext.curr_class -> Clang_ast_t.decl_info -> - Clang_ast_t.obj_c_property_impl_decl_info -> Clang_ast_t.decl list - val get_methods : CContext.curr_class -> Clang_ast_t.decl list -> Procname.t list -val reset_property_table : unit -> unit - -val print_property_table : unit -> unit - -val find_properties_class : CContext.curr_class -> - (Clang_ast_t.named_decl_info * property_type) list - (* Given a property type returns whether the property is strong *) val is_strong_property : Clang_ast_t.obj_c_property_decl_info -> bool