[clang] Adding getters and setters for all the methods

master
Dulma Rodriguez 9 years ago
parent c9f07e31e3
commit d7655a087e

@ -724,6 +724,12 @@ let get_all_procs cfg =
let get_defined_procs cfg = let get_defined_procs cfg =
list_filter Procdesc.is_defined (get_all_procs cfg) list_filter Procdesc.is_defined (get_all_procs cfg)
(** Get the objc procedures whose body is generated *)
let get_objc_generated_procs cfg =
list_filter (
fun procdesc ->
(Procdesc.get_attributes procdesc).Sil.is_generated) (get_all_procs cfg)
(** get the function names which should be analyzed before the other ones *) (** get the function names which should be analyzed before the other ones *)
let get_priority_procnames cfg = let get_priority_procnames cfg =
cfg.Node.priority_set cfg.Node.priority_set

@ -297,6 +297,9 @@ val get_all_procs : cfg -> Procdesc.t list
(** Get the procedures whose body is defined in this cfg *) (** Get the procedures whose body is defined in this cfg *)
val get_defined_procs : cfg -> Procdesc.t list val get_defined_procs : cfg -> Procdesc.t list
(** Get the objc procedures whose body is generated *)
val get_objc_generated_procs : cfg -> Procdesc.t list
(** get the function names which should be analyzed before the other ones *) (** get the function names which should be analyzed before the other ones *)
val get_priority_procnames : cfg -> Procname.Set.t val get_priority_procnames : cfg -> Procname.Set.t

@ -140,6 +140,12 @@ let node_defined (g: t) n =
info.defined info.defined
with Not_found -> false with Not_found -> false
let node_set_defined (g: t) n defined =
try
let info = Procname.Hash.find g.node_map n in
info.defined <- defined
with Not_found -> ()
let add_edge g nfrom nto = let add_edge g nfrom nto =
_add_node g nfrom false; _add_node g nfrom false;
_add_node g nto false; _add_node g nto false;

@ -50,3 +50,4 @@ val node_defined : t -> Procname.t -> bool (** Returns true if the node is defin
val restrict_defined : t -> Procname.Set.t option -> unit (** if not None, restrict defined nodes to the given set *) val restrict_defined : t -> Procname.Set.t option -> unit (** if not None, restrict defined nodes to the given set *)
val save_call_graph_dotty : DB.filename option -> (Procname.t -> 'a list) -> t -> unit (** Print the current call graph as a dotty file. If the filename is [None], use the current file dir inside the DB dir. *) val save_call_graph_dotty : DB.filename option -> (Procname.t -> 'a list) -> t -> unit (** Print the current call graph as a dotty file. If the filename is [None], use the current file dir inside the DB dir. *)
val store_to_file : DB.filename -> t -> unit (** Save a call graph into a file *) val store_to_file : DB.filename -> t -> unit (** Save a call graph into a file *)
val node_set_defined : t -> Procname.t -> bool -> unit (** Change the defined flag of a node *)

@ -903,10 +903,12 @@ let pp_cfgnodelabel fmt (n : Cfg.Node.t) =
let pp_label fmt n = let pp_label fmt n =
match Cfg.Node.get_kind n with match Cfg.Node.get_kind n with
| Cfg.Node.Start_node (pdesc) -> | Cfg.Node.Start_node (pdesc) ->
let gen = if (Cfg.Procdesc.get_attributes pdesc).Sil.is_generated then " (generated)" else "" in
(* let def = if Cfg.Procdesc.is_defined pdesc then "defined" else "declared" in *) (* let def = if Cfg.Procdesc.is_defined pdesc then "defined" else "declared" in *)
(* Format.fprintf fmt "Start %a (%s)" pp_id (Procname.to_string (Cfg.Procdesc.get_proc_name pdesc)) def *) (* Format.fprintf fmt "Start %a (%s)" pp_id (Procname.to_string (Cfg.Procdesc.get_proc_name pdesc)) def *)
Format.fprintf fmt "Start %s\\nFormals: %a\\nLocals: %a" Format.fprintf fmt "Start %s%s\\nFormals: %a\\nLocals: %a"
(Procname.to_string (Cfg.Procdesc.get_proc_name pdesc)) (Procname.to_string (Cfg.Procdesc.get_proc_name pdesc))
gen
pp_etlist (Cfg.Procdesc.get_formals pdesc) pp_etlist (Cfg.Procdesc.get_formals pdesc)
pp_local_list (Cfg.Procdesc.get_locals pdesc); pp_local_list (Cfg.Procdesc.get_locals pdesc);
if list_length (Cfg.Procdesc.get_captured pdesc) <> 0 then if list_length (Cfg.Procdesc.get_captured pdesc) <> 0 then

@ -736,12 +736,15 @@ let analyzer_err_name = "analyzer_err"
let () = let () =
let () = let () =
match !cluster_cmdline with match !cluster_cmdline with
| None -> L.stdout "Starting analysis (Infer version %s)@." Version.versionString; | None ->
if !Sil.curr_language = Sil.C_CPP then
Objc_preanal.do_objc_preanalysis ();
L.stdout "Starting analysis (Infer version %s)@." Version.versionString;
| Some clname -> L.stdout "Cluster %s@." clname in | Some clname -> L.stdout "Cluster %s@." clname in
RegisterCheckers.register (); RegisterCheckers.register ();
Facebook.register_checkers (); Facebook.register_checkers ();
if !allow_specs_cleanup = true && !incremental_mode = ANALYZE_ALL && !cluster_cmdline = None then if !allow_specs_cleanup = true && !incremental_mode = ANALYZE_ALL && !cluster_cmdline = None then
DB.Results_dir.clean_specs_dir (); DB.Results_dir.clean_specs_dir ();
let log_dir = DB.filename_to_string (DB.Results_dir.path_to_filename DB.Results_dir.Abs_root [log_dir_name]) in let log_dir = DB.filename_to_string (DB.Results_dir.path_to_filename DB.Results_dir.Abs_root [log_dir_name]) in

@ -0,0 +1,102 @@
(*
* Copyright (c) 2015 - 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.
*)
open Utils
type procedure_type =
| ALL
| DEFINED
| OBJC_GENERATED
let print_map procname_map =
Procname.Hash.iter
(fun pname redefined ->
print_endline ((Procname.to_string pname)^" "^(string_of_bool redefined)))
procname_map
let process_all_cfgs process_function default_value =
let source_dirs = DB.find_source_dirs () in
let process_dir source_dir value =
let cfg_name = DB.source_dir_get_internal_file source_dir ".cfg" in
let cfg_opt = Cfg.load_cfg_from_file cfg_name in
match cfg_opt with
| None -> value
| Some cfg -> process_function cfg source_dir in
list_fold_right process_dir source_dirs default_value
let process_procedures process_function default_value procedure_type =
let process_cfg_procedures cfg source_dir =
let procdescs =
match procedure_type with
| DEFINED -> Cfg.get_defined_procs cfg
| ALL -> Cfg.get_all_procs cfg
| OBJC_GENERATED -> Cfg.get_objc_generated_procs cfg in
list_fold_right (process_function cfg source_dir) procdescs default_value in
process_all_cfgs process_cfg_procedures default_value
let process_all_procedures process_function default_value =
process_procedures process_function default_value ALL
let process_defined_procedures process_function default_value =
process_procedures process_function default_value DEFINED
let process_objc_generated_procedures process_function default_value =
process_procedures process_function default_value OBJC_GENERATED
(* first run to fill the map. The bool that indicates whether the method *)
(* has a real implementation is false by default *)
let fill_generated_proc_map generated_proc_map =
let add_generated_pname_to_map cfg source_dir procdesc () =
let pname = Cfg.Procdesc.get_proc_name procdesc in
Procname.Hash.replace generated_proc_map pname false in
process_objc_generated_procedures add_generated_pname_to_map ()
(* second run to update the map. Now we check whether there is a real *)
(* implementation for the generated methods *)
let update_generate_proc_map generated_proc_map =
let update_generated_pname_to_map cfg source_dir procdesc () =
let cfg_pname = Cfg.Procdesc.get_proc_name procdesc in
if not (Cfg.Procdesc.get_attributes procdesc).Sil.is_generated then
try ignore(Procname.Hash.find generated_proc_map cfg_pname);
Procname.Hash.replace generated_proc_map cfg_pname true
with Not_found -> () in
process_defined_procedures update_generated_pname_to_map ()
(* third run to change the cfgs according to the map. The generated methods *)
(* that have implementations get deleted. *)
let update_cfgs generated_proc_map =
let update_cfg cfg source_dir =
let generated_procs = Cfg.get_objc_generated_procs cfg in
let cfg_name = DB.source_dir_get_internal_file source_dir ".cfg" in
let cg_name = DB.source_dir_get_internal_file source_dir ".cg" in
let cg_opt = Cg.load_from_file cg_name in
match cg_opt with
| None -> assert false
| Some cg ->
let update_cfg_procdesc procdesc need_updating =
let pname = Cfg.Procdesc.get_proc_name procdesc in
let is_redefined =
try Procname.Hash.find generated_proc_map pname
with Not_found -> assert false in
if is_redefined then
(Cfg.Procdesc.remove cfg pname true;
Cg.node_set_defined cg pname false;
true)
else need_updating in
let need_updating = list_fold_right update_cfg_procdesc generated_procs false in
if need_updating then
(Cfg.store_cfg_to_file cfg_name false cfg;
Cg.store_to_file cg_name cg) in
process_all_cfgs update_cfg ()
let do_objc_preanalysis () =
let generated_proc_map = Procname.Hash.create 100 in
fill_generated_proc_map generated_proc_map;
update_generate_proc_map generated_proc_map;
update_cfgs generated_proc_map

@ -0,0 +1,10 @@
(*
* Copyright (c) 2015 - 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 do_objc_preanalysis : unit -> unit

@ -178,6 +178,12 @@ let c_method_replace_class t class_name =
| C_METHOD osig -> C_METHOD { osig with class_name = class_name } | C_METHOD osig -> C_METHOD { osig with class_name = class_name }
| _ -> assert false | _ -> assert false
(** Get the class name of a Objective-C/C++ procedure name. *)
let c_get_class t =
match t with
| C_METHOD osig -> osig.class_name
| _ -> assert false
(** Return the package.classname of a java procname. *) (** Return the package.classname of a java procname. *)
let java_get_class = function let java_get_class = function
| JAVA j -> java_type_to_string j.classname VERBOSE | JAVA j -> java_type_to_string j.classname VERBOSE
@ -321,12 +327,10 @@ let is_constructor = function
| C_METHOD name -> Utils.string_is_prefix "init" name.method_name | C_METHOD name -> Utils.string_is_prefix "init" name.method_name
| _ -> false | _ -> false
let java_is_close = function let java_is_close = function
| JAVA js -> js.methodname = "close" | JAVA js -> js.methodname = "close"
| _ -> false | _ -> false
(** [is_class_initializer pname] returns true if [pname] is a class initializer *) (** [is_class_initializer pname] returns true if [pname] is a class initializer *)
let is_class_initializer = function let is_class_initializer = function
| JAVA js -> js.methodname = "<clinit>" | JAVA js -> js.methodname = "<clinit>"

@ -63,6 +63,9 @@ val java_replace_return_type : t -> java_type -> t
(** Replace the class name of an Objective-C procedure name. *) (** Replace the class name of an Objective-C procedure name. *)
val c_method_replace_class : t -> string -> t val c_method_replace_class : t -> string -> t
(** Get the class name of a Objective-C/C++ procedure name. *)
val c_get_class : t -> string
(** Return the class name of a java procedure name. *) (** Return the class name of a java procedure name. *)
val java_get_class : t -> string val java_get_class : t -> string

@ -51,6 +51,7 @@ type proc_attributes =
language : language; language : language;
func_attributes : func_attribute list; func_attributes : func_attribute list;
method_annotation : method_annotation; method_annotation : method_annotation;
is_generated : bool;
} }
let copy_proc_attributes pa = let copy_proc_attributes pa =
@ -64,6 +65,7 @@ let copy_proc_attributes pa =
language = pa.language; language = pa.language;
func_attributes = pa.func_attributes; func_attributes = pa.func_attributes;
method_annotation = pa.method_annotation; method_annotation = pa.method_annotation;
is_generated = pa.is_generated;
} }
(** Compare function for annotations. *) (** Compare function for annotations. *)

@ -65,6 +65,7 @@ type proc_attributes =
language : language; language : language;
func_attributes : func_attribute list; func_attributes : func_attribute list;
method_annotation : method_annotation; method_annotation : method_annotation;
is_generated : bool;
} }
(** Create a copy of a proc_attributes *) (** Create a copy of a proc_attributes *)

@ -787,6 +787,7 @@ let reset_summary call_graph proc_name loc =
Sil.language = !Sil.curr_language; Sil.language = !Sil.curr_language;
Sil.func_attributes = []; Sil.func_attributes = [];
Sil.method_annotation = Sil.method_annotation_empty; Sil.method_annotation = Sil.method_annotation_empty;
Sil.is_generated = false;
} in } in
init_summary ( init_summary (
proc_name, proc_name,

@ -37,6 +37,20 @@ let dummy_decl_info decl_info =
Clang_ast_t.di_source_range = dummy_source_range (); Clang_ast_t.di_source_range = dummy_source_range ();
} }
let dummy_decl_info_in_curr_file decl_info =
let source_loc = {
sl_file = Some (DB.source_file_to_abs_path !CLocation.current_source_file);
sl_line = None;
sl_column = None
} in {
decl_info with
Clang_ast_t.di_pointer = Ast_utils.get_fresh_pointer ();
Clang_ast_t.di_source_range =
if !CFrontend_config.testing_mode then
decl_info.Clang_ast_t.di_source_range
else (source_loc, source_loc)
}
let empty_decl_info = { let empty_decl_info = {
Clang_ast_t.di_pointer = ""; Clang_ast_t.di_pointer = "";
Clang_ast_t.di_parent_pointer = None; Clang_ast_t.di_parent_pointer = None;
@ -265,16 +279,7 @@ let make_deref_self_field class_decl_opt di qt field_name =
let cast_exp' = ImplicitCastExpr(stmt_info, [ivar_ref_exp], expr_info', cast_exp_info) in let cast_exp' = ImplicitCastExpr(stmt_info, [ivar_ref_exp], expr_info', cast_exp_info) in
cast_exp' cast_exp'
let make_objc_ivar_decl decl_info qt property_impl_decl_info = let make_objc_ivar_decl decl_info qt property_impl_decl_info ivar_name =
let name = Ast_utils.property_name property_impl_decl_info in
let qt = match qt with
| Some qt' -> qt'
| None -> (* a qual_type was not found by the caller, so we try to get it out of property_impl_decl_info *)
(match property_impl_decl_info.Clang_ast_t.opidi_ivar_decl with
| Some decl_ref -> (match decl_ref.Clang_ast_t.dr_qual_type with
| Some qt' -> qt'
| None -> assert false)
| _ -> assert false) in
let field_decl_info = { let field_decl_info = {
Clang_ast_t.fldi_is_mutable = true; Clang_ast_t.fldi_is_mutable = true;
Clang_ast_t.fldi_is_module_private = true; Clang_ast_t.fldi_is_module_private = true;
@ -283,7 +288,7 @@ let make_objc_ivar_decl decl_info qt property_impl_decl_info =
let obj_c_ivar_decl_info = { let obj_c_ivar_decl_info = {
Clang_ast_t.ovdi_is_synthesize = true; (* NOTE: We set true here because we use this definition to synthesize the getter/setter*) Clang_ast_t.ovdi_is_synthesize = true; (* NOTE: We set true here because we use this definition to synthesize the getter/setter*)
Clang_ast_t.ovdi_access_control = `Private } in Clang_ast_t.ovdi_access_control = `Private } in
ObjCIvarDecl(decl_info, make_name_decl name, qt, field_decl_info, obj_c_ivar_decl_info) ObjCIvarDecl(decl_info, make_name_decl ivar_name, qt, field_decl_info, obj_c_ivar_decl_info)
let make_expr_info qt = let make_expr_info qt =
{ {

@ -15,6 +15,8 @@ val dummy_stmt : unit -> stmt
val dummy_decl_info : decl_info -> decl_info val dummy_decl_info : decl_info -> decl_info
val dummy_decl_info_in_curr_file : decl_info -> decl_info
val dummy_source_range : unit -> source_range val dummy_source_range : unit -> source_range
val dummy_stmt_info : unit -> stmt_info val dummy_stmt_info : unit -> stmt_info
@ -23,7 +25,7 @@ val create_qual_type : string -> qual_type
val create_pointer_type : string -> qual_type val create_pointer_type : string -> qual_type
val make_objc_ivar_decl : decl_info -> qual_type option -> obj_c_property_impl_decl_info -> decl val make_objc_ivar_decl : decl_info -> qual_type -> obj_c_property_impl_decl_info -> string -> decl
val make_deref_self_field : string -> decl_info -> qual_type -> string -> stmt val make_deref_self_field : string -> decl_info -> qual_type -> string -> stmt

@ -254,9 +254,11 @@ let get_curr_class_name curr_class =
let curr_class_to_string curr_class = let curr_class_to_string curr_class =
match curr_class with match curr_class with
| ContextCls (name, _, _) -> ("class "^name) | ContextCls (name, superclass, protocols) ->
| ContextCategory (name, cls) -> ("category "^name^" of class "^cls) ("class " ^ name ^ ", superclass: " ^ (Option.default "" superclass) ^
| ContextProtocol name -> ("protocol "^name) ", protocols: " ^ (Utils.list_to_string (fun x -> x) protocols))
| ContextCategory (name, cls) -> ("category " ^ name ^ " of class " ^ cls)
| ContextProtocol name -> ("protocol " ^ name)
| ContextNoCls -> "no class" | ContextNoCls -> "no class"
let curr_class_compare curr_class1 curr_class2 = let curr_class_compare curr_class1 curr_class2 =
@ -290,5 +292,13 @@ let get_qt_curr_class curr_class =
let get_captured_vars context = context.captured_vars let get_captured_vars context = context.captured_vars
let create_curr_class tenv class_name =
let class_tn_name = Sil.TN_csu (Sil.Class, (Mangled.from_string class_name)) in
match Sil.tenv_lookup tenv class_tn_name with
| Some Sil.Tstruct(intf_fields, _, _, _, superclasses, methods, annotation) ->
(let superclasses_names = list_map (fun (_, name) -> Mangled.to_string name) superclasses in
match superclasses_names with
| superclass:: protocols ->
ContextCls (class_name, Some superclass, protocols)
| [] -> ContextCls (class_name, None, []))
| _ -> assert false

@ -75,4 +75,5 @@ val get_tenv : t -> Sil.tenv
val create_context : Sil.tenv -> Cg.t -> Cfg.cfg -> Cfg.Procdesc.t -> val create_context : Sil.tenv -> Cg.t -> Cfg.cfg -> Cfg.Procdesc.t ->
string option -> curr_class -> bool -> (Mangled.t * Sil.typ * bool) list -> bool -> t string option -> curr_class -> bool -> (Mangled.t * Sil.typ * bool) list -> bool -> t
val create_curr_class : Sil.tenv -> string -> curr_class

@ -27,6 +27,7 @@ let create_empty_procdesc () =
Sil.language = Sil.C_CPP; Sil.language = Sil.C_CPP;
Sil.func_attributes = []; Sil.func_attributes = [];
Sil.method_annotation = Sil.method_annotation_empty; Sil.method_annotation = Sil.method_annotation_empty;
Sil.is_generated = false;
} in } in
create { create {
cfg = Cfg.Node.create_cfg (); cfg = Cfg.Node.create_cfg ();

@ -16,6 +16,8 @@ open Clang_ast_t
module L = Logging module L = Logging
type field_type = Ident.fieldname * Sil.typ * (Sil.annotation * bool) list
let rec get_fields_super_classes tenv super_class = let rec get_fields_super_classes tenv super_class =
Printing.log_out " ... Getting fields of superclass '%s'\n" (Sil.typename_to_string super_class); Printing.log_out " ... Getting fields of superclass '%s'\n" (Sil.typename_to_string super_class);
match Sil.tenv_lookup tenv super_class with match Sil.tenv_lookup tenv super_class with
@ -50,14 +52,16 @@ let get_field_www name_field fl =
let rec build_sil_field tenv class_name field_name qual_type prop_atts = let rec build_sil_field tenv class_name field_name qual_type prop_atts =
let annotation_from_type t = let annotation_from_type t =
match t with match t with
| Sil.Tptr(_,Sil.Pk_objc_weak) -> [Config.weak] | Sil.Tptr (_, Sil.Pk_objc_weak) -> [Config.weak]
| Sil.Tptr(_,Sil.Pk_objc_unsafe_unretained) -> [Config.unsafe_unret] | Sil.Tptr (_, Sil.Pk_objc_unsafe_unretained) -> [Config.unsafe_unret]
| _ -> [] in | _ -> [] in
let fname = mk_class_field_name class_name field_name in let fname = mk_class_field_name class_name field_name in
let typ = CTypes_decl.qual_type_to_sil_type tenv qual_type in let typ = CTypes_decl.qual_type_to_sil_type tenv qual_type in
let item_annotations = match prop_atts with let item_annotations = match prop_atts with
| None -> [({ Sil.class_name = Config.ivar_attributes; Sil.parameters = annotation_from_type typ }, true)] | [] ->
| Some atts -> [({ Sil.class_name = Config.property_attributes; Sil.parameters = atts }, true)] in [({ Sil.class_name = Config.ivar_attributes; Sil.parameters = annotation_from_type typ }, true)]
| _ ->
[({ Sil.class_name = Config.property_attributes; Sil.parameters = prop_atts }, true)] in
fname, typ, item_annotations fname, typ, item_annotations
(* From an ivar look for its property and if it finds it returns its attributes *) (* From an ivar look for its property and if it finds it returns its attributes *)
@ -68,17 +72,24 @@ let ivar_property curr_class ivar =
(Printing.log_out "Found property name from ivar: '%s'" pname'; (Printing.log_out "Found property name from ivar: '%s'" pname';
try try
let _, atts, _, _, _, _ = ObjcProperty_decl.Property.find_property curr_class pname' in let _, atts, _, _, _, _ = ObjcProperty_decl.Property.find_property curr_class pname' in
let atts_str = list_map Clang_ast_j.string_of_property_attribute atts in atts
Some atts_str
with Not_found -> with Not_found ->
Printing.log_out "Didn't find property for pname '%s'" pname'; Printing.log_out "Didn't find property for pname '%s'" pname';
None) [])
| None -> Printing.log_out "No property found for ivar '%s'@." ivar; | None -> Printing.log_out "No property found for ivar '%s'@." ivar;
None []
let build_sil_field_property curr_class tenv field_name qual_type prop_attributes_opt =
let class_name = CContext.get_curr_class_name curr_class in
let prop_attributes =
match prop_attributes_opt with
| Some prop_attributes -> prop_attributes
| None -> ivar_property curr_class field_name in
let atts_str = list_map Clang_ast_j.string_of_property_attribute prop_attributes in
build_sil_field tenv class_name field_name qual_type atts_str
(* Given a list of declarations in an interface returns a list of fields *) (* Given a list of declarations in an interface returns a list of fields *)
let rec get_fields tenv curr_class decl_list = let rec get_fields tenv curr_class decl_list =
let class_name = CContext.get_curr_class_name curr_class in
match decl_list with match decl_list with
| [] -> [] | [] -> []
| ObjCIvarDecl(decl_info, name_info, qual_type, field_decl_info, obj_c_ivar_decl_info) :: decl_list' -> | ObjCIvarDecl(decl_info, name_info, qual_type, field_decl_info, obj_c_ivar_decl_info) :: decl_list' ->
@ -87,8 +98,8 @@ let rec get_fields tenv curr_class decl_list =
(* Doing a post visit here. Adding Ivar after all the declaration have been visited so that *) (* 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. *) (* ivar names will be added in the property list. *)
Printing.log_out " ...Adding Instance Variable '%s' @." field_name; Printing.log_out " ...Adding Instance Variable '%s' @." field_name;
let prop_attributes = ivar_property curr_class field_name in let (fname, typ, ia) = build_sil_field_property curr_class tenv field_name qual_type None in
let (fname, typ, ia) = build_sil_field tenv class_name field_name qual_type prop_attributes in
Printing.log_out " ...Resulting sil field: (%s) with attributes:@." ((Ident.fieldname_to_string fname) ^":"^(Sil.typ_to_string typ)); Printing.log_out " ...Resulting sil field: (%s) with attributes:@." ((Ident.fieldname_to_string fname) ^":"^(Sil.typ_to_string typ));
list_iter (fun (ia', _) -> list_iter (fun (ia', _) ->
list_iter (fun a -> Printing.log_out " '%s'@." a) ia'.Sil.parameters) ia; list_iter (fun a -> Printing.log_out " '%s'@." a) ia'.Sil.parameters) ia;
@ -101,3 +112,20 @@ let rec get_fields tenv curr_class decl_list =
| (d : Clang_ast_t.decl):: decl_list' -> | (d : Clang_ast_t.decl):: decl_list' ->
get_fields tenv curr_class decl_list' get_fields 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. *)
let add_missing_fields tenv class_name fields =
let mang_name = Mangled.from_string class_name in
let class_tn_name = Sil.TN_csu (Sil.Class, mang_name) in
match Sil.tenv_lookup tenv class_tn_name with
| Some Sil.Tstruct(intf_fields, _, _, _, superclass, methods, annotation) ->
let new_fields = append_no_duplicates_fields fields intf_fields in
let new_fields = CFrontend_utils.General_utils.sort_fields new_fields in
let class_type_info =
Sil.Tstruct (
new_fields, [], Sil.Class, Some mang_name, superclass, methods, annotation
) in
Printing.log_out " Updating info for class '%s' in tenv\n" class_name;
Sil.tenv_add tenv class_tn_name class_type_info
| _ -> assert false

@ -9,8 +9,17 @@
(** Utility module to retrieve fields of structs of classes *) (** Utility module to retrieve fields of structs of classes *)
val get_fields : Sil.tenv -> CContext.curr_class -> Clang_ast_t.decl list ->
(Ident.fieldname * Sil.typ * Sil.item_annotation) list
val fields_superclass : Sil.tenv -> Clang_ast_t.obj_c_interface_decl_info -> val fields_superclass : Sil.tenv -> Clang_ast_t.obj_c_interface_decl_info ->
(Ident.fieldname * Sil.typ * Sil.item_annotation) list (Ident.fieldname * Sil.typ * Sil.item_annotation) list
type field_type = Ident.fieldname * Sil.typ * (Sil.annotation * bool) list
val get_fields : Sil.tenv -> CContext.curr_class -> Clang_ast_t.decl list -> field_type list
val fields_superclass : Sil.tenv -> Clang_ast_t.obj_c_interface_decl_info -> field_type list
val build_sil_field_property : CContext.curr_class -> Sil.tenv -> string -> Clang_ast_t.qual_type ->
Clang_ast_t.property_attribute list option -> field_type
val add_missing_fields : Sil.tenv -> string -> field_type list -> unit

@ -144,4 +144,6 @@ let objects = "objects"
let ns_array_ptr = "NSArray *" let ns_array_ptr = "NSArray *"
let enumerateObjectsUsingBlock = "enumerateObjectsUsingBlock:" let enumerateObjectsUsingBlock = "enumerateObjectsUsingBlock:"
let generated_suffix = "*generated"

@ -141,4 +141,6 @@ val objects : string
val ns_array_ptr : string val ns_array_ptr : string
val enumerateObjectsUsingBlock : string val enumerateObjectsUsingBlock : string
val generated_suffix : string

@ -156,6 +156,9 @@ struct
| _ -> no_property_name) | _ -> no_property_name)
| None -> no_property_name | None -> no_property_name
let generated_ivar_name property_name =
"_"^property_name
let property_attribute_compare att1 att2 = let property_attribute_compare att1 att2 =
match att1, att2 with match att1, att2 with
`Readonly, `Readonly -> 0 `Readonly, `Readonly -> 0
@ -211,11 +214,10 @@ struct
attribute = `Copy attribute = `Copy
| _ -> false | _ -> false
let name_opt_of_name_info_opt name_info_opt =
let name_opt_of_name_info_opt name_info_opt = match name_info_opt with
match name_info_opt with | Some name_info -> Some name_info.Clang_ast_t.ni_name
| Some name_info -> Some name_info.Clang_ast_t.ni_name | None -> None
| None -> None
let rec getter_attribute_opt attributes = let rec getter_attribute_opt attributes =
match attributes with match attributes with
@ -251,6 +253,11 @@ struct
| Some qt -> Some qt | Some qt -> Some qt
| None -> None | None -> None
let is_generated name_info =
match name_info.Clang_ast_t.ni_qual_name with
| generated:: rest -> generated = CFrontend_config.generated_suffix
| _ -> false
end end
(* Global counter for anonymous block*) (* Global counter for anonymous block*)

@ -51,6 +51,8 @@ sig
val property_attribute_compare : property_attribute -> property_attribute -> int val property_attribute_compare : property_attribute -> property_attribute -> int
val generated_ivar_name : string -> string
val property_attribute_eq : property_attribute -> property_attribute -> bool val property_attribute_eq : property_attribute -> property_attribute -> bool
val getter_attribute_opt : property_attribute list -> string option val getter_attribute_opt : property_attribute list -> string option
@ -72,6 +74,8 @@ sig
val type_from_unary_expr_or_type_trait_expr_info : val type_from_unary_expr_or_type_trait_expr_info :
Clang_ast_t.unary_expr_or_type_trait_expr_info -> Clang_ast_t.qual_type option Clang_ast_t.unary_expr_or_type_trait_expr_info -> Clang_ast_t.qual_type option
val is_generated : Clang_ast_t.named_decl_info -> bool
end end
module General_utils : module General_utils :

@ -9,6 +9,14 @@
(** Module for function to retrieve the location (file, line, etc) of instructions *) (** Module for function to retrieve the location (file, line, etc) of instructions *)
(* The file passed as an argument to InferClang *)
val current_source_file : DB.source_file ref
(* Inside the json there may be code or type definitions from other files *)
(* than the one passed as an argument. That current file in the translation is saved*)
(* in this variable. *)
val curr_file : DB.source_file ref
val clang_to_sil_location : Clang_ast_t.source_location -> int -> Cfg.Procdesc.t option -> val clang_to_sil_location : Clang_ast_t.source_location -> int -> Cfg.Procdesc.t option ->
Sil.location Sil.location

@ -12,6 +12,7 @@
open Utils open Utils
open CFrontend_utils open CFrontend_utils
open Clang_ast_t open Clang_ast_t
open CContext
module L = Logging module L = Logging
@ -24,6 +25,8 @@ module type CMethod_decl = sig
val create_function_signature : Clang_ast_t.decl_info -> Clang_ast_t.function_decl_info -> string -> val create_function_signature : Clang_ast_t.decl_info -> Clang_ast_t.function_decl_info -> string ->
Clang_ast_t.qual_type -> bool -> Procname.t option -> Clang_ast_t.stmt option * CMethod_signature.method_signature Clang_ast_t.qual_type -> bool -> Procname.t option -> Clang_ast_t.stmt option * CMethod_signature.method_signature
val process_getter_setter : CContext.t -> Procname.t -> bool
end end
module CMethod_decl_funct(T: CModule_type.CTranslation) : CMethod_decl = module CMethod_decl_funct(T: CModule_type.CTranslation) : CMethod_decl =
@ -73,13 +76,13 @@ struct
let qt = method_decl_info.Clang_ast_t.omdi_result_type in let qt = method_decl_info.Clang_ast_t.omdi_result_type in
CTypes.get_type qt CTypes.get_type qt
let build_method_signature decl_info procname function_method_decl_info is_instance is_anonym_block = let build_method_signature decl_info procname function_method_decl_info is_instance is_anonym_block is_generated =
let source_range = decl_info.Clang_ast_t.di_source_range in let source_range = decl_info.Clang_ast_t.di_source_range in
let qt = get_return_type function_method_decl_info in let qt = get_return_type function_method_decl_info in
let is_instance_method = is_instance_method function_method_decl_info is_instance is_anonym_block in let is_instance_method = is_instance_method function_method_decl_info is_instance is_anonym_block in
let parameters = get_parameters function_method_decl_info in let parameters = get_parameters function_method_decl_info in
let attributes = decl_info.Clang_ast_t.di_attributes in let attributes = decl_info.Clang_ast_t.di_attributes in
CMethod_signature.make_ms procname parameters qt attributes source_range is_instance_method CMethod_signature.make_ms procname parameters qt attributes source_range is_instance_method is_generated
let create_function_signature di fdecl_info name qt is_instance anonym_block_opt = let create_function_signature di fdecl_info name qt is_instance anonym_block_opt =
let procname, is_anonym_block = let procname, is_anonym_block =
@ -87,7 +90,7 @@ struct
| Some block -> block, true | Some block -> block, true
| None -> CMethod_trans.mk_procname_from_function name (CTypes.get_type qt), false in | None -> CMethod_trans.mk_procname_from_function name (CTypes.get_type qt), false in
let ms = build_method_signature di procname let ms = build_method_signature di procname
(Func_decl_info (fdecl_info, CTypes.get_type qt)) is_instance is_anonym_block in (Func_decl_info (fdecl_info, CTypes.get_type qt)) is_instance is_anonym_block false in
(match method_body_to_translate di ms fdecl_info.Clang_ast_t.fdi_body with (match method_body_to_translate di ms fdecl_info.Clang_ast_t.fdi_body with
| Some body -> Some body, ms | Some body -> Some body, ms
| None -> None, ms) | None -> None, ms)
@ -154,42 +157,45 @@ struct
match create_function_signature di fdecl_info name qt is_instance anonym_block_opt with match create_function_signature di fdecl_info name qt is_instance anonym_block_opt with
| Some body, ms -> (* Only in the case the function declaration has a defined body we create a procdesc *) | Some body, ms -> (* Only in the case the function declaration has a defined body we create a procdesc *)
let procname = CMethod_signature.ms_get_name ms in let procname = CMethod_signature.ms_get_name ms in
CMethod_trans.create_local_procdesc cfg tenv ms [body] captured_vars false; if CMethod_trans.create_local_procdesc cfg tenv ms [body] captured_vars false then
let is_instance = CMethod_signature.ms_is_instance ms in let is_instance = CMethod_signature.ms_is_instance ms in
let is_anonym_block = Option.is_some anonym_block_opt in let is_anonym_block = Option.is_some anonym_block_opt in
let is_objc_method = is_anonym_block in let is_objc_method = is_anonym_block in
let curr_class = if is_anonym_block then curr_class else CContext.ContextNoCls in let curr_class = if is_anonym_block then curr_class else CContext.ContextNoCls in
let attributes = CMethod_signature.ms_get_attributes ms in let attributes = CMethod_signature.ms_get_attributes ms in
CMethod_signature.add ms; CMethod_signature.add ms;
add_method tenv cg cfg curr_class procname namespace [body] is_objc_method is_instance add_method tenv cg cfg curr_class procname namespace [body] is_objc_method is_instance
captured_vars is_anonym_block fdecl_info.Clang_ast_t.fdi_parameters attributes captured_vars is_anonym_block fdecl_info.Clang_ast_t.fdi_parameters attributes
| None, ms -> CMethod_signature.add ms | None, ms -> CMethod_signature.add ms
let process_objc_method_decl tenv cg cfg namespace curr_class decl_info method_name method_decl_info = let process_objc_method_decl tenv cg cfg namespace curr_class decl_info name_info method_decl_info =
let class_name = CContext.get_curr_class_name curr_class in let class_name = CContext.get_curr_class_name curr_class in
let method_name = name_info.Clang_ast_t.ni_name in
let procname = CMethod_trans.mk_procname_from_method class_name method_name in let procname = CMethod_trans.mk_procname_from_method class_name method_name in
let method_decl = Meth_decl_info (method_decl_info, class_name) in let method_decl = Meth_decl_info (method_decl_info, class_name) in
let ms = build_method_signature decl_info procname method_decl false false in let is_generated = Ast_utils.is_generated name_info in
let ms = build_method_signature decl_info procname method_decl false false is_generated in
Printing.log_out " ....Processing implementation for method '%s'\n" (Procname.to_string procname); Printing.log_out " ....Processing implementation for method '%s'\n" (Procname.to_string procname);
CMethod_signature.add ms; CMethod_signature.add ms;
(match method_body_to_translate decl_info ms method_decl_info.Clang_ast_t.omdi_body with (match method_body_to_translate decl_info ms method_decl_info.Clang_ast_t.omdi_body with
| Some body -> | Some body ->
let is_instance = CMethod_signature.ms_is_instance ms in let is_instance = CMethod_signature.ms_is_instance ms in
let attributes = CMethod_signature.ms_get_attributes ms in let attributes = CMethod_signature.ms_get_attributes ms in
CMethod_trans.create_local_procdesc cfg tenv ms [body] [] is_instance; if CMethod_trans.create_local_procdesc cfg tenv ms [body] [] is_instance then
add_method tenv cg cfg curr_class procname namespace [body] true is_instance [] false add_method tenv cg cfg curr_class procname namespace [body] true is_instance [] false
method_decl_info.Clang_ast_t.omdi_parameters attributes method_decl_info.Clang_ast_t.omdi_parameters attributes
| None -> ()) | None -> ())
let rec process_one_method_decl tenv cg cfg curr_class namespace dec = let rec process_one_method_decl tenv cg cfg curr_class namespace dec =
match dec with match dec with
| ObjCMethodDecl(decl_info, name_info, method_decl_info) -> | ObjCMethodDecl(decl_info, name_info, method_decl_info) ->
let method_name = name_info.Clang_ast_t.ni_name in process_objc_method_decl tenv cg cfg namespace curr_class decl_info name_info method_decl_info
process_objc_method_decl tenv cg cfg namespace curr_class decl_info method_name method_decl_info
| ObjCPropertyImplDecl(decl_info, property_impl_decl_info) -> | ObjCPropertyImplDecl(decl_info, property_impl_decl_info) ->
let prop_methods = ObjcProperty_decl.make_getter_setter cfg curr_class decl_info property_impl_decl_info in let pname = Ast_utils.property_name property_impl_decl_info in
list_iter (process_one_method_decl tenv cg cfg curr_class namespace) prop_methods Printing.log_out "ADDING: ObjCPropertyImplDecl for property '%s' " pname;
let getter_setter = ObjcProperty_decl.make_getter_setter curr_class decl_info pname in
list_iter (process_one_method_decl tenv cg cfg curr_class namespace) getter_setter
| EmptyDecl _ | ObjCIvarDecl _ | ObjCPropertyDecl _ -> () | EmptyDecl _ | ObjCIvarDecl _ | ObjCPropertyDecl _ -> ()
| d -> Printing.log_err | d -> Printing.log_err
@ -199,4 +205,23 @@ struct
let process_methods tenv cg cfg curr_class namespace decl_list = let process_methods tenv cg cfg curr_class namespace decl_list =
list_iter (process_one_method_decl tenv cg cfg curr_class namespace) decl_list list_iter (process_one_method_decl tenv cg cfg curr_class namespace) decl_list
let process_getter_setter context procname =
let class_name = Procname.c_get_class procname in
let cls = CContext.create_curr_class context.tenv class_name in
let method_name = Procname.c_get_method procname in
match ObjcProperty_decl.method_is_property_accesor cls method_name with
| Some (property_name, property_type, is_getter) when
CMethod_trans.should_create_procdesc context.cfg procname true true ->
(match property_type with qt, atts, decl_info, _, _, ivar_opt ->
let ivar_name = ObjcProperty_decl.get_ivar_name property_name ivar_opt in
let field = CField_decl.build_sil_field_property cls context.tenv ivar_name qt (Some atts) in
ignore (CField_decl.add_missing_fields context.tenv class_name [field]);
let accessor =
if is_getter then
ObjcProperty_decl.make_getter cls property_name property_type
else ObjcProperty_decl.make_setter cls property_name property_type in
list_iter (process_one_method_decl context.tenv context.cg context.cfg cls context.namespace) accessor;
true)
| _ -> false
end end

@ -17,7 +17,10 @@ module CMethod_decl_funct(T: CModule_type.CTranslation) : sig
string -> Clang_ast_t.qual_type -> Clang_ast_t.function_decl_info -> (Mangled.t * Sil.typ * bool) list -> Procname.t option -> CContext.curr_class -> unit string -> Clang_ast_t.qual_type -> Clang_ast_t.function_decl_info -> (Mangled.t * Sil.typ * bool) list -> Procname.t option -> CContext.curr_class -> unit
val create_function_signature : Clang_ast_t.decl_info -> Clang_ast_t.function_decl_info -> string -> val create_function_signature : Clang_ast_t.decl_info -> Clang_ast_t.function_decl_info -> string ->
Clang_ast_t.qual_type -> bool -> Procname.t option -> Clang_ast_t.stmt option * CMethod_signature.method_signature Clang_ast_t.qual_type -> bool -> Procname.t option -> Clang_ast_t.stmt option * CMethod_signature.method_signature
val process_getter_setter : CContext.t -> Procname.t -> bool
end end
module type CMethod_decl = sig module type CMethod_decl = sig
@ -29,4 +32,6 @@ module type CMethod_decl = sig
val create_function_signature : Clang_ast_t.decl_info -> Clang_ast_t.function_decl_info -> string -> val create_function_signature : Clang_ast_t.decl_info -> Clang_ast_t.function_decl_info -> string ->
Clang_ast_t.qual_type -> bool -> Procname.t option -> Clang_ast_t.stmt option * CMethod_signature.method_signature Clang_ast_t.qual_type -> bool -> Procname.t option -> Clang_ast_t.stmt option * CMethod_signature.method_signature
val process_getter_setter : CContext.t -> Procname.t -> bool
end end

@ -16,7 +16,8 @@ type method_signature = {
_ret_type : string; _ret_type : string;
_attributes : Clang_ast_t.attribute list; _attributes : Clang_ast_t.attribute list;
_loc : Clang_ast_t.source_range; _loc : Clang_ast_t.source_range;
_is_instance : bool _is_instance : bool;
_is_generated : bool;
} }
let ms_get_name ms = let ms_get_name ms =
@ -37,25 +38,30 @@ let ms_get_loc ms =
let ms_is_instance ms = let ms_is_instance ms =
ms._is_instance ms._is_instance
let ms_is_generated ms =
ms._is_generated
type methodMap = method_signature Procname.Map.t type methodMap = method_signature Procname.Map.t
let methodMap = ref Procname.Map.empty let methodMap = ref Procname.Map.empty
let make_ms procname args ret_type attributes loc is_instance = let make_ms procname args ret_type attributes loc is_instance is_generated =
let meth_signature = { let meth_signature = {
_name = procname; _name = procname;
_args = args; _args = args;
_ret_type = ret_type; _ret_type = ret_type;
_attributes = attributes; _attributes = attributes;
_loc = loc; _loc = loc;
_is_instance = is_instance } in _is_instance = is_instance;
_is_generated = is_generated} in
meth_signature meth_signature
let replace_name_ms ms name = let replace_name_ms ms name =
{ ms with _name = name } { ms with _name = name }
let ms_to_string ms = let ms_to_string ms =
"Method "^(Procname.to_string ms._name)^" "^ let gen = if ms._is_generated then " (generated)" else "" in
"Method "^(Procname.to_string ms._name)^gen^" "^
(Utils.list_to_string (fun (s1, s2, _) -> s1^", "^s2) ms._args)^"->"^ms._ret_type^" "^ (Utils.list_to_string (fun (s1, s2, _) -> s1^", "^s2) ms._args)^"->"^ms._ret_type^" "^
Clang_ast_j.string_of_source_range ms._loc Clang_ast_j.string_of_source_range ms._loc

@ -31,8 +31,10 @@ val ms_get_loc : method_signature -> Clang_ast_t.source_range
val ms_is_instance : method_signature -> bool val ms_is_instance : method_signature -> bool
val make_ms : Procname.t -> (string * string * Clang_ast_t.stmt option) list -> string -> Clang_ast_t.attribute list -> val make_ms : Procname.t -> (string * string * Clang_ast_t.stmt option) list -> string -> Clang_ast_t.attribute list ->
Clang_ast_t.source_range -> bool -> method_signature Clang_ast_t.source_range -> bool -> bool -> method_signature
val replace_name_ms : method_signature -> Procname.t -> method_signature val replace_name_ms : method_signature -> Procname.t -> method_signature
val ms_to_string : method_signature -> string val ms_to_string : method_signature -> string
val ms_is_generated : method_signature -> bool

@ -73,19 +73,19 @@ let get_superclass_curr_class context =
let get_class_selector_instance context obj_c_message_expr_info act_params = let get_class_selector_instance context obj_c_message_expr_info act_params =
let selector = obj_c_message_expr_info.Clang_ast_t.omei_selector in let selector = obj_c_message_expr_info.Clang_ast_t.omei_selector in
match obj_c_message_expr_info.Clang_ast_t.omei_receiver_kind with match obj_c_message_expr_info.Clang_ast_t.omei_receiver_kind with
| `Class qt -> (CTypes.get_type qt, selector, MCStatic) | `Class qt -> (CTypes.get_type qt, selector, MCStatic)
| `Instance -> | `Instance ->
(match act_params with (match act_params with
| (instance_obj, Sil.Tptr(t, _)):: _ | (instance_obj, Sil.Tptr(t, _)):: _
| (instance_obj, t):: _ -> | (instance_obj, t):: _ ->
(CTypes.classname_of_type t, selector, MCVirtual) (CTypes.classname_of_type t, selector, MCVirtual)
| _ -> assert false) | _ -> assert false)
| `SuperInstance -> | `SuperInstance ->
let superclass = get_superclass_curr_class context in let superclass = get_superclass_curr_class context in
(superclass, selector, MCNoVirtual) (superclass, selector, MCNoVirtual)
| `SuperClass -> | `SuperClass ->
let superclass = get_superclass_curr_class context in let superclass = get_superclass_curr_class context in
(superclass, selector, MCStatic) (superclass, selector, MCStatic)
let get_formal_parameters tenv ms = let get_formal_parameters tenv ms =
let rec defined_parameters pl = let rec defined_parameters pl =
@ -137,21 +137,35 @@ let get_return_type tenv ms =
let sil_func_attributes_of_attributes attrs = let sil_func_attributes_of_attributes attrs =
let rec do_translation acc al = match al with let rec do_translation acc al = match al with
| [] -> list_rev acc | [] -> list_rev acc
| Clang_ast_t.SentinelAttr attribute_info::tl -> | Clang_ast_t.SentinelAttr attribute_info:: tl ->
let (sentinel, null_pos) = match attribute_info.Clang_ast_t.ai_parameters with let (sentinel, null_pos) = match attribute_info.Clang_ast_t.ai_parameters with
| a::b::[] -> (int_of_string a, int_of_string b) | a:: b::[] -> (int_of_string a, int_of_string b)
| _ -> assert false | _ -> assert false
in in
do_translation (Sil.FA_sentinel(sentinel, null_pos)::acc) tl do_translation (Sil.FA_sentinel(sentinel, null_pos):: acc) tl
| _::tl -> do_translation acc tl in | _:: tl -> do_translation acc tl in
do_translation [] attrs do_translation [] attrs
let should_create_procdesc cfg procname defined generated =
match Cfg.Procdesc.find_from_name cfg procname with
| Some prevoius_procdesc ->
let is_defined_previous = Cfg.Procdesc.is_defined prevoius_procdesc in
let is_generated_previous =
(Cfg.Procdesc.get_attributes prevoius_procdesc).Sil.is_generated in
if defined &&
((not is_defined_previous) || (generated && is_generated_previous)) then
(Cfg.Procdesc.remove cfg (Cfg.Procdesc.get_proc_name prevoius_procdesc) true;
true)
else false
| None -> true
(** Creates a procedure description. *) (** Creates a procedure description. *)
let create_local_procdesc cfg tenv ms fbody captured is_objc_inst_method = let create_local_procdesc cfg tenv ms fbody captured is_objc_inst_method =
let defined = not ((list_length fbody) == 0) in let defined = not ((list_length fbody) == 0) in
let procname = CMethod_signature.ms_get_name ms in let procname = CMethod_signature.ms_get_name ms in
let pname = Procname.to_string procname in let pname = Procname.to_string procname in
let attributes = sil_func_attributes_of_attributes (CMethod_signature.ms_get_attributes ms) in let attributes = sil_func_attributes_of_attributes (CMethod_signature.ms_get_attributes ms) in
let is_generated = CMethod_signature.ms_is_generated ms in
let create_new_procdesc () = let create_new_procdesc () =
let formals = get_formal_parameters tenv ms in let formals = get_formal_parameters tenv ms in
let captured_str = list_map (fun (s, t, _) -> (Mangled.to_string s, t)) captured in let captured_str = list_map (fun (s, t, _) -> (Mangled.to_string s, t)) captured in
@ -178,6 +192,7 @@ let create_local_procdesc cfg tenv ms fbody captured is_objc_inst_method =
Sil.language = Sil.C_CPP; Sil.language = Sil.C_CPP;
Sil.func_attributes = attributes; Sil.func_attributes = attributes;
Sil.method_annotation = Sil.method_annotation_empty; Sil.method_annotation = Sil.method_annotation_empty;
Sil.is_generated = is_generated;
} in } in
create { create {
cfg = cfg; cfg = cfg;
@ -199,13 +214,10 @@ let create_local_procdesc cfg tenv ms fbody captured is_objc_inst_method =
let exit_node = Cfg.Node.create cfg loc_exit exit_kind [] 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_start_node procdesc start_node;
Cfg.Procdesc.set_exit_node procdesc exit_node) in Cfg.Procdesc.set_exit_node procdesc exit_node) in
match Cfg.Procdesc.find_from_name cfg procname with let generated = CMethod_signature.ms_is_generated ms in
| Some prevoius_procdesc -> if should_create_procdesc cfg procname defined generated then
Printing.log_err "\n\n!!!WARNING: procdesc for %s already defined \n" pname; (create_new_procdesc (); true)
if defined && not (Cfg.Procdesc.is_defined prevoius_procdesc) then else false
(Cfg.Procdesc.remove cfg (Cfg.Procdesc.get_proc_name prevoius_procdesc) true;
create_new_procdesc ())
| None -> create_new_procdesc ()
(** Create a procdesc for objc methods whose signature cannot be found. *) (** Create a procdesc for objc methods whose signature cannot be found. *)
let create_external_procdesc cfg procname is_objc_inst_method type_opt = let create_external_procdesc cfg procname is_objc_inst_method type_opt =
@ -231,6 +243,7 @@ let create_external_procdesc cfg procname is_objc_inst_method type_opt =
Sil.language = Sil.C_CPP; Sil.language = Sil.C_CPP;
Sil.func_attributes = []; Sil.func_attributes = [];
Sil.method_annotation = Sil.method_annotation_empty; Sil.method_annotation = Sil.method_annotation_empty;
Sil.is_generated = false;
} in } in
create { create {
cfg = cfg; cfg = cfg;
@ -248,25 +261,3 @@ let create_external_procdesc cfg procname is_objc_inst_method type_opt =
let instance_to_method_call_type instance = let instance_to_method_call_type instance =
if instance then MCVirtual if instance then MCVirtual
else MCStatic else MCStatic
(*Returns the procname and whether is instance, according to the selector *)
(* information and according to the method signature *)
let get_callee_objc_method context obj_c_message_expr_info act_params =
let (class_name, method_name, mc_type) =
get_class_selector_instance context obj_c_message_expr_info act_params in
let is_instance = mc_type != MCStatic in
match CTrans_models.get_predefined_model_method_signature class_name method_name
mk_procname_from_method with
| Some ms ->
create_local_procdesc context.cfg context.tenv ms [] [] is_instance;
CMethod_signature.ms_get_name ms, MCNoVirtual
| None ->
match resolve_method context.tenv class_name method_name with
| Some callee_ms ->
let is_instance = is_instance || (CMethod_signature.ms_is_instance callee_ms) in
create_local_procdesc context.cfg context.tenv callee_ms [] [] is_instance;
(CMethod_signature.ms_get_name callee_ms), mc_type
| None ->
let callee_pn = mk_procname_from_method class_name method_name in
create_external_procdesc context.cfg callee_pn is_instance None;
callee_pn, mc_type

@ -20,11 +20,8 @@ type method_call_type =
| MCNoVirtual | MCNoVirtual
| MCStatic | MCStatic
val get_callee_objc_method : CContext.t -> Clang_ast_t.obj_c_message_expr_info -> (Sil.exp * Sil.typ) list
-> Procname.t * method_call_type
val create_local_procdesc : Cfg.cfg -> Sil.tenv -> CMethod_signature.method_signature -> val create_local_procdesc : Cfg.cfg -> Sil.tenv -> CMethod_signature.method_signature ->
Clang_ast_t.stmt list -> (Mangled.t * Sil.typ * bool) list -> bool -> unit Clang_ast_t.stmt list -> (Mangled.t * Sil.typ * bool) list -> bool -> bool
val create_external_procdesc : Cfg.cfg -> Procname.t -> bool -> (Sil.typ * Sil.typ list) option -> unit val create_external_procdesc : Cfg.cfg -> Procname.t -> bool -> (Sil.typ * Sil.typ list) option -> unit
@ -36,3 +33,7 @@ val mk_procname_from_function : string -> string -> Procname.t
val get_class_selector_instance : CContext.t -> Clang_ast_t.obj_c_message_expr_info -> (Sil.exp * Sil.typ) list val get_class_selector_instance : CContext.t -> Clang_ast_t.obj_c_message_expr_info -> (Sil.exp * Sil.typ) list
-> (string * string * method_call_type) -> (string * string * method_call_type)
val resolve_method : Sil.tenv -> string -> string -> CMethod_signature.method_signature option
val should_create_procdesc : Cfg.cfg -> Procname.t -> bool -> bool -> bool

@ -16,4 +16,6 @@ module type CMethod_declaration =
sig sig
val function_decl : Sil.tenv -> Cfg.cfg -> Cg.t -> string option -> bool -> Clang_ast_t.decl_info -> val function_decl : Sil.tenv -> Cfg.cfg -> Cg.t -> string option -> bool -> Clang_ast_t.decl_info ->
string -> Clang_ast_t.qual_type -> Clang_ast_t.function_decl_info -> (Mangled.t * Sil.typ * bool) list -> Procname.t option -> CContext.curr_class -> unit string -> Clang_ast_t.qual_type -> Clang_ast_t.function_decl_info -> (Mangled.t * Sil.typ * bool) list -> Procname.t option -> CContext.curr_class -> unit
val process_getter_setter : CContext.t -> Procname.t -> bool
end end

@ -37,6 +37,30 @@ end
module CTrans_funct(M: CModule_type.CMethod_declaration) : CTrans = module CTrans_funct(M: CModule_type.CMethod_declaration) : CTrans =
struct struct
(*Returns the procname and whether is instance, according to the selector *)
(* information and according to the method signature *)
let get_callee_objc_method context obj_c_message_expr_info act_params =
let (class_name, method_name, mc_type) =
CMethod_trans.get_class_selector_instance context obj_c_message_expr_info act_params in
let is_instance = mc_type != CMethod_trans.MCStatic in
match CTrans_models.get_predefined_model_method_signature class_name method_name
CMethod_trans.mk_procname_from_method with
| Some ms ->
ignore (CMethod_trans.create_local_procdesc context.cfg context.tenv ms [] [] is_instance);
CMethod_signature.ms_get_name ms, CMethod_trans.MCNoVirtual
| None ->
match CMethod_trans.resolve_method context.tenv class_name method_name with
| Some callee_ms ->
(let procname = CMethod_signature.ms_get_name callee_ms in
if not (M.process_getter_setter context procname) then
(let is_instance = is_instance || (CMethod_signature.ms_is_instance callee_ms) in
ignore (CMethod_trans.create_local_procdesc context.cfg context.tenv callee_ms [] [] is_instance));
procname, mc_type)
| None ->
let callee_pn = CMethod_trans.mk_procname_from_method class_name method_name in
CMethod_trans.create_external_procdesc context.cfg callee_pn is_instance None;
callee_pn, mc_type
let add_autorelease_call context exp typ sil_loc = let add_autorelease_call context exp typ sil_loc =
let method_name = Procname.c_get_method (Cfg.Procdesc.get_proc_name context.procdesc) in let method_name = Procname.c_get_method (Cfg.Procdesc.get_proc_name context.procdesc) in
if !Config.arc_mode && if !Config.arc_mode &&
@ -590,7 +614,7 @@ struct
Cg.add_edge context.cg procname callee_pname; Cg.add_edge context.cg procname callee_pname;
try try
let callee_ms = CMethod_signature.find callee_pname in let callee_ms = CMethod_signature.find callee_pname in
CMethod_trans.create_local_procdesc context.cfg context.tenv callee_ms [] [] false ignore (CMethod_trans.create_local_procdesc context.cfg context.tenv callee_ms [] [] false)
with Not_found -> with Not_found ->
CMethod_trans.create_external_procdesc context.cfg callee_pname false None CMethod_trans.create_external_procdesc context.cfg callee_pname false None
end end
@ -642,8 +666,7 @@ struct
CTrans_utils.trans_assume_false sil_loc context trans_state.succ_nodes CTrans_utils.trans_assume_false sil_loc context trans_state.succ_nodes
else else
let procname = Cfg.Procdesc.get_proc_name context.procdesc in let procname = Cfg.Procdesc.get_proc_name context.procdesc in
let callee_name, method_call_type = let callee_name, method_call_type = get_callee_objc_method context obj_c_message_expr_info res_trans_par.exps in
CMethod_trans.get_callee_objc_method context obj_c_message_expr_info res_trans_par.exps in
let res_trans_par = Self.add_self_parameter_for_super_instance context procname sil_loc let res_trans_par = Self.add_self_parameter_for_super_instance context procname sil_loc
obj_c_message_expr_info res_trans_par in obj_c_message_expr_info res_trans_par in
let is_virtual = method_call_type = CMethod_trans.MCVirtual in let is_virtual = method_call_type = CMethod_trans.MCVirtual in

@ -129,7 +129,7 @@ let get_predefined_ms_method condition class_name method_name mk_procname
| Some procname -> procname | Some procname -> procname
| None -> mk_procname class_name method_name in | None -> mk_procname class_name method_name in
let ms = CMethod_signature.make_ms procname arguments return_type attributes let ms = CMethod_signature.make_ms procname arguments return_type attributes
(Ast_expressions.dummy_source_range ()) false in (Ast_expressions.dummy_source_range ()) false false in
Some ms Some ms
else None else None

@ -130,44 +130,6 @@ let add_class_to_tenv tenv class_name decl_list obj_c_interface_decl_info =
| None -> Printing.log_out " >>>NOT Found!!\n"); | None -> Printing.log_out " >>>NOT Found!!\n");
curr_class curr_class
(* Add potential extra fields defined only in the implementation of the class *)
(* to the info given in the interface. Update the tenv accordingly.*)
let add_missing_fields tenv class_name decl_list idi =
let curr_class, superclasses, fields =
create_curr_class_and_superclasses_fields tenv decl_list class_name
idi.Clang_ast_t.oidi_super [] in
let mang_name = Mangled.from_string class_name in
let class_tn_name = Sil.TN_csu (Sil.Class, mang_name) in
Printing.log_out
" >>>Verifying that Typename TN_csu('%s') is in tenv\n"
(Sil.typename_to_string class_tn_name);
let curr_class =
(match Sil.tenv_lookup tenv class_tn_name with
| Some Sil.Tstruct(intf_fields, _, _, _, superclass, methods, annotation) ->
(let compute_extra_fields fields intf_fields =
let equal_fields (fn1, _, _) (fn2, _, _) = Ident.fieldname_equal fn1 fn2 in
let missing_field f = not (list_mem equal_fields f intf_fields) in
list_filter missing_field fields in
Printing.log_out
" Looking for extra fields defined only in the implementation of '%s'\n"
class_name;
let extra_fields = compute_extra_fields fields intf_fields in
list_iter (fun (fn, _, _) ->
Printing.log_out
" ---> Extra non-static field: '%s'\n" (Ident.fieldname_to_string fn))
extra_fields;
let new_fields = append_no_duplicates_fields extra_fields intf_fields in
let new_fields = CFrontend_utils.General_utils.sort_fields new_fields in
let class_type_info =
Sil.Tstruct (
new_fields, [], Sil.Class, Some mang_name, superclass, methods, annotation
) in
Printing.log_out " Updating info for class '%s' in tenv\n" class_name;
Sil.tenv_add tenv class_tn_name class_type_info;
update_curr_class curr_class superclass )
| _ -> assert false) in
curr_class
let add_missing_methods tenv class_name decl_list curr_class = let add_missing_methods tenv class_name decl_list curr_class =
let methods = ObjcProperty_decl.get_methods curr_class decl_list in let methods = ObjcProperty_decl.get_methods curr_class decl_list in
let class_tn_name = Sil.TN_csu (Sil.Class, (Mangled.from_string class_name)) in let class_tn_name = Sil.TN_csu (Sil.Class, (Mangled.from_string class_name)) in
@ -180,15 +142,15 @@ let add_missing_methods tenv class_name decl_list curr_class =
(* Interface_type_info has the name of instance variables and the name of methods. *) (* Interface_type_info has the name of instance variables and the name of methods. *)
let interface_declaration tenv class_name decl_list obj_c_interface_decl_info = let interface_declaration tenv class_name decl_list obj_c_interface_decl_info =
let curr_class = add_class_to_tenv tenv class_name decl_list obj_c_interface_decl_info in add_class_to_tenv tenv class_name decl_list obj_c_interface_decl_info
curr_class
(* Translate the methods defined in the implementation.*) (* Translate the methods defined in the implementation.*)
let interface_impl_declaration tenv class_name decl_list implementation_decl_info = let interface_impl_declaration tenv class_name decl_list idi =
let curr_class = add_missing_fields tenv class_name decl_list implementation_decl_info in
add_missing_methods tenv class_name decl_list curr_class;
Printing.log_out "ADDING: ObjCImplementationDecl for class '%s'\n" class_name; Printing.log_out "ADDING: ObjCImplementationDecl for class '%s'\n" class_name;
Printing.log_out " Processing method declarations...\n"; let curr_class = CContext.create_curr_class tenv class_name in
let fields = CField_decl.get_fields tenv curr_class decl_list in
CField_decl.add_missing_fields tenv class_name fields;
add_missing_methods tenv class_name decl_list curr_class;
curr_class curr_class
(* search for definition of interface with non empty set of fields that may come after their use.*) (* search for definition of interface with non empty set of fields that may come after their use.*)
@ -231,19 +193,19 @@ let rec find_field tenv nfield str searched_late_defined =
match s with match s with
| [] -> None | [] -> None
| (Sil.Class, sname):: s' -> | (Sil.Class, sname):: s' ->
L.err "@. ....Searching field in superclass (Class, '%s')@." (Mangled.to_string sname); Printing.log_err "@. ....Searching field in superclass (Class, '%s')@." (Mangled.to_string sname);
let str' = Sil.tenv_lookup tenv (Sil.TN_csu(Sil.Class, sname)) in let str' = Sil.tenv_lookup tenv (Sil.TN_csu(Sil.Class, sname)) in
(match find_field tenv nfield str' searched_late_defined with (match find_field tenv nfield str' searched_late_defined with
| Some field -> Some field | Some field -> Some field
| None -> search_super s') | None -> search_super s')
| (Sil.Protocol, sname):: s' -> | (Sil.Protocol, sname):: s' ->
L.err "@. ... Searching field in protocol (Protocol, '%s')@." (Mangled.to_string sname); Printing.log_err "@. ... Searching field in protocol (Protocol, '%s')@." (Mangled.to_string sname);
search_super s' search_super s'
| (Sil.Struct, sname):: s' -> | (Sil.Struct, sname):: s' ->
L.err "@. ... Searching field in struct (Struct, '%s')@." (Mangled.to_string sname); Printing.log_err "@. ... Searching field in struct (Struct, '%s')@." (Mangled.to_string sname);
None None
| (Sil.Union, sname):: s' -> | (Sil.Union, sname):: s' ->
L.err "@. ... Searching field in (Union, '%s')@." (Mangled.to_string sname); Printing.log_err "@. ... Searching field in (Union, '%s')@." (Mangled.to_string sname);
None in None in
match str with match str with
| Some Sil.Tstruct (sf, nsf, Sil.Struct, Some cname, _, _, _) | Some Sil.Tstruct (sf, nsf, Sil.Struct, Some cname, _, _, _)

@ -108,7 +108,7 @@ struct
let res = ref None in let res = ref None in
PropertyTableHash.iter (fun (cl, pname) (_, _, _, _, _, ivar') -> PropertyTableHash.iter (fun (cl, pname) (_, _, _, _, _, ivar') ->
match ivar' with match ivar' with
| Some s when (CContext.curr_class_equal curr_class cl) && s = ivar -> res:= Some pname | Some s when (CContext.curr_class_equal curr_class cl) && s = ivar -> res:= Some pname
| _ -> ()) property_table; | _ -> ()) property_table;
!res !res
@ -206,26 +206,40 @@ let check_for_property curr_class method_name meth_decl body =
check_property_accessor curr_class method_name true; check_property_accessor curr_class method_name true;
check_property_accessor curr_class method_name false check_property_accessor curr_class method_name false
let method_is_property_accesor cls method_name =
let properties_class = find_properties_class cls in
let method_is_getter (property_name, property_type) res_opt =
match res_opt with
| Some res -> res_opt
| None ->
match property_type with (_, _, _, (getter_name, _), (setter_name, _), _) ->
if method_name = getter_name then Some (property_name, property_type, true)
else if method_name = setter_name then Some (property_name, property_type, false)
else None in
list_fold_right method_is_getter properties_class None
let prepare_dynamic_property curr_class decl_info property_impl_decl_info = let prepare_dynamic_property curr_class decl_info property_impl_decl_info =
let pname = Ast_utils.property_name property_impl_decl_info in let pname = Ast_utils.property_name property_impl_decl_info in
let qt = (try let res = (try
let qt', atts, di, getter, setter, _ = Property.find_property curr_class pname in let qt', 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 let ivar = (match property_impl_decl_info.Clang_ast_t.opidi_ivar_decl with
| Some dr -> Ast_utils.name_opt_of_name_info_opt dr.Clang_ast_t.dr_name | Some dr -> (match dr.Clang_ast_t.dr_name with
| None -> None) in | Some name_info -> name_info.Clang_ast_t.ni_name
| None -> assert false)
| None -> Ast_utils.generated_ivar_name pname) in
(* update property info with proper ivar name *) (* update property info with proper ivar name *)
Property.replace_property (curr_class, pname) (qt', atts, di, getter, setter, ivar); Property.replace_property (curr_class, pname) (qt', atts, di, getter, setter, Some ivar);
Printing.log_out "Updated property table by adding ivar name for property pname '%s'\n" pname; Printing.log_out "Updated property table by adding ivar name for property pname '%s'\n" pname;
Some qt' Some (qt', ivar)
with Not_found -> L.err "Property '%s' not found in the table. Ivar not updated and qual_type not found.@." pname; with Not_found -> L.err "Property '%s' not found in the table. Ivar not updated and qual_type not found.@." pname;
None) in None) in
match property_impl_decl_info.Clang_ast_t.opidi_implementation with match property_impl_decl_info.Clang_ast_t.opidi_implementation, res with
| `Dynamic -> | `Dynamic, Some (qt, ivar) ->
(* For Dynamic property we need to create the ObjCIvarDecl which specifies*) (* 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.*) (* 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 *) (* Once created the ObjCIvarDecl then we treat the property as synthesized *)
[Ast_expressions.make_objc_ivar_decl decl_info qt property_impl_decl_info] [Ast_expressions.make_objc_ivar_decl decl_info qt property_impl_decl_info ivar]
| `Synthesize -> | _ ->
(* No names of fields/method to collect from ObjCPropertyImplDecl when Synthesized *) (* No names of fields/method to collect from ObjCPropertyImplDecl when Synthesized *)
[] []
@ -241,14 +255,6 @@ let method_exists cfg class_name name attributes =
let is_property_read_only attributes = let is_property_read_only attributes =
list_mem (Ast_utils.property_attribute_eq) `Readonly attributes list_mem (Ast_utils.property_attribute_eq) `Readonly attributes
let should_generate_getter cfg class_name name attributes =
not (method_exists cfg class_name name attributes)
let should_generate_setter cfg class_name name attributes =
let setter_exists = not (method_exists cfg class_name name attributes) in
let is_read_only = is_property_read_only attributes in
setter_exists && not is_read_only
let get_memory_management_attribute attributes = let get_memory_management_attribute attributes =
let memory_management_attributes = Ast_utils.get_memory_management_attributes () in let memory_management_attributes = Ast_utils.get_memory_management_attributes () in
try Some (list_find ( try Some (list_find (
@ -256,54 +262,46 @@ let get_memory_management_attribute attributes =
att memory_management_attributes) attributes) att memory_management_attributes) attributes)
with Not_found -> None with Not_found -> None
(*Makes the getters and setters according to the attributes: *) let create_generated_method_name name_info =
(* - If readonly is available, only write getter *) { ni_name = name_info.Clang_ast_t.ni_name;
(* - If strong or retain are available then write the following code in the setter: *) ni_qual_name = CFrontend_config.generated_suffix:: name_info.Clang_ast_t.ni_qual_name;
(* [param retain] *) }
(* [self->_field release] *)
(* [self->_field = param] *) let get_ivar_name prop_name ivar_opt =
(* - If copy is available then write the following code: *) match ivar_opt with
(* [self->_field = [param copy] *) | Some ivar_name -> ivar_name
let make_getter_setter cfg curr_class decl_info property_impl_decl_info = | None -> Ast_utils.generated_ivar_name prop_name
let class_name = CContext.get_curr_class_name curr_class in
let prop_name = Ast_utils.property_name property_impl_decl_info in let make_getter curr_class prop_name prop_type =
Printing.log_out "ADDING: ObjCPropertyImplDecl for property '%s' " prop_name; match prop_type with
Printing.log_out "pointer = '%s'\n" decl_info.Clang_ast_t.di_pointer; | qt, attributes, decl_info, (getter_name, getter), (setter_name, setter), ivar_opt ->
let qt, attributes, decl_info, (getter_name, getter), (setter_name, setter), _ = (try let ivar_name = get_ivar_name prop_name ivar_opt in
Property.find_property curr_class prop_name
with _ ->
Printing.log_out "Property %s not found@." prop_name;
assert false) in
let ivar_name = get_ivarname_property property_impl_decl_info in
let make_getter () =
(
match getter with match getter with
| Some (ObjCMethodDecl(di, name_info, mdi), _) -> | Some (ObjCMethodDecl(di, name_info, mdi), _) ->
let dummy_info = Ast_expressions.dummy_decl_info di in let dummy_info = Ast_expressions.dummy_decl_info_in_curr_file di in
if should_generate_getter cfg class_name name_info.Clang_ast_t.ni_name attributes then let deref_self_field = Ast_expressions.make_deref_self_field
let deref_self_field = Ast_expressions.make_deref_self_field (CContext.get_qt_curr_class curr_class) dummy_info mdi.Clang_ast_t.omdi_result_type ivar_name in
(CContext.get_qt_curr_class curr_class) dummy_info mdi.Clang_ast_t.omdi_result_type ivar_name in let body = ReturnStmt(Ast_expressions.make_stmt_info dummy_info, [deref_self_field]) in
let body = ReturnStmt(Ast_expressions.make_stmt_info dummy_info, [deref_self_field]) in let mdi'= Ast_expressions.make_method_decl_info mdi body in
let mdi'= Ast_expressions.make_method_decl_info mdi body in let generated_name_info = create_generated_method_name name_info in
let method_decl = ObjCMethodDecl(di, name_info, mdi) in Property.replace_property
Property.replace_property (curr_class, prop_name)
(curr_class, prop_name) (qt, attributes, decl_info,
(qt, attributes, decl_info, (getter_name, Some (ObjCMethodDecl(di, name_info, mdi), true)), (setter_name, setter), Some ivar_name);
(getter_name, Some (method_decl, true)), (setter_name, setter), Some ivar_name); [ObjCMethodDecl(dummy_info, generated_name_info, mdi')]
[ObjCMethodDecl(dummy_info, name_info, mdi')] | _ -> []
else []
| _ -> []) in let make_setter curr_class prop_name prop_type =
let make_setter () = match prop_type with
match setter with | qt, attributes, decl_info, (getter_name, getter), (setter_name, setter), ivar_opt ->
| Some (ObjCMethodDecl(di, name_info, mdi), _) -> let ivar_name = get_ivar_name prop_name ivar_opt in
if should_generate_setter cfg class_name name_info.Clang_ast_t.ni_name attributes then match setter with
let dummy_info = Ast_expressions.dummy_decl_info di in | Some (ObjCMethodDecl(di, name, mdi), _) when not (is_property_read_only attributes) ->
let dummy_info = Ast_expressions.dummy_decl_info_in_curr_file di in
let param_name, qt_param = (match mdi.Clang_ast_t.omdi_parameters with let param_name, qt_param = (match mdi.Clang_ast_t.omdi_parameters with
| [ParmVarDecl(_, name_info, qt_param, _)] -> name_info.Clang_ast_t.ni_name, qt_param | [ParmVarDecl(_, name_info, qt_param, _)] -> name_info.Clang_ast_t.ni_name, qt_param
| _ -> assert false) in | _ -> assert false) in
let is_hidden = (match property_impl_decl_info.Clang_ast_t.opidi_ivar_decl with let is_hidden = false in
| Some dr -> dr.Clang_ast_t.dr_is_hidden
| _ -> false) in
let decl_ptr = Ast_utils.get_invalid_pointer () in let decl_ptr = Ast_utils.get_invalid_pointer () in
let drti_decl_ref' = let drti_decl_ref' =
Ast_expressions.make_decl_ref_qt (`ParmVar) decl_ptr param_name is_hidden qt_param in Ast_expressions.make_decl_ref_qt (`ParmVar) decl_ptr param_name is_hidden qt_param in
@ -318,62 +316,68 @@ let make_getter_setter cfg curr_class decl_info property_impl_decl_info =
let memory_management_attribute = (get_memory_management_attribute attributes) in let memory_management_attribute = (get_memory_management_attribute attributes) in
let code = let code =
if Ast_utils.is_retain memory_management_attribute then if Ast_utils.is_retain memory_management_attribute then
let param_decl = let param_decl = Ast_expressions.make_decl_ref_exp_var (param_name, qt_param, decl_ptr) `ParmVar stmt_info in
Ast_expressions.make_decl_ref_exp_var (param_name, qt_param, decl_ptr) `ParmVar stmt_info in let retain_call = Ast_expressions.make_message_expr qt_param retain param_decl stmt_info true in
let retain_call = let release_call = Ast_expressions.make_message_expr qt_param release lhs_exp stmt_info true in
Ast_expressions.make_message_expr qt_param retain param_decl stmt_info true in
let release_call =
Ast_expressions.make_message_expr qt_param release lhs_exp stmt_info true in
[retain_call; release_call; setter] [retain_call; release_call; setter]
else if Ast_utils.is_copy memory_management_attribute then else if Ast_utils.is_copy memory_management_attribute then
let param_decl = let param_decl = Ast_expressions.make_decl_ref_exp_var (param_name, qt_param, decl_ptr) `ParmVar stmt_info in
Ast_expressions.make_decl_ref_exp_var (param_name, qt_param, decl_ptr) `ParmVar stmt_info in let copy_call = Ast_expressions.make_message_expr qt_param copy param_decl stmt_info true in
let copy_call = let setter = Ast_expressions.make_binary_stmt lhs_exp copy_call stmt_info expr_info boi in
Ast_expressions.make_message_expr qt_param copy param_decl stmt_info true in
let setter =
Ast_expressions.make_binary_stmt lhs_exp copy_call stmt_info expr_info boi in
[setter] [setter]
else [setter] in else [setter] in
let body = Ast_expressions.make_compound_stmt code stmt_info in let body = Ast_expressions.make_compound_stmt code stmt_info in
let mdi'= Ast_expressions.make_method_decl_info mdi body in let mdi'= Ast_expressions.make_method_decl_info mdi body in
let name_generated = create_generated_method_name name in
Property.replace_property Property.replace_property
(curr_class, prop_name) (curr_class, prop_name)
(qt, attributes, decl_info, (qt, attributes, decl_info,
(getter_name, getter), (getter_name, getter),
(setter_name, Some (ObjCMethodDecl(di, name_info, mdi), true)), Some ivar_name); (setter_name, Some (ObjCMethodDecl(di, name, mdi), true)), Some ivar_name);
[ObjCMethodDecl(dummy_info, name_info, mdi')] [ObjCMethodDecl(dummy_info, name_generated, mdi')]
else [] | _ -> []
| _ -> [] in
match property_impl_decl_info.Clang_ast_t.opidi_implementation with (*Makes the getters and setters according to the attributes: *)
| `Dynamic (* - If readonly is available, only write getter *)
(* For the moment we treat Dynamic properties as Synthesize. This imply that setter/getter very simply, getting and setting *) (* - If strong or retain are available then write the following code in the setter: *)
(* the value. Therefore we are assuming that the dynamic setter/getter won't have any other side effect.*) (* [param retain] *)
| `Synthesize -> (* [self->_field release] *)
(make_getter ()) @ (make_setter ()) (* [self->_field = param] *)
(* - If copy is available then write the following code: *)
(* Given a list of declarations in an interface returns a triple *) (* [self->_field = [param copy] *)
(* (list of non static fields, list of static fields, list of methods)*) let make_getter_setter curr_class decl_info prop_name =
(* TODO: this part is a bit redundant: we could add the methods to the tenv *) Printing.log_out "pointer = '%s'\n" decl_info.Clang_ast_t.di_pointer;
(* at the same time that we add them to the cfg *) let prop_type =
let rec get_methods curr_class decl_list = try
Property.find_property curr_class prop_name
with _ ->
Printing.log_out "Property %s not found@." prop_name;
assert false in
(make_getter curr_class prop_name prop_type)@ (make_setter curr_class prop_name prop_type)
let add_properties_to_table curr_class decl_list =
let add_property_to_table dec =
match dec with
| 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, pname) pdi.opdi_qual_type pdi.opdi_property_attributes decl_info;
| _ -> () in
list_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 let class_name = CContext.get_curr_class_name curr_class in
match decl_list with add_properties_to_table curr_class decl_list;
| [] -> [] let get_method decl list_methods =
| (ObjCMethodDecl(decl_info, name_info, method_decl_info) as d):: decl_list' -> match decl with
let method_name = name_info.Clang_ast_t.ni_name in ObjCMethodDecl(decl_info, name_info, method_decl_info) as d ->
Printing.log_out " ...Adding Method '%s' \n" (class_name^"_"^method_name); let method_name = name_info.Clang_ast_t.ni_name in
let methods = get_methods curr_class decl_list' in Printing.log_out " ...Adding Method '%s' \n" (class_name^"_"^method_name);
let _ = check_for_property curr_class method_name d method_decl_info.Clang_ast_t.omdi_body in let _ = check_for_property curr_class method_name d method_decl_info.Clang_ast_t.omdi_body in
let meth_name = CMethod_trans.mk_procname_from_method class_name method_name in let meth_name = CMethod_trans.mk_procname_from_method class_name method_name in
meth_name:: methods meth_name:: list_methods
| _ -> list_methods in
| ObjCPropertyDecl(decl_info, name_info, pdi):: decl_list' -> list_fold_right get_method decl_list []
(* Property declaration register the property on the property table to be *)
(* used later on in case getter and setters need to be synthesized by ObjCPropertyImplDecl *)
let pname = name_info.Clang_ast_t.ni_name in
Printing.log_out " ...Adding Property Declaration '%s' " pname;
Printing.log_out " pointer= '%s' \n" decl_info.Clang_ast_t.di_pointer;
Property.add_property (curr_class, pname) pdi.opdi_qual_type pdi.opdi_property_attributes decl_info;
get_methods curr_class decl_list' (* TODO maybe add prop_name here *)
| (d : Clang_ast_t.decl):: decl_list' -> get_methods curr_class decl_list'

@ -7,9 +7,6 @@
* of patent rights can be found in the PATENTS file in the same directory. * of patent rights can be found in the PATENTS file in the same directory.
*) *)
(** Process properties by creating their getters and setters in the case that they need to be syntethized *)
(** or in the case of dynamic. *)
type prop_getter_setter = string * (Clang_ast_t.decl * bool) option 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). *) (** For each property, we save the getter and the setter method declarations (no implementation). *)
@ -18,23 +15,6 @@ type prop_getter_setter = string * (Clang_ast_t.decl * bool) option
type property_type = Clang_ast_t.qual_type * Clang_ast_t.property_attribute list * type property_type = Clang_ast_t.qual_type * Clang_ast_t.property_attribute list *
Clang_ast_t.decl_info * prop_getter_setter * prop_getter_setter * string option Clang_ast_t.decl_info * prop_getter_setter * prop_getter_setter * string option
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 make_getter_setter : Cfg.cfg -> CContext.curr_class -> Clang_ast_t.decl_info -> Clang_ast_t.obj_c_property_impl_decl_info ->
Clang_ast_t.decl list
val reset_property_table : unit -> unit
val print_property_table : unit -> unit
val is_property_read_only : Clang_ast_t.property_attribute list -> bool
val find_properties_class : CContext.curr_class -> (string * property_type) list
module type PropertySig = module type PropertySig =
sig sig
@ -60,6 +40,33 @@ sig
val print_property_table : unit -> unit val print_property_table : unit -> unit
val find_property_name_from_ivar : CContext.curr_class -> string -> string option val find_property_name_from_ivar : CContext.curr_class -> string -> string option
end end
module Property: PropertySig 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 is_property_read_only : Clang_ast_t.property_attribute list -> bool
val find_properties_class : CContext.curr_class -> (string * property_type) list
val make_getter : CContext.curr_class -> string -> property_type -> Clang_ast_t.decl list
val make_setter : CContext.curr_class -> string -> property_type -> Clang_ast_t.decl list
val make_getter_setter : CContext.curr_class -> Clang_ast_t.decl_info -> string -> Clang_ast_t.decl list
val method_is_property_accesor : CContext.curr_class -> string -> (string * property_type * bool) option
val get_ivar_name : string -> string option -> string

@ -292,6 +292,7 @@ let add_harness_to_cg harness_name harness_cfg harness_node loc cg tenv =
Sil.language = Sil.Java; Sil.language = Sil.Java;
Sil.func_attributes = []; Sil.func_attributes = [];
Sil.method_annotation = Sil.method_annotation_empty; Sil.method_annotation = Sil.method_annotation_empty;
Sil.is_generated = false;
} in } in
create { create {
cfg = harness_cfg; cfg = harness_cfg;
@ -343,6 +344,7 @@ let setup_harness_cfg harness_name harness_cfg env proc_file_map tenv =
Sil.language = Sil.Java; Sil.language = Sil.Java;
Sil.func_attributes = []; Sil.func_attributes = [];
Sil.method_annotation = Sil.method_annotation_empty; Sil.method_annotation = Sil.method_annotation_empty;
Sil.is_generated = false;
} in } in
create { create {
cfg = harness_cfg; cfg = harness_cfg;

@ -295,6 +295,7 @@ let create_local_procdesc program linereader cfg tenv node m =
Sil.language = Sil.Java; Sil.language = Sil.Java;
Sil.func_attributes = []; Sil.func_attributes = [];
Sil.method_annotation = method_annotation; Sil.method_annotation = method_annotation;
Sil.is_generated = false;
} in } in
create { create {
cfg = cfg; cfg = cfg;
@ -330,6 +331,7 @@ let create_local_procdesc program linereader cfg tenv node m =
Sil.language = Sil.Java; Sil.language = Sil.Java;
Sil.func_attributes = []; Sil.func_attributes = [];
Sil.method_annotation = method_annotation; Sil.method_annotation = method_annotation;
Sil.is_generated = false;
} in } in
create { create {
cfg = cfg; cfg = cfg;
@ -366,6 +368,7 @@ let create_local_procdesc program linereader cfg tenv node m =
Sil.language = Sil.Java; Sil.language = Sil.Java;
Sil.func_attributes = []; Sil.func_attributes = [];
Sil.method_annotation = method_annotation; Sil.method_annotation = method_annotation;
Sil.is_generated = false;
} in } in
create { create {
cfg = cfg; cfg = cfg;
@ -421,6 +424,7 @@ let create_external_procdesc program cfg tenv cn ms method_annotation kind =
Sil.language = Sil.Java; Sil.language = Sil.Java;
Sil.func_attributes = []; Sil.func_attributes = [];
Sil.method_annotation = method_annotation; Sil.method_annotation = method_annotation;
Sil.is_generated = false;
} in } in
create { create {
cfg = cfg; cfg = cfg;

@ -1,6 +1,10 @@
(* (*
* Copyright (c) 2015 - Facebook. * Copyright (c) 2015 - present Facebook, Inc.
* All rights reserved. * 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.
*) *)
open LAst open LAst
@ -47,11 +51,12 @@ let gen_func_def (old_cfg : Cfg.cfg) : func_def -> unit = function
is_synthetic_method = false; is_synthetic_method = false;
language = Sil.C_CPP; language = Sil.C_CPP;
func_attributes = []; func_attributes = [];
method_annotation = Sil.method_annotation_empty method_annotation = Sil.method_annotation_empty;
is_generated = false
} in } in
let (pdesc_builder : Cfg.Procdesc.proc_desc_builder) = let (pdesc_builder : Cfg.Procdesc.proc_desc_builder) =
{ cfg = old_cfg; { cfg = old_cfg;
name = Procname.from_string (string_of_variable func_name); name = Procname.from_string_c_fun (string_of_variable func_name);
is_defined = true; (** is defined and not just declared *) is_defined = true; (** is defined and not just declared *)
proc_attributes = proc_attrs; proc_attributes = proc_attrs;
ret_type = (match ret_tp_opt with ret_type = (match ret_tp_opt with

@ -1,23 +1,23 @@
digraph iCFG { digraph iCFG {
14 [label="14: BinaryOperatorStmt: Assign \n n$10=*&self:class A * [line 16]\n n$11=*&son:class A * [line 16]\n _fun___objc_retain(n$11:class A *) [line -1]\n n$12=*n$10._son:class A * [line -1]\n *n$10._son:class A *=n$11 [line -1]\n _fun___objc_release(n$12:class A *) [line -1]\n REMOVE_TEMPS(n$10,n$11,n$12); [line -1]\n NULLIFY(&self,false); [line -1]\n NULLIFY(&son,false); [line -1]\n APPLY_ABSTRACTION; [line -1]\n " shape="box"] 14 [label="14: BinaryOperatorStmt: Assign \n n$10=*&self:class A * [line 16]\n n$11=*&son:class A * [line 16]\n _fun___objc_retain(n$11:class A *) [line 16]\n n$12=*n$10._son:class A * [line 16]\n *n$10._son:class A *=n$11 [line 16]\n _fun___objc_release(n$12:class A *) [line 16]\n REMOVE_TEMPS(n$10,n$11,n$12); [line 16]\n NULLIFY(&self,false); [line 16]\n NULLIFY(&son,false); [line 16]\n APPLY_ABSTRACTION; [line 16]\n " shape="box"]
14 -> 13 ; 14 -> 13 ;
13 [label="13: Exit A_setSon: \n " color=yellow style=filled] 13 [label="13: Exit A_setSon: \n " color=yellow style=filled]
12 [label="12: Start A_setSon:\nFormals: self:class A * son:class A *\nLocals: \n DECLARE_LOCALS(&return); [line -1]\n " color=yellow style=filled] 12 [label="12: Start A_setSon: (generated)\nFormals: self:class A * son:class A *\nLocals: \n DECLARE_LOCALS(&return); [line 16]\n " color=yellow style=filled]
12 -> 14 ; 12 -> 14 ;
11 [label="11: Return Stmt \n n$7=*&self:class A * [line -1]\n n$8=*n$7._son:class A * [line -1]\n *&return:class A *=n$8 [line -1]\n n$9=_fun___set_autorelease_attribute(n$8:class A *) [line -1]\n REMOVE_TEMPS(n$7,n$8,n$9); [line -1]\n NULLIFY(&self,false); [line -1]\n APPLY_ABSTRACTION; [line -1]\n " shape="box"] 11 [label="11: Return Stmt \n n$7=*&self:class A * [line 16]\n n$8=*n$7._son:class A * [line 16]\n *&return:class A *=n$8 [line 16]\n n$9=_fun___set_autorelease_attribute(n$8:class A *) [line 16]\n REMOVE_TEMPS(n$7,n$8,n$9); [line 16]\n NULLIFY(&self,false); [line 16]\n APPLY_ABSTRACTION; [line 16]\n " shape="box"]
11 -> 10 ; 11 -> 10 ;
10 [label="10: Exit A_son \n " color=yellow style=filled] 10 [label="10: Exit A_son \n " color=yellow style=filled]
9 [label="9: Start A_son\nFormals: self:class A *\nLocals: \n DECLARE_LOCALS(&return); [line -1]\n " color=yellow style=filled] 9 [label="9: Start A_son (generated)\nFormals: self:class A *\nLocals: \n DECLARE_LOCALS(&return); [line 16]\n " color=yellow style=filled]
9 -> 11 ; 9 -> 11 ;

@ -119,25 +119,25 @@ digraph iCFG {
11 -> 14 ; 11 -> 14 ;
10 [label="10: BinaryOperatorStmt: Assign \n n$6=*&self:class A * [line 17]\n n$7=*&son:class A * [line 17]\n *n$6._son:class A *=n$7 [line -1]\n REMOVE_TEMPS(n$6,n$7); [line -1]\n NULLIFY(&self,false); [line -1]\n NULLIFY(&son,false); [line -1]\n APPLY_ABSTRACTION; [line -1]\n " shape="box"] 10 [label="10: BinaryOperatorStmt: Assign \n n$6=*&self:class A * [line 17]\n n$7=*&son:class A * [line 17]\n *n$6._son:class A *=n$7 [line 17]\n REMOVE_TEMPS(n$6,n$7); [line 17]\n NULLIFY(&self,false); [line 17]\n NULLIFY(&son,false); [line 17]\n APPLY_ABSTRACTION; [line 17]\n " shape="box"]
10 -> 9 ; 10 -> 9 ;
9 [label="9: Exit A_setSon: \n " color=yellow style=filled] 9 [label="9: Exit A_setSon: \n " color=yellow style=filled]
8 [label="8: Start A_setSon:\nFormals: self:class A * son:class A *\nLocals: \n DECLARE_LOCALS(&return); [line -1]\n " color=yellow style=filled] 8 [label="8: Start A_setSon: (generated)\nFormals: self:class A * son:class A *\nLocals: \n DECLARE_LOCALS(&return); [line 17]\n " color=yellow style=filled]
8 -> 10 ; 8 -> 10 ;
7 [label="7: Return Stmt \n n$4=*&self:class A * [line -1]\n n$5=*n$4._son:class A * [line -1]\n *&return:class A *=n$5 [line -1]\n REMOVE_TEMPS(n$4,n$5); [line -1]\n NULLIFY(&self,false); [line -1]\n APPLY_ABSTRACTION; [line -1]\n " shape="box"] 7 [label="7: Return Stmt \n n$4=*&self:class A * [line 17]\n n$5=*n$4._son:class A * [line 17]\n *&return:class A *=n$5 [line 17]\n REMOVE_TEMPS(n$4,n$5); [line 17]\n NULLIFY(&self,false); [line 17]\n APPLY_ABSTRACTION; [line 17]\n " shape="box"]
7 -> 6 ; 7 -> 6 ;
6 [label="6: Exit A_son \n " color=yellow style=filled] 6 [label="6: Exit A_son \n " color=yellow style=filled]
5 [label="5: Start A_son\nFormals: self:class A *\nLocals: \n DECLARE_LOCALS(&return); [line -1]\n " color=yellow style=filled] 5 [label="5: Start A_son (generated)\nFormals: self:class A *\nLocals: \n DECLARE_LOCALS(&return); [line 17]\n " color=yellow style=filled]
5 -> 7 ; 5 -> 7 ;

@ -1,48 +1,4 @@
digraph iCFG { digraph iCFG {
60 [label="60: BinaryOperatorStmt: Assign \n n$41=*&self:class MemoryLeakExample * [line 16]\n n$42=*&attachmentContainerView:class UIView * [line 16]\n *n$41._attachmentContainerView:class UIView *=n$42 [line -1]\n REMOVE_TEMPS(n$41,n$42); [line -1]\n NULLIFY(&attachmentContainerView,false); [line -1]\n NULLIFY(&self,false); [line -1]\n APPLY_ABSTRACTION; [line -1]\n " shape="box"]
60 -> 59 ;
59 [label="59: Exit MemoryLeakExample_setAttachmentContainerView: \n " color=yellow style=filled]
58 [label="58: Start MemoryLeakExample_setAttachmentContainerView:\nFormals: self:class MemoryLeakExample * attachmentContainerView:class UIView *\nLocals: \n DECLARE_LOCALS(&return); [line -1]\n " color=yellow style=filled]
58 -> 60 ;
57 [label="57: Return Stmt \n n$39=*&self:class MemoryLeakExample * [line -1]\n n$40=*n$39._attachmentContainerView:class UIView * [line -1]\n *&return:class UIView *=n$40 [line -1]\n REMOVE_TEMPS(n$39,n$40); [line -1]\n NULLIFY(&self,false); [line -1]\n APPLY_ABSTRACTION; [line -1]\n " shape="box"]
57 -> 56 ;
56 [label="56: Exit MemoryLeakExample_attachmentContainerView \n " color=yellow style=filled]
55 [label="55: Start MemoryLeakExample_attachmentContainerView\nFormals: self:class MemoryLeakExample *\nLocals: \n DECLARE_LOCALS(&return); [line -1]\n " color=yellow style=filled]
55 -> 57 ;
54 [label="54: BinaryOperatorStmt: Assign \n n$37=*&self:class MemoryLeakExample * [line 15]\n n$38=*&backgroundCoveringView:class UIView * [line 15]\n *n$37._backgroundCoveringView:class UIView *=n$38 [line -1]\n REMOVE_TEMPS(n$37,n$38); [line -1]\n NULLIFY(&backgroundCoveringView,false); [line -1]\n NULLIFY(&self,false); [line -1]\n APPLY_ABSTRACTION; [line -1]\n " shape="box"]
54 -> 53 ;
53 [label="53: Exit MemoryLeakExample_setBackgroundCoveringView: \n " color=yellow style=filled]
52 [label="52: Start MemoryLeakExample_setBackgroundCoveringView:\nFormals: self:class MemoryLeakExample * backgroundCoveringView:class UIView *\nLocals: \n DECLARE_LOCALS(&return); [line -1]\n " color=yellow style=filled]
52 -> 54 ;
51 [label="51: Return Stmt \n n$35=*&self:class MemoryLeakExample * [line -1]\n n$36=*n$35._backgroundCoveringView:class UIView * [line -1]\n *&return:class UIView *=n$36 [line -1]\n REMOVE_TEMPS(n$35,n$36); [line -1]\n NULLIFY(&self,false); [line -1]\n APPLY_ABSTRACTION; [line -1]\n " shape="box"]
51 -> 50 ;
50 [label="50: Exit MemoryLeakExample_backgroundCoveringView \n " color=yellow style=filled]
49 [label="49: Start MemoryLeakExample_backgroundCoveringView\nFormals: self:class MemoryLeakExample *\nLocals: \n DECLARE_LOCALS(&return); [line -1]\n " color=yellow style=filled]
49 -> 51 ;
48 [label="48: DeclStmt \n n$34=_fun_FBColorCreateWithGray(0.000000:double ,0.300000:double ) [line 95]\n *&borderColor:struct CGColor *=n$34 [line 95]\n REMOVE_TEMPS(n$34); [line 95]\n " shape="box"] 48 [label="48: DeclStmt \n n$34=_fun_FBColorCreateWithGray(0.000000:double ,0.300000:double ) [line 95]\n *&borderColor:struct CGColor *=n$34 [line 95]\n REMOVE_TEMPS(n$34); [line 95]\n " shape="box"]

@ -18,43 +18,27 @@
@end @end
@implementation AA
@end
@interface BBStrong : NSObject @interface BBStrong : NSObject
@property (nonatomic, strong) AA* a; @property (nonatomic, strong) AA* a;
@end @end
@implementation BBStrong
@end
@interface BBUnsafeUnretained : NSObject @interface BBUnsafeUnretained : NSObject
@property (nonatomic, unsafe_unretained) AA* a; @property (nonatomic, unsafe_unretained) AA* a;
@end @end
@implementation BBUnsafeUnretained
@end
@interface BBWeak : NSObject @interface BBWeak : NSObject
@property (nonatomic, weak) AA* a; @property (nonatomic, weak) AA* a;
@end @end
@implementation BBWeak
@end
@interface BBAssign : NSObject @interface BBAssign : NSObject
@property (nonatomic) AA* a; @property (nonatomic) AA* a;
@end @end
@implementation BBAssign
@end
int strongcycle() { int strongcycle() {
AA* a_obj =[AA alloc]; AA* a_obj =[AA alloc];

@ -18,25 +18,25 @@ digraph iCFG {
16 -> 15 ; 16 -> 15 ;
15 [label="15: BinaryOperatorStmt: Assign \n n$14=*&self:class C * [line 31]\n n$16=*&name:class NSString * [line -1]\n n$15=_fun_NSString_copy(n$16:class NSString *) virtual [line -1]\n *n$14._name:class NSString *=n$15 [line -1]\n REMOVE_TEMPS(n$14,n$15,n$16); [line -1]\n NULLIFY(&name,false); [line -1]\n NULLIFY(&self,false); [line -1]\n APPLY_ABSTRACTION; [line -1]\n " shape="box"] 15 [label="15: BinaryOperatorStmt: Assign \n n$14=*&self:class C * [line 31]\n n$16=*&name:class NSString * [line 31]\n n$15=_fun_NSString_copy(n$16:class NSString *) virtual [line 31]\n *n$14._name:class NSString *=n$15 [line 31]\n REMOVE_TEMPS(n$14,n$15,n$16); [line 31]\n NULLIFY(&name,false); [line 31]\n NULLIFY(&self,false); [line 31]\n APPLY_ABSTRACTION; [line 31]\n " shape="box"]
15 -> 14 ; 15 -> 14 ;
14 [label="14: Exit C_setName: \n " color=yellow style=filled] 14 [label="14: Exit C_setName: \n " color=yellow style=filled]
13 [label="13: Start C_setName:\nFormals: self:class C * name:class NSString *\nLocals: \n DECLARE_LOCALS(&return); [line -1]\n " color=yellow style=filled] 13 [label="13: Start C_setName: (generated)\nFormals: self:class C * name:class NSString *\nLocals: \n DECLARE_LOCALS(&return); [line 31]\n " color=yellow style=filled]
13 -> 16 ; 13 -> 16 ;
12 [label="12: Return Stmt \n n$11=*&self:class C * [line -1]\n n$12=*n$11._name:class NSString * [line -1]\n *&return:class NSString *=n$12 [line -1]\n n$13=_fun___set_autorelease_attribute(n$12:class NSString *) [line -1]\n REMOVE_TEMPS(n$11,n$12,n$13); [line -1]\n NULLIFY(&self,false); [line -1]\n APPLY_ABSTRACTION; [line -1]\n " shape="box"] 12 [label="12: Return Stmt \n n$11=*&self:class C * [line 31]\n n$12=*n$11._name:class NSString * [line 31]\n *&return:class NSString *=n$12 [line 31]\n n$13=_fun___set_autorelease_attribute(n$12:class NSString *) [line 31]\n REMOVE_TEMPS(n$11,n$12,n$13); [line 31]\n NULLIFY(&self,false); [line 31]\n APPLY_ABSTRACTION; [line 31]\n " shape="box"]
12 -> 11 ; 12 -> 11 ;
11 [label="11: Exit C_name \n " color=yellow style=filled] 11 [label="11: Exit C_name \n " color=yellow style=filled]
10 [label="10: Start C_name\nFormals: self:class C *\nLocals: \n DECLARE_LOCALS(&return); [line -1]\n " color=yellow style=filled] 10 [label="10: Start C_name (generated)\nFormals: self:class C *\nLocals: \n DECLARE_LOCALS(&return); [line 31]\n " color=yellow style=filled]
10 -> 12 ; 10 -> 12 ;

@ -1,275 +1,275 @@
digraph iCFG { digraph iCFG {
69 [label="69: Assertion failure \n _fun___infer_fail(\"ASSERTION_FAILURE\":void ) [line 36]\n APPLY_ABSTRACTION; [line 36]\n " shape="box"] 81 [label="81: Assertion failure \n _fun___infer_fail(\"ASSERTION_FAILURE\":void ) [line 36]\n APPLY_ABSTRACTION; [line 36]\n " shape="box"]
69 -> 56 ; 81 -> 65 ;
68 [label="68: Prune (false branch) \n n$33=*&SIL_temp_conditional___62:int [line 38]\n NULLIFY(&SIL_temp_conditional___62,true); [line 38]\n PRUNE((n$33 == 0), false); [line 38]\n REMOVE_TEMPS(n$33); [line 38]\n " shape="invhouse"] 80 [label="80: Prune (false branch) \n n$41=*&SIL_temp_conditional___74:int [line 38]\n NULLIFY(&SIL_temp_conditional___74,true); [line 38]\n PRUNE((n$41 == 0), false); [line 38]\n REMOVE_TEMPS(n$41); [line 38]\n " shape="invhouse"]
68 -> 61 ; 80 -> 73 ;
67 [label="67: Prune (true branch) \n n$33=*&SIL_temp_conditional___62:int [line 38]\n NULLIFY(&SIL_temp_conditional___62,true); [line 38]\n PRUNE((n$33 != 0), true); [line 38]\n REMOVE_TEMPS(n$33); [line 38]\n NULLIFY(&target,false); [line 38]\n " shape="invhouse"] 79 [label="79: Prune (true branch) \n n$41=*&SIL_temp_conditional___74:int [line 38]\n NULLIFY(&SIL_temp_conditional___74,true); [line 38]\n PRUNE((n$41 != 0), true); [line 38]\n REMOVE_TEMPS(n$41); [line 38]\n NULLIFY(&target,false); [line 38]\n " shape="invhouse"]
67 -> 69 ; 79 -> 81 ;
66 [label="66: ConditinalStmt Branch \n DECLARE_LOCALS(&SIL_temp_conditional___62); [line 38]\n *&SIL_temp_conditional___62:int =1 [line 38]\n APPLY_ABSTRACTION; [line 38]\n " shape="box"] 78 [label="78: ConditinalStmt Branch \n DECLARE_LOCALS(&SIL_temp_conditional___74); [line 38]\n *&SIL_temp_conditional___74:int =1 [line 38]\n APPLY_ABSTRACTION; [line 38]\n " shape="box"]
66 -> 62 ; 78 -> 74 ;
65 [label="65: ConditinalStmt Branch \n DECLARE_LOCALS(&SIL_temp_conditional___62); [line 38]\n *&SIL_temp_conditional___62:int =0 [line 38]\n APPLY_ABSTRACTION; [line 38]\n " shape="box"] 77 [label="77: ConditinalStmt Branch \n DECLARE_LOCALS(&SIL_temp_conditional___74); [line 38]\n *&SIL_temp_conditional___74:int =0 [line 38]\n APPLY_ABSTRACTION; [line 38]\n " shape="box"]
65 -> 62 ; 77 -> 74 ;
64 [label="64: Prune (false branch) \n n$32=*&target:class A * [line 38]\n PRUNE((n$32 == 0), false); [line 38]\n REMOVE_TEMPS(n$32); [line 38]\n " shape="invhouse"] 76 [label="76: Prune (false branch) \n n$40=*&target:class A * [line 38]\n PRUNE((n$40 == 0), false); [line 38]\n REMOVE_TEMPS(n$40); [line 38]\n " shape="invhouse"]
64 -> 66 ; 76 -> 78 ;
63 [label="63: Prune (true branch) \n n$32=*&target:class A * [line 38]\n PRUNE((n$32 != 0), true); [line 38]\n REMOVE_TEMPS(n$32); [line 38]\n " shape="invhouse"] 75 [label="75: Prune (true branch) \n n$40=*&target:class A * [line 38]\n PRUNE((n$40 != 0), true); [line 38]\n REMOVE_TEMPS(n$40); [line 38]\n " shape="invhouse"]
63 -> 65 ; 75 -> 77 ;
62 [label="62: + \n " ] 74 [label="74: + \n " ]
62 -> 67 ; 74 -> 79 ;
62 -> 68 ; 74 -> 80 ;
61 [label="61: + \n " ] 73 [label="73: + \n " ]
61 -> 59 ; 73 -> 71 ;
61 -> 60 ; 73 -> 72 ;
60 [label="60: Prune (false branch) \n PRUNE((0 == 0), false); [line 36]\n " shape="invhouse"] 72 [label="72: Prune (false branch) \n PRUNE((0 == 0), false); [line 36]\n " shape="invhouse"]
60 -> 57 ; 72 -> 66 ;
59 [label="59: Prune (true branch) \n PRUNE((0 != 0), true); [line 36]\n APPLY_ABSTRACTION; [line 36]\n " shape="invhouse"] 71 [label="71: Prune (true branch) \n PRUNE((0 != 0), true); [line 36]\n APPLY_ABSTRACTION; [line 36]\n " shape="invhouse"]
59 -> 58 ; 71 -> 70 ;
58 [label="58: + \n " ] 70 [label="70: + \n " ]
58 -> 63 ; 70 -> 75 ;
58 -> 64 ; 70 -> 76 ;
57 [label="57: Return Stmt \n n$31=*&target:class A * [line 37]\n n$30=_fun_A_x(n$31:class A *) virtual [line 37]\n *&return:int =n$30 [line 37]\n REMOVE_TEMPS(n$30,n$31); [line 37]\n NULLIFY(&target,false); [line 37]\n APPLY_ABSTRACTION; [line 37]\n " shape="box"] 69 [label="69: Return Stmt \n n$38=*&self:class A * [line 13]\n n$39=*n$38._x:int [line 13]\n *&return:int =n$39 [line 13]\n REMOVE_TEMPS(n$38,n$39); [line 13]\n NULLIFY(&self,false); [line 13]\n APPLY_ABSTRACTION; [line 13]\n " shape="box"]
57 -> 56 ; 69 -> 68 ;
56 [label="56: Exit test2 \n " color=yellow style=filled] 68 [label="68: Exit A_x \n " color=yellow style=filled]
55 [label="55: Start test2\nFormals: target:class A *\nLocals: \n DECLARE_LOCALS(&return); [line 35]\n " color=yellow style=filled] 67 [label="67: Start A_x (generated)\nFormals: self:class A *\nLocals: \n DECLARE_LOCALS(&return); [line 13]\n " color=yellow style=filled]
55 -> 58 ; 67 -> 69 ;
54 [label="54: Assertion failure \n _fun___infer_fail(\"ASSERTION_FAILURE\":void ) [line 31]\n APPLY_ABSTRACTION; [line 31]\n " shape="box"] 66 [label="66: Return Stmt \n n$37=*&target:class A * [line 37]\n n$36=_fun_A_x(n$37:class A *) virtual [line 37]\n *&return:int =n$36 [line 37]\n REMOVE_TEMPS(n$36,n$37); [line 37]\n NULLIFY(&target,false); [line 37]\n APPLY_ABSTRACTION; [line 37]\n " shape="box"]
54 -> 40 ; 66 -> 65 ;
53 [label="53: Prune (false branch) \n n$25=*&SIL_temp_conditional___46:int [line 33]\n NULLIFY(&SIL_temp_conditional___46,true); [line 33]\n PRUNE((n$25 == 0), false); [line 33]\n REMOVE_TEMPS(n$25); [line 33]\n " shape="invhouse"] 65 [label="65: Exit test2 \n " color=yellow style=filled]
53 -> 45 ; 64 [label="64: Start test2\nFormals: target:class A *\nLocals: \n DECLARE_LOCALS(&return); [line 35]\n " color=yellow style=filled]
52 [label="52: Prune (true branch) \n n$25=*&SIL_temp_conditional___46:int [line 33]\n NULLIFY(&SIL_temp_conditional___46,true); [line 33]\n PRUNE((n$25 != 0), true); [line 33]\n REMOVE_TEMPS(n$25); [line 33]\n NULLIFY(&target,false); [line 33]\n " shape="invhouse"]
52 -> 54 ; 64 -> 70 ;
51 [label="51: ConditinalStmt Branch \n DECLARE_LOCALS(&SIL_temp_conditional___46); [line 33]\n *&SIL_temp_conditional___46:int =1 [line 33]\n APPLY_ABSTRACTION; [line 33]\n " shape="box"] 63 [label="63: Assertion failure \n _fun___infer_fail(\"ASSERTION_FAILURE\":void ) [line 31]\n APPLY_ABSTRACTION; [line 31]\n " shape="box"]
51 -> 46 ; 63 -> 46 ;
50 [label="50: ConditinalStmt Branch \n DECLARE_LOCALS(&SIL_temp_conditional___46); [line 33]\n *&SIL_temp_conditional___46:int =0 [line 33]\n APPLY_ABSTRACTION; [line 33]\n " shape="box"] 62 [label="62: Prune (false branch) \n n$31=*&SIL_temp_conditional___55:int [line 33]\n NULLIFY(&SIL_temp_conditional___55,true); [line 33]\n PRUNE((n$31 == 0), false); [line 33]\n REMOVE_TEMPS(n$31); [line 33]\n " shape="invhouse"]
50 -> 46 ; 62 -> 54 ;
49 [label="49: Prune (false branch) \n PRUNE(((n$24 != (void *)0) == 0), false); [line 31]\n REMOVE_TEMPS(n$24); [line 31]\n " shape="invhouse"] 61 [label="61: Prune (true branch) \n n$31=*&SIL_temp_conditional___55:int [line 33]\n NULLIFY(&SIL_temp_conditional___55,true); [line 33]\n PRUNE((n$31 != 0), true); [line 33]\n REMOVE_TEMPS(n$31); [line 33]\n NULLIFY(&target,false); [line 33]\n " shape="invhouse"]
49 -> 51 ; 61 -> 63 ;
48 [label="48: Prune (true branch) \n PRUNE(((n$24 != (void *)0) != 0), true); [line 31]\n REMOVE_TEMPS(n$24); [line 31]\n " shape="invhouse"] 60 [label="60: ConditinalStmt Branch \n DECLARE_LOCALS(&SIL_temp_conditional___55); [line 33]\n *&SIL_temp_conditional___55:int =1 [line 33]\n APPLY_ABSTRACTION; [line 33]\n " shape="box"]
48 -> 50 ; 60 -> 55 ;
47 [label="47: BinaryOperatorStmt: NE \n n$24=*&target:class A * [line 31]\n " shape="box"] 59 [label="59: ConditinalStmt Branch \n DECLARE_LOCALS(&SIL_temp_conditional___55); [line 33]\n *&SIL_temp_conditional___55:int =0 [line 33]\n APPLY_ABSTRACTION; [line 33]\n " shape="box"]
47 -> 48 ; 59 -> 55 ;
47 -> 49 ; 58 [label="58: Prune (false branch) \n PRUNE(((n$30 != (void *)0) == 0), false); [line 31]\n REMOVE_TEMPS(n$30); [line 31]\n " shape="invhouse"]
46 [label="46: + \n " ]
46 -> 52 ; 58 -> 60 ;
46 -> 53 ; 57 [label="57: Prune (true branch) \n PRUNE(((n$30 != (void *)0) != 0), true); [line 31]\n REMOVE_TEMPS(n$30); [line 31]\n " shape="invhouse"]
45 [label="45: + \n " ]
45 -> 43 ; 57 -> 59 ;
45 -> 44 ; 56 [label="56: BinaryOperatorStmt: NE \n n$30=*&target:class A * [line 31]\n " shape="box"]
44 [label="44: Prune (false branch) \n PRUNE((0 == 0), false); [line 31]\n " shape="invhouse"]
44 -> 41 ; 56 -> 57 ;
43 [label="43: Prune (true branch) \n PRUNE((0 != 0), true); [line 31]\n APPLY_ABSTRACTION; [line 31]\n " shape="invhouse"] 56 -> 58 ;
55 [label="55: + \n " ]
43 -> 42 ; 55 -> 61 ;
42 [label="42: + \n " ] 55 -> 62 ;
54 [label="54: + \n " ]
42 -> 47 ; 54 -> 52 ;
41 [label="41: Return Stmt \n n$23=*&target:class A * [line 32]\n n$22=_fun_A_x(n$23:class A *) virtual [line 32]\n *&return:int =n$22 [line 32]\n REMOVE_TEMPS(n$22,n$23); [line 32]\n NULLIFY(&target,false); [line 32]\n APPLY_ABSTRACTION; [line 32]\n " shape="box"] 54 -> 53 ;
53 [label="53: Prune (false branch) \n PRUNE((0 == 0), false); [line 31]\n " shape="invhouse"]
41 -> 40 ; 53 -> 47 ;
40 [label="40: Exit test1 \n " color=yellow style=filled] 52 [label="52: Prune (true branch) \n PRUNE((0 != 0), true); [line 31]\n APPLY_ABSTRACTION; [line 31]\n " shape="invhouse"]
39 [label="39: Start test1\nFormals: target:class A *\nLocals: \n DECLARE_LOCALS(&return); [line 30]\n " color=yellow style=filled] 52 -> 51 ;
51 [label="51: + \n " ]
39 -> 42 ; 51 -> 56 ;
38 [label="38: BinaryOperatorStmt: Assign \n n$20=*&self:class A * [line 13]\n n$21=*&x:int [line 13]\n *n$20._x:int =n$21 [line -1]\n REMOVE_TEMPS(n$20,n$21); [line -1]\n NULLIFY(&self,false); [line -1]\n NULLIFY(&x,false); [line -1]\n APPLY_ABSTRACTION; [line -1]\n " shape="box"] 47 [label="47: Return Stmt \n n$27=*&target:class A * [line 32]\n n$26=_fun_A_x(n$27:class A *) virtual [line 32]\n *&return:int =n$26 [line 32]\n REMOVE_TEMPS(n$26,n$27); [line 32]\n NULLIFY(&target,false); [line 32]\n APPLY_ABSTRACTION; [line 32]\n " shape="box"]
38 -> 37 ; 47 -> 46 ;
37 [label="37: Exit A_setX: \n " color=yellow style=filled] 46 [label="46: Exit test1 \n " color=yellow style=filled]
36 [label="36: Start A_setX:\nFormals: self:class A * x:int \nLocals: \n DECLARE_LOCALS(&return); [line -1]\n " color=yellow style=filled] 45 [label="45: Start test1\nFormals: target:class A *\nLocals: \n DECLARE_LOCALS(&return); [line 30]\n " color=yellow style=filled]
36 -> 38 ; 45 -> 51 ;
35 [label="35: Return Stmt \n n$18=*&self:class A * [line -1]\n n$19=*n$18._x:int [line -1]\n *&return:int =n$19 [line -1]\n REMOVE_TEMPS(n$18,n$19); [line -1]\n NULLIFY(&self,false); [line -1]\n APPLY_ABSTRACTION; [line -1]\n " shape="box"] 44 [label="44: BinaryOperatorStmt: Assign \n n$24=*&self:class A * [line 13]\n n$25=*&x:int [line 13]\n *n$24._x:int =n$25 [line 13]\n REMOVE_TEMPS(n$24,n$25); [line 13]\n NULLIFY(&self,false); [line 13]\n NULLIFY(&x,false); [line 13]\n APPLY_ABSTRACTION; [line 13]\n " shape="box"]
35 -> 34 ; 44 -> 43 ;
34 [label="34: Exit A_x \n " color=yellow style=filled] 43 [label="43: Exit A_setX: \n " color=yellow style=filled]
33 [label="33: Start A_x\nFormals: self:class A *\nLocals: \n DECLARE_LOCALS(&return); [line -1]\n " color=yellow style=filled] 42 [label="42: Start A_setX: (generated)\nFormals: self:class A * x:int \nLocals: \n DECLARE_LOCALS(&return); [line 13]\n " color=yellow style=filled]
33 -> 35 ; 42 -> 44 ;
32 [label="32: Assertion failure \n _fun___infer_fail(\"ASSERTION_FAILURE\":void ) [line 24]\n APPLY_ABSTRACTION; [line 24]\n " shape="box"] 38 [label="38: Assertion failure \n _fun___infer_fail(\"ASSERTION_FAILURE\":void ) [line 24]\n APPLY_ABSTRACTION; [line 24]\n " shape="box"]
32 -> 18 ; 38 -> 21 ;
31 [label="31: Prune (false branch) \n n$12=*&SIL_temp_conditional___24:int [line 26]\n NULLIFY(&SIL_temp_conditional___24,true); [line 26]\n PRUNE((n$12 == 0), false); [line 26]\n REMOVE_TEMPS(n$12); [line 26]\n " shape="invhouse"] 37 [label="37: Prune (false branch) \n n$16=*&SIL_temp_conditional___30:int [line 26]\n NULLIFY(&SIL_temp_conditional___30,true); [line 26]\n PRUNE((n$16 == 0), false); [line 26]\n REMOVE_TEMPS(n$16); [line 26]\n " shape="invhouse"]
31 -> 23 ; 37 -> 29 ;
30 [label="30: Prune (true branch) \n n$12=*&SIL_temp_conditional___24:int [line 26]\n NULLIFY(&SIL_temp_conditional___24,true); [line 26]\n PRUNE((n$12 != 0), true); [line 26]\n REMOVE_TEMPS(n$12); [line 26]\n NULLIFY(&a,false); [line 26]\n " shape="invhouse"] 36 [label="36: Prune (true branch) \n n$16=*&SIL_temp_conditional___30:int [line 26]\n NULLIFY(&SIL_temp_conditional___30,true); [line 26]\n PRUNE((n$16 != 0), true); [line 26]\n REMOVE_TEMPS(n$16); [line 26]\n NULLIFY(&a,false); [line 26]\n " shape="invhouse"]
30 -> 32 ; 36 -> 38 ;
29 [label="29: ConditinalStmt Branch \n DECLARE_LOCALS(&SIL_temp_conditional___24); [line 26]\n *&SIL_temp_conditional___24:int =1 [line 26]\n APPLY_ABSTRACTION; [line 26]\n " shape="box"] 35 [label="35: ConditinalStmt Branch \n DECLARE_LOCALS(&SIL_temp_conditional___30); [line 26]\n *&SIL_temp_conditional___30:int =1 [line 26]\n APPLY_ABSTRACTION; [line 26]\n " shape="box"]
29 -> 24 ; 35 -> 30 ;
28 [label="28: ConditinalStmt Branch \n DECLARE_LOCALS(&SIL_temp_conditional___24); [line 26]\n *&SIL_temp_conditional___24:int =0 [line 26]\n APPLY_ABSTRACTION; [line 26]\n " shape="box"] 34 [label="34: ConditinalStmt Branch \n DECLARE_LOCALS(&SIL_temp_conditional___30); [line 26]\n *&SIL_temp_conditional___30:int =0 [line 26]\n APPLY_ABSTRACTION; [line 26]\n " shape="box"]
28 -> 24 ; 34 -> 30 ;
27 [label="27: Prune (false branch) \n PRUNE(((n$11 != (void *)0) == 0), false); [line 24]\n REMOVE_TEMPS(n$11); [line 24]\n " shape="invhouse"] 33 [label="33: Prune (false branch) \n PRUNE(((n$15 != (void *)0) == 0), false); [line 24]\n REMOVE_TEMPS(n$15); [line 24]\n " shape="invhouse"]
27 -> 29 ; 33 -> 35 ;
26 [label="26: Prune (true branch) \n PRUNE(((n$11 != (void *)0) != 0), true); [line 24]\n REMOVE_TEMPS(n$11); [line 24]\n " shape="invhouse"] 32 [label="32: Prune (true branch) \n PRUNE(((n$15 != (void *)0) != 0), true); [line 24]\n REMOVE_TEMPS(n$15); [line 24]\n " shape="invhouse"]
26 -> 28 ; 32 -> 34 ;
25 [label="25: BinaryOperatorStmt: NE \n n$11=*&a:class A * [line 24]\n " shape="box"] 31 [label="31: BinaryOperatorStmt: NE \n n$15=*&a:class A * [line 24]\n " shape="box"]
25 -> 26 ; 31 -> 32 ;
25 -> 27 ; 31 -> 33 ;
24 [label="24: + \n " ] 30 [label="30: + \n " ]
24 -> 30 ; 30 -> 36 ;
24 -> 31 ; 30 -> 37 ;
23 [label="23: + \n " ] 29 [label="29: + \n " ]
23 -> 21 ; 29 -> 27 ;
23 -> 22 ; 29 -> 28 ;
22 [label="22: Prune (false branch) \n PRUNE((0 == 0), false); [line 24]\n " shape="invhouse"] 28 [label="28: Prune (false branch) \n PRUNE((0 == 0), false); [line 24]\n " shape="invhouse"]
22 -> 19 ; 28 -> 22 ;
21 [label="21: Prune (true branch) \n PRUNE((0 != 0), true); [line 24]\n APPLY_ABSTRACTION; [line 24]\n " shape="invhouse"] 27 [label="27: Prune (true branch) \n PRUNE((0 != 0), true); [line 24]\n APPLY_ABSTRACTION; [line 24]\n " shape="invhouse"]
21 -> 20 ; 27 -> 26 ;
20 [label="20: + \n " ] 26 [label="26: + \n " ]
20 -> 25 ; 26 -> 31 ;
19 [label="19: Return Stmt \n n$10=*&a:class A * [line 25]\n n$9=_fun_A_x(n$10:class A *) virtual [line 25]\n *&return:int =n$9 [line 25]\n REMOVE_TEMPS(n$9,n$10); [line 25]\n NULLIFY(&a,false); [line 25]\n APPLY_ABSTRACTION; [line 25]\n " shape="box"] 22 [label="22: Return Stmt \n n$12=*&a:class A * [line 25]\n n$11=_fun_A_x(n$12:class A *) virtual [line 25]\n *&return:int =n$11 [line 25]\n REMOVE_TEMPS(n$11,n$12); [line 25]\n NULLIFY(&a,false); [line 25]\n APPLY_ABSTRACTION; [line 25]\n " shape="box"]
19 -> 18 ; 22 -> 21 ;
18 [label="18: Exit A_initWithRequest: \n " color=yellow style=filled] 21 [label="21: Exit A_initWithRequest: \n " color=yellow style=filled]
17 [label="17: Start A_initWithRequest:\nFormals: self:class A * a:class A *\nLocals: \n DECLARE_LOCALS(&return); [line 23]\n NULLIFY(&self,false); [line 23]\n " color=yellow style=filled] 20 [label="20: Start A_initWithRequest:\nFormals: self:class A * a:class A *\nLocals: \n DECLARE_LOCALS(&return); [line 23]\n NULLIFY(&self,false); [line 23]\n " color=yellow style=filled]
17 -> 20 ; 20 -> 26 ;
16 [label="16: Assertion failure \n _fun___infer_fail(\"ASSERTION_FAILURE\":void ) [line 19]\n APPLY_ABSTRACTION; [line 19]\n " shape="box"] 19 [label="19: Assertion failure \n _fun___infer_fail(\"ASSERTION_FAILURE\":void ) [line 19]\n APPLY_ABSTRACTION; [line 19]\n " shape="box"]
16 -> 2 ; 19 -> 2 ;
15 [label="15: Prune (false branch) \n n$3=*&SIL_temp_conditional___8:int [line 21]\n NULLIFY(&SIL_temp_conditional___8,true); [line 21]\n PRUNE((n$3 == 0), false); [line 21]\n REMOVE_TEMPS(n$3); [line 21]\n " shape="invhouse"] 18 [label="18: Prune (false branch) \n n$5=*&SIL_temp_conditional___11:int [line 21]\n NULLIFY(&SIL_temp_conditional___11,true); [line 21]\n PRUNE((n$5 == 0), false); [line 21]\n REMOVE_TEMPS(n$5); [line 21]\n " shape="invhouse"]
15 -> 7 ; 18 -> 10 ;
14 [label="14: Prune (true branch) \n n$3=*&SIL_temp_conditional___8:int [line 21]\n NULLIFY(&SIL_temp_conditional___8,true); [line 21]\n PRUNE((n$3 != 0), true); [line 21]\n REMOVE_TEMPS(n$3); [line 21]\n NULLIFY(&target,false); [line 21]\n " shape="invhouse"] 17 [label="17: Prune (true branch) \n n$5=*&SIL_temp_conditional___11:int [line 21]\n NULLIFY(&SIL_temp_conditional___11,true); [line 21]\n PRUNE((n$5 != 0), true); [line 21]\n REMOVE_TEMPS(n$5); [line 21]\n NULLIFY(&target,false); [line 21]\n " shape="invhouse"]
14 -> 16 ; 17 -> 19 ;
13 [label="13: ConditinalStmt Branch \n DECLARE_LOCALS(&SIL_temp_conditional___8); [line 21]\n *&SIL_temp_conditional___8:int =1 [line 21]\n APPLY_ABSTRACTION; [line 21]\n " shape="box"] 16 [label="16: ConditinalStmt Branch \n DECLARE_LOCALS(&SIL_temp_conditional___11); [line 21]\n *&SIL_temp_conditional___11:int =1 [line 21]\n APPLY_ABSTRACTION; [line 21]\n " shape="box"]
13 -> 8 ; 16 -> 11 ;
12 [label="12: ConditinalStmt Branch \n DECLARE_LOCALS(&SIL_temp_conditional___8); [line 21]\n *&SIL_temp_conditional___8:int =0 [line 21]\n APPLY_ABSTRACTION; [line 21]\n " shape="box"] 15 [label="15: ConditinalStmt Branch \n DECLARE_LOCALS(&SIL_temp_conditional___11); [line 21]\n *&SIL_temp_conditional___11:int =0 [line 21]\n APPLY_ABSTRACTION; [line 21]\n " shape="box"]
12 -> 8 ; 15 -> 11 ;
11 [label="11: Prune (false branch) \n PRUNE(((n$2 != (void *)0) == 0), false); [line 19]\n REMOVE_TEMPS(n$2); [line 19]\n " shape="invhouse"] 14 [label="14: Prune (false branch) \n PRUNE(((n$4 != (void *)0) == 0), false); [line 19]\n REMOVE_TEMPS(n$4); [line 19]\n " shape="invhouse"]
11 -> 13 ; 14 -> 16 ;
10 [label="10: Prune (true branch) \n PRUNE(((n$2 != (void *)0) != 0), true); [line 19]\n REMOVE_TEMPS(n$2); [line 19]\n " shape="invhouse"] 13 [label="13: Prune (true branch) \n PRUNE(((n$4 != (void *)0) != 0), true); [line 19]\n REMOVE_TEMPS(n$4); [line 19]\n " shape="invhouse"]
10 -> 12 ; 13 -> 15 ;
9 [label="9: BinaryOperatorStmt: NE \n n$2=*&target:class A * [line 19]\n " shape="box"] 12 [label="12: BinaryOperatorStmt: NE \n n$4=*&target:class A * [line 19]\n " shape="box"]
9 -> 10 ; 12 -> 13 ;
9 -> 11 ; 12 -> 14 ;
8 [label="8: + \n " ] 11 [label="11: + \n " ]
8 -> 14 ; 11 -> 17 ;
8 -> 15 ; 11 -> 18 ;
7 [label="7: + \n " ] 10 [label="10: + \n " ]
7 -> 5 ; 10 -> 8 ;
7 -> 6 ; 10 -> 9 ;
6 [label="6: Prune (false branch) \n PRUNE((0 == 0), false); [line 19]\n " shape="invhouse"] 9 [label="9: Prune (false branch) \n PRUNE((0 == 0), false); [line 19]\n " shape="invhouse"]
6 -> 3 ; 9 -> 3 ;
5 [label="5: Prune (true branch) \n PRUNE((0 != 0), true); [line 19]\n APPLY_ABSTRACTION; [line 19]\n " shape="invhouse"] 8 [label="8: Prune (true branch) \n PRUNE((0 != 0), true); [line 19]\n APPLY_ABSTRACTION; [line 19]\n " shape="invhouse"]
5 -> 4 ; 8 -> 7 ;
4 [label="4: + \n " ] 7 [label="7: + \n " ]
4 -> 9 ; 7 -> 12 ;
3 [label="3: Return Stmt \n n$1=*&target:class A * [line 20]\n n$0=_fun_A_x(n$1:class A *) virtual [line 20]\n *&return:int =n$0 [line 20]\n REMOVE_TEMPS(n$0,n$1); [line 20]\n NULLIFY(&target,false); [line 20]\n APPLY_ABSTRACTION; [line 20]\n " shape="box"] 3 [label="3: Return Stmt \n n$1=*&target:class A * [line 20]\n n$0=_fun_A_x(n$1:class A *) virtual [line 20]\n *&return:int =n$0 [line 20]\n REMOVE_TEMPS(n$0,n$1); [line 20]\n NULLIFY(&target,false); [line 20]\n APPLY_ABSTRACTION; [line 20]\n " shape="box"]
@ -280,5 +280,5 @@ digraph iCFG {
1 [label="1: Start A_addTarget:\nFormals: self:class A * target:class A *\nLocals: \n DECLARE_LOCALS(&return); [line 18]\n NULLIFY(&self,false); [line 18]\n " color=yellow style=filled] 1 [label="1: Start A_addTarget:\nFormals: self:class A * target:class A *\nLocals: \n DECLARE_LOCALS(&return); [line 18]\n NULLIFY(&self,false); [line 18]\n " color=yellow style=filled]
1 -> 4 ; 1 -> 7 ;
} }

@ -1,42 +1,42 @@
digraph iCFG { digraph iCFG {
27 [label="27: DeclStmt \n n$18=_fun_A_sharedInstance() [line 50]\n *&b:class A *=n$18 [line 50]\n REMOVE_TEMPS(n$18); [line 50]\n " shape="box"] 30 [label="30: DeclStmt \n n$20=_fun_A_sharedInstance() [line 50]\n *&b:class A *=n$20 [line 50]\n REMOVE_TEMPS(n$20); [line 50]\n " shape="box"]
27 -> 26 ; 30 -> 29 ;
26 [label="26: Message Call: setX: \n n$17=*&b:class A * [line 51]\n _fun_A_setX:(n$17:class A *,17:int ) virtual [line 51]\n REMOVE_TEMPS(n$17); [line 51]\n NULLIFY(&b,false); [line 51]\n " shape="box"] 29 [label="29: Message Call: setX: \n n$17=*&b:class A * [line 51]\n _fun_A_setX:(n$17:class A *,17:int ) virtual [line 51]\n REMOVE_TEMPS(n$17); [line 51]\n NULLIFY(&b,false); [line 51]\n " shape="box"]
26 -> 25 ; 29 -> 25 ;
25 [label="25: Return Stmt \n *&return:int =0 [line 52]\n APPLY_ABSTRACTION; [line 52]\n " shape="box"] 28 [label="28: BinaryOperatorStmt: Assign \n n$18=*&self:class A * [line 14]\n n$19=*&x:int [line 14]\n *n$18._x:int =n$19 [line 14]\n REMOVE_TEMPS(n$18,n$19); [line 14]\n NULLIFY(&self,false); [line 14]\n NULLIFY(&x,false); [line 14]\n APPLY_ABSTRACTION; [line 14]\n " shape="box"]
25 -> 24 ; 28 -> 27 ;
24 [label="24: Exit main \n " color=yellow style=filled] 27 [label="27: Exit A_setX: \n " color=yellow style=filled]
23 [label="23: Start main\nFormals: \nLocals: b:class A * \n DECLARE_LOCALS(&return,&b); [line 49]\n NULLIFY(&b,false); [line 49]\n " color=yellow style=filled] 26 [label="26: Start A_setX: (generated)\nFormals: self:class A * x:int \nLocals: \n DECLARE_LOCALS(&return); [line 14]\n " color=yellow style=filled]
23 -> 27 ; 26 -> 28 ;
22 [label="22: BinaryOperatorStmt: Assign \n n$15=*&self:class A * [line 14]\n n$16=*&x:int [line 14]\n *n$15._x:int =n$16 [line -1]\n REMOVE_TEMPS(n$15,n$16); [line -1]\n NULLIFY(&self,false); [line -1]\n NULLIFY(&x,false); [line -1]\n APPLY_ABSTRACTION; [line -1]\n " shape="box"] 25 [label="25: Return Stmt \n *&return:int =0 [line 52]\n APPLY_ABSTRACTION; [line 52]\n " shape="box"]
22 -> 21 ; 25 -> 24 ;
21 [label="21: Exit A_setX: \n " color=yellow style=filled] 24 [label="24: Exit main \n " color=yellow style=filled]
20 [label="20: Start A_setX:\nFormals: self:class A * x:int \nLocals: \n DECLARE_LOCALS(&return); [line -1]\n " color=yellow style=filled] 23 [label="23: Start main\nFormals: \nLocals: b:class A * \n DECLARE_LOCALS(&return,&b); [line 49]\n NULLIFY(&b,false); [line 49]\n " color=yellow style=filled]
20 -> 22 ; 23 -> 30 ;
19 [label="19: Return Stmt \n n$13=*&self:class A * [line -1]\n n$14=*n$13._x:int [line -1]\n *&return:int =n$14 [line -1]\n REMOVE_TEMPS(n$13,n$14); [line -1]\n NULLIFY(&self,false); [line -1]\n APPLY_ABSTRACTION; [line -1]\n " shape="box"] 19 [label="19: Return Stmt \n n$13=*&self:class A * [line 14]\n n$14=*n$13._x:int [line 14]\n *&return:int =n$14 [line 14]\n REMOVE_TEMPS(n$13,n$14); [line 14]\n NULLIFY(&self,false); [line 14]\n APPLY_ABSTRACTION; [line 14]\n " shape="box"]
19 -> 18 ; 19 -> 18 ;
18 [label="18: Exit A_x \n " color=yellow style=filled] 18 [label="18: Exit A_x \n " color=yellow style=filled]
17 [label="17: Start A_x\nFormals: self:class A *\nLocals: \n DECLARE_LOCALS(&return); [line -1]\n " color=yellow style=filled] 17 [label="17: Start A_x (generated)\nFormals: self:class A *\nLocals: \n DECLARE_LOCALS(&return); [line 14]\n " color=yellow style=filled]
17 -> 19 ; 17 -> 19 ;

@ -1,98 +1,98 @@
digraph iCFG { digraph iCFG {
36 [label="36: DeclStmt \n n$37=_fun___objc_alloc_no_fail(sizeof(class A ):class A *) [line 39]\n n$35=_fun_A_init(n$37:class A *) virtual [line 39]\n *&a:class A *=n$35 [line 39]\n REMOVE_TEMPS(n$35,n$37); [line 39]\n " shape="box"] 39 [label="39: DeclStmt \n n$39=_fun___objc_alloc_no_fail(sizeof(class A ):class A *) [line 39]\n n$37=_fun_A_init(n$39:class A *) virtual [line 39]\n *&a:class A *=n$37 [line 39]\n REMOVE_TEMPS(n$37,n$39); [line 39]\n " shape="box"]
36 -> 35 ; 39 -> 38 ;
35 [label="35: Message Call: setLast_name: \n n$33=*&a:class A * [line 40]\n n$34=*&a2:class A * [line 40]\n _fun_A_setLast_name:(n$33:class A *,n$34:class A *) virtual [line 40]\n REMOVE_TEMPS(n$33,n$34); [line 40]\n NULLIFY(&a2,false); [line 40]\n " shape="box"] 38 [label="38: Message Call: setLast_name: \n n$33=*&a:class A * [line 40]\n n$34=*&a2:class A * [line 40]\n _fun_A_setLast_name:(n$33:class A *,n$34:class A *) virtual [line 40]\n REMOVE_TEMPS(n$33,n$34); [line 40]\n NULLIFY(&a2,false); [line 40]\n " shape="box"]
35 -> 34 ; 38 -> 34 ;
34 [label="34: Message Call: release \n n$32=*&a:class A * [line 41]\n _fun___objc_release(n$32:class A *) [line 41]\n REMOVE_TEMPS(n$32); [line 41]\n NULLIFY(&a,false); [line 41]\n " shape="box"] 37 [label="37: BinaryOperatorStmt: Assign \n n$35=*&self:class A * [line 18]\n n$36=*&last_name:class A * [line 18]\n *n$35._last_name:class A *=n$36 [line 18]\n REMOVE_TEMPS(n$35,n$36); [line 18]\n NULLIFY(&last_name,false); [line 18]\n NULLIFY(&self,false); [line 18]\n APPLY_ABSTRACTION; [line 18]\n " shape="box"]
34 -> 33 ; 37 -> 36 ;
33 [label="33: Return Stmt \n *&return:int =0 [line 42]\n APPLY_ABSTRACTION; [line 42]\n " shape="box"] 36 [label="36: Exit A_setLast_name: \n " color=yellow style=filled]
33 -> 32 ; 35 [label="35: Start A_setLast_name: (generated)\nFormals: self:class A * last_name:class A *\nLocals: \n DECLARE_LOCALS(&return); [line 18]\n " color=yellow style=filled]
32 [label="32: Exit test \n " color=yellow style=filled]
31 [label="31: Start test\nFormals: a2:class A *\nLocals: a:class A * \n DECLARE_LOCALS(&return,&a); [line 38]\n NULLIFY(&a,false); [line 38]\n " color=yellow style=filled] 35 -> 37 ;
34 [label="34: Message Call: release \n n$32=*&a:class A * [line 41]\n _fun___objc_release(n$32:class A *) [line 41]\n REMOVE_TEMPS(n$32); [line 41]\n NULLIFY(&a,false); [line 41]\n " shape="box"]
31 -> 36 ; 34 -> 33 ;
30 [label="30: BinaryOperatorStmt: Assign \n n$30=*&self:class A * [line 18]\n n$31=*&last_name:class A * [line 18]\n *n$30._last_name:class A *=n$31 [line -1]\n REMOVE_TEMPS(n$30,n$31); [line -1]\n NULLIFY(&last_name,false); [line -1]\n NULLIFY(&self,false); [line -1]\n APPLY_ABSTRACTION; [line -1]\n " shape="box"] 33 [label="33: Return Stmt \n *&return:int =0 [line 42]\n APPLY_ABSTRACTION; [line 42]\n " shape="box"]
30 -> 29 ; 33 -> 32 ;
29 [label="29: Exit A_setLast_name: \n " color=yellow style=filled] 32 [label="32: Exit test \n " color=yellow style=filled]
28 [label="28: Start A_setLast_name:\nFormals: self:class A * last_name:class A *\nLocals: \n DECLARE_LOCALS(&return); [line -1]\n " color=yellow style=filled] 31 [label="31: Start test\nFormals: a2:class A *\nLocals: a:class A * \n DECLARE_LOCALS(&return,&a); [line 38]\n NULLIFY(&a,false); [line 38]\n " color=yellow style=filled]
28 -> 30 ; 31 -> 39 ;
27 [label="27: Return Stmt \n n$28=*&self:class A * [line -1]\n n$29=*n$28._last_name:class A * [line -1]\n *&return:class A *=n$29 [line -1]\n REMOVE_TEMPS(n$28,n$29); [line -1]\n NULLIFY(&self,false); [line -1]\n APPLY_ABSTRACTION; [line -1]\n " shape="box"] 27 [label="27: Return Stmt \n n$28=*&self:class A * [line 18]\n n$29=*n$28._last_name:class A * [line 18]\n *&return:class A *=n$29 [line 18]\n REMOVE_TEMPS(n$28,n$29); [line 18]\n NULLIFY(&self,false); [line 18]\n APPLY_ABSTRACTION; [line 18]\n " shape="box"]
27 -> 26 ; 27 -> 26 ;
26 [label="26: Exit A_last_name \n " color=yellow style=filled] 26 [label="26: Exit A_last_name \n " color=yellow style=filled]
25 [label="25: Start A_last_name\nFormals: self:class A *\nLocals: \n DECLARE_LOCALS(&return); [line -1]\n " color=yellow style=filled] 25 [label="25: Start A_last_name (generated)\nFormals: self:class A *\nLocals: \n DECLARE_LOCALS(&return); [line 18]\n " color=yellow style=filled]
25 -> 27 ; 25 -> 27 ;
24 [label="24: Message Call: retain \n n$27=*&name:class A * [line -1]\n n$26=_fun___objc_retain(n$27:class A *) [line -1]\n REMOVE_TEMPS(n$26,n$27); [line -1]\n " shape="box"] 24 [label="24: Message Call: retain \n n$27=*&name:class A * [line 16]\n n$26=_fun___objc_retain(n$27:class A *) [line 16]\n REMOVE_TEMPS(n$26,n$27); [line 16]\n " shape="box"]
24 -> 23 ; 24 -> 23 ;
23 [label="23: Message Call: release \n n$24=*&self:class A * [line 16]\n n$25=*n$24._name:class A * [line -1]\n n$23=_fun___objc_release(n$25:class A *) [line -1]\n REMOVE_TEMPS(n$23,n$24,n$25); [line -1]\n " shape="box"] 23 [label="23: Message Call: release \n n$24=*&self:class A * [line 16]\n n$25=*n$24._name:class A * [line 16]\n n$23=_fun___objc_release(n$25:class A *) [line 16]\n REMOVE_TEMPS(n$23,n$24,n$25); [line 16]\n " shape="box"]
23 -> 22 ; 23 -> 22 ;
22 [label="22: BinaryOperatorStmt: Assign \n n$21=*&self:class A * [line 16]\n n$22=*&name:class A * [line 16]\n *n$21._name:class A *=n$22 [line -1]\n REMOVE_TEMPS(n$21,n$22); [line -1]\n NULLIFY(&name,false); [line -1]\n NULLIFY(&self,false); [line -1]\n APPLY_ABSTRACTION; [line -1]\n " shape="box"] 22 [label="22: BinaryOperatorStmt: Assign \n n$21=*&self:class A * [line 16]\n n$22=*&name:class A * [line 16]\n *n$21._name:class A *=n$22 [line 16]\n REMOVE_TEMPS(n$21,n$22); [line 16]\n NULLIFY(&name,false); [line 16]\n NULLIFY(&self,false); [line 16]\n APPLY_ABSTRACTION; [line 16]\n " shape="box"]
22 -> 21 ; 22 -> 21 ;
21 [label="21: Exit A_setName: \n " color=yellow style=filled] 21 [label="21: Exit A_setName: \n " color=yellow style=filled]
20 [label="20: Start A_setName:\nFormals: self:class A * name:class A *\nLocals: \n DECLARE_LOCALS(&return); [line -1]\n " color=yellow style=filled] 20 [label="20: Start A_setName: (generated)\nFormals: self:class A * name:class A *\nLocals: \n DECLARE_LOCALS(&return); [line 16]\n " color=yellow style=filled]
20 -> 24 ; 20 -> 24 ;
19 [label="19: Return Stmt \n n$19=*&self:class A * [line -1]\n n$20=*n$19._name:class A * [line -1]\n *&return:class A *=n$20 [line -1]\n REMOVE_TEMPS(n$19,n$20); [line -1]\n NULLIFY(&self,false); [line -1]\n APPLY_ABSTRACTION; [line -1]\n " shape="box"] 19 [label="19: Return Stmt \n n$19=*&self:class A * [line 16]\n n$20=*n$19._name:class A * [line 16]\n *&return:class A *=n$20 [line 16]\n REMOVE_TEMPS(n$19,n$20); [line 16]\n NULLIFY(&self,false); [line 16]\n APPLY_ABSTRACTION; [line 16]\n " shape="box"]
19 -> 18 ; 19 -> 18 ;
18 [label="18: Exit A_name \n " color=yellow style=filled] 18 [label="18: Exit A_name \n " color=yellow style=filled]
17 [label="17: Start A_name\nFormals: self:class A *\nLocals: \n DECLARE_LOCALS(&return); [line -1]\n " color=yellow style=filled] 17 [label="17: Start A_name (generated)\nFormals: self:class A *\nLocals: \n DECLARE_LOCALS(&return); [line 16]\n " color=yellow style=filled]
17 -> 19 ; 17 -> 19 ;
16 [label="16: BinaryOperatorStmt: Assign \n n$16=*&self:class A * [line 14]\n n$18=*&child:class A * [line -1]\n n$17=_fun_A_copy(n$18:class A *) virtual [line -1]\n *n$16._child:class A *=n$17 [line -1]\n REMOVE_TEMPS(n$16,n$17,n$18); [line -1]\n NULLIFY(&child,false); [line -1]\n NULLIFY(&self,false); [line -1]\n APPLY_ABSTRACTION; [line -1]\n " shape="box"] 16 [label="16: BinaryOperatorStmt: Assign \n n$16=*&self:class A * [line 14]\n n$18=*&child:class A * [line 14]\n n$17=_fun_A_copy(n$18:class A *) virtual [line 14]\n *n$16._child:class A *=n$17 [line 14]\n REMOVE_TEMPS(n$16,n$17,n$18); [line 14]\n NULLIFY(&child,false); [line 14]\n NULLIFY(&self,false); [line 14]\n APPLY_ABSTRACTION; [line 14]\n " shape="box"]
16 -> 15 ; 16 -> 15 ;
15 [label="15: Exit A_setChild: \n " color=yellow style=filled] 15 [label="15: Exit A_setChild: \n " color=yellow style=filled]
14 [label="14: Start A_setChild:\nFormals: self:class A * child:class A *\nLocals: \n DECLARE_LOCALS(&return); [line -1]\n " color=yellow style=filled] 14 [label="14: Start A_setChild: (generated)\nFormals: self:class A * child:class A *\nLocals: \n DECLARE_LOCALS(&return); [line 14]\n " color=yellow style=filled]
14 -> 16 ; 14 -> 16 ;
13 [label="13: Return Stmt \n n$14=*&self:class A * [line -1]\n n$15=*n$14._child:class A * [line -1]\n *&return:class A *=n$15 [line -1]\n REMOVE_TEMPS(n$14,n$15); [line -1]\n NULLIFY(&self,false); [line -1]\n APPLY_ABSTRACTION; [line -1]\n " shape="box"] 13 [label="13: Return Stmt \n n$14=*&self:class A * [line 14]\n n$15=*n$14._child:class A * [line 14]\n *&return:class A *=n$15 [line 14]\n REMOVE_TEMPS(n$14,n$15); [line 14]\n NULLIFY(&self,false); [line 14]\n APPLY_ABSTRACTION; [line 14]\n " shape="box"]
13 -> 12 ; 13 -> 12 ;
12 [label="12: Exit A_child \n " color=yellow style=filled] 12 [label="12: Exit A_child \n " color=yellow style=filled]
11 [label="11: Start A_child\nFormals: self:class A *\nLocals: \n DECLARE_LOCALS(&return); [line -1]\n " color=yellow style=filled] 11 [label="11: Start A_child (generated)\nFormals: self:class A *\nLocals: \n DECLARE_LOCALS(&return); [line 14]\n " color=yellow style=filled]
11 -> 13 ; 11 -> 13 ;

@ -1,23 +1,23 @@
digraph iCFG { digraph iCFG {
6 [label="6: BinaryOperatorStmt: Assign \n n$2=*&self:class ASDisplayNode * [line 14]\n n$3=*&opaque:signed char [line 14]\n *n$2._opaque:signed char =n$3 [line -1]\n REMOVE_TEMPS(n$2,n$3); [line -1]\n NULLIFY(&opaque,false); [line -1]\n NULLIFY(&self,false); [line -1]\n APPLY_ABSTRACTION; [line -1]\n " shape="box"] 6 [label="6: BinaryOperatorStmt: Assign \n n$2=*&self:class ASDisplayNode * [line 14]\n n$3=*&opaque:signed char [line 14]\n *n$2._opaque:signed char =n$3 [line 14]\n REMOVE_TEMPS(n$2,n$3); [line 14]\n NULLIFY(&opaque,false); [line 14]\n NULLIFY(&self,false); [line 14]\n APPLY_ABSTRACTION; [line 14]\n " shape="box"]
6 -> 5 ; 6 -> 5 ;
5 [label="5: Exit ASDisplayNode_setOpaque: \n " color=yellow style=filled] 5 [label="5: Exit ASDisplayNode_setOpaque: \n " color=yellow style=filled]
4 [label="4: Start ASDisplayNode_setOpaque:\nFormals: self:class ASDisplayNode * opaque:signed char \nLocals: \n DECLARE_LOCALS(&return); [line -1]\n " color=yellow style=filled] 4 [label="4: Start ASDisplayNode_setOpaque: (generated)\nFormals: self:class ASDisplayNode * opaque:signed char \nLocals: \n DECLARE_LOCALS(&return); [line 14]\n " color=yellow style=filled]
4 -> 6 ; 4 -> 6 ;
3 [label="3: Return Stmt \n n$0=*&self:class ASDisplayNode * [line -1]\n n$1=*n$0._opaque:signed char [line -1]\n *&return:signed char =n$1 [line -1]\n REMOVE_TEMPS(n$0,n$1); [line -1]\n NULLIFY(&self,false); [line -1]\n APPLY_ABSTRACTION; [line -1]\n " shape="box"] 3 [label="3: Return Stmt \n n$0=*&self:class ASDisplayNode * [line 14]\n n$1=*n$0._opaque:signed char [line 14]\n *&return:signed char =n$1 [line 14]\n REMOVE_TEMPS(n$0,n$1); [line 14]\n NULLIFY(&self,false); [line 14]\n APPLY_ABSTRACTION; [line 14]\n " shape="box"]
3 -> 2 ; 3 -> 2 ;
2 [label="2: Exit ASDisplayNode_isOpaque \n " color=yellow style=filled] 2 [label="2: Exit ASDisplayNode_isOpaque \n " color=yellow style=filled]
1 [label="1: Start ASDisplayNode_isOpaque\nFormals: self:class ASDisplayNode *\nLocals: \n DECLARE_LOCALS(&return); [line -1]\n " color=yellow style=filled] 1 [label="1: Start ASDisplayNode_isOpaque (generated)\nFormals: self:class ASDisplayNode *\nLocals: \n DECLARE_LOCALS(&return); [line 14]\n " color=yellow style=filled]
1 -> 3 ; 1 -> 3 ;

@ -1,15 +1,4 @@
digraph iCFG { digraph iCFG {
6 [label="6: Return Stmt \n n$1=*&self:class PropertyImplSetter * [line -1]\n n$2=*n$1._maximumFileSize:int [line -1]\n *&return:int =n$2 [line -1]\n REMOVE_TEMPS(n$1,n$2); [line -1]\n NULLIFY(&self,false); [line -1]\n APPLY_ABSTRACTION; [line -1]\n " shape="box"]
6 -> 5 ;
5 [label="5: Exit PropertyImplSetter_maximumFileSize \n " color=yellow style=filled]
4 [label="4: Start PropertyImplSetter_maximumFileSize\nFormals: self:class PropertyImplSetter *\nLocals: \n DECLARE_LOCALS(&return); [line -1]\n " color=yellow style=filled]
4 -> 6 ;
3 [label="3: BinaryOperatorStmt: Assign \n n$0=*&self:class PropertyImplSetter * [line 16]\n *n$0._maximumFileSize:int =0 [line 16]\n REMOVE_TEMPS(n$0); [line 16]\n NULLIFY(&self,false); [line 16]\n APPLY_ABSTRACTION; [line 16]\n " shape="box"] 3 [label="3: BinaryOperatorStmt: Assign \n n$0=*&self:class PropertyImplSetter * [line 16]\n *n$0._maximumFileSize:int =0 [line 16]\n REMOVE_TEMPS(n$0); [line 16]\n NULLIFY(&self,false); [line 16]\n APPLY_ABSTRACTION; [line 16]\n " shape="box"]

@ -1,26 +1,26 @@
digraph iCFG { digraph iCFG {
9 [label="9: BinaryOperatorStmt: Assign \n n$4=*&self:class A * [line 13]\n n$5=*&x:int [line 13]\n *n$4._x:int =n$5 [line -1]\n REMOVE_TEMPS(n$4,n$5); [line -1]\n NULLIFY(&self,false); [line -1]\n NULLIFY(&x,false); [line -1]\n APPLY_ABSTRACTION; [line -1]\n " shape="box"] 12 [label="12: BinaryOperatorStmt: Assign \n n$6=*&self:class A * [line 13]\n n$7=*&x:int [line 13]\n *n$6._x:int =n$7 [line 13]\n REMOVE_TEMPS(n$6,n$7); [line 13]\n NULLIFY(&self,false); [line 13]\n NULLIFY(&x,false); [line 13]\n APPLY_ABSTRACTION; [line 13]\n " shape="box"]
9 -> 8 ; 12 -> 11 ;
8 [label="8: Exit A_setX: \n " color=yellow style=filled] 11 [label="11: Exit A_setX: \n " color=yellow style=filled]
7 [label="7: Start A_setX:\nFormals: self:class A * x:int \nLocals: \n DECLARE_LOCALS(&return); [line -1]\n " color=yellow style=filled] 10 [label="10: Start A_setX: (generated)\nFormals: self:class A * x:int \nLocals: \n DECLARE_LOCALS(&return); [line 13]\n " color=yellow style=filled]
7 -> 9 ; 10 -> 12 ;
6 [label="6: Return Stmt \n n$2=*&self:class A * [line -1]\n n$3=*n$2._x:int [line -1]\n *&return:int =n$3 [line -1]\n REMOVE_TEMPS(n$2,n$3); [line -1]\n NULLIFY(&self,false); [line -1]\n APPLY_ABSTRACTION; [line -1]\n " shape="box"] 9 [label="9: Return Stmt \n n$4=*&self:class A * [line 13]\n n$5=*n$4._x:int [line 13]\n *&return:int =n$5 [line 13]\n REMOVE_TEMPS(n$4,n$5); [line 13]\n NULLIFY(&self,false); [line 13]\n APPLY_ABSTRACTION; [line 13]\n " shape="box"]
6 -> 5 ; 9 -> 8 ;
5 [label="5: Exit A_x \n " color=yellow style=filled] 8 [label="8: Exit A_x \n " color=yellow style=filled]
4 [label="4: Start A_x\nFormals: self:class A *\nLocals: \n DECLARE_LOCALS(&return); [line -1]\n " color=yellow style=filled] 7 [label="7: Start A_x (generated)\nFormals: self:class A *\nLocals: \n DECLARE_LOCALS(&return); [line 13]\n " color=yellow style=filled]
4 -> 6 ; 7 -> 9 ;
3 [label="3: Return Stmt \n n$1=*&target:class A * [line 19]\n n$0=_fun_A_x(n$1:class A *) virtual [line 19]\n *&return:int =n$0 [line 19]\n REMOVE_TEMPS(n$0,n$1); [line 19]\n NULLIFY(&target,false); [line 19]\n APPLY_ABSTRACTION; [line 19]\n " shape="box"] 3 [label="3: Return Stmt \n n$1=*&target:class A * [line 19]\n n$0=_fun_A_x(n$1:class A *) virtual [line 19]\n *&return:int =n$0 [line 19]\n REMOVE_TEMPS(n$0,n$1); [line 19]\n NULLIFY(&target,false); [line 19]\n APPLY_ABSTRACTION; [line 19]\n " shape="box"]

@ -1,31 +1,31 @@
digraph iCFG { digraph iCFG {
8 [label="8: Message Call: retain \n n$8=*&aDynValue:class NSObject * [line -1]\n n$7=_fun___objc_retain(n$8:class NSObject *) [line -1]\n REMOVE_TEMPS(n$7,n$8); [line -1]\n " shape="box"] 8 [label="8: Message Call: retain \n n$8=*&aDynValue:class NSObject * [line 13]\n n$7=_fun___objc_retain(n$8:class NSObject *) [line 13]\n REMOVE_TEMPS(n$7,n$8); [line 13]\n " shape="box"]
8 -> 7 ; 8 -> 7 ;
7 [label="7: Message Call: release \n n$5=*&self:class AClass * [line 13]\n n$6=*n$5.aDynValue:class NSObject * [line -1]\n n$4=_fun___objc_release(n$6:class NSObject *) [line -1]\n REMOVE_TEMPS(n$4,n$5,n$6); [line -1]\n " shape="box"] 7 [label="7: Message Call: release \n n$5=*&self:class AClass * [line 13]\n n$6=*n$5._aDynValue:class NSObject * [line 13]\n n$4=_fun___objc_release(n$6:class NSObject *) [line 13]\n REMOVE_TEMPS(n$4,n$5,n$6); [line 13]\n " shape="box"]
7 -> 6 ; 7 -> 6 ;
6 [label="6: BinaryOperatorStmt: Assign \n n$2=*&self:class AClass * [line 13]\n n$3=*&aDynValue:class NSObject * [line 13]\n *n$2.aDynValue:class NSObject *=n$3 [line -1]\n REMOVE_TEMPS(n$2,n$3); [line -1]\n NULLIFY(&aDynValue,false); [line -1]\n NULLIFY(&self,false); [line -1]\n APPLY_ABSTRACTION; [line -1]\n " shape="box"] 6 [label="6: BinaryOperatorStmt: Assign \n n$2=*&self:class AClass * [line 13]\n n$3=*&aDynValue:class NSObject * [line 13]\n *n$2._aDynValue:class NSObject *=n$3 [line 13]\n REMOVE_TEMPS(n$2,n$3); [line 13]\n NULLIFY(&aDynValue,false); [line 13]\n NULLIFY(&self,false); [line 13]\n APPLY_ABSTRACTION; [line 13]\n " shape="box"]
6 -> 5 ; 6 -> 5 ;
5 [label="5: Exit AClass_setADynValue: \n " color=yellow style=filled] 5 [label="5: Exit AClass_setADynValue: \n " color=yellow style=filled]
4 [label="4: Start AClass_setADynValue:\nFormals: self:class AClass * aDynValue:class NSObject *\nLocals: \n DECLARE_LOCALS(&return); [line -1]\n " color=yellow style=filled] 4 [label="4: Start AClass_setADynValue: (generated)\nFormals: self:class AClass * aDynValue:class NSObject *\nLocals: \n DECLARE_LOCALS(&return); [line 13]\n " color=yellow style=filled]
4 -> 8 ; 4 -> 8 ;
3 [label="3: Return Stmt \n n$0=*&self:class AClass * [line -1]\n n$1=*n$0.aDynValue:class NSObject * [line -1]\n *&return:class NSObject *=n$1 [line -1]\n REMOVE_TEMPS(n$0,n$1); [line -1]\n NULLIFY(&self,false); [line -1]\n APPLY_ABSTRACTION; [line -1]\n " shape="box"] 3 [label="3: Return Stmt \n n$0=*&self:class AClass * [line 13]\n n$1=*n$0._aDynValue:class NSObject * [line 13]\n *&return:class NSObject *=n$1 [line 13]\n REMOVE_TEMPS(n$0,n$1); [line 13]\n NULLIFY(&self,false); [line 13]\n APPLY_ABSTRACTION; [line 13]\n " shape="box"]
3 -> 2 ; 3 -> 2 ;
2 [label="2: Exit AClass_aDynValue \n " color=yellow style=filled] 2 [label="2: Exit AClass_aDynValue \n " color=yellow style=filled]
1 [label="1: Start AClass_aDynValue\nFormals: self:class AClass *\nLocals: \n DECLARE_LOCALS(&return); [line -1]\n " color=yellow style=filled] 1 [label="1: Start AClass_aDynValue (generated)\nFormals: self:class AClass *\nLocals: \n DECLARE_LOCALS(&return); [line 13]\n " color=yellow style=filled]
1 -> 3 ; 1 -> 3 ;

@ -7,7 +7,7 @@
* of patent rights can be found in the PATENTS file in the same directory. * of patent rights can be found in the PATENTS file in the same directory.
*/ */
#import <Foundation/Foundation.h> #import <Foundation/NSObject.h>
@protocol MyProtocol <NSObject> @protocol MyProtocol <NSObject>

@ -1,24 +0,0 @@
digraph iCFG {
6 [label="6: BinaryOperatorStmt: Assign \n n$2=*&self:class Test * [line 14]\n n$3=*&numberOfFiles:int [line 14]\n *n$2.numberOfFiles:int =n$3 [line -1]\n REMOVE_TEMPS(n$2,n$3); [line -1]\n NULLIFY(&numberOfFiles,false); [line -1]\n NULLIFY(&self,false); [line -1]\n APPLY_ABSTRACTION; [line -1]\n " shape="box"]
6 -> 5 ;
5 [label="5: Exit Test_setNumberOfFiles: \n " color=yellow style=filled]
4 [label="4: Start Test_setNumberOfFiles:\nFormals: self:class Test * numberOfFiles:int \nLocals: \n DECLARE_LOCALS(&return); [line -1]\n " color=yellow style=filled]
4 -> 6 ;
3 [label="3: Return Stmt \n n$0=*&self:class Test * [line -1]\n n$1=*n$0.numberOfFiles:int [line -1]\n *&return:int =n$1 [line -1]\n REMOVE_TEMPS(n$0,n$1); [line -1]\n NULLIFY(&self,false); [line -1]\n APPLY_ABSTRACTION; [line -1]\n " shape="box"]
3 -> 2 ;
2 [label="2: Exit Test_numberOfFiles \n " color=yellow style=filled]
1 [label="1: Start Test_numberOfFiles\nFormals: self:class Test *\nLocals: \n DECLARE_LOCALS(&return); [line -1]\n " color=yellow style=filled]
1 -> 3 ;
}

@ -7,7 +7,7 @@
* of patent rights can be found in the PATENTS file in the same directory. * of patent rights can be found in the PATENTS file in the same directory.
*/ */
#import <Foundation/Foundation.h> #import <Foundation/NSObject.h>
#import "MyProtocol.h" #import "MyProtocol.h"
@interface Test : NSObject<MyProtocol> { @interface Test : NSObject<MyProtocol> {

@ -1,6 +1,10 @@
/* /*
* Copyright (c) 2013- Facebook. * Copyright (c) 2013 - present Facebook, Inc.
* All rights reserved. * 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.
*/ */
package endtoend.c; package endtoend.c;

Loading…
Cancel
Save