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
master
Dulma Rodriguez 9 years ago committed by facebook-github-bot-5
parent 0bf6333708
commit 742cb4146e

@ -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. *)

@ -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

@ -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 =

@ -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,22 +44,17 @@ 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 (
(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---> 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
)
)
)
"---> 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, _, _) =

@ -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 :

@ -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

@ -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

Loading…
Cancel
Save