diff --git a/infer/src/clang/ast_expressions.ml b/infer/src/clang/ast_expressions.ml index c3c9380a0..a4d322c91 100644 --- a/infer/src/clang/ast_expressions.ml +++ b/infer/src/clang/ast_expressions.ml @@ -214,11 +214,11 @@ let make_obj_c_message_expr_info_instance sel = { omei_decl_pointer = None; (* TODO look into it *) } -let make_obj_c_message_expr_info_class selector tp = { +let make_obj_c_message_expr_info_class selector tp pointer = { Clang_ast_t.omei_selector = selector; omei_receiver_kind = `Class (create_class_type tp); omei_is_definition_found = false; - omei_decl_pointer = None (* TODO look into it *) + omei_decl_pointer = pointer } let make_decl_ref k decl_ptr name is_hidden tp_opt = { diff --git a/infer/src/clang/ast_expressions.mli b/infer/src/clang/ast_expressions.mli index d02aa9ae9..7aefdcca3 100644 --- a/infer/src/clang/ast_expressions.mli +++ b/infer/src/clang/ast_expressions.mli @@ -83,7 +83,8 @@ val make_decl_ref_exp_var : named_decl_info * type_ptr * pointer -> decl_kind -> val make_binary_stmt : stmt -> stmt -> stmt_info -> expr_info -> binary_operator_info -> stmt -val make_obj_c_message_expr_info_class : string -> string -> obj_c_message_expr_info +val make_obj_c_message_expr_info_class : string -> string -> pointer option -> + obj_c_message_expr_info val make_obj_c_message_expr_info_instance : string -> obj_c_message_expr_info diff --git a/infer/src/clang/cFrontend_utils.ml b/infer/src/clang/cFrontend_utils.ml index 1ffc79a10..7e78db259 100644 --- a/infer/src/clang/cFrontend_utils.ml +++ b/infer/src/clang/cFrontend_utils.ml @@ -292,6 +292,11 @@ struct Some (Clang_ast_main.PointerMap.find decl_ptr !CFrontend_config.pointer_decl_index) with Not_found -> Printing.log_stats "decl with pointer %s not found\n" decl_ptr; None + let get_decl_opt decl_ptr_opt = + match decl_ptr_opt with + | Some decl_ptr -> get_decl decl_ptr + | None -> None + let update_sil_types_map type_ptr sil_type = CFrontend_config.sil_types_map := Clang_ast_types.TypePointerMap.add type_ptr sil_type !CFrontend_config.sil_types_map diff --git a/infer/src/clang/cFrontend_utils.mli b/infer/src/clang/cFrontend_utils.mli index de592b65f..d5632f777 100644 --- a/infer/src/clang/cFrontend_utils.mli +++ b/infer/src/clang/cFrontend_utils.mli @@ -77,6 +77,8 @@ sig val get_decl : Clang_ast_t.pointer -> Clang_ast_t.decl option + val get_decl_opt : Clang_ast_t.pointer option -> Clang_ast_t.decl option + val update_sil_types_map : Clang_ast_t.type_ptr -> Sil.typ -> unit val update_enum_map : Clang_ast_t.pointer -> Sil.exp -> unit diff --git a/infer/src/clang/cMethod_signature.ml b/infer/src/clang/cMethod_signature.ml index 7d0d1aea2..f877b83b5 100644 --- a/infer/src/clang/cMethod_signature.ml +++ b/infer/src/clang/cMethod_signature.ml @@ -11,7 +11,7 @@ (** return type, location and whether its an instance method. *) type method_signature = { - _name : Procname.t; + mutable _name : Procname.t; _args : (string * Clang_ast_t.type_ptr) list; _ret_type : Clang_ast_t.type_ptr; _attributes : Clang_ast_t.attribute list; @@ -19,11 +19,15 @@ type method_signature = { _is_instance : bool; _is_generated : bool; _language : CFrontend_config.lang; + _pointer_to_parent : Clang_ast_t.pointer option } let ms_get_name ms = ms._name +let ms_set_name ms name = + ms._name <- name + let ms_get_args ms = ms._args @@ -45,7 +49,10 @@ let ms_is_generated ms = let ms_get_lang ms = ms._language -let make_ms procname args ret_type attributes loc is_instance is_generated lang = +let ms_get_pointer_to_parent ms = + ms._pointer_to_parent + +let make_ms procname args ret_type attributes loc is_instance is_generated lang pointer_to_parent = let meth_signature = { _name = procname; _args = args; @@ -55,6 +62,7 @@ let make_ms procname args ret_type attributes loc is_instance is_generated lang _is_instance = is_instance; _is_generated = is_generated; _language = lang; + _pointer_to_parent = pointer_to_parent; } in meth_signature diff --git a/infer/src/clang/cMethod_signature.mli b/infer/src/clang/cMethod_signature.mli index 14f6de603..630c0ba65 100644 --- a/infer/src/clang/cMethod_signature.mli +++ b/infer/src/clang/cMethod_signature.mli @@ -14,6 +14,8 @@ type method_signature val ms_get_name : method_signature -> Procname.t +val ms_set_name : method_signature -> Procname.t -> unit + val ms_get_args : method_signature -> (string * Clang_ast_t.type_ptr) list @@ -27,9 +29,11 @@ val ms_is_instance : method_signature -> bool val ms_get_lang : method_signature -> CFrontend_config.lang +val ms_get_pointer_to_parent : method_signature -> Clang_ast_t.pointer option + val make_ms : Procname.t -> (string * Clang_ast_t.type_ptr) list -> Clang_ast_t.type_ptr -> Clang_ast_t.attribute list -> Clang_ast_t.source_range -> bool -> - bool -> CFrontend_config.lang -> method_signature + bool -> CFrontend_config.lang -> Clang_ast_t.pointer option -> method_signature val replace_name_ms : method_signature -> Procname.t -> method_signature diff --git a/infer/src/clang/cMethod_trans.ml b/infer/src/clang/cMethod_trans.ml index f03fa2215..851dc03b1 100644 --- a/infer/src/clang/cMethod_trans.ml +++ b/infer/src/clang/cMethod_trans.ml @@ -86,7 +86,8 @@ let get_return_type function_method_decl_info = | Block_decl_info (_, typ, _) -> CTypes.return_type_of_function_type typ | ObjC_Meth_decl_info (method_decl_info, _) -> method_decl_info.Clang_ast_t.omdi_result_type -let build_method_signature decl_info procname function_method_decl_info is_anonym_block is_generated = +let build_method_signature decl_info procname function_method_decl_info is_anonym_block is_generated + parent_pointer = let source_range = decl_info.Clang_ast_t.di_source_range in let tp = get_return_type function_method_decl_info in let is_instance_method = is_instance_method function_method_decl_info in @@ -94,7 +95,7 @@ let build_method_signature decl_info procname function_method_decl_info is_anony let attributes = decl_info.Clang_ast_t.di_attributes in let lang = get_language function_method_decl_info in CMethod_signature.make_ms procname parameters tp attributes source_range is_instance_method - is_generated lang + is_generated lang parent_pointer let get_assume_not_null_calls ms param_decls = let attributes = CMethod_signature.ms_get_attributes ms in @@ -119,7 +120,7 @@ let method_signature_of_decl meth_decl block_data_opt = let func_decl = Func_decl_info (fdi, tp, language) in let function_info = Some (decl_info, fdi) in let procname = General_utils.mk_procname_from_function name function_info tp language in - let ms = build_method_signature decl_info procname func_decl false false in + let ms = build_method_signature decl_info procname func_decl false false None in let extra_instrs = get_assume_not_null_calls ms fdi.Clang_ast_t.fdi_parameters in ms, fdi.Clang_ast_t.fdi_body, extra_instrs | CXXMethodDecl (decl_info, name_info, tp, fdi, mdi), _ @@ -128,7 +129,8 @@ let method_signature_of_decl meth_decl block_data_opt = let class_name = Ast_utils.get_class_name_from_member name_info in let procname = General_utils.mk_procname_from_cpp_method class_name method_name tp in let method_decl = Cpp_Meth_decl_info (fdi, mdi, class_name, tp) in - let ms = build_method_signature decl_info procname method_decl false false in + let parent_pointer = decl_info.Clang_ast_t.di_parent_pointer in + let ms = build_method_signature decl_info procname method_decl false false parent_pointer in let non_null_instrs = get_assume_not_null_calls ms fdi.Clang_ast_t.fdi_parameters in let init_list_instrs = get_init_list_instrs mdi in (* it will be empty for methods *) ms, fdi.Clang_ast_t.fdi_body, (init_list_instrs @ non_null_instrs) @@ -140,12 +142,14 @@ let method_signature_of_decl meth_decl block_data_opt = let procname = General_utils.mk_procname_from_objc_method class_name method_name method_kind in let method_decl = ObjC_Meth_decl_info (mdi, class_name) in let is_generated = Ast_utils.is_generated name_info in - let ms = build_method_signature decl_info procname method_decl false is_generated in + let parent_pointer = decl_info.Clang_ast_t.di_parent_pointer in + let ms = build_method_signature decl_info procname method_decl false is_generated + parent_pointer in let extra_instrs = get_assume_not_null_calls ms mdi.omdi_parameters in ms, mdi.omdi_body, extra_instrs | BlockDecl (decl_info, bdi), Some (outer_context, tp, procname, _) -> let func_decl = Block_decl_info (bdi, tp, outer_context) in - let ms = build_method_signature decl_info procname func_decl true false in + let ms = build_method_signature decl_info procname func_decl true false None in let extra_instrs = get_assume_not_null_calls ms bdi.bdi_parameters in ms, bdi.bdi_body, extra_instrs | _ -> raise Invalid_declaration @@ -159,6 +163,24 @@ let method_signature_of_pointer pointer = | None -> None with Invalid_declaration -> None +let get_method_name_from_clang tenv ms_opt = + match ms_opt with + | Some ms -> + (match Ast_utils.get_decl_opt (CMethod_signature.ms_get_pointer_to_parent ms) with + | Some decl -> + if ObjcProtocol_decl.is_protocol decl then None + else + (ignore (CTypes_decl.add_types_from_decl_to_tenv tenv decl); + match ObjcCategory_decl.get_base_class_name_from_category decl with + | Some class_name -> + let procname = CMethod_signature.ms_get_name ms in + let new_procname = Procname.c_method_replace_class procname class_name in + CMethod_signature.ms_set_name ms new_procname; + Some ms + | None -> Some ms) + | None -> Some ms) + | None -> None + let get_superclass_curr_class context = let retrive_super cname super_opt = let iname = Sil.TN_csu (Sil.Class, Mangled.from_string cname) in @@ -179,25 +201,39 @@ let get_superclass_curr_class context = | CContext.ContextNoCls | CContext.ContextProtocol _ -> assert false -let get_class_selector_instance context obj_c_message_expr_info act_params = - let selector = obj_c_message_expr_info.Clang_ast_t.omei_selector in - let pointer = obj_c_message_expr_info.Clang_ast_t.omei_decl_pointer in +(* Gets the class name from a method signature found by clang, if search is successful *) +let get_class_name_method_call_from_clang obj_c_message_expr_info = + match obj_c_message_expr_info.Clang_ast_t.omei_decl_pointer with + | Some pointer -> + (match method_signature_of_pointer pointer with + | Some ms -> + let class_name = Procname.c_get_class (CMethod_signature.ms_get_name ms) in + Some class_name + | None -> None) + | None -> None + +(* Get class name from a method call accorsing to the info given by the receiver kind *) +let get_class_name_method_call_from_receiver_kind context obj_c_message_expr_info act_params = match obj_c_message_expr_info.Clang_ast_t.omei_receiver_kind with | `Class tp -> let sil_type = CTypes_decl.type_ptr_to_sil_type context.CContext.tenv tp in - ((CTypes.classname_of_type sil_type), selector, pointer, MCStatic) + (CTypes.classname_of_type sil_type) | `Instance -> (match act_params with | (instance_obj, Sil.Tptr(t, _)):: _ - | (instance_obj, t):: _ -> - (CTypes.classname_of_type t, selector, pointer, MCVirtual) + | (instance_obj, t):: _ -> CTypes.classname_of_type t | _ -> assert false) - | `SuperInstance -> - let superclass = get_superclass_curr_class context in - (superclass, selector, pointer, MCNoVirtual) - | `SuperClass -> - let superclass = get_superclass_curr_class context in - (superclass, selector, pointer, MCStatic) + | `SuperInstance ->get_superclass_curr_class context + | `SuperClass -> get_superclass_curr_class context + +let get_objc_method_data obj_c_message_expr_info = + let selector = obj_c_message_expr_info.Clang_ast_t.omei_selector in + let pointer = obj_c_message_expr_info.Clang_ast_t.omei_decl_pointer in + match obj_c_message_expr_info.Clang_ast_t.omei_receiver_kind with + | `Instance -> (selector, pointer, MCVirtual) + | `SuperInstance -> (selector, pointer, MCNoVirtual) + | `Class _ + | `SuperClass -> (selector, pointer, MCStatic) let get_formal_parameters tenv ms = let rec defined_parameters pl = diff --git a/infer/src/clang/cMethod_trans.mli b/infer/src/clang/cMethod_trans.mli index 968fd25af..f329a8419 100644 --- a/infer/src/clang/cMethod_trans.mli +++ b/infer/src/clang/cMethod_trans.mli @@ -25,8 +25,13 @@ val create_local_procdesc : Cfg.cfg -> Sil.tenv -> CMethod_signature.method_sign val create_external_procdesc : Cfg.cfg -> Procname.t -> bool -> (Sil.typ * Sil.typ list) option -> unit -val get_class_selector_instance : CContext.t -> Clang_ast_t.obj_c_message_expr_info -> (Sil.exp * Sil.typ) list - -> (string * string * Clang_ast_t.pointer option * method_call_type) +val get_objc_method_data : Clang_ast_t.obj_c_message_expr_info -> + (string * Clang_ast_t.pointer option * method_call_type) + +val get_class_name_method_call_from_receiver_kind : CContext.t -> + Clang_ast_t.obj_c_message_expr_info -> (Sil.exp * Sil.typ) list -> string + +val get_class_name_method_call_from_clang : Clang_ast_t.obj_c_message_expr_info -> string option val should_create_procdesc : Cfg.cfg -> Procname.t -> bool -> bool -> bool @@ -35,5 +40,8 @@ val method_signature_of_decl : Clang_ast_t.decl -> CModule_type.block_data optio val method_signature_of_pointer : Clang_ast_t.pointer -> CMethod_signature.method_signature option +val get_method_name_from_clang : Sil.tenv -> CMethod_signature.method_signature option -> + CMethod_signature.method_signature option + val create_procdesc_with_pointer : CContext.t -> Clang_ast_t.pointer -> string option -> string -> Clang_ast_t.type_ptr -> Procname.t diff --git a/infer/src/clang/cTrans.ml b/infer/src/clang/cTrans.ml index 27e3cd873..a58d59e64 100644 --- a/infer/src/clang/cTrans.ml +++ b/infer/src/clang/cTrans.ml @@ -31,33 +31,44 @@ 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 *) + (* information and according to the method signature with the following priority: *) + (* 1. method is a predefined model *) + (* 2. method is found by clang's resolution*) + (* 3. Method is found by our resolution *) let get_callee_objc_method context obj_c_message_expr_info act_params = - let (class_name, method_name, method_pointer_opt, mc_type) = - CMethod_trans.get_class_selector_instance context obj_c_message_expr_info act_params in + let open CContext in + let (selector, method_pointer_opt, mc_type) = + CMethod_trans.get_objc_method_data obj_c_message_expr_info in let is_instance = mc_type != CMethod_trans.MCStatic in let method_kind = Procname.objc_method_kind_of_bool is_instance in - let callee_pn = General_utils.mk_procname_from_objc_method class_name method_name method_kind in - let open CContext in - match CTrans_models.get_predefined_model_method_signature class_name method_name - General_utils.mk_procname_from_objc_method CFrontend_config.OBJC with - | Some ms -> + let ms_opt = + match method_pointer_opt with + | Some pointer -> CMethod_trans.method_signature_of_pointer pointer + | None -> None in + let procname = + match CMethod_trans.get_method_name_from_clang context.tenv ms_opt with + | Some ms -> CMethod_signature.ms_get_name ms + | None -> (* fall back to our method resolution if clang's fails *) + let class_name = CMethod_trans.get_class_name_method_call_from_receiver_kind context + obj_c_message_expr_info act_params in + General_utils.mk_procname_from_objc_method class_name selector method_kind in + let class_name = Procname.c_get_class procname in + let predefined_ms_opt = + CTrans_models.get_predefined_model_method_signature class_name selector + General_utils.mk_procname_from_objc_method CFrontend_config.OBJC in + match predefined_ms_opt, ms_opt 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 -> - let found_method = - match method_pointer_opt with - | Some pointer -> - (match CMethod_trans.method_signature_of_pointer pointer with - | Some callee_ms -> - if not (M.process_getter_setter context callee_pn) then - (ignore (CMethod_trans.create_local_procdesc context.cfg context.tenv callee_ms [] [] is_instance)); - true - | None -> false) - | None -> false in - if not found_method then - CMethod_trans.create_external_procdesc context.cfg callee_pn is_instance None; - callee_pn, mc_type + | None, Some ms -> + if not (M.process_getter_setter context procname) then + (ignore (CMethod_trans.create_local_procdesc context.cfg context.tenv + ms [] [] is_instance)); + procname, mc_type + | _ -> + CMethod_trans.create_external_procdesc context.cfg procname is_instance None; + procname, mc_type + let add_autorelease_call context exp typ sil_loc = let method_name = Procname.c_get_method (Cfg.Procdesc.get_proc_name context.CContext.procdesc) in @@ -817,71 +828,101 @@ struct Sil.Tvoid | _ -> assert false + and objCMessageExpr_trans_special_cases trans_state si obj_c_message_expr_info stmt_list + expr_info method_type trans_state_pri sil_loc act_params = + let context = trans_state.context in + let receiver_kind = obj_c_message_expr_info.Clang_ast_t.omei_receiver_kind in + let selector = obj_c_message_expr_info.Clang_ast_t.omei_selector in + (* class method *) + if selector = CFrontend_config.class_method && CTypes.is_class method_type then + let class_name = CMethod_trans.get_class_name_method_call_from_receiver_kind context + obj_c_message_expr_info act_params in + raise (Self.SelfClassException class_name) + (* alloc or new *) + else if (selector = CFrontend_config.alloc) || (selector = CFrontend_config.new_str) then + match receiver_kind with + | `Class type_ptr -> + let class_opt = + CMethod_trans.get_class_name_method_call_from_clang obj_c_message_expr_info in + Some (new_or_alloc_trans trans_state_pri sil_loc si type_ptr class_opt selector) + | _ -> None + (* assertions *) + else if CTrans_models.is_handleFailureInMethod selector then + if Config.report_assertion_failure then + Some (CTrans_utils.trans_assertion_failure sil_loc context) + else Some (CTrans_utils.trans_assume_false sil_loc context trans_state.succ_nodes) + else None + + (* If the first argument of the call is self in a static context, remove it as an argument *) + (* and change the call from instance to static *) + and objCMessageExpr_deal_with_static_self trans_state_param stmt_list obj_c_message_expr_info = + match stmt_list with + | stmt :: rest -> + let obj_c_message_expr_info, fst_res_trans = + try + let fst_res_trans = instruction trans_state_param stmt in + obj_c_message_expr_info, fst_res_trans + with Self.SelfClassException class_name -> + let pointer = obj_c_message_expr_info.Clang_ast_t.omei_decl_pointer in + let selector = obj_c_message_expr_info.Clang_ast_t.omei_selector in + let obj_c_message_expr_info = + Ast_expressions.make_obj_c_message_expr_info_class selector class_name pointer in + obj_c_message_expr_info, empty_res_trans in + let instruction' = + exec_with_self_exception (exec_with_lvalue_as_reference instruction) in + let l = IList.map (instruction' trans_state_param) rest in + obj_c_message_expr_info, collect_res_trans (fst_res_trans :: l) + | [] -> obj_c_message_expr_info, empty_res_trans + and objCMessageExpr_trans trans_state si obj_c_message_expr_info stmt_list expr_info = Printing.log_out " priority node free = '%s'\n@." (string_of_bool (PriorityNode.is_priority_free trans_state)); let context = trans_state.context in let parent_line_number = trans_state.parent_line_number in + let line_number = CLocation.get_line si parent_line_number in let sil_loc = CLocation.get_sil_location si parent_line_number context in - let selector, receiver_kind = get_selector_receiver obj_c_message_expr_info in - let is_alloc_or_new = (selector = CFrontend_config.alloc) || (selector = CFrontend_config.new_str) in - Printing.log_out "\n!!!!!!! Calling with selector = '%s' " selector; - Printing.log_out " receiver_kind= '%s'\n\n" (Clang_ast_j.string_of_receiver_kind receiver_kind); let method_type = CTypes_decl.get_type_from_expr_info expr_info context.CContext.tenv in - let ret_id = if Sil.typ_equal method_type Sil.Tvoid then [] + let ret_id = + if Sil.typ_equal method_type Sil.Tvoid then [] else [Ident.create_fresh Ident.knormal] in let trans_state_pri = PriorityNode.try_claim_priority_node trans_state si in - let line_number = CLocation.get_line si parent_line_number in let trans_state_param = { trans_state_pri with parent_line_number = line_number; succ_nodes = [] } in let obj_c_message_expr_info, res_trans_par = - (match stmt_list with - | stmt :: rest -> - let obj_c_message_expr_info, fst_res_trans = - (try - let fst_res_trans = instruction trans_state_param stmt in - obj_c_message_expr_info, fst_res_trans - with Self.SelfClassException class_name -> - let obj_c_message_expr_info = Ast_expressions.make_obj_c_message_expr_info_class selector class_name in - obj_c_message_expr_info, empty_res_trans) in - let instruction' = - exec_with_self_exception (exec_with_lvalue_as_reference instruction) in - let l = IList.map (instruction' trans_state_param) rest in - obj_c_message_expr_info, collect_res_trans (fst_res_trans :: l) - | [] -> obj_c_message_expr_info, empty_res_trans) in - let (class_type, _, _, _) = CMethod_trans.get_class_selector_instance context obj_c_message_expr_info res_trans_par.exps in - if (selector = CFrontend_config.class_method && CTypes.is_class method_type) then - raise (Self.SelfClassException class_type) - else if is_alloc_or_new then - new_or_alloc_trans trans_state_pri sil_loc si class_type selector - else if (CTrans_models.is_handleFailureInMethod selector) then - if Config.report_assertion_failure then - CTrans_utils.trans_assertion_failure sil_loc context - else - CTrans_utils.trans_assume_false sil_loc context trans_state.succ_nodes - else - let procname = Cfg.Procdesc.get_proc_name context.CContext.procdesc 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 - Cg.add_edge context.CContext.cg procname callee_name; - let call_flags = { Sil.cf_virtual = is_virtual; Sil.cf_noreturn = false; Sil.cf_is_objc_block = false; } in - let param_exps, instr_block_param, ids_block_param = extract_block_from_tuple procname res_trans_par.exps sil_loc in - let stmt_call = Sil.Call(ret_id, (Sil.Const (Sil.Cfun callee_name)), param_exps, sil_loc, call_flags) in - let nname = "Message Call: "^selector in - let res_trans_tmp = { - res_trans_par with - ids = ret_id @ res_trans_par.ids @ids_block_param ; - instrs = res_trans_par.instrs@instr_block_param@[stmt_call]; - exps =[] - } in - let res_trans_to_parent = ( - PriorityNode.compute_results_to_parent trans_state_pri sil_loc nname si res_trans_tmp) in - (match ret_id with - | [] -> { res_trans_to_parent with exps = [] } - | [ret_id'] -> { res_trans_to_parent with exps = [(Sil.Var ret_id', method_type)] } - | _ -> assert false) (* by construction of red_id, we cannot be in this case *) + objCMessageExpr_deal_with_static_self trans_state_param stmt_list obj_c_message_expr_info in + match objCMessageExpr_trans_special_cases trans_state si obj_c_message_expr_info stmt_list + expr_info method_type trans_state_pri sil_loc res_trans_par.exps with + | Some res -> res + | None -> + let procname = Cfg.Procdesc.get_proc_name context.CContext.procdesc 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 + Cg.add_edge context.CContext.cg procname callee_name; + let call_flags = { + Sil.cf_virtual = is_virtual; + Sil.cf_noreturn = false; + Sil.cf_is_objc_block = false; } in + let param_exps, instr_block_param, ids_block_param = + extract_block_from_tuple procname res_trans_par.exps sil_loc in + let stmt_call = + Sil.Call (ret_id, (Sil.Const (Sil.Cfun callee_name)), param_exps, sil_loc, call_flags) in + let selector = obj_c_message_expr_info.Clang_ast_t.omei_selector in + let nname = "Message Call: "^selector in + let res_trans_tmp = { + res_trans_par with + ids = ret_id @ res_trans_par.ids @ids_block_param ; + instrs = res_trans_par.instrs @ instr_block_param @ [stmt_call]; + exps = [] + } in + let res_trans_to_parent = ( + PriorityNode.compute_results_to_parent trans_state_pri sil_loc nname si res_trans_tmp) in + match ret_id with + | [] -> { res_trans_to_parent with exps = [] } + | [ret_id'] -> { res_trans_to_parent with exps = [(Sil.Var ret_id', method_type)] } + | _ -> assert false (* by construction of red_id, we cannot be in this case *) and dispatch_function_trans trans_state stmt_info stmt_list ei n = Printing.log_out "\n Call to a dispatch function treated as special case...\n"; @@ -1816,16 +1857,16 @@ struct and objCBoxedExpr_trans trans_state info sel stmt_info stmts = let typ = CTypes_decl.class_from_pointer_type trans_state.context.CContext.tenv info.Clang_ast_t.ei_type_ptr in - let obj_c_message_expr_info = Ast_expressions.make_obj_c_message_expr_info_class sel typ in + let obj_c_message_expr_info = Ast_expressions.make_obj_c_message_expr_info_class sel typ None in let message_stmt = Clang_ast_t.ObjCMessageExpr (stmt_info, stmts, info, obj_c_message_expr_info) in instruction trans_state message_stmt and objCArrayLiteral_trans trans_state info stmt_info stmts = let typ = CTypes_decl.class_from_pointer_type trans_state.context.CContext.tenv info.Clang_ast_t.ei_type_ptr in - let obj_c_message_expr_info = - Ast_expressions.make_obj_c_message_expr_info_class CFrontend_config.array_with_objects_count_m typ in + let meth = CFrontend_config.array_with_objects_count_m in + let obj_c_mes_expr_info = Ast_expressions.make_obj_c_message_expr_info_class meth typ None in let stmts = stmts @ [Ast_expressions.create_nil stmt_info] in - let message_stmt = Clang_ast_t.ObjCMessageExpr (stmt_info, stmts, info, obj_c_message_expr_info) in + let message_stmt = Clang_ast_t.ObjCMessageExpr (stmt_info, stmts, info, obj_c_mes_expr_info) in instruction trans_state message_stmt and objCDictionaryLiteral_trans trans_state info stmt_info stmts = @@ -1833,7 +1874,7 @@ struct let dictionary_literal_pname = SymExec.ModelBuiltins.__objc_dictionary_literal in let dictionary_literal_s = Procname.c_get_method dictionary_literal_pname in let obj_c_message_expr_info = - Ast_expressions.make_obj_c_message_expr_info_class dictionary_literal_s typ in + Ast_expressions.make_obj_c_message_expr_info_class dictionary_literal_s typ None in let stmts = General_utils.swap_elements_list stmts in let stmts = stmts @ [Ast_expressions.create_nil stmt_info] in let message_stmt = Clang_ast_t.ObjCMessageExpr (stmt_info, stmts, info, obj_c_message_expr_info) in @@ -1843,9 +1884,9 @@ struct let stmts = [Ast_expressions.create_implicit_cast_expr stmt_info stmts Ast_expressions.create_char_star_type `ArrayToPointerDecay] in let typ = CTypes_decl.class_from_pointer_type trans_state.context.CContext.tenv info.Clang_ast_t.ei_type_ptr in - let obj_c_message_expr_info = - Ast_expressions.make_obj_c_message_expr_info_class CFrontend_config.string_with_utf8_m typ in - let message_stmt = Clang_ast_t.ObjCMessageExpr (stmt_info, stmts, info, obj_c_message_expr_info) in + let meth = CFrontend_config.string_with_utf8_m in + let obj_c_mess_expr_info = Ast_expressions.make_obj_c_message_expr_info_class meth typ None in + let message_stmt = Clang_ast_t.ObjCMessageExpr (stmt_info, stmts, info, obj_c_mess_expr_info) in instruction trans_state message_stmt (** When objects are autoreleased, they get added a flag AUTORELEASE. All these objects will be diff --git a/infer/src/clang/cTrans_models.ml b/infer/src/clang/cTrans_models.ml index d94119828..ea1e9d036 100644 --- a/infer/src/clang/cTrans_models.ml +++ b/infer/src/clang/cTrans_models.ml @@ -127,7 +127,7 @@ let get_predefined_ms_method condition class_name method_name method_kind mk_pro | Some procname -> procname | None -> mk_procname class_name method_name method_kind in let ms = CMethod_signature.make_ms procname arguments return_type attributes - (Ast_expressions.dummy_source_range ()) false false lang in + (Ast_expressions.dummy_source_range ()) false false lang None in Some ms else None diff --git a/infer/src/clang/cTrans_utils.ml b/infer/src/clang/cTrans_utils.ml index 86e78617e..d69465c5e 100644 --- a/infer/src/clang/cTrans_utils.ml +++ b/infer/src/clang/cTrans_utils.ml @@ -317,8 +317,13 @@ let objc_new_trans trans_state loc stmt_info cls_name function_type = PriorityNode.compute_results_to_parent trans_state loc "Call objC new" stmt_info res_trans_tmp in { res_trans with exps = [(Sil.Var init_ret_id, alloc_ret_type)]} -let new_or_alloc_trans trans_state loc stmt_info class_name selector = - let function_type = CTypes_decl.type_name_to_sil_type trans_state.context.CContext.tenv class_name in +let new_or_alloc_trans trans_state loc stmt_info type_ptr class_name_opt selector = + let tenv = trans_state.context.CContext.tenv in + let function_type = CTypes_decl.type_ptr_to_sil_type tenv type_ptr in + let class_name = + match class_name_opt with + | Some class_name -> class_name + | None -> CTypes.classname_of_type function_type in if selector = CFrontend_config.alloc then alloc_trans trans_state loc stmt_info function_type true else if selector = CFrontend_config.new_str then diff --git a/infer/src/clang/cTrans_utils.mli b/infer/src/clang/cTrans_utils.mli index a04986f18..2019ca3a4 100644 --- a/infer/src/clang/cTrans_utils.mli +++ b/infer/src/clang/cTrans_utils.mli @@ -106,8 +106,8 @@ val builtin_trans : trans_state -> Location.t -> Clang_ast_t.stmt_info -> val alloc_trans : trans_state -> Location.t -> Clang_ast_t.stmt_info -> Sil.typ -> bool -> trans_result -val new_or_alloc_trans : - trans_state -> Location.t -> Clang_ast_t.stmt_info -> string -> string -> trans_result +val new_or_alloc_trans : trans_state -> Location.t -> Clang_ast_t.stmt_info -> + Clang_ast_t.type_ptr -> string option -> string -> trans_result val cpp_new_trans : trans_state -> Location.t -> Clang_ast_t.stmt_info -> Sil.typ -> trans_result diff --git a/infer/src/clang/objcCategory_decl.ml b/infer/src/clang/objcCategory_decl.ml index a9050443f..cb6d5cadf 100644 --- a/infer/src/clang/objcCategory_decl.ml +++ b/infer/src/clang/objcCategory_decl.ml @@ -49,6 +49,23 @@ let add_category_implementation type_ptr_to_sil_type tenv category_decl_info = let decl_ref_opt = category_decl_info.Clang_ast_t.odi_implementation in Ast_utils.add_type_from_decl_ref type_ptr_to_sil_type tenv decl_ref_opt false +let get_base_class_name_from_category decl = + let open Clang_ast_t in + let base_class_pointer_opt = + match decl with + | ObjCCategoryDecl (decl_info, name_info, decl_list, decl_context_info, cdi) -> + cdi.Clang_ast_t.odi_class_interface + | ObjCCategoryImplDecl (decl_info, name_info, decl_list, decl_context_info, cii) -> + cii.Clang_ast_t.ocidi_class_interface + | _ -> None in + match base_class_pointer_opt with + | Some decl_ref -> + (match Ast_utils.get_decl decl_ref.Clang_ast_t.dr_decl_pointer with + | Some ObjCInterfaceDecl (decl_info, name_info, decl_list, _, ocidi) -> + Some (Ast_utils.get_qualified_name name_info) + | _ -> None) + | None -> None + (* Add potential extra fields defined only in the category *) (* to the corresponding class. Update the tenv accordingly.*) let process_category type_ptr_to_sil_type tenv curr_class decl_info decl_list = diff --git a/infer/src/clang/objcCategory_decl.mli b/infer/src/clang/objcCategory_decl.mli index a79118183..d0280e99d 100644 --- a/infer/src/clang/objcCategory_decl.mli +++ b/infer/src/clang/objcCategory_decl.mli @@ -23,3 +23,5 @@ val get_curr_class_from_category_decl : string -> Clang_ast_t.obj_c_category_dec val get_curr_class_from_category_impl : string -> Clang_ast_t.obj_c_category_impl_decl_info -> CContext.curr_class + +val get_base_class_name_from_category : Clang_ast_t.decl -> string option diff --git a/infer/src/clang/objcProtocol_decl.ml b/infer/src/clang/objcProtocol_decl.ml index f510ee991..d59502753 100644 --- a/infer/src/clang/objcProtocol_decl.ml +++ b/infer/src/clang/objcProtocol_decl.ml @@ -38,3 +38,9 @@ let protocol_decl type_ptr_to_sil_type tenv decl = add_protocol_super type_ptr_to_sil_type tenv obj_c_protocol_decl_info; Sil.Tvar protocol_name | _ -> assert false + +let is_protocol decl = + let open Clang_ast_t in + match decl with + | ObjCProtocolDecl(decl_info, name_info, decl_list, _, obj_c_protocol_decl_info) -> true + | _ -> false diff --git a/infer/src/clang/objcProtocol_decl.mli b/infer/src/clang/objcProtocol_decl.mli index 58614c2da..06c6725bc 100644 --- a/infer/src/clang/objcProtocol_decl.mli +++ b/infer/src/clang/objcProtocol_decl.mli @@ -13,3 +13,5 @@ open CFrontend_utils val protocol_decl : Ast_utils.type_ptr_to_sil_type -> Sil.tenv -> Clang_ast_t.decl -> Sil.typ + +val is_protocol : Clang_ast_t.decl -> bool diff --git a/infer/tests/codetoanalyze/objc/errors/category_procdesc/main.dot b/infer/tests/codetoanalyze/objc/errors/category_procdesc/main.dot index 585a80d2c..86f67bc7a 100644 --- a/infer/tests/codetoanalyze/objc/errors/category_procdesc/main.dot +++ b/infer/tests/codetoanalyze/objc/errors/category_procdesc/main.dot @@ -1,5 +1,5 @@ digraph iCFG { -6 [label="6: DeclStmt \n n$4=_fun___objc_alloc_no_fail(sizeof(class EOCPerson ):unsigned long ) [line 14]\n n$2=_fun_EOCPerson_init(n$4:class EOCPerson *) virtual [line 14]\n *&person:class EOCPerson *=n$2 [line 14]\n REMOVE_TEMPS(n$2,n$4); [line 14]\n " shape="box"] +6 [label="6: DeclStmt \n n$4=_fun___objc_alloc_no_fail(sizeof(class EOCPerson ):unsigned long ) [line 14]\n n$2=_fun_NSObject_init(n$4:class EOCPerson *) virtual [line 14]\n *&person:class EOCPerson *=n$2 [line 14]\n REMOVE_TEMPS(n$2,n$4); [line 14]\n " shape="box"] 6 -> 5 ; diff --git a/infer/tests/codetoanalyze/objc/errors/field_superclass/SuperExample.dot b/infer/tests/codetoanalyze/objc/errors/field_superclass/SuperExample.dot index 6e193bd1d..2e8883f7e 100644 --- a/infer/tests/codetoanalyze/objc/errors/field_superclass/SuperExample.dot +++ b/infer/tests/codetoanalyze/objc/errors/field_superclass/SuperExample.dot @@ -1,5 +1,5 @@ digraph iCFG { -12 [label="12: DeclStmt \n n$2=_fun___objc_alloc_no_fail(sizeof(class A ):unsigned long ) [line 45]\n n$3=_fun_A_init(n$2:class A *) virtual [line 45]\n *&a:struct objc_object *=n$3 [line 45]\n REMOVE_TEMPS(n$2,n$3); [line 45]\n NULLIFY(&a,false); [line 45]\n " shape="box"] +12 [label="12: DeclStmt \n n$2=_fun___objc_alloc_no_fail(sizeof(class A ):unsigned long ) [line 45]\n n$3=_fun_NSObject_init(n$2:class A *) virtual [line 45]\n *&a:struct objc_object *=n$3 [line 45]\n REMOVE_TEMPS(n$2,n$3); [line 45]\n NULLIFY(&a,false); [line 45]\n " shape="box"] 12 -> 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 b83ca241b..2dd59d833 100644 --- a/infer/tests/codetoanalyze/objc/errors/memory_leaks_benchmark/AutoreleaseExample.dot +++ b/infer/tests/codetoanalyze/objc/errors/memory_leaks_benchmark/AutoreleaseExample.dot @@ -1,5 +1,5 @@ digraph iCFG { -41 [label="41: DeclStmt \n n$7=_fun___objc_alloc_no_fail(sizeof(class NSAutoreleasePool ):unsigned long ) [line 60]\n n$5=_fun_NSAutoreleasePool_init(n$7:class NSAutoreleasePool *) [line 60]\n *&pool:class NSAutoreleasePool *=n$5 [line 60]\n REMOVE_TEMPS(n$5,n$7); [line 60]\n " shape="box"] +41 [label="41: DeclStmt \n n$7=_fun___objc_alloc_no_fail(sizeof(class NSAutoreleasePool ):unsigned long ) [line 60]\n n$5=_fun_NSObject_init(n$7:class NSAutoreleasePool *) virtual [line 60]\n *&pool:class NSAutoreleasePool *=n$5 [line 60]\n REMOVE_TEMPS(n$5,n$7); [line 60]\n " shape="box"] 41 -> 40 ; @@ -104,7 +104,7 @@ digraph iCFG { 15 -> 25 ; -14 [label="14: DeclStmt \n n$4=_fun___objc_alloc_no_fail(sizeof(class A ):unsigned long ) [line 30]\n n$2=_fun_A_init(n$4:class A *) virtual [line 30]\n *&s1:class A *=n$2 [line 30]\n REMOVE_TEMPS(n$2,n$4); [line 30]\n " shape="box"] +14 [label="14: DeclStmt \n n$4=_fun___objc_alloc_no_fail(sizeof(class A ):unsigned long ) [line 30]\n n$2=_fun_NSObject_init(n$4:class A *) virtual [line 30]\n *&s1:class A *=n$2 [line 30]\n REMOVE_TEMPS(n$2,n$4); [line 30]\n " shape="box"] 14 -> 13 ; diff --git a/infer/tests/codetoanalyze/objc/errors/memory_leaks_benchmark/RetainReleaseExample.dot b/infer/tests/codetoanalyze/objc/errors/memory_leaks_benchmark/RetainReleaseExample.dot index a825f2b61..be09771bb 100644 --- a/infer/tests/codetoanalyze/objc/errors/memory_leaks_benchmark/RetainReleaseExample.dot +++ b/infer/tests/codetoanalyze/objc/errors/memory_leaks_benchmark/RetainReleaseExample.dot @@ -1,5 +1,5 @@ digraph iCFG { -5 [label="5: DeclStmt \n n$5=_fun___objc_alloc_no_fail(sizeof(class A ):unsigned long ) [line 21]\n n$3=_fun_A_init(n$5:class A *) virtual [line 21]\n *&a:class A *=n$3 [line 21]\n REMOVE_TEMPS(n$3,n$5); [line 21]\n " shape="box"] +5 [label="5: DeclStmt \n n$5=_fun___objc_alloc_no_fail(sizeof(class A ):unsigned long ) [line 21]\n n$3=_fun_NSObject_init(n$5:class A *) virtual [line 21]\n *&a:class A *=n$3 [line 21]\n REMOVE_TEMPS(n$3,n$5); [line 21]\n " shape="box"] 5 -> 4 ; diff --git a/infer/tests/codetoanalyze/objc/errors/memory_leaks_benchmark/RetainReleaseExample2.dot b/infer/tests/codetoanalyze/objc/errors/memory_leaks_benchmark/RetainReleaseExample2.dot index decb20624..6ae541cd3 100644 --- a/infer/tests/codetoanalyze/objc/errors/memory_leaks_benchmark/RetainReleaseExample2.dot +++ b/infer/tests/codetoanalyze/objc/errors/memory_leaks_benchmark/RetainReleaseExample2.dot @@ -23,7 +23,7 @@ digraph iCFG { 27 -> 30 ; 27 -> 31 ; -26 [label="26: DeclStmt \n n$5=_fun___objc_alloc_no_fail(sizeof(class A ):unsigned long ) [line 62]\n n$3=_fun_A_init(n$5:class A *) virtual [line 62]\n *&a:class A *=n$3 [line 62]\n REMOVE_TEMPS(n$3,n$5); [line 62]\n " shape="box"] +26 [label="26: DeclStmt \n n$5=_fun___objc_alloc_no_fail(sizeof(class A ):unsigned long ) [line 62]\n n$3=_fun_NSObject_init(n$5:class A *) virtual [line 62]\n *&a:class A *=n$3 [line 62]\n REMOVE_TEMPS(n$3,n$5); [line 62]\n " shape="box"] 26 -> 25 ; @@ -42,7 +42,7 @@ digraph iCFG { 22 -> 26 ; -21 [label="21: DeclStmt \n n$3=_fun___objc_alloc_no_fail(sizeof(class A ):unsigned long ) [line 55]\n n$1=_fun_A_init(n$3:class A *) virtual [line 55]\n *&a:class A *=n$1 [line 55]\n REMOVE_TEMPS(n$1,n$3); [line 55]\n " shape="box"] +21 [label="21: DeclStmt \n n$3=_fun___objc_alloc_no_fail(sizeof(class A ):unsigned long ) [line 55]\n n$1=_fun_NSObject_init(n$3:class A *) virtual [line 55]\n *&a:class A *=n$1 [line 55]\n REMOVE_TEMPS(n$1,n$3); [line 55]\n " shape="box"] 21 -> 20 ; @@ -98,7 +98,7 @@ digraph iCFG { 7 -> 10 ; -6 [label="6: DeclStmt \n n$6=_fun___objc_alloc_no_fail(sizeof(class A ):unsigned long ) [line 26]\n n$4=_fun_A_init(n$6:class A *) virtual [line 26]\n *&a:class A *=n$4 [line 26]\n REMOVE_TEMPS(n$4,n$6); [line 26]\n " shape="box"] +6 [label="6: DeclStmt \n n$6=_fun___objc_alloc_no_fail(sizeof(class A ):unsigned long ) [line 26]\n n$4=_fun_NSObject_init(n$6:class A *) virtual [line 26]\n *&a:class A *=n$4 [line 26]\n REMOVE_TEMPS(n$4,n$6); [line 26]\n " shape="box"] 6 -> 5 ; diff --git a/infer/tests/codetoanalyze/objc/errors/memory_leaks_benchmark/arc_methods.dot b/infer/tests/codetoanalyze/objc/errors/memory_leaks_benchmark/arc_methods.dot index a202b47ca..dd2e58bca 100644 --- a/infer/tests/codetoanalyze/objc/errors/memory_leaks_benchmark/arc_methods.dot +++ b/infer/tests/codetoanalyze/objc/errors/memory_leaks_benchmark/arc_methods.dot @@ -26,7 +26,7 @@ digraph iCFG { 9 -> 15 ; -8 [label="8: DeclStmt \n n$8=_fun___objc_alloc_no_fail(sizeof(class A ):unsigned long ) [line 28]\n n$6=_fun_A_init(n$8:class A *) virtual [line 28]\n *&a:class A *=n$6 [line 28]\n REMOVE_TEMPS(n$6,n$8); [line 28]\n " shape="box"] +8 [label="8: DeclStmt \n n$8=_fun___objc_alloc_no_fail(sizeof(class A ):unsigned long ) [line 28]\n n$6=_fun_NSObject_init(n$8:class A *) virtual [line 28]\n *&a:class A *=n$6 [line 28]\n REMOVE_TEMPS(n$6,n$8); [line 28]\n " shape="box"] 8 -> 7 ; @@ -41,7 +41,7 @@ digraph iCFG { 5 -> 8 ; -4 [label="4: DeclStmt \n n$3=_fun___objc_alloc_no_fail(sizeof(class A ):unsigned long ) [line 23]\n n$1=_fun_A_init(n$3:class A *) virtual [line 23]\n *&a:class A *=n$1 [line 23]\n REMOVE_TEMPS(n$1,n$3); [line 23]\n " shape="box"] +4 [label="4: DeclStmt \n n$3=_fun___objc_alloc_no_fail(sizeof(class A ):unsigned long ) [line 23]\n n$1=_fun_NSObject_init(n$3:class A *) virtual [line 23]\n *&a:class A *=n$1 [line 23]\n REMOVE_TEMPS(n$1,n$3); [line 23]\n " shape="box"] 4 -> 3 ; 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 f1497991c..3e6b485e7 100644 --- a/infer/tests/codetoanalyze/objc/errors/npe/Nonnull_attribute_example.dot +++ b/infer/tests/codetoanalyze/objc/errors/npe/Nonnull_attribute_example.dot @@ -63,7 +63,7 @@ digraph iCFG { 4 -> 9 ; -3 [label="3: Return Stmt \n n$1=_fun___objc_alloc_no_fail(sizeof(class A ):unsigned long ) [line 25]\n n$2=_fun_A_init(n$1:class A *) virtual [line 25]\n *&return:class A *=n$2 [line 25]\n n$3=_fun___set_autorelease_attribute(n$2:class A *) [line 25]\n REMOVE_TEMPS(n$1,n$2,n$3); [line 25]\n APPLY_ABSTRACTION; [line 25]\n " shape="box"] +3 [label="3: Return Stmt \n n$1=_fun___objc_alloc_no_fail(sizeof(class A ):unsigned long ) [line 25]\n n$2=_fun_NSObject_init(n$1:class A *) virtual [line 25]\n *&return:class A *=n$2 [line 25]\n n$3=_fun___set_autorelease_attribute(n$2:class A *) [line 25]\n REMOVE_TEMPS(n$1,n$2,n$3); [line 25]\n APPLY_ABSTRACTION; [line 25]\n " shape="box"] 3 -> 2 ; diff --git a/infer/tests/codetoanalyze/objc/frontend/block/dispatch_examples.dot b/infer/tests/codetoanalyze/objc/frontend/block/dispatch_examples.dot index 05daa1d69..0b4110bda 100644 --- a/infer/tests/codetoanalyze/objc/frontend/block/dispatch_examples.dot +++ b/infer/tests/codetoanalyze/objc/frontend/block/dispatch_examples.dot @@ -3,7 +3,7 @@ digraph iCFG { 60 -> 55 ; -59 [label="59: BinaryOperatorStmt: Assign \n n$57=_fun___objc_alloc_no_fail(sizeof(class A ):unsigned long ) [line 71]\n n$55=_fun_A_init(n$57:class A *) virtual [line 71]\n *&#GB$A_dispatch_barrier_example_a:class A *=n$55 [line 71]\n REMOVE_TEMPS(n$55,n$57); [line 71]\n " shape="box"] +59 [label="59: BinaryOperatorStmt: Assign \n n$57=_fun___objc_alloc_no_fail(sizeof(class A ):unsigned long ) [line 71]\n n$55=_fun_NSObject_init(n$57:class A *) virtual [line 71]\n *&#GB$A_dispatch_barrier_example_a:class A *=n$55 [line 71]\n REMOVE_TEMPS(n$55,n$57); [line 71]\n " shape="box"] 59 -> 58 ; @@ -41,7 +41,7 @@ digraph iCFG { 50 -> 45 ; -49 [label="49: BinaryOperatorStmt: Assign \n n$47=_fun___objc_alloc_no_fail(sizeof(class A ):unsigned long ) [line 62]\n n$45=_fun_A_init(n$47:class A *) virtual [line 62]\n *&#GB$A_dispatch_group_notify_example_a:class A *=n$45 [line 62]\n REMOVE_TEMPS(n$45,n$47); [line 62]\n " shape="box"] +49 [label="49: BinaryOperatorStmt: Assign \n n$47=_fun___objc_alloc_no_fail(sizeof(class A ):unsigned long ) [line 62]\n n$45=_fun_NSObject_init(n$47:class A *) virtual [line 62]\n *&#GB$A_dispatch_group_notify_example_a:class A *=n$45 [line 62]\n REMOVE_TEMPS(n$45,n$47); [line 62]\n " shape="box"] 49 -> 48 ; @@ -79,7 +79,7 @@ digraph iCFG { 40 -> 35 ; -39 [label="39: BinaryOperatorStmt: Assign \n n$37=_fun___objc_alloc_no_fail(sizeof(class A ):unsigned long ) [line 53]\n n$35=_fun_A_init(n$37:class A *) virtual [line 53]\n *&#GB$A_dispatch_group_example_a:class A *=n$35 [line 53]\n REMOVE_TEMPS(n$35,n$37); [line 53]\n " shape="box"] +39 [label="39: BinaryOperatorStmt: Assign \n n$37=_fun___objc_alloc_no_fail(sizeof(class A ):unsigned long ) [line 53]\n n$35=_fun_NSObject_init(n$37:class A *) virtual [line 53]\n *&#GB$A_dispatch_group_example_a:class A *=n$35 [line 53]\n REMOVE_TEMPS(n$35,n$37); [line 53]\n " shape="box"] 39 -> 38 ; @@ -117,7 +117,7 @@ digraph iCFG { 30 -> 25 ; -29 [label="29: BinaryOperatorStmt: Assign \n n$27=_fun___objc_alloc_no_fail(sizeof(class A ):unsigned long ) [line 44]\n n$25=_fun_A_init(n$27:class A *) virtual [line 44]\n *&#GB$A_dispatch_after_example_a:class A *=n$25 [line 44]\n REMOVE_TEMPS(n$25,n$27); [line 44]\n " shape="box"] +29 [label="29: BinaryOperatorStmt: Assign \n n$27=_fun___objc_alloc_no_fail(sizeof(class A ):unsigned long ) [line 44]\n n$25=_fun_NSObject_init(n$27:class A *) virtual [line 44]\n *&#GB$A_dispatch_after_example_a:class A *=n$25 [line 44]\n REMOVE_TEMPS(n$25,n$27); [line 44]\n " shape="box"] 29 -> 28 ; @@ -155,7 +155,7 @@ digraph iCFG { 20 -> 15 ; -19 [label="19: BinaryOperatorStmt: Assign \n n$17=_fun___objc_alloc_no_fail(sizeof(class A ):unsigned long ) [line 34]\n n$15=_fun_A_init(n$17:class A *) virtual [line 34]\n *&#GB$A_dispatch_async_example_a:class A *=n$15 [line 34]\n REMOVE_TEMPS(n$15,n$17); [line 34]\n " shape="box"] +19 [label="19: BinaryOperatorStmt: Assign \n n$17=_fun___objc_alloc_no_fail(sizeof(class A ):unsigned long ) [line 34]\n n$15=_fun_NSObject_init(n$17:class A *) virtual [line 34]\n *&#GB$A_dispatch_async_example_a:class A *=n$15 [line 34]\n REMOVE_TEMPS(n$15,n$17); [line 34]\n " shape="box"] 19 -> 18 ; @@ -193,7 +193,7 @@ digraph iCFG { 10 -> 5 ; -9 [label="9: BinaryOperatorStmt: Assign \n n$7=_fun___objc_alloc_no_fail(sizeof(class A ):unsigned long ) [line 25]\n n$5=_fun_A_init(n$7:class A *) virtual [line 25]\n *&#GB$A_dispatch_once_example_a:class A *=n$5 [line 25]\n REMOVE_TEMPS(n$5,n$7); [line 25]\n " shape="box"] +9 [label="9: BinaryOperatorStmt: Assign \n n$7=_fun___objc_alloc_no_fail(sizeof(class A ):unsigned long ) [line 25]\n n$5=_fun_NSObject_init(n$7:class A *) virtual [line 25]\n *&#GB$A_dispatch_once_example_a:class A *=n$5 [line 25]\n REMOVE_TEMPS(n$5,n$7); [line 25]\n " shape="box"] 9 -> 8 ; diff --git a/infer/tests/codetoanalyze/objc/frontend/property/PropertyAttributes.dot b/infer/tests/codetoanalyze/objc/frontend/property/PropertyAttributes.dot index 3302eb983..4068248fa 100644 --- a/infer/tests/codetoanalyze/objc/frontend/property/PropertyAttributes.dot +++ b/infer/tests/codetoanalyze/objc/frontend/property/PropertyAttributes.dot @@ -1,5 +1,5 @@ digraph iCFG { -39 [label="39: DeclStmt \n n$7=_fun___objc_alloc_no_fail(sizeof(class A ):unsigned long ) [line 39]\n n$5=_fun_A_init(n$7:class A *) virtual [line 39]\n *&a:class A *=n$5 [line 39]\n REMOVE_TEMPS(n$5,n$7); [line 39]\n " shape="box"] +39 [label="39: DeclStmt \n n$7=_fun___objc_alloc_no_fail(sizeof(class A ):unsigned long ) [line 39]\n n$5=_fun_NSObject_init(n$7:class A *) virtual [line 39]\n *&a:class A *=n$5 [line 39]\n REMOVE_TEMPS(n$5,n$7); [line 39]\n " shape="box"] 39 -> 38 ; @@ -96,7 +96,7 @@ digraph iCFG { 11 -> 13 ; -10 [label="10: DeclStmt \n n$13=_fun___objc_alloc_no_fail(sizeof(class A ):unsigned long ) [line 27]\n n$11=_fun_A_init(n$13:class A *) virtual [line 27]\n *&other:class A *=n$11 [line 27]\n REMOVE_TEMPS(n$11,n$13); [line 27]\n " shape="box"] +10 [label="10: DeclStmt \n n$13=_fun___objc_alloc_no_fail(sizeof(class A ):unsigned long ) [line 27]\n n$11=_fun_NSObject_init(n$13:class A *) virtual [line 27]\n *&other:class A *=n$11 [line 27]\n REMOVE_TEMPS(n$11,n$13); [line 27]\n " shape="box"] 10 -> 5 ; diff --git a/infer/tests/codetoanalyze/objc/frontend/property/main_car.dot b/infer/tests/codetoanalyze/objc/frontend/property/main_car.dot index 178512e4a..39b046b59 100644 --- a/infer/tests/codetoanalyze/objc/frontend/property/main_car.dot +++ b/infer/tests/codetoanalyze/objc/frontend/property/main_car.dot @@ -1,5 +1,5 @@ digraph iCFG { -6 [label="6: DeclStmt \n n$6=_fun___objc_alloc_no_fail(sizeof(class Car ):unsigned long ) [line 13]\n n$4=_fun_Car_init(n$6:class Car *) virtual [line 13]\n *&honda:class Car *=n$4 [line 13]\n REMOVE_TEMPS(n$4,n$6); [line 13]\n " shape="box"] +6 [label="6: DeclStmt \n n$6=_fun___objc_alloc_no_fail(sizeof(class Car ):unsigned long ) [line 13]\n n$4=_fun_NSObject_init(n$6:class Car *) virtual [line 13]\n *&honda:class Car *=n$4 [line 13]\n REMOVE_TEMPS(n$4,n$6); [line 13]\n " shape="box"] 6 -> 5 ; diff --git a/infer/tests/codetoanalyze/objc/frontend/self_static/Self.dot b/infer/tests/codetoanalyze/objc/frontend/self_static/Self.dot index c5218c66e..f7b555712 100644 --- a/infer/tests/codetoanalyze/objc/frontend/self_static/Self.dot +++ b/infer/tests/codetoanalyze/objc/frontend/self_static/Self.dot @@ -42,7 +42,7 @@ digraph iCFG { 41 -> 43 ; -40 [label="40: Message Call: init \n n$19=*&self:class A * [line 88]\n n$18=_fun_C_init(n$19:class A *) [line 88]\n REMOVE_TEMPS(n$18,n$19); [line 88]\n NULLIFY(&self,false); [line 88]\n APPLY_ABSTRACTION; [line 88]\n " shape="box"] +40 [label="40: Message Call: init \n n$19=*&self:class A * [line 88]\n n$18=_fun_NSObject_init(n$19:class A *) [line 88]\n REMOVE_TEMPS(n$18,n$19); [line 88]\n NULLIFY(&self,false); [line 88]\n APPLY_ABSTRACTION; [line 88]\n " shape="box"] 40 -> 39 ; @@ -75,7 +75,7 @@ digraph iCFG { 32 -> 34 ; -31 [label="31: DeclStmt \n n$12=_fun___objc_alloc_no_fail(sizeof(class B ):unsigned long ) [line 75]\n n$13=_fun_B_init(n$12:class B *) virtual [line 75]\n *&b:class B *=n$13 [line 75]\n REMOVE_TEMPS(n$12,n$13); [line 75]\n NULLIFY(&b,false); [line 75]\n " shape="box"] +31 [label="31: DeclStmt \n n$12=_fun___objc_alloc_no_fail(sizeof(class B ):unsigned long ) [line 75]\n n$13=_fun_NSObject_init(n$12:class B *) virtual [line 75]\n *&b:class B *=n$13 [line 75]\n REMOVE_TEMPS(n$12,n$13); [line 75]\n NULLIFY(&b,false); [line 75]\n " shape="box"] 31 -> 30 ; diff --git a/infer/tests/codetoanalyze/objc/frontend/subclass/main.dot b/infer/tests/codetoanalyze/objc/frontend/subclass/main.dot index 99f40ae69..fdd1dd286 100644 --- a/infer/tests/codetoanalyze/objc/frontend/subclass/main.dot +++ b/infer/tests/codetoanalyze/objc/frontend/subclass/main.dot @@ -1,5 +1,5 @@ digraph iCFG { -4 [label="4: DeclStmt \n n$2=_fun___objc_alloc_no_fail(sizeof(class A ):unsigned long ) [line 13]\n n$0=_fun_A_init(n$2:class A *) virtual [line 13]\n *&a:class A *=n$0 [line 13]\n REMOVE_TEMPS(n$0,n$2); [line 13]\n NULLIFY(&a,false); [line 13]\n " shape="box"] +4 [label="4: DeclStmt \n n$2=_fun___objc_alloc_no_fail(sizeof(class A ):unsigned long ) [line 13]\n n$0=_fun_NSObject_init(n$2:class A *) virtual [line 13]\n *&a:class A *=n$0 [line 13]\n REMOVE_TEMPS(n$0,n$2); [line 13]\n NULLIFY(&a,false); [line 13]\n " shape="box"] 4 -> 3 ; diff --git a/infer/tests/codetoanalyze/objc/frontend/vardecl/initlist.dot b/infer/tests/codetoanalyze/objc/frontend/vardecl/initlist.dot index 2c70dd106..278948d1f 100644 --- a/infer/tests/codetoanalyze/objc/frontend/vardecl/initlist.dot +++ b/infer/tests/codetoanalyze/objc/frontend/vardecl/initlist.dot @@ -7,7 +7,7 @@ digraph iCFG { 7 -> 6 ; -6 [label="6: InitListExp \n n$1=*&c1:class C * [line 24]\n n$0=_fun_C_init(n$1:class C *) virtual [line 24]\n n$2=*&c1:class C * [line 24]\n n$3=*&c2:class C * [line 24]\n *&a[0]:class C *=n$0 [line 24]\n _fun___objc_retain(n$2:class C *) [line 24]\n *&a[1]:class C *=n$2 [line 24]\n _fun___objc_retain(n$3:class C *) [line 24]\n *&a[2]:class C *=n$3 [line 24]\n REMOVE_TEMPS(n$0,n$1,n$2,n$3); [line 24]\n NULLIFY(&c1,false); [line 24]\n NULLIFY(&c2,false); [line 24]\n APPLY_ABSTRACTION; [line 24]\n " shape="box"] +6 [label="6: InitListExp \n n$1=*&c1:class C * [line 24]\n n$0=_fun_NSObject_init(n$1:class C *) virtual [line 24]\n n$2=*&c1:class C * [line 24]\n n$3=*&c2:class C * [line 24]\n *&a[0]:class C *=n$0 [line 24]\n _fun___objc_retain(n$2:class C *) [line 24]\n *&a[1]:class C *=n$2 [line 24]\n _fun___objc_retain(n$3:class C *) [line 24]\n *&a[2]:class C *=n$3 [line 24]\n REMOVE_TEMPS(n$0,n$1,n$2,n$3); [line 24]\n NULLIFY(&c1,false); [line 24]\n NULLIFY(&c2,false); [line 24]\n APPLY_ABSTRACTION; [line 24]\n " shape="box"] 6 -> 5 ;