diff --git a/infer/src/backend/cfg.ml b/infer/src/backend/cfg.ml index 860eff218..54fbe9267 100644 --- a/infer/src/backend/cfg.ml +++ b/infer/src/backend/cfg.ml @@ -724,6 +724,12 @@ let get_all_procs cfg = let get_defined_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 *) let get_priority_procnames cfg = cfg.Node.priority_set diff --git a/infer/src/backend/cfg.mli b/infer/src/backend/cfg.mli index 7d288f448..586ea8998 100644 --- a/infer/src/backend/cfg.mli +++ b/infer/src/backend/cfg.mli @@ -297,6 +297,9 @@ val get_all_procs : cfg -> Procdesc.t list (** Get the procedures whose body is defined in this cfg *) 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 *) val get_priority_procnames : cfg -> Procname.Set.t diff --git a/infer/src/backend/cg.ml b/infer/src/backend/cg.ml index 50d1acca5..8034e499f 100644 --- a/infer/src/backend/cg.ml +++ b/infer/src/backend/cg.ml @@ -140,6 +140,12 @@ let node_defined (g: t) n = info.defined 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 = _add_node g nfrom false; _add_node g nto false; diff --git a/infer/src/backend/cg.mli b/infer/src/backend/cg.mli index 94fa9542a..27be7eba0 100644 --- a/infer/src/backend/cg.mli +++ b/infer/src/backend/cg.mli @@ -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 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 node_set_defined : t -> Procname.t -> bool -> unit (** Change the defined flag of a node *) diff --git a/infer/src/backend/dotty.ml b/infer/src/backend/dotty.ml index a0b24bb4c..64cbae157 100644 --- a/infer/src/backend/dotty.ml +++ b/infer/src/backend/dotty.ml @@ -903,10 +903,12 @@ let pp_cfgnodelabel fmt (n : Cfg.Node.t) = let pp_label fmt n = match Cfg.Node.get_kind n with | 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 *) (* 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)) + gen pp_etlist (Cfg.Procdesc.get_formals pdesc) pp_local_list (Cfg.Procdesc.get_locals pdesc); if list_length (Cfg.Procdesc.get_captured pdesc) <> 0 then diff --git a/infer/src/backend/inferanalyze.ml b/infer/src/backend/inferanalyze.ml index 0dd9edb64..81be30f2c 100644 --- a/infer/src/backend/inferanalyze.ml +++ b/infer/src/backend/inferanalyze.ml @@ -736,12 +736,15 @@ let analyzer_err_name = "analyzer_err" let () = let () = 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 RegisterCheckers.register (); 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 (); let log_dir = DB.filename_to_string (DB.Results_dir.path_to_filename DB.Results_dir.Abs_root [log_dir_name]) in diff --git a/infer/src/backend/objc_preanal.ml b/infer/src/backend/objc_preanal.ml new file mode 100644 index 000000000..c61d10e69 --- /dev/null +++ b/infer/src/backend/objc_preanal.ml @@ -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 diff --git a/infer/src/backend/objc_preanal.mli b/infer/src/backend/objc_preanal.mli new file mode 100644 index 000000000..9c1ebe9c9 --- /dev/null +++ b/infer/src/backend/objc_preanal.mli @@ -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 diff --git a/infer/src/backend/procname.ml b/infer/src/backend/procname.ml index 36fde0e27..966a0a656 100644 --- a/infer/src/backend/procname.ml +++ b/infer/src/backend/procname.ml @@ -178,6 +178,12 @@ let c_method_replace_class t class_name = | C_METHOD osig -> C_METHOD { osig with class_name = class_name } | _ -> 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. *) let java_get_class = function | 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 | _ -> false - let java_is_close = function | JAVA js -> js.methodname = "close" | _ -> false - (** [is_class_initializer pname] returns true if [pname] is a class initializer *) let is_class_initializer = function | JAVA js -> js.methodname = "" diff --git a/infer/src/backend/procname.mli b/infer/src/backend/procname.mli index 588e0dffb..edf85d161 100644 --- a/infer/src/backend/procname.mli +++ b/infer/src/backend/procname.mli @@ -63,6 +63,9 @@ val java_replace_return_type : t -> java_type -> t (** Replace the class name of an Objective-C procedure name. *) 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. *) val java_get_class : t -> string diff --git a/infer/src/backend/sil.ml b/infer/src/backend/sil.ml index e5f3aa4a4..2e7309460 100644 --- a/infer/src/backend/sil.ml +++ b/infer/src/backend/sil.ml @@ -51,6 +51,7 @@ type proc_attributes = language : language; func_attributes : func_attribute list; method_annotation : method_annotation; + is_generated : bool; } let copy_proc_attributes pa = @@ -64,6 +65,7 @@ let copy_proc_attributes pa = language = pa.language; func_attributes = pa.func_attributes; method_annotation = pa.method_annotation; + is_generated = pa.is_generated; } (** Compare function for annotations. *) diff --git a/infer/src/backend/sil.mli b/infer/src/backend/sil.mli index 5a12bd818..4f1e228ea 100644 --- a/infer/src/backend/sil.mli +++ b/infer/src/backend/sil.mli @@ -65,6 +65,7 @@ type proc_attributes = language : language; func_attributes : func_attribute list; method_annotation : method_annotation; + is_generated : bool; } (** Create a copy of a proc_attributes *) diff --git a/infer/src/backend/specs.ml b/infer/src/backend/specs.ml index c8d2704be..45edfe02c 100644 --- a/infer/src/backend/specs.ml +++ b/infer/src/backend/specs.ml @@ -787,6 +787,7 @@ let reset_summary call_graph proc_name loc = Sil.language = !Sil.curr_language; Sil.func_attributes = []; Sil.method_annotation = Sil.method_annotation_empty; + Sil.is_generated = false; } in init_summary ( proc_name, diff --git a/infer/src/clang/ast_expressions.ml b/infer/src/clang/ast_expressions.ml index ec20740c4..e4b7a2252 100644 --- a/infer/src/clang/ast_expressions.ml +++ b/infer/src/clang/ast_expressions.ml @@ -37,6 +37,20 @@ let dummy_decl_info decl_info = 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 = { Clang_ast_t.di_pointer = ""; 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 cast_exp' -let make_objc_ivar_decl decl_info qt property_impl_decl_info = - 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 make_objc_ivar_decl decl_info qt property_impl_decl_info ivar_name = let field_decl_info = { Clang_ast_t.fldi_is_mutable = 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 = { 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 - 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 = { diff --git a/infer/src/clang/ast_expressions.mli b/infer/src/clang/ast_expressions.mli index abc1e4e62..2375af805 100644 --- a/infer/src/clang/ast_expressions.mli +++ b/infer/src/clang/ast_expressions.mli @@ -15,6 +15,8 @@ val dummy_stmt : unit -> stmt 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_stmt_info : unit -> stmt_info @@ -23,7 +25,7 @@ val create_qual_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 diff --git a/infer/src/clang/cContext.ml b/infer/src/clang/cContext.ml index b836e40b9..ac4f2dfd4 100644 --- a/infer/src/clang/cContext.ml +++ b/infer/src/clang/cContext.ml @@ -254,9 +254,11 @@ let get_curr_class_name curr_class = let curr_class_to_string curr_class = match curr_class with - | ContextCls (name, _, _) -> ("class "^name) - | ContextCategory (name, cls) -> ("category "^name^" of class "^cls) - | ContextProtocol name -> ("protocol "^name) + | ContextCls (name, superclass, protocols) -> + ("class " ^ name ^ ", superclass: " ^ (Option.default "" superclass) ^ + ", protocols: " ^ (Utils.list_to_string (fun x -> x) protocols)) + | ContextCategory (name, cls) -> ("category " ^ name ^ " of class " ^ cls) + | ContextProtocol name -> ("protocol " ^ name) | ContextNoCls -> "no class" 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 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 diff --git a/infer/src/clang/cContext.mli b/infer/src/clang/cContext.mli index d76ffe9c3..be47bec86 100644 --- a/infer/src/clang/cContext.mli +++ b/infer/src/clang/cContext.mli @@ -75,4 +75,5 @@ val get_tenv : t -> Sil.tenv 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 +val create_curr_class : Sil.tenv -> string -> curr_class diff --git a/infer/src/clang/cEnum_decl.ml b/infer/src/clang/cEnum_decl.ml index 1c63e0d6c..cced6090a 100644 --- a/infer/src/clang/cEnum_decl.ml +++ b/infer/src/clang/cEnum_decl.ml @@ -27,6 +27,7 @@ let create_empty_procdesc () = Sil.language = Sil.C_CPP; Sil.func_attributes = []; Sil.method_annotation = Sil.method_annotation_empty; + Sil.is_generated = false; } in create { cfg = Cfg.Node.create_cfg (); diff --git a/infer/src/clang/cField_decl.ml b/infer/src/clang/cField_decl.ml index 60630e41c..8cd26f24f 100644 --- a/infer/src/clang/cField_decl.ml +++ b/infer/src/clang/cField_decl.ml @@ -16,6 +16,8 @@ open Clang_ast_t module L = Logging +type field_type = Ident.fieldname * Sil.typ * (Sil.annotation * bool) list + let rec get_fields_super_classes tenv 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 @@ -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 annotation_from_type t = match t with - | Sil.Tptr(_,Sil.Pk_objc_weak) -> [Config.weak] - | Sil.Tptr(_,Sil.Pk_objc_unsafe_unretained) -> [Config.unsafe_unret] + | Sil.Tptr (_, Sil.Pk_objc_weak) -> [Config.weak] + | Sil.Tptr (_, Sil.Pk_objc_unsafe_unretained) -> [Config.unsafe_unret] | _ -> [] 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 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 (* 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'; try 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 - Some atts_str + atts with Not_found -> Printing.log_out "Didn't find property for pname '%s'" pname'; - None) + []) | 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 *) let rec get_fields tenv curr_class decl_list = - let class_name = CContext.get_curr_class_name curr_class in match decl_list with | [] -> [] | 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 *) (* ivar names will be added in the property list. *) 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 tenv class_name field_name qual_type prop_attributes in + let (fname, typ, ia) = build_sil_field_property curr_class tenv field_name qual_type None in + 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 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' -> 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 diff --git a/infer/src/clang/cField_decl.mli b/infer/src/clang/cField_decl.mli index 7c71f5ac1..2d4e1b857 100644 --- a/infer/src/clang/cField_decl.mli +++ b/infer/src/clang/cField_decl.mli @@ -9,8 +9,17 @@ (** 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 -> (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 diff --git a/infer/src/clang/cFrontend_config.ml b/infer/src/clang/cFrontend_config.ml index 938906cb1..96a7c1812 100644 --- a/infer/src/clang/cFrontend_config.ml +++ b/infer/src/clang/cFrontend_config.ml @@ -144,4 +144,6 @@ let objects = "objects" let ns_array_ptr = "NSArray *" -let enumerateObjectsUsingBlock = "enumerateObjectsUsingBlock:" \ No newline at end of file +let enumerateObjectsUsingBlock = "enumerateObjectsUsingBlock:" + +let generated_suffix = "*generated" diff --git a/infer/src/clang/cFrontend_config.mli b/infer/src/clang/cFrontend_config.mli index d6e967483..05ff8e8de 100644 --- a/infer/src/clang/cFrontend_config.mli +++ b/infer/src/clang/cFrontend_config.mli @@ -141,4 +141,6 @@ val objects : string val ns_array_ptr : string -val enumerateObjectsUsingBlock : string \ No newline at end of file +val enumerateObjectsUsingBlock : string + +val generated_suffix : string diff --git a/infer/src/clang/cFrontend_utils.ml b/infer/src/clang/cFrontend_utils.ml index db860e69e..4fd3ceff7 100644 --- a/infer/src/clang/cFrontend_utils.ml +++ b/infer/src/clang/cFrontend_utils.ml @@ -156,6 +156,9 @@ struct | _ -> no_property_name) | None -> no_property_name + let generated_ivar_name property_name = + "_"^property_name + let property_attribute_compare att1 att2 = match att1, att2 with `Readonly, `Readonly -> 0 @@ -211,11 +214,10 @@ struct attribute = `Copy | _ -> false - - let name_opt_of_name_info_opt name_info_opt = - match name_info_opt with - | Some name_info -> Some name_info.Clang_ast_t.ni_name - | None -> None + let name_opt_of_name_info_opt name_info_opt = + match name_info_opt with + | Some name_info -> Some name_info.Clang_ast_t.ni_name + | None -> None let rec getter_attribute_opt attributes = match attributes with @@ -251,6 +253,11 @@ struct | Some qt -> Some qt | 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 (* Global counter for anonymous block*) diff --git a/infer/src/clang/cFrontend_utils.mli b/infer/src/clang/cFrontend_utils.mli index 2481811de..76643194f 100644 --- a/infer/src/clang/cFrontend_utils.mli +++ b/infer/src/clang/cFrontend_utils.mli @@ -51,6 +51,8 @@ sig 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 getter_attribute_opt : property_attribute list -> string option @@ -72,6 +74,8 @@ sig 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 + val is_generated : Clang_ast_t.named_decl_info -> bool + end module General_utils : diff --git a/infer/src/clang/cLocation.mli b/infer/src/clang/cLocation.mli index 43c88e4c6..ed5e3ad5e 100644 --- a/infer/src/clang/cLocation.mli +++ b/infer/src/clang/cLocation.mli @@ -9,6 +9,14 @@ (** 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 -> Sil.location diff --git a/infer/src/clang/cMethod_decl.ml b/infer/src/clang/cMethod_decl.ml index 9c7a965d5..e5c4b3c9b 100644 --- a/infer/src/clang/cMethod_decl.ml +++ b/infer/src/clang/cMethod_decl.ml @@ -12,6 +12,7 @@ open Utils open CFrontend_utils open Clang_ast_t +open CContext 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 -> 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 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 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 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 parameters = get_parameters function_method_decl_info 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 procname, is_anonym_block = @@ -87,7 +90,7 @@ struct | Some block -> block, true | None -> CMethod_trans.mk_procname_from_function name (CTypes.get_type qt), false in 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 | Some body -> Some body, ms | None -> None, ms) @@ -154,42 +157,45 @@ struct 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 *) let procname = CMethod_signature.ms_get_name ms in - CMethod_trans.create_local_procdesc cfg tenv ms [body] captured_vars false; - let is_instance = CMethod_signature.ms_is_instance ms in - let is_anonym_block = Option.is_some anonym_block_opt in - let is_objc_method = is_anonym_block in - let curr_class = if is_anonym_block then curr_class else CContext.ContextNoCls in - let attributes = CMethod_signature.ms_get_attributes ms in - CMethod_signature.add ms; - 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 + 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_anonym_block = Option.is_some anonym_block_opt in + let is_objc_method = is_anonym_block in + let curr_class = if is_anonym_block then curr_class else CContext.ContextNoCls in + let attributes = CMethod_signature.ms_get_attributes ms in + CMethod_signature.add ms; + 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 | 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 method_name = name_info.Clang_ast_t.ni_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 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); CMethod_signature.add ms; (match method_body_to_translate decl_info ms method_decl_info.Clang_ast_t.omdi_body with | Some body -> let is_instance = CMethod_signature.ms_is_instance ms in let attributes = CMethod_signature.ms_get_attributes ms in - CMethod_trans.create_local_procdesc cfg tenv ms [body] [] is_instance; - add_method tenv cg cfg curr_class procname namespace [body] true is_instance [] false - method_decl_info.Clang_ast_t.omdi_parameters attributes + 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 + method_decl_info.Clang_ast_t.omdi_parameters attributes | None -> ()) let rec process_one_method_decl tenv cg cfg curr_class namespace dec = match dec with | 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 method_name method_decl_info + process_objc_method_decl tenv cg cfg namespace curr_class decl_info name_info method_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 - list_iter (process_one_method_decl tenv cg cfg curr_class namespace) prop_methods + let pname = Ast_utils.property_name property_impl_decl_info in + 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 _ -> () | d -> Printing.log_err @@ -199,4 +205,23 @@ struct 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 + 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 diff --git a/infer/src/clang/cMethod_decl.mli b/infer/src/clang/cMethod_decl.mli index d242b78a2..c9425d629 100644 --- a/infer/src/clang/cMethod_decl.mli +++ b/infer/src/clang/cMethod_decl.mli @@ -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 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 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 -> 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 diff --git a/infer/src/clang/cMethod_signature.ml b/infer/src/clang/cMethod_signature.ml index a849431af..df69c16cd 100644 --- a/infer/src/clang/cMethod_signature.ml +++ b/infer/src/clang/cMethod_signature.ml @@ -16,7 +16,8 @@ type method_signature = { _ret_type : string; _attributes : Clang_ast_t.attribute list; _loc : Clang_ast_t.source_range; - _is_instance : bool + _is_instance : bool; + _is_generated : bool; } let ms_get_name ms = @@ -37,25 +38,30 @@ let ms_get_loc ms = let ms_is_instance ms = ms._is_instance +let ms_is_generated ms = + ms._is_generated + type methodMap = method_signature Procname.Map.t 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 = { _name = procname; _args = args; _ret_type = ret_type; _attributes = attributes; _loc = loc; - _is_instance = is_instance } in + _is_instance = is_instance; + _is_generated = is_generated} in meth_signature let replace_name_ms ms name = { ms with _name = name } 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^" "^ Clang_ast_j.string_of_source_range ms._loc diff --git a/infer/src/clang/cMethod_signature.mli b/infer/src/clang/cMethod_signature.mli index 21f807e5e..7e42ee66a 100644 --- a/infer/src/clang/cMethod_signature.mli +++ b/infer/src/clang/cMethod_signature.mli @@ -31,8 +31,10 @@ val ms_get_loc : method_signature -> Clang_ast_t.source_range 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 -> -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 ms_to_string : method_signature -> string + +val ms_is_generated : method_signature -> bool diff --git a/infer/src/clang/cMethod_trans.ml b/infer/src/clang/cMethod_trans.ml index 6dd6dd127..2fa2d8686 100644 --- a/infer/src/clang/cMethod_trans.ml +++ b/infer/src/clang/cMethod_trans.ml @@ -73,19 +73,19 @@ let get_superclass_curr_class context = 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 match obj_c_message_expr_info.Clang_ast_t.omei_receiver_kind with - | `Class qt -> (CTypes.get_type qt, selector, MCStatic) - | `Instance -> - (match act_params with - | (instance_obj, Sil.Tptr(t, _)):: _ - | (instance_obj, t):: _ -> - (CTypes.classname_of_type t, selector, MCVirtual) - | _ -> assert false) - | `SuperInstance -> - let superclass = get_superclass_curr_class context in - (superclass, selector, MCNoVirtual) - | `SuperClass -> - let superclass = get_superclass_curr_class context in - (superclass, selector, MCStatic) + | `Class qt -> (CTypes.get_type qt, selector, MCStatic) + | `Instance -> + (match act_params with + | (instance_obj, Sil.Tptr(t, _)):: _ + | (instance_obj, t):: _ -> + (CTypes.classname_of_type t, selector, MCVirtual) + | _ -> assert false) + | `SuperInstance -> + let superclass = get_superclass_curr_class context in + (superclass, selector, MCNoVirtual) + | `SuperClass -> + let superclass = get_superclass_curr_class context in + (superclass, selector, MCStatic) let get_formal_parameters tenv ms = let rec defined_parameters pl = @@ -137,21 +137,35 @@ let get_return_type tenv ms = let sil_func_attributes_of_attributes attrs = let rec do_translation acc al = match al with | [] -> list_rev acc - | Clang_ast_t.SentinelAttr attribute_info::tl -> - let (sentinel, null_pos) = match attribute_info.Clang_ast_t.ai_parameters with - | a::b::[] -> (int_of_string a, int_of_string b) - | _ -> assert false - in - do_translation (Sil.FA_sentinel(sentinel, null_pos)::acc) tl - | _::tl -> do_translation acc tl in + | Clang_ast_t.SentinelAttr attribute_info:: tl -> + let (sentinel, null_pos) = match attribute_info.Clang_ast_t.ai_parameters with + | a:: b::[] -> (int_of_string a, int_of_string b) + | _ -> assert false + in + do_translation (Sil.FA_sentinel(sentinel, null_pos):: acc) tl + | _:: tl -> do_translation acc tl in 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. *) let create_local_procdesc cfg tenv ms fbody captured is_objc_inst_method = let defined = not ((list_length fbody) == 0) in let procname = CMethod_signature.ms_get_name ms in let pname = Procname.to_string procname 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 formals = get_formal_parameters tenv ms 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.func_attributes = attributes; Sil.method_annotation = Sil.method_annotation_empty; + Sil.is_generated = is_generated; } in create { 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 Cfg.Procdesc.set_start_node procdesc start_node; Cfg.Procdesc.set_exit_node procdesc exit_node) in - match Cfg.Procdesc.find_from_name cfg procname with - | Some prevoius_procdesc -> - Printing.log_err "\n\n!!!WARNING: procdesc for %s already defined \n" pname; - if defined && not (Cfg.Procdesc.is_defined prevoius_procdesc) then - (Cfg.Procdesc.remove cfg (Cfg.Procdesc.get_proc_name prevoius_procdesc) true; - create_new_procdesc ()) - | None -> create_new_procdesc () + let generated = CMethod_signature.ms_is_generated ms in + if should_create_procdesc cfg procname defined generated then + (create_new_procdesc (); true) + else false (** Create a procdesc for objc methods whose signature cannot be found. *) 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.func_attributes = []; Sil.method_annotation = Sil.method_annotation_empty; + Sil.is_generated = false; } in create { 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 = if instance then MCVirtual 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 diff --git a/infer/src/clang/cMethod_trans.mli b/infer/src/clang/cMethod_trans.mli index 7d9b63640..738bca2b1 100644 --- a/infer/src/clang/cMethod_trans.mli +++ b/infer/src/clang/cMethod_trans.mli @@ -20,11 +20,8 @@ type method_call_type = | MCNoVirtual | 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 -> -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 @@ -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 -> (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 diff --git a/infer/src/clang/cModule_type.ml b/infer/src/clang/cModule_type.ml index 21a834dd0..63daf7f58 100644 --- a/infer/src/clang/cModule_type.ml +++ b/infer/src/clang/cModule_type.ml @@ -16,4 +16,6 @@ module type CMethod_declaration = sig 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 + + val process_getter_setter : CContext.t -> Procname.t -> bool end diff --git a/infer/src/clang/cTrans.ml b/infer/src/clang/cTrans.ml index 861e40ab1..d6fde6ca5 100644 --- a/infer/src/clang/cTrans.ml +++ b/infer/src/clang/cTrans.ml @@ -37,6 +37,30 @@ end module CTrans_funct(M: CModule_type.CMethod_declaration) : CTrans = 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 method_name = Procname.c_get_method (Cfg.Procdesc.get_proc_name context.procdesc) in if !Config.arc_mode && @@ -590,7 +614,7 @@ struct Cg.add_edge context.cg procname callee_pname; try 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 -> CMethod_trans.create_external_procdesc context.cfg callee_pname false None end @@ -642,8 +666,7 @@ struct CTrans_utils.trans_assume_false sil_loc context trans_state.succ_nodes else let procname = Cfg.Procdesc.get_proc_name context.procdesc in - let callee_name, method_call_type = - CMethod_trans.get_callee_objc_method context obj_c_message_expr_info res_trans_par.exps in + let callee_name, method_call_type = 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 obj_c_message_expr_info res_trans_par in let is_virtual = method_call_type = CMethod_trans.MCVirtual in diff --git a/infer/src/clang/cTrans_models.ml b/infer/src/clang/cTrans_models.ml index d725616da..4438e65a0 100644 --- a/infer/src/clang/cTrans_models.ml +++ b/infer/src/clang/cTrans_models.ml @@ -129,7 +129,7 @@ let get_predefined_ms_method condition class_name method_name mk_procname | Some procname -> procname | None -> mk_procname class_name method_name in 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 else None diff --git a/infer/src/clang/objcInterface_decl.ml b/infer/src/clang/objcInterface_decl.ml index 0a5a90c24..05a9b0b05 100644 --- a/infer/src/clang/objcInterface_decl.ml +++ b/infer/src/clang/objcInterface_decl.ml @@ -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"); 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 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 @@ -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. *) 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 - curr_class + add_class_to_tenv tenv class_name decl_list obj_c_interface_decl_info (* Translate the methods defined in the implementation.*) -let interface_impl_declaration tenv class_name decl_list implementation_decl_info = - 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; +let interface_impl_declaration tenv class_name decl_list idi = 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 (* 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 | [] -> None | (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 (match find_field tenv nfield str' searched_late_defined with | Some field -> Some field | None -> search_super 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' | (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 | (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 match str with | Some Sil.Tstruct (sf, nsf, Sil.Struct, Some cname, _, _, _) diff --git a/infer/src/clang/objcProperty_decl.ml b/infer/src/clang/objcProperty_decl.ml index 9c60a91d1..37a355ef4 100644 --- a/infer/src/clang/objcProperty_decl.ml +++ b/infer/src/clang/objcProperty_decl.ml @@ -108,7 +108,7 @@ struct let res = ref None in PropertyTableHash.iter (fun (cl, pname) (_, _, _, _, _, ivar') -> match ivar' with - | Some s when (CContext.curr_class_equal curr_class cl) && s = ivar -> res:= Some pname + | Some s when (CContext.curr_class_equal curr_class cl) && s = ivar -> res:= Some pname | _ -> ()) property_table; !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 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 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 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 - | None -> None) in + | Some dr -> (match dr.Clang_ast_t.dr_name with + | 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 *) - Property.replace_property (curr_class, pname) (qt', atts, di, getter, setter, ivar); - Printing.log_out "Updated property table by adding ivar name for property pname '%s'\n" pname; - Some qt' + 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; + Some (qt', ivar) with Not_found -> L.err "Property '%s' not found in the table. Ivar not updated and qual_type not found.@." pname; None) in - match property_impl_decl_info.Clang_ast_t.opidi_implementation with - | `Dynamic -> + match property_impl_decl_info.Clang_ast_t.opidi_implementation, res with + | `Dynamic, Some (qt, ivar) -> (* For Dynamic property we need to create the ObjCIvarDecl which specifies*) (* the field of the property. In case of Dynamic this is not in the AST.*) (* Once created the ObjCIvarDecl then we treat the property as synthesized *) - [Ast_expressions.make_objc_ivar_decl decl_info qt property_impl_decl_info] - | `Synthesize -> + [Ast_expressions.make_objc_ivar_decl decl_info qt property_impl_decl_info ivar] + | _ -> (* 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 = 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 memory_management_attributes = Ast_utils.get_memory_management_attributes () in try Some (list_find ( @@ -256,54 +262,46 @@ let get_memory_management_attribute attributes = att memory_management_attributes) attributes) with Not_found -> None -(*Makes the getters and setters according to the attributes: *) -(* - If readonly is available, only write getter *) -(* - If strong or retain are available then write the following code in the setter: *) -(* [param retain] *) -(* [self->_field release] *) -(* [self->_field = param] *) -(* - If copy is available then write the following code: *) -(* [self->_field = [param copy] *) -let make_getter_setter cfg curr_class decl_info property_impl_decl_info = - let class_name = CContext.get_curr_class_name curr_class in - let prop_name = Ast_utils.property_name property_impl_decl_info in - Printing.log_out "ADDING: ObjCPropertyImplDecl for property '%s' " prop_name; - Printing.log_out "pointer = '%s'\n" decl_info.Clang_ast_t.di_pointer; - let qt, attributes, decl_info, (getter_name, getter), (setter_name, setter), _ = (try - 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 () = - ( +let create_generated_method_name name_info = + { ni_name = name_info.Clang_ast_t.ni_name; + ni_qual_name = CFrontend_config.generated_suffix:: name_info.Clang_ast_t.ni_qual_name; + } + +let get_ivar_name prop_name ivar_opt = + match ivar_opt with + | Some ivar_name -> ivar_name + | None -> Ast_utils.generated_ivar_name prop_name + +let make_getter curr_class prop_name prop_type = + match prop_type with + | qt, attributes, decl_info, (getter_name, getter), (setter_name, setter), ivar_opt -> + let ivar_name = get_ivar_name prop_name ivar_opt in match getter with | Some (ObjCMethodDecl(di, name_info, mdi), _) -> - let dummy_info = Ast_expressions.dummy_decl_info 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 - (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 mdi'= Ast_expressions.make_method_decl_info mdi body in - let method_decl = ObjCMethodDecl(di, name_info, mdi) in - Property.replace_property - (curr_class, prop_name) - (qt, attributes, decl_info, - (getter_name, Some (method_decl, true)), (setter_name, setter), Some ivar_name); - [ObjCMethodDecl(dummy_info, name_info, mdi')] - else [] - | _ -> []) in - let make_setter () = - match setter with - | Some (ObjCMethodDecl(di, name_info, mdi), _) -> - if should_generate_setter cfg class_name name_info.Clang_ast_t.ni_name attributes then - let dummy_info = Ast_expressions.dummy_decl_info di in + let dummy_info = Ast_expressions.dummy_decl_info_in_curr_file di in + 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 + 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 generated_name_info = create_generated_method_name name_info in + Property.replace_property + (curr_class, prop_name) + (qt, attributes, decl_info, + (getter_name, Some (ObjCMethodDecl(di, name_info, mdi), true)), (setter_name, setter), Some ivar_name); + [ObjCMethodDecl(dummy_info, generated_name_info, mdi')] + | _ -> [] + +let make_setter curr_class prop_name prop_type = + match prop_type with + | qt, attributes, decl_info, (getter_name, getter), (setter_name, setter), ivar_opt -> + let ivar_name = get_ivar_name prop_name ivar_opt in + match setter with + | 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 | [ParmVarDecl(_, name_info, qt_param, _)] -> name_info.Clang_ast_t.ni_name, qt_param | _ -> assert false) in - let is_hidden = (match property_impl_decl_info.Clang_ast_t.opidi_ivar_decl with - | Some dr -> dr.Clang_ast_t.dr_is_hidden - | _ -> false) in + let is_hidden = false in let decl_ptr = Ast_utils.get_invalid_pointer () in let drti_decl_ref' = 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 code = if Ast_utils.is_retain memory_management_attribute then - let param_decl = - 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 release_call = - Ast_expressions.make_message_expr qt_param release lhs_exp stmt_info true in + let param_decl = 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 release_call = Ast_expressions.make_message_expr qt_param release lhs_exp stmt_info true in [retain_call; release_call; setter] else if Ast_utils.is_copy memory_management_attribute then - let param_decl = - 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 setter = - Ast_expressions.make_binary_stmt lhs_exp copy_call stmt_info expr_info boi in + let param_decl = 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 setter = Ast_expressions.make_binary_stmt lhs_exp copy_call stmt_info expr_info boi in [setter] else [setter] in let body = Ast_expressions.make_compound_stmt code stmt_info in let mdi'= Ast_expressions.make_method_decl_info mdi body in + let name_generated = create_generated_method_name name in Property.replace_property (curr_class, prop_name) (qt, attributes, decl_info, (getter_name, getter), - (setter_name, Some (ObjCMethodDecl(di, name_info, mdi), true)), Some ivar_name); - [ObjCMethodDecl(dummy_info, name_info, mdi')] - else [] - | _ -> [] in - match property_impl_decl_info.Clang_ast_t.opidi_implementation with - | `Dynamic - (* For the moment we treat Dynamic properties as Synthesize. This imply that setter/getter very simply, getting and setting *) - (* the value. Therefore we are assuming that the dynamic setter/getter won't have any other side effect.*) - | `Synthesize -> - (make_getter ()) @ (make_setter ()) - -(* Given a list of declarations in an interface returns a triple *) -(* (list of non static fields, list of static fields, list of methods)*) -(* TODO: this part is a bit redundant: we could add the methods to the tenv *) -(* at the same time that we add them to the cfg *) -let rec get_methods curr_class decl_list = + (setter_name, Some (ObjCMethodDecl(di, name, mdi), true)), Some ivar_name); + [ObjCMethodDecl(dummy_info, name_generated, mdi')] + | _ -> [] + +(*Makes the getters and setters according to the attributes: *) +(* - If readonly is available, only write getter *) +(* - If strong or retain are available then write the following code in the setter: *) +(* [param retain] *) +(* [self->_field release] *) +(* [self->_field = param] *) +(* - If copy is available then write the following code: *) +(* [self->_field = [param copy] *) +let make_getter_setter curr_class decl_info prop_name = + Printing.log_out "pointer = '%s'\n" decl_info.Clang_ast_t.di_pointer; + let prop_type = + 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 - match decl_list with - | [] -> [] - | (ObjCMethodDecl(decl_info, name_info, method_decl_info) as d):: decl_list' -> - let method_name = name_info.Clang_ast_t.ni_name in - Printing.log_out " ...Adding Method '%s' \n" (class_name^"_"^method_name); - let methods = get_methods curr_class decl_list' 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 - meth_name:: methods - - | ObjCPropertyDecl(decl_info, name_info, pdi):: 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' + add_properties_to_table curr_class decl_list; + let get_method decl list_methods = + match decl with + ObjCMethodDecl(decl_info, name_info, method_decl_info) as d -> + let method_name = name_info.Clang_ast_t.ni_name in + Printing.log_out " ...Adding Method '%s' \n" (class_name^"_"^method_name); + let _ = check_for_property curr_class method_name d method_decl_info.Clang_ast_t.omdi_body in + let meth_name = CMethod_trans.mk_procname_from_method class_name method_name in + meth_name:: list_methods + | _ -> list_methods in + list_fold_right get_method decl_list [] diff --git a/infer/src/clang/objcProperty_decl.mli b/infer/src/clang/objcProperty_decl.mli index 8a0a52a96..d791da022 100644 --- a/infer/src/clang/objcProperty_decl.mli +++ b/infer/src/clang/objcProperty_decl.mli @@ -7,9 +7,6 @@ * 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 (** 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 * 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 = sig @@ -60,6 +40,33 @@ sig val print_property_table : unit -> unit val find_property_name_from_ivar : CContext.curr_class -> string -> string option + end module Property: PropertySig + +(** Process properties by creating their getters and setters in the case that they need to be syntethized *) +(** or in the case of dynamic. *) + +val prepare_dynamic_property : CContext.curr_class -> Clang_ast_t.decl_info -> +Clang_ast_t.obj_c_property_impl_decl_info -> Clang_ast_t.decl list + +val get_methods : CContext.curr_class -> Clang_ast_t.decl list -> Procname.t list + +val reset_property_table : unit -> unit + +val print_property_table : unit -> unit + +val 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 diff --git a/infer/src/harness/inhabit.ml b/infer/src/harness/inhabit.ml index 189575f6a..7513e60ca 100644 --- a/infer/src/harness/inhabit.ml +++ b/infer/src/harness/inhabit.ml @@ -292,6 +292,7 @@ let add_harness_to_cg harness_name harness_cfg harness_node loc cg tenv = Sil.language = Sil.Java; Sil.func_attributes = []; Sil.method_annotation = Sil.method_annotation_empty; + Sil.is_generated = false; } in create { 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.func_attributes = []; Sil.method_annotation = Sil.method_annotation_empty; + Sil.is_generated = false; } in create { cfg = harness_cfg; diff --git a/infer/src/java/jTrans.ml b/infer/src/java/jTrans.ml index fbaa8c83d..ee31521cc 100644 --- a/infer/src/java/jTrans.ml +++ b/infer/src/java/jTrans.ml @@ -295,6 +295,7 @@ let create_local_procdesc program linereader cfg tenv node m = Sil.language = Sil.Java; Sil.func_attributes = []; Sil.method_annotation = method_annotation; + Sil.is_generated = false; } in create { cfg = cfg; @@ -330,6 +331,7 @@ let create_local_procdesc program linereader cfg tenv node m = Sil.language = Sil.Java; Sil.func_attributes = []; Sil.method_annotation = method_annotation; + Sil.is_generated = false; } in create { cfg = cfg; @@ -366,6 +368,7 @@ let create_local_procdesc program linereader cfg tenv node m = Sil.language = Sil.Java; Sil.func_attributes = []; Sil.method_annotation = method_annotation; + Sil.is_generated = false; } in create { cfg = cfg; @@ -421,6 +424,7 @@ let create_external_procdesc program cfg tenv cn ms method_annotation kind = Sil.language = Sil.Java; Sil.func_attributes = []; Sil.method_annotation = method_annotation; + Sil.is_generated = false; } in create { cfg = cfg; diff --git a/infer/src/llvm/lTrans.ml b/infer/src/llvm/lTrans.ml index 5268e91e5..9028f8905 100644 --- a/infer/src/llvm/lTrans.ml +++ b/infer/src/llvm/lTrans.ml @@ -1,6 +1,10 @@ (* -* Copyright (c) 2015 - Facebook. +* 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 LAst @@ -47,11 +51,12 @@ let gen_func_def (old_cfg : Cfg.cfg) : func_def -> unit = function is_synthetic_method = false; language = Sil.C_CPP; func_attributes = []; - method_annotation = Sil.method_annotation_empty + method_annotation = Sil.method_annotation_empty; + is_generated = false } in let (pdesc_builder : Cfg.Procdesc.proc_desc_builder) = { 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 *) proc_attributes = proc_attrs; ret_type = (match ret_tp_opt with diff --git a/infer/tests/codetoanalyze/objc/errors/memory_leaks_benchmark/ArcExample.dot b/infer/tests/codetoanalyze/objc/errors/memory_leaks_benchmark/ArcExample.dot index 09f7eaae9..faa8d08e9 100644 --- a/infer/tests/codetoanalyze/objc/errors/memory_leaks_benchmark/ArcExample.dot +++ b/infer/tests/codetoanalyze/objc/errors/memory_leaks_benchmark/ArcExample.dot @@ -1,23 +1,23 @@ 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 ; 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 ; -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 ; 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 ; diff --git a/infer/tests/codetoanalyze/objc/errors/memory_leaks_benchmark/AutoreleaseExample.dot b/infer/tests/codetoanalyze/objc/errors/memory_leaks_benchmark/AutoreleaseExample.dot index 3c25daa1d..931c7da90 100644 --- a/infer/tests/codetoanalyze/objc/errors/memory_leaks_benchmark/AutoreleaseExample.dot +++ b/infer/tests/codetoanalyze/objc/errors/memory_leaks_benchmark/AutoreleaseExample.dot @@ -119,25 +119,25 @@ digraph iCFG { 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 ; 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 ; -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 ; 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 ; diff --git a/infer/tests/codetoanalyze/objc/errors/memory_leaks_benchmark/MemoryLeakExample.dot b/infer/tests/codetoanalyze/objc/errors/memory_leaks_benchmark/MemoryLeakExample.dot index ccfa7712b..35d603da8 100644 --- a/infer/tests/codetoanalyze/objc/errors/memory_leaks_benchmark/MemoryLeakExample.dot +++ b/infer/tests/codetoanalyze/objc/errors/memory_leaks_benchmark/MemoryLeakExample.dot @@ -1,48 +1,4 @@ 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"] diff --git a/infer/tests/codetoanalyze/objc/errors/memory_leaks_benchmark/retain_cycle.m b/infer/tests/codetoanalyze/objc/errors/memory_leaks_benchmark/retain_cycle.m index 82c881a44..40c54c0fd 100644 --- a/infer/tests/codetoanalyze/objc/errors/memory_leaks_benchmark/retain_cycle.m +++ b/infer/tests/codetoanalyze/objc/errors/memory_leaks_benchmark/retain_cycle.m @@ -18,43 +18,27 @@ @end -@implementation AA -@end - - @interface BBStrong : NSObject @property (nonatomic, strong) AA* a; @end -@implementation BBStrong -@end - @interface BBUnsafeUnretained : NSObject @property (nonatomic, unsafe_unretained) AA* a; @end -@implementation BBUnsafeUnretained -@end - @interface BBWeak : NSObject @property (nonatomic, weak) AA* a; @end -@implementation BBWeak -@end - @interface BBAssign : NSObject @property (nonatomic) AA* a; @end -@implementation BBAssign -@end - int strongcycle() { AA* a_obj =[AA alloc]; diff --git a/infer/tests/codetoanalyze/objc/errors/npe/Nonnull_attribute_example.dot b/infer/tests/codetoanalyze/objc/errors/npe/Nonnull_attribute_example.dot index 27c8fab6e..f8139f6fb 100644 --- a/infer/tests/codetoanalyze/objc/errors/npe/Nonnull_attribute_example.dot +++ b/infer/tests/codetoanalyze/objc/errors/npe/Nonnull_attribute_example.dot @@ -18,25 +18,25 @@ digraph iCFG { 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 ; 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 ; -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 ; 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 ; diff --git a/infer/tests/codetoanalyze/objc/frontend/assertions/NSAssert_example.dot b/infer/tests/codetoanalyze/objc/frontend/assertions/NSAssert_example.dot index 1db9ddd49..dc4e8c318 100644 --- a/infer/tests/codetoanalyze/objc/frontend/assertions/NSAssert_example.dot +++ b/infer/tests/codetoanalyze/objc/frontend/assertions/NSAssert_example.dot @@ -1,275 +1,275 @@ 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 ; -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"] + 81 -> 65 ; +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 ; -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"] + 80 -> 73 ; +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 ; -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"] + 79 -> 81 ; +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 ; -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"] + 78 -> 74 ; +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 ; -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"] + 77 -> 74 ; +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 ; -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"] + 76 -> 78 ; +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 ; -62 [label="62: + \n " ] + 75 -> 77 ; +74 [label="74: + \n " ] - 62 -> 67 ; - 62 -> 68 ; -61 [label="61: + \n " ] + 74 -> 79 ; + 74 -> 80 ; +73 [label="73: + \n " ] - 61 -> 59 ; - 61 -> 60 ; -60 [label="60: Prune (false branch) \n PRUNE((0 == 0), false); [line 36]\n " shape="invhouse"] + 73 -> 71 ; + 73 -> 72 ; +72 [label="72: Prune (false branch) \n PRUNE((0 == 0), false); [line 36]\n " shape="invhouse"] - 60 -> 57 ; -59 [label="59: Prune (true branch) \n PRUNE((0 != 0), true); [line 36]\n APPLY_ABSTRACTION; [line 36]\n " shape="invhouse"] + 72 -> 66 ; +71 [label="71: Prune (true branch) \n PRUNE((0 != 0), true); [line 36]\n APPLY_ABSTRACTION; [line 36]\n " shape="invhouse"] - 59 -> 58 ; -58 [label="58: + \n " ] + 71 -> 70 ; +70 [label="70: + \n " ] - 58 -> 63 ; - 58 -> 64 ; -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"] + 70 -> 75 ; + 70 -> 76 ; +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 ; -56 [label="56: Exit test2 \n " color=yellow style=filled] + 69 -> 68 ; +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 ; -54 [label="54: Assertion failure \n _fun___infer_fail(\"ASSERTION_FAILURE\":void ) [line 31]\n APPLY_ABSTRACTION; [line 31]\n " shape="box"] + 67 -> 69 ; +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 ; -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"] + 66 -> 65 ; +65 [label="65: Exit test2 \n " color=yellow style=filled] - 53 -> 45 ; -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"] +64 [label="64: Start test2\nFormals: target:class A *\nLocals: \n DECLARE_LOCALS(&return); [line 35]\n " color=yellow style=filled] - 52 -> 54 ; -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"] + 64 -> 70 ; +63 [label="63: Assertion failure \n _fun___infer_fail(\"ASSERTION_FAILURE\":void ) [line 31]\n APPLY_ABSTRACTION; [line 31]\n " shape="box"] - 51 -> 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"] + 63 -> 46 ; +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 ; -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"] + 62 -> 54 ; +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 ; -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"] + 61 -> 63 ; +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 ; -47 [label="47: BinaryOperatorStmt: NE \n n$24=*&target:class A * [line 31]\n " shape="box"] + 60 -> 55 ; +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 ; - 47 -> 49 ; -46 [label="46: + \n " ] + 59 -> 55 ; +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 -> 52 ; - 46 -> 53 ; -45 [label="45: + \n " ] + 58 -> 60 ; +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 -> 43 ; - 45 -> 44 ; -44 [label="44: Prune (false branch) \n PRUNE((0 == 0), false); [line 31]\n " shape="invhouse"] + 57 -> 59 ; +56 [label="56: BinaryOperatorStmt: NE \n n$30=*&target:class A * [line 31]\n " shape="box"] - 44 -> 41 ; -43 [label="43: Prune (true branch) \n PRUNE((0 != 0), true); [line 31]\n APPLY_ABSTRACTION; [line 31]\n " shape="invhouse"] + 56 -> 57 ; + 56 -> 58 ; +55 [label="55: + \n " ] - 43 -> 42 ; -42 [label="42: + \n " ] + 55 -> 61 ; + 55 -> 62 ; +54 [label="54: + \n " ] - 42 -> 47 ; -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 -> 52 ; + 54 -> 53 ; +53 [label="53: Prune (false branch) \n PRUNE((0 == 0), false); [line 31]\n " shape="invhouse"] - 41 -> 40 ; -40 [label="40: Exit test1 \n " color=yellow style=filled] + 53 -> 47 ; +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 ; -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"] + 51 -> 56 ; +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 ; -37 [label="37: Exit A_setX: \n " color=yellow style=filled] + 47 -> 46 ; +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 ; -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"] + 45 -> 51 ; +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 ; -34 [label="34: Exit A_x \n " color=yellow style=filled] + 44 -> 43 ; +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 ; -32 [label="32: Assertion failure \n _fun___infer_fail(\"ASSERTION_FAILURE\":void ) [line 24]\n APPLY_ABSTRACTION; [line 24]\n " shape="box"] + 42 -> 44 ; +38 [label="38: Assertion failure \n _fun___infer_fail(\"ASSERTION_FAILURE\":void ) [line 24]\n APPLY_ABSTRACTION; [line 24]\n " shape="box"] - 32 -> 18 ; -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"] + 38 -> 21 ; +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 ; -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"] + 37 -> 29 ; +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 ; -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"] + 36 -> 38 ; +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 ; -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"] + 35 -> 30 ; +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 ; -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"] + 34 -> 30 ; +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 ; -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"] + 33 -> 35 ; +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 ; -25 [label="25: BinaryOperatorStmt: NE \n n$11=*&a:class A * [line 24]\n " shape="box"] + 32 -> 34 ; +31 [label="31: BinaryOperatorStmt: NE \n n$15=*&a:class A * [line 24]\n " shape="box"] - 25 -> 26 ; - 25 -> 27 ; -24 [label="24: + \n " ] + 31 -> 32 ; + 31 -> 33 ; +30 [label="30: + \n " ] - 24 -> 30 ; - 24 -> 31 ; -23 [label="23: + \n " ] + 30 -> 36 ; + 30 -> 37 ; +29 [label="29: + \n " ] - 23 -> 21 ; - 23 -> 22 ; -22 [label="22: Prune (false branch) \n PRUNE((0 == 0), false); [line 24]\n " shape="invhouse"] + 29 -> 27 ; + 29 -> 28 ; +28 [label="28: Prune (false branch) \n PRUNE((0 == 0), false); [line 24]\n " shape="invhouse"] - 22 -> 19 ; -21 [label="21: Prune (true branch) \n PRUNE((0 != 0), true); [line 24]\n APPLY_ABSTRACTION; [line 24]\n " shape="invhouse"] + 28 -> 22 ; +27 [label="27: Prune (true branch) \n PRUNE((0 != 0), true); [line 24]\n APPLY_ABSTRACTION; [line 24]\n " shape="invhouse"] - 21 -> 20 ; -20 [label="20: + \n " ] + 27 -> 26 ; +26 [label="26: + \n " ] - 20 -> 25 ; -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"] + 26 -> 31 ; +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 ; -18 [label="18: Exit A_initWithRequest: \n " color=yellow style=filled] + 22 -> 21 ; +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 ; -16 [label="16: Assertion failure \n _fun___infer_fail(\"ASSERTION_FAILURE\":void ) [line 19]\n APPLY_ABSTRACTION; [line 19]\n " shape="box"] + 20 -> 26 ; +19 [label="19: Assertion failure \n _fun___infer_fail(\"ASSERTION_FAILURE\":void ) [line 19]\n APPLY_ABSTRACTION; [line 19]\n " shape="box"] - 16 -> 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"] + 19 -> 2 ; +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 ; -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"] + 18 -> 10 ; +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 ; -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"] + 17 -> 19 ; +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 ; -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"] + 16 -> 11 ; +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 ; -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"] + 15 -> 11 ; +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 ; -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"] + 14 -> 16 ; +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 ; -9 [label="9: BinaryOperatorStmt: NE \n n$2=*&target:class A * [line 19]\n " shape="box"] + 13 -> 15 ; +12 [label="12: BinaryOperatorStmt: NE \n n$4=*&target:class A * [line 19]\n " shape="box"] - 9 -> 10 ; - 9 -> 11 ; -8 [label="8: + \n " ] + 12 -> 13 ; + 12 -> 14 ; +11 [label="11: + \n " ] - 8 -> 14 ; - 8 -> 15 ; -7 [label="7: + \n " ] + 11 -> 17 ; + 11 -> 18 ; +10 [label="10: + \n " ] - 7 -> 5 ; - 7 -> 6 ; -6 [label="6: Prune (false branch) \n PRUNE((0 == 0), false); [line 19]\n " shape="invhouse"] + 10 -> 8 ; + 10 -> 9 ; +9 [label="9: Prune (false branch) \n PRUNE((0 == 0), false); [line 19]\n " shape="invhouse"] - 6 -> 3 ; -5 [label="5: Prune (true branch) \n PRUNE((0 != 0), true); [line 19]\n APPLY_ABSTRACTION; [line 19]\n " shape="invhouse"] + 9 -> 3 ; +8 [label="8: Prune (true branch) \n PRUNE((0 != 0), true); [line 19]\n APPLY_ABSTRACTION; [line 19]\n " shape="invhouse"] - 5 -> 4 ; -4 [label="4: + \n " ] + 8 -> 7 ; +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"] @@ -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 -> 4 ; + 1 -> 7 ; } diff --git a/infer/tests/codetoanalyze/objc/frontend/block/dispatch.dot b/infer/tests/codetoanalyze/objc/frontend/block/dispatch.dot index ddfd7535d..b86bdfe9f 100644 --- a/infer/tests/codetoanalyze/objc/frontend/block/dispatch.dot +++ b/infer/tests/codetoanalyze/objc/frontend/block/dispatch.dot @@ -1,42 +1,42 @@ 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 ; -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"] + 30 -> 29 ; +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 ; -25 [label="25: Return Stmt \n *&return:int =0 [line 52]\n APPLY_ABSTRACTION; [line 52]\n " shape="box"] + 29 -> 25 ; +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 ; -24 [label="24: Exit main \n " color=yellow style=filled] + 28 -> 27 ; +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 ; -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"] + 26 -> 28 ; +25 [label="25: Return Stmt \n *&return:int =0 [line 52]\n APPLY_ABSTRACTION; [line 52]\n " shape="box"] - 22 -> 21 ; -21 [label="21: Exit A_setX: \n " color=yellow style=filled] + 25 -> 24 ; +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 ; -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"] + 23 -> 30 ; +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 ; 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 ; diff --git a/infer/tests/codetoanalyze/objc/frontend/property/PropertyAttributes.dot b/infer/tests/codetoanalyze/objc/frontend/property/PropertyAttributes.dot index c0d075ebd..348adc1c4 100644 --- a/infer/tests/codetoanalyze/objc/frontend/property/PropertyAttributes.dot +++ b/infer/tests/codetoanalyze/objc/frontend/property/PropertyAttributes.dot @@ -1,98 +1,98 @@ 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 ; -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"] + 39 -> 38 ; +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 ; -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"] + 38 -> 34 ; +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 ; -33 [label="33: Return Stmt \n *&return:int =0 [line 42]\n APPLY_ABSTRACTION; [line 42]\n " shape="box"] + 37 -> 36 ; +36 [label="36: Exit A_setLast_name: \n " color=yellow style=filled] - 33 -> 32 ; -32 [label="32: Exit test \n " color=yellow style=filled] +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] -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 ; -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"] + 34 -> 33 ; +33 [label="33: Return Stmt \n *&return:int =0 [line 42]\n APPLY_ABSTRACTION; [line 42]\n " shape="box"] - 30 -> 29 ; -29 [label="29: Exit A_setLast_name: \n " color=yellow style=filled] + 33 -> 32 ; +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 ; -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"] + 31 -> 39 ; +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 ; 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 ; -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 ; -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 ; -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 ; 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 ; -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 ; 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 ; -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 ; 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 ; -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 ; 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 ; diff --git a/infer/tests/codetoanalyze/objc/frontend/property/PropertyCustomAccessor.dot b/infer/tests/codetoanalyze/objc/frontend/property/PropertyCustomAccessor.dot index ea886c7b1..aedc3dd87 100644 --- a/infer/tests/codetoanalyze/objc/frontend/property/PropertyCustomAccessor.dot +++ b/infer/tests/codetoanalyze/objc/frontend/property/PropertyCustomAccessor.dot @@ -1,23 +1,23 @@ 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 ; 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 ; -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 ; 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 ; diff --git a/infer/tests/codetoanalyze/objc/frontend/property/PropertyImplSetter.dot b/infer/tests/codetoanalyze/objc/frontend/property/PropertyImplSetter.dot index 4fdcd3fbe..19f8877e6 100644 --- a/infer/tests/codetoanalyze/objc/frontend/property/PropertyImplSetter.dot +++ b/infer/tests/codetoanalyze/objc/frontend/property/PropertyImplSetter.dot @@ -1,15 +1,4 @@ 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"] diff --git a/infer/tests/codetoanalyze/objc/frontend/property/Property_getter.dot b/infer/tests/codetoanalyze/objc/frontend/property/Property_getter.dot index 9d7f9f0ad..6d4df21ed 100644 --- a/infer/tests/codetoanalyze/objc/frontend/property/Property_getter.dot +++ b/infer/tests/codetoanalyze/objc/frontend/property/Property_getter.dot @@ -1,26 +1,26 @@ 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 ; -8 [label="8: Exit A_setX: \n " color=yellow style=filled] + 12 -> 11 ; +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 ; -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"] + 10 -> 12 ; +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 ; -5 [label="5: Exit A_x \n " color=yellow style=filled] + 9 -> 8 ; +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"] diff --git a/infer/tests/codetoanalyze/objc/frontend/property/aclass.dot b/infer/tests/codetoanalyze/objc/frontend/property/aclass.dot index 99866a93b..0546095d9 100644 --- a/infer/tests/codetoanalyze/objc/frontend/property/aclass.dot +++ b/infer/tests/codetoanalyze/objc/frontend/property/aclass.dot @@ -1,31 +1,31 @@ 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 ; -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 ; -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 ; 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 ; -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 ; 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 ; diff --git a/infer/tests/codetoanalyze/objc/frontend/property_in_protocol/MyProtocol.h b/infer/tests/codetoanalyze/objc/frontend/property_in_protocol/MyProtocol.h index 0fbe00d80..a855c3ae3 100644 --- a/infer/tests/codetoanalyze/objc/frontend/property_in_protocol/MyProtocol.h +++ b/infer/tests/codetoanalyze/objc/frontend/property_in_protocol/MyProtocol.h @@ -7,7 +7,7 @@ * of patent rights can be found in the PATENTS file in the same directory. */ -#import +#import @protocol MyProtocol diff --git a/infer/tests/codetoanalyze/objc/frontend/property_in_protocol/Test.dot b/infer/tests/codetoanalyze/objc/frontend/property_in_protocol/Test.dot index 183948113..e69de29bb 100644 --- a/infer/tests/codetoanalyze/objc/frontend/property_in_protocol/Test.dot +++ b/infer/tests/codetoanalyze/objc/frontend/property_in_protocol/Test.dot @@ -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 ; -} diff --git a/infer/tests/codetoanalyze/objc/frontend/property_in_protocol/Test.h b/infer/tests/codetoanalyze/objc/frontend/property_in_protocol/Test.h index 6fd706c2e..dbd21b973 100644 --- a/infer/tests/codetoanalyze/objc/frontend/property_in_protocol/Test.h +++ b/infer/tests/codetoanalyze/objc/frontend/property_in_protocol/Test.h @@ -7,7 +7,7 @@ * of patent rights can be found in the PATENTS file in the same directory. */ -#import +#import #import "MyProtocol.h" @interface Test : NSObject { diff --git a/infer/tests/endtoend/c/SentinelTest.java b/infer/tests/endtoend/c/SentinelTest.java index afdc5ad38..0ec266898 100644 --- a/infer/tests/endtoend/c/SentinelTest.java +++ b/infer/tests/endtoend/c/SentinelTest.java @@ -1,6 +1,10 @@ /* - * Copyright (c) 2013- Facebook. - * All rights reserved. +* Copyright (c) 2013 - 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. */ package endtoend.c;