diff --git a/infer/src/IR/Mangled.ml b/infer/src/IR/Mangled.ml index e8b8f92c9..ccf44a681 100644 --- a/infer/src/IR/Mangled.ml +++ b/infer/src/IR/Mangled.ml @@ -48,10 +48,14 @@ let rename ~f {plain; mangled} = {plain; mangled} -module Set = Caml.Set.Make (struct +module Set = PrettyPrintable.MakePPSet (struct type nonrec t = t [@@deriving compare] + + let pp = pp end) -module Map = Caml.Map.Make (struct +module Map = PrettyPrintable.MakePPMap (struct type nonrec t = t [@@deriving compare] + + let pp = pp end) diff --git a/infer/src/IR/Mangled.mli b/infer/src/IR/Mangled.mli index 994657d6a..374be78d7 100644 --- a/infer/src/IR/Mangled.mli +++ b/infer/src/IR/Mangled.mli @@ -43,7 +43,7 @@ val rename : f:(string -> string) -> t -> t (** Maps over both the plain and the mangled components. *) (** Set of Mangled. *) -module Set : Caml.Set.S with type elt = t +module Set : PrettyPrintable.PPSet with type elt = t (** Map with Mangled as key *) -module Map : Caml.Map.S with type key = t +module Map : PrettyPrintable.PPMap with type key = t diff --git a/infer/src/IR/ProcAttributes.ml b/infer/src/IR/ProcAttributes.ml index 627191d5a..07d604ea6 100644 --- a/infer/src/IR/ProcAttributes.ml +++ b/infer/src/IR/ProcAttributes.ml @@ -38,6 +38,11 @@ let pp_var_data fmt {name; typ; modify_in_block; is_declared_unused} = Mangled.pp name (Typ.pp_full Pp.text) typ modify_in_block is_declared_unused +type specialized_with_blocks_info = + { orig_proc: Procname.t + ; formals_to_procs_and_new_formals: (Procname.t * (Mangled.t * Typ.t) list) Mangled.Map.t } +[@@deriving compare] + type t = { access: PredSymb.access (** visibility access *) ; captured: (Mangled.t * Typ.t * Pvar.capture_mode) list @@ -58,6 +63,10 @@ type t = ; is_synthetic_method: bool (** the procedure is a synthetic method *) ; is_variadic: bool (** the procedure is variadic, only supported for Clang procedures *) ; sentinel_attr: (int * int) option (** __attribute__((sentinel(int, int))) *) + ; specialized_with_blocks_info: specialized_with_blocks_info option + (** the procedure is a clone specialized with calls to concrete closures, with link to the + original procedure, and a map that links the original formals to the elements of the + closure used to specialize the procedure. *) ; clang_method_kind: ClangMethodKind.t (** the kind of method the procedure is *) ; loc: Location.t (** location of this procedure in the source code *) ; translation_unit: SourceFile.t (** translation unit to which the procedure belongs *) @@ -102,6 +111,7 @@ let default translation_unit proc_name = ; passed_as_noescape_block_to= None ; is_no_return= false ; is_specialized= false + ; specialized_with_blocks_info= None ; is_synthetic_method= false ; is_variadic= false ; sentinel_attr= None @@ -120,6 +130,16 @@ let pp_parameters = Pp.semicolon_seq ~print_env:Pp.text_break (Pp.pair ~fst:Mangled.pp ~snd:(Typ.pp_full Pp.text)) +let pp_specialized_with_blocks_info fmt info = + let pp_new_formal fmt el = + F.fprintf fmt "%a:%a" Mangled.pp (fst el) (Typ.pp_full Pp.text) (snd el) + in + let pp_new_formals = Pp.semicolon_seq ~print_env:Pp.text_break pp_new_formal in + F.fprintf fmt "orig_procname=%a, formals_to_procs_and_new_formals=%a" Procname.pp info.orig_proc + (Mangled.Map.pp ~pp_value:(Pp.pair ~fst:Procname.pp ~snd:pp_new_formals)) + info.formals_to_procs_and_new_formals + + let pp_captured_var fmt (var, typ, mode) = F.fprintf fmt "(%a,@,%a,@,%s)" Mangled.pp var (Typ.pp_full Pp.text) typ (Pvar.string_of_capture_mode mode) @@ -141,6 +161,7 @@ let pp f ; passed_as_noescape_block_to ; is_no_return ; is_specialized + ; specialized_with_blocks_info ; is_synthetic_method ; is_variadic ; sentinel_attr @@ -188,6 +209,14 @@ let pp f passed_as_noescape_block_to ; pp_bool_default ~default:default.is_no_return "is_no_return" is_no_return f () ; pp_bool_default ~default:default.is_specialized "is_specialized" is_specialized f () ; + if + not + ([%compare.equal: specialized_with_blocks_info option] default.specialized_with_blocks_info + specialized_with_blocks_info) + then + F.fprintf f "; specialized_with_blocks_info %a@," + (Pp.option pp_specialized_with_blocks_info) + specialized_with_blocks_info ; pp_bool_default ~default:default.is_synthetic_method "is_synthetic_method" is_synthetic_method f () ; pp_bool_default ~default:default.is_variadic "is_variadic" is_variadic f () ; diff --git a/infer/src/IR/ProcAttributes.mli b/infer/src/IR/ProcAttributes.mli index 1118539a3..08eed4d6f 100644 --- a/infer/src/IR/ProcAttributes.mli +++ b/infer/src/IR/ProcAttributes.mli @@ -20,6 +20,11 @@ type var_data = ; is_constexpr: bool ; is_declared_unused: bool (** variable declared with attribute [unused] *) } +type specialized_with_blocks_info = + { orig_proc: Procname.t + ; formals_to_procs_and_new_formals: (Procname.t * (Mangled.t * Typ.t) list) Mangled.Map.t } +[@@deriving compare] + type t = { access: PredSymb.access (** visibility access *) ; captured: (Mangled.t * Typ.t * Pvar.capture_mode) list @@ -40,6 +45,10 @@ type t = ; is_synthetic_method: bool (** the procedure is a synthetic method *) ; is_variadic: bool (** the procedure is variadic, only supported for Clang procedures *) ; sentinel_attr: (int * int) option (** __attribute__((sentinel(int, int))) *) + ; specialized_with_blocks_info: specialized_with_blocks_info option + (** the procedure is a clone specialized with calls to concrete closures, with link to the + original procedure, and a map that links the original formals to the elements of the + closure used to specialize the procedure. *) ; clang_method_kind: ClangMethodKind.t (** the kind of method the procedure is *) ; loc: Location.t (** location of this procedure in the source code *) ; translation_unit: SourceFile.t (** source file where the procedure was captured *) diff --git a/infer/src/IR/Procname.ml b/infer/src/IR/Procname.ml index b64b18e62..5bf9f880d 100644 --- a/infer/src/IR/Procname.ml +++ b/infer/src/IR/Procname.ml @@ -553,6 +553,13 @@ let get_global_name_of_initializer = function None +let pp_with_block_parameters pp fmt base blocks = + pp fmt base ; + F.pp_print_string fmt "[" ; + Pp.seq ~sep:"^" F.pp_print_string fmt blocks ; + F.pp_print_string fmt "]" + + (** Very verbose representation of an existing Procname.t *) let rec pp_unique_id fmt = function | Java j -> @@ -566,9 +573,7 @@ let rec pp_unique_id fmt = function | WithBlockParameters (base, []) -> pp_unique_id fmt base | WithBlockParameters (base, (_ :: _ as blocks)) -> - pp_unique_id fmt base ; - F.pp_print_string fmt "_" ; - Pp.seq ~sep:"_" F.pp_print_string fmt blocks + pp_with_block_parameters pp_unique_id fmt base blocks | Linters_dummy_method -> F.pp_print_string fmt "Linters_dummy_method" @@ -588,9 +593,7 @@ let rec pp fmt = function | WithBlockParameters (base, []) -> pp fmt base | WithBlockParameters (base, (_ :: _ as blocks)) -> - pp fmt base ; - F.pp_print_string fmt "_" ; - Pp.seq ~sep:"_" F.pp_print_string fmt blocks + pp_with_block_parameters pp fmt base blocks | Linters_dummy_method -> pp_unique_id fmt Linters_dummy_method diff --git a/infer/src/IR/Pvar.ml b/infer/src/IR/Pvar.ml index 4a91b9ef8..e4bfab0d3 100644 --- a/infer/src/IR/Pvar.ml +++ b/infer/src/IR/Pvar.ml @@ -35,10 +35,13 @@ type pvar_kind = (** Names for program variables. *) type t = {pv_hash: int; pv_name: Mangled.t; pv_kind: pvar_kind} [@@deriving compare] -let get_name_of_local_with_procname var = +let build_formal_from_pvar var = match var.pv_kind with | Local_var pname -> - Mangled.from_string (F.asprintf "%s_%a" (Mangled.to_string var.pv_name) Procname.pp pname) + Mangled.from_string + (F.asprintf "%s[%a]" (Mangled.to_string var.pv_name) + (Procname.pp_simplified_string ~withclass:false) + pname) | _ -> var.pv_name diff --git a/infer/src/IR/Pvar.mli b/infer/src/IR/Pvar.mli index 0b943b609..537fc5a9d 100644 --- a/infer/src/IR/Pvar.mli +++ b/infer/src/IR/Pvar.mli @@ -161,9 +161,9 @@ val is_pod : t -> bool val get_initializer_pname : t -> Procname.t option (** Get the procname of the initializer function for the given global variable *) -val get_name_of_local_with_procname : t -> Mangled.t -(** [get_name_of_local_with_procname var] Return a name that is composed of the name of var and the - name of the procname in case of locals *) +val build_formal_from_pvar : t -> Mangled.t +(** [build_formal_from_pvar var] Return a name that is composed of the name of var (and the name of + the procname in case of locals) *) val materialized_cpp_temporary : string diff --git a/infer/src/IR/SpecializeProcdesc.ml b/infer/src/IR/SpecializeProcdesc.ml index 5d64bacdc..5ff38db44 100644 --- a/infer/src/IR/SpecializeProcdesc.ml +++ b/infer/src/IR/SpecializeProcdesc.ml @@ -307,7 +307,7 @@ let with_block_args callee_pdesc pname_with_block_args block_args = ~f:(fun (_, var, typ, _) -> (* Here we create fresh names for the new formals, based on the names of the captured variables annotated with the name of the caller method *) - (Pvar.get_name_of_local_with_procname var, typ) ) + (Pvar.build_formal_from_pvar var, typ) ) cl.captured_vars in Mangled.Map.add param_name (cl.name, formals_from_captured) subts diff --git a/infer/src/clang/CCallSpecializedWithClosures.ml b/infer/src/clang/CCallSpecializedWithClosures.ml new file mode 100644 index 000000000..1125aa79f --- /dev/null +++ b/infer/src/clang/CCallSpecializedWithClosures.ml @@ -0,0 +1,172 @@ +(* + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + *) + +open! IStd +module F = Format + +type formal_annot = {formal_type: Mangled.t * Typ.t; formal_annot: Annot.Item.t} +[@@deriving compare] + +type formal_actual = {formal: formal_annot; actual: Exp.t * Typ.t [@ignore]} [@@deriving compare] + +let pp_formal_annot fmt formal = + F.fprintf fmt "(formal_type=%a, formal_annot=%a)" + (Pp.pair ~fst:Mangled.pp ~snd:(Typ.pp Pp.text)) + formal.formal_type Annot.Item.pp formal.formal_annot + + +let pp_formal_actual fmt formal_actual = + F.fprintf fmt "(formal=%a, actual=%a)" pp_formal_annot formal_actual.formal + (Pp.pair ~fst:Exp.pp ~snd:(Typ.pp Pp.text)) + formal_actual.actual + + +module FormalsMap = PrettyPrintable.MakePPMap (struct + type t = formal_annot [@@deriving compare] + + let pp = pp_formal_annot +end) + +module FormalsActualsSet = PrettyPrintable.MakePPSet (struct + type t = formal_actual [@@deriving compare] + + let pp = pp_formal_actual +end) + +let formals_actuals_map formals annotations actual_params = + let rec formals_actuals_map_inner acc formals annotations actual_params = + match (formals, annotations, actual_params) with + | [], [], [] -> + Some acc + | fml :: fmls, an :: ans, act :: acts -> + let acc = FormalsMap.add {formal_type= fml; formal_annot= an} act acc in + formals_actuals_map_inner acc fmls ans acts + | _, _, _ -> + None + in + formals_actuals_map_inner FormalsMap.empty formals annotations actual_params + + +let formals_actuals_new_set map = + FormalsMap.fold + (fun formal actual set -> + match actual with + | Exp.Closure closure, _ -> + List.fold_left closure.Exp.captured_vars ~init:set ~f:(fun set (exp, var, typ, _) -> + let formal_annot = + {formal_type= (Pvar.build_formal_from_pvar var, typ); formal_annot= Annot.Item.empty} + in + let formal_actual = {formal= formal_annot; actual= (exp, typ)} in + FormalsActualsSet.add formal_actual set ) + | actual -> + FormalsActualsSet.add {formal; actual} set ) + map FormalsActualsSet.empty + + +let formals_annots_actuals_lists new_formals_actuals = + FormalsActualsSet.fold + (fun {formal; actual} (fs, ans, acts) -> + (formal.formal_type :: fs, formal.formal_annot :: ans, actual :: acts) ) + new_formals_actuals ([], [], []) + + +let has_closure actual_params = + List.exists actual_params ~f:(fun (exp, _) -> + match exp with Exp.Closure c -> Procname.is_objc_block c.name | _ -> false ) + + +let should_specialize actual_params call_flags = + let block_is_receiver actual_params = + Int.equal (List.length actual_params) 1 && call_flags.CallFlags.cf_virtual + in + has_closure actual_params && not (block_is_receiver actual_params) + + +(* name for the specialized method instantiated with closure arguments *) +let pname_with_closure_args callee_pname actual_params = + let block_name_args = + List.filter_map actual_params ~f:(function + | Exp.Closure cl, _ when Procname.is_objc_block cl.name -> + Some (Procname.block_name_of_procname cl.name) + | _ -> + None ) + in + Procname.with_block_parameters callee_pname block_name_args + + +let formals_closures_map map = + FormalsMap.fold + (fun formal actual new_map -> + match actual with + | Exp.Closure closure, _ -> + let captured_as_formals = + List.map + ~f:(fun (_, var, typ, _) -> (Pvar.build_formal_from_pvar var, typ)) + closure.captured_vars + in + Mangled.Map.add (fst formal.formal_type) (closure.name, captured_as_formals) new_map + | _ -> + new_map ) + map Mangled.Map.empty + + +let is_objc_setter proc_desc = + let attributes = Procdesc.get_attributes proc_desc in + match attributes.ProcAttributes.objc_accessor with Some (Objc_setter _) -> true | _ -> false + + +let is_initializer proc_desc = + let proc_name = Procdesc.get_proc_name proc_desc in + Procname.is_constructor proc_name + + +let replace_with_specialize_methods cfg _node instr = + match instr with + | Sil.Call (ret, Exp.Const (Const.Cfun callee_pname), actual_params, loc, flags) + when should_specialize actual_params flags -> ( + match Procname.Hash.find_opt cfg callee_pname with + (*TODO(T74127433): This specialization works well only when the we specialize methods that take a block + parameter and then run the block. It doesn't work well when the block is instead stored in + a field. This case will be left as future work, and we won't specialize common cases where this + happens such as setters or initializers. *) + | Some proc_desc when (not (is_objc_setter proc_desc)) && not (is_initializer proc_desc) -> ( + let callee_attributes = Procdesc.get_attributes proc_desc in + match + formals_actuals_map callee_attributes.formals callee_attributes.method_annotation.params + actual_params + with + | Some map -> + let set = formals_actuals_new_set map in + let new_formals, new_annots, new_actuals = formals_annots_actuals_lists set in + let annot = callee_attributes.method_annotation in + let specialized_pname = pname_with_closure_args callee_pname actual_params in + let new_attributes = + { callee_attributes with + specialized_with_blocks_info= + Some + { orig_proc= callee_pname + ; formals_to_procs_and_new_formals= formals_closures_map map } + ; is_defined= true + ; formals= new_formals + ; method_annotation= {annot with params= new_annots} + ; proc_name= specialized_pname } + in + Cfg.create_proc_desc cfg new_attributes |> ignore ; + Sil.Call (ret, Exp.Const (Const.Cfun specialized_pname), new_actuals, loc, flags) + | None -> + instr ) + | _ -> + instr ) + | _ -> + instr + + +let process cfg = + let process_pdesc _proc_name proc_desc = + Procdesc.replace_instrs proc_desc ~f:(replace_with_specialize_methods cfg) |> ignore + in + Procname.Hash.iter process_pdesc cfg diff --git a/infer/src/clang/CCallSpecializedWithClosures.mli b/infer/src/clang/CCallSpecializedWithClosures.mli new file mode 100644 index 000000000..3f8610f73 --- /dev/null +++ b/infer/src/clang/CCallSpecializedWithClosures.mli @@ -0,0 +1,10 @@ +(* + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + *) + +open! IStd + +val process : Cfg.t -> unit diff --git a/infer/src/clang/cFrontend.ml b/infer/src/clang/cFrontend.ml index fc1c97fee..3a8d36a4c 100644 --- a/infer/src/clang/cFrontend.ml +++ b/infer/src/clang/cFrontend.ml @@ -52,6 +52,7 @@ let do_source_file (translation_unit_context : CFrontend_config.translation_unit let cfg = compute_icfg translation_unit_context tenv ast in CAddImplicitDeallocImpl.process cfg tenv ; CAddImplicitGettersSetters.process cfg ; + CCallSpecializedWithClosures.process cfg ; L.(debug Capture Verbose) "@\n End building call/cfg graph for '%a'.@\n" SourceFile.pp source_file ; NullabilityPreanalysis.analysis cfg tenv ; SourceFiles.add source_file cfg (Tenv.FileLocal tenv) (Some integer_type_widths) ; diff --git a/infer/tests/codetoanalyze/objc/biabduction/Makefile b/infer/tests/codetoanalyze/objc/biabduction/Makefile index c3a29601a..237cd6989 100644 --- a/infer/tests/codetoanalyze/objc/biabduction/Makefile +++ b/infer/tests/codetoanalyze/objc/biabduction/Makefile @@ -104,6 +104,7 @@ SOURCES_ARC = \ npe/nullable.m \ property/ExplicitIvarName.m \ shared/block/dispatch_examples.m \ + specialized_methods_with_blocks/BlockAsReceiver.m \ subtyping/KindOfClassExample.m \ variadic_methods/premature_nil_termination.m \ diff --git a/infer/tests/codetoanalyze/objc/biabduction/specialized_methods_with_blocks/BlockAsReceiver.m b/infer/tests/codetoanalyze/objc/biabduction/specialized_methods_with_blocks/BlockAsReceiver.m new file mode 100644 index 000000000..63a83d288 --- /dev/null +++ b/infer/tests/codetoanalyze/objc/biabduction/specialized_methods_with_blocks/BlockAsReceiver.m @@ -0,0 +1,31 @@ +/* + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ +#include + +@interface BlockAsReceiver : NSObject + +@end + +@implementation BlockAsReceiver + +static bool _isAppStartingUp() { return true; } + +/* This program would crash if we would specialize NSObject.copy +here because it would become a virtual call without receiver, +as the receiver is the block parameter. Blocks as also objects! */ +static void setupTimerOk() { + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + dispatch_block_t _timerBlock = [^{ + if (_isAppStartingUp()) { + return; + } + } copy]; + }); +} + +@end diff --git a/infer/tests/codetoanalyze/objc/frontend/block/retain_cycle.m.dot b/infer/tests/codetoanalyze/objc/frontend/block/retain_cycle.m.dot index 5eee73bb4..16f2ca51b 100644 --- a/infer/tests/codetoanalyze/objc/frontend/block/retain_cycle.m.dot +++ b/infer/tests/codetoanalyze/objc/frontend/block/retain_cycle.m.dot @@ -52,7 +52,7 @@ digraph cfg { "capture#A#instance.d411336575e4bf632a1828f5f5979726_2" [label="2: Exit A.capture \n " color=yellow style=filled] -"capture#A#instance.d411336575e4bf632a1828f5f5979726_3" [label="3: Message Call: sHandler: \n n$3=*&self:A* [line 45, column 4]\n n$4=*n$3._b:B* [line 45, column 4]\n n$0=*&self:A* [line 45, column 16]\n n$5=_fun_B.sHandler:(n$4:B*,(_fun_objc_blockA.capture_1,([by ref]n$0 &self:A*)):_fn_(*)) block_params virtual [line 45, column 3]\n " shape="box"] +"capture#A#instance.d411336575e4bf632a1828f5f5979726_3" [label="3: Message Call: sHandler: \n n$3=*&self:A* [line 45, column 4]\n n$4=*n$3._b:B* [line 45, column 4]\n n$0=*&self:A* [line 45, column 16]\n n$5=_fun_B.sHandler:[objc_blockA.capture_1](n$0:A*,n$4:B*) block_params virtual [line 45, column 3]\n " shape="box"] "capture#A#instance.d411336575e4bf632a1828f5f5979726_3" -> "capture#A#instance.d411336575e4bf632a1828f5f5979726_2" ; diff --git a/infer/tests/codetoanalyze/objc/frontend/block/specialized_method_with_block_params.m b/infer/tests/codetoanalyze/objc/frontend/block/specialized_method_with_block_params.m new file mode 100644 index 000000000..36b7a7e8a --- /dev/null +++ b/infer/tests/codetoanalyze/objc/frontend/block/specialized_method_with_block_params.m @@ -0,0 +1,50 @@ +/* + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ +@interface A + +typedef void (^MyBlock)(int x); + +@end + +int p() { return 0; } + +foo(_Nullable MyBlock my_block1, _Nullable MyBlock my_block2, _Nonnull A* a) { + my_block1(22); +} + +@implementation A { + + int x; +} + +- (int)bar:(A*)a { + int x = 0; + foo( + ^(int i) { + self->x = x; + }, + ^(int i) { + self->x = i; + }, + a); + int y = p(); + return self->x; +} + +- (int)bar2 { + foo( + ^(int i) { + self->x = 5; + }, + ^(int i) { + self->x = 5; + }, + self); + return self->x; +} + +@end diff --git a/infer/tests/codetoanalyze/objc/frontend/block/specialized_method_with_block_params.m.dot b/infer/tests/codetoanalyze/objc/frontend/block/specialized_method_with_block_params.m.dot new file mode 100644 index 000000000..01678eb7c --- /dev/null +++ b/infer/tests/codetoanalyze/objc/frontend/block/specialized_method_with_block_params.m.dot @@ -0,0 +1,118 @@ +/* @generated */ +digraph cfg { +"foo.acbd18db4cc2f85cedef654fccc4a4d8_1" [label="1: Start foo\nFormals: my_block1:_fn_(*) my_block2:_fn_(*) a:A*\nLocals: \nAnnotation: <> foo(<_Nullable> <_Nullable> <_Nonnull>) \n " color=yellow style=filled] + + + "foo.acbd18db4cc2f85cedef654fccc4a4d8_1" -> "foo.acbd18db4cc2f85cedef654fccc4a4d8_3" ; +"foo.acbd18db4cc2f85cedef654fccc4a4d8_2" [label="2: Exit foo \n " color=yellow style=filled] + + +"foo.acbd18db4cc2f85cedef654fccc4a4d8_3" [label="3: Call n$0 \n n$0=*&my_block1:_fn_(*) [line 16, column 3]\n n$1=n$0(22:int) objc_block [line 16, column 3]\n " shape="box"] + + + "foo.acbd18db4cc2f85cedef654fccc4a4d8_3" -> "foo.acbd18db4cc2f85cedef654fccc4a4d8_2" ; +"p.83878c91171338902e0fe0fb97a8c47a_1" [label="1: Start p\nFormals: \nLocals: \n " color=yellow style=filled] + + + "p.83878c91171338902e0fe0fb97a8c47a_1" -> "p.83878c91171338902e0fe0fb97a8c47a_3" ; +"p.83878c91171338902e0fe0fb97a8c47a_2" [label="2: Exit p \n " color=yellow style=filled] + + +"p.83878c91171338902e0fe0fb97a8c47a_3" [label="3: Return Stmt \n *&return:int=0 [line 13, column 11]\n " shape="box"] + + + "p.83878c91171338902e0fe0fb97a8c47a_3" -> "p.83878c91171338902e0fe0fb97a8c47a_2" ; +"objc_blockA.bar2_3(class A).d749ef9e4d7f0a45237d8fe9e40fc593_1" [label="1: Start objc_blockA.bar2_3\nFormals: self:A* i:int\nLocals: \nCaptured: [by ref]self:A* \n " color=yellow style=filled] + + + "objc_blockA.bar2_3(class A).d749ef9e4d7f0a45237d8fe9e40fc593_1" -> "objc_blockA.bar2_3(class A).d749ef9e4d7f0a45237d8fe9e40fc593_3" ; +"objc_blockA.bar2_3(class A).d749ef9e4d7f0a45237d8fe9e40fc593_2" [label="2: Exit objc_blockA.bar2_3 \n " color=yellow style=filled] + + +"objc_blockA.bar2_3(class A).d749ef9e4d7f0a45237d8fe9e40fc593_3" [label="3: BinaryOperatorStmt: Assign \n n$15=*&self:A* [line 41, column 9]\n *n$15.x:int=5 [line 41, column 9]\n " shape="box"] + + + "objc_blockA.bar2_3(class A).d749ef9e4d7f0a45237d8fe9e40fc593_3" -> "objc_blockA.bar2_3(class A).d749ef9e4d7f0a45237d8fe9e40fc593_2" ; +"objc_blockA.bar2_4(class A).a4f29e420077ca6ce7e44776941a7430_1" [label="1: Start objc_blockA.bar2_4\nFormals: self:A* i:int\nLocals: \nCaptured: [by ref]self:A* \n " color=yellow style=filled] + + + "objc_blockA.bar2_4(class A).a4f29e420077ca6ce7e44776941a7430_1" -> "objc_blockA.bar2_4(class A).a4f29e420077ca6ce7e44776941a7430_3" ; +"objc_blockA.bar2_4(class A).a4f29e420077ca6ce7e44776941a7430_2" [label="2: Exit objc_blockA.bar2_4 \n " color=yellow style=filled] + + +"objc_blockA.bar2_4(class A).a4f29e420077ca6ce7e44776941a7430_3" [label="3: BinaryOperatorStmt: Assign \n n$17=*&self:A* [line 44, column 9]\n *n$17.x:int=5 [line 44, column 9]\n " shape="box"] + + + "objc_blockA.bar2_4(class A).a4f29e420077ca6ce7e44776941a7430_3" -> "objc_blockA.bar2_4(class A).a4f29e420077ca6ce7e44776941a7430_2" ; +"objc_blockA.bar:_1(class A).3dfd8f5104e9624c9f972777203745e3_1" [label="1: Start objc_blockA.bar:_1\nFormals: self:A* x:int i:int\nLocals: \nCaptured: [by ref]self:A* [by ref]x:int \n " color=yellow style=filled] + + + "objc_blockA.bar:_1(class A).3dfd8f5104e9624c9f972777203745e3_1" -> "objc_blockA.bar:_1(class A).3dfd8f5104e9624c9f972777203745e3_3" ; +"objc_blockA.bar:_1(class A).3dfd8f5104e9624c9f972777203745e3_2" [label="2: Exit objc_blockA.bar:_1 \n " color=yellow style=filled] + + +"objc_blockA.bar:_1(class A).3dfd8f5104e9624c9f972777203745e3_3" [label="3: BinaryOperatorStmt: Assign \n n$5=*&self:A* [line 28, column 9]\n n$6=*&x:int [line 28, column 19]\n *n$5.x:int=n$6 [line 28, column 9]\n " shape="box"] + + + "objc_blockA.bar:_1(class A).3dfd8f5104e9624c9f972777203745e3_3" -> "objc_blockA.bar:_1(class A).3dfd8f5104e9624c9f972777203745e3_2" ; +"objc_blockA.bar:_2(class A).714c02790d023adc163c946a9f0220cd_1" [label="1: Start objc_blockA.bar:_2\nFormals: self:A* i:int\nLocals: \nCaptured: [by ref]self:A* \n " color=yellow style=filled] + + + "objc_blockA.bar:_2(class A).714c02790d023adc163c946a9f0220cd_1" -> "objc_blockA.bar:_2(class A).714c02790d023adc163c946a9f0220cd_3" ; +"objc_blockA.bar:_2(class A).714c02790d023adc163c946a9f0220cd_2" [label="2: Exit objc_blockA.bar:_2 \n " color=yellow style=filled] + + +"objc_blockA.bar:_2(class A).714c02790d023adc163c946a9f0220cd_3" [label="3: BinaryOperatorStmt: Assign \n n$8=*&self:A* [line 31, column 9]\n n$9=*&i:int [line 31, column 19]\n *n$8.x:int=n$9 [line 31, column 9]\n " shape="box"] + + + "objc_blockA.bar:_2(class A).714c02790d023adc163c946a9f0220cd_3" -> "objc_blockA.bar:_2(class A).714c02790d023adc163c946a9f0220cd_2" ; +"bar2#A#instance.413fa5106d6a23f2bf18df99659efb82_1" [label="1: Start A.bar2\nFormals: self:A*\nLocals: \n " color=yellow style=filled] + + + "bar2#A#instance.413fa5106d6a23f2bf18df99659efb82_1" -> "bar2#A#instance.413fa5106d6a23f2bf18df99659efb82_4" ; +"bar2#A#instance.413fa5106d6a23f2bf18df99659efb82_2" [label="2: Exit A.bar2 \n " color=yellow style=filled] + + +"bar2#A#instance.413fa5106d6a23f2bf18df99659efb82_3" [label="3: Return Stmt \n n$12=*&self:A* [line 47, column 10]\n n$13=*n$12.x:int [line 47, column 10]\n *&return:int=n$13 [line 47, column 3]\n " shape="box"] + + + "bar2#A#instance.413fa5106d6a23f2bf18df99659efb82_3" -> "bar2#A#instance.413fa5106d6a23f2bf18df99659efb82_2" ; +"bar2#A#instance.413fa5106d6a23f2bf18df99659efb82_4" [label="4: Call _fun_foo \n n$14=*&self:A* [line 40, column 7]\n n$16=*&self:A* [line 43, column 7]\n n$18=*&self:A* [line 46, column 7]\n n$19=_fun_foo[objc_blockA.bar2_3^objc_blockA.bar2_4](n$14:A*,n$18:A*) block_params [line 39, column 3]\n " shape="box"] + + + "bar2#A#instance.413fa5106d6a23f2bf18df99659efb82_4" -> "bar2#A#instance.413fa5106d6a23f2bf18df99659efb82_3" ; +"bar:#A(class A)#instance.3e4a860660eb436d473f8ceeb9c1a72b_1" [label="1: Start A.bar:\nFormals: self:A* a:A*\nLocals: y:int x:int \n " color=yellow style=filled] + + + "bar:#A(class A)#instance.3e4a860660eb436d473f8ceeb9c1a72b_1" -> "bar:#A(class A)#instance.3e4a860660eb436d473f8ceeb9c1a72b_6" ; +"bar:#A(class A)#instance.3e4a860660eb436d473f8ceeb9c1a72b_2" [label="2: Exit A.bar: \n " color=yellow style=filled] + + +"bar:#A(class A)#instance.3e4a860660eb436d473f8ceeb9c1a72b_3" [label="3: Return Stmt \n n$0=*&self:A* [line 35, column 10]\n n$1=*n$0.x:int [line 35, column 10]\n *&return:int=n$1 [line 35, column 3]\n " shape="box"] + + + "bar:#A(class A)#instance.3e4a860660eb436d473f8ceeb9c1a72b_3" -> "bar:#A(class A)#instance.3e4a860660eb436d473f8ceeb9c1a72b_2" ; +"bar:#A(class A)#instance.3e4a860660eb436d473f8ceeb9c1a72b_4" [label="4: DeclStmt \n VARIABLE_DECLARED(y:int); [line 34, column 3]\n n$2=_fun_p() [line 34, column 11]\n *&y:int=n$2 [line 34, column 3]\n " shape="box"] + + + "bar:#A(class A)#instance.3e4a860660eb436d473f8ceeb9c1a72b_4" -> "bar:#A(class A)#instance.3e4a860660eb436d473f8ceeb9c1a72b_3" ; +"bar:#A(class A)#instance.3e4a860660eb436d473f8ceeb9c1a72b_5" [label="5: Call _fun_foo \n n$3=*&self:A* [line 27, column 7]\n n$4=*&x:int [line 27, column 7]\n n$7=*&self:A* [line 30, column 7]\n n$10=*&a:A* [line 33, column 7]\n n$11=_fun_foo[objc_blockA.bar:_1^objc_blockA.bar:_2](n$4:int,n$3:A*,n$10:A*) block_params [line 26, column 3]\n " shape="box"] + + + "bar:#A(class A)#instance.3e4a860660eb436d473f8ceeb9c1a72b_5" -> "bar:#A(class A)#instance.3e4a860660eb436d473f8ceeb9c1a72b_4" ; +"bar:#A(class A)#instance.3e4a860660eb436d473f8ceeb9c1a72b_6" [label="6: DeclStmt \n VARIABLE_DECLARED(x:int); [line 25, column 3]\n *&x:int=0 [line 25, column 3]\n " shape="box"] + + + "bar:#A(class A)#instance.3e4a860660eb436d473f8ceeb9c1a72b_6" -> "bar:#A(class A)#instance.3e4a860660eb436d473f8ceeb9c1a72b_5" ; +"dealloc#A#instance.55ac864e91dcd5d484e8ab7d8eb94fcb_1" [label="1: Start A.dealloc\nFormals: self:A*\nLocals: \n " color=yellow style=filled] + + + "dealloc#A#instance.55ac864e91dcd5d484e8ab7d8eb94fcb_1" -> "dealloc#A#instance.55ac864e91dcd5d484e8ab7d8eb94fcb_3" ; +"dealloc#A#instance.55ac864e91dcd5d484e8ab7d8eb94fcb_2" [label="2: Exit A.dealloc \n " color=yellow style=filled] + + +"dealloc#A#instance.55ac864e91dcd5d484e8ab7d8eb94fcb_3" [label="3: Call dealloc \n " shape="box"] + + + "dealloc#A#instance.55ac864e91dcd5d484e8ab7d8eb94fcb_3" -> "dealloc#A#instance.55ac864e91dcd5d484e8ab7d8eb94fcb_2" ; +} diff --git a/infer/tests/codetoanalyze/objc/frontend/noarc/Makefile b/infer/tests/codetoanalyze/objc/frontend/noarc/Makefile index 564b1acde..f7199f987 100644 --- a/infer/tests/codetoanalyze/objc/frontend/noarc/Makefile +++ b/infer/tests/codetoanalyze/objc/frontend/noarc/Makefile @@ -10,6 +10,7 @@ CLANG_OPTIONS = -c $(OBJC_CLANG_OPTIONS) SOURCES = \ ../block/retain_cycle.m \ ../block/static.m \ + ../block/specialized_method_with_block_params.m \ ../boxing/Boxing.m \ ../boxing/array.m \ ../boxing/array_literal.c \ diff --git a/infer/tests/codetoanalyze/objc/shared/block/Blocks_as_parameters.m.dot b/infer/tests/codetoanalyze/objc/shared/block/Blocks_as_parameters.m.dot index 2e38b858b..1b885bbd1 100644 --- a/infer/tests/codetoanalyze/objc/shared/block/Blocks_as_parameters.m.dot +++ b/infer/tests/codetoanalyze/objc/shared/block/Blocks_as_parameters.m.dot @@ -33,7 +33,7 @@ digraph cfg { "f#B#instance.f1371ff5e7f410d3df6a2e71ff0a814e_3" -> "f#B#instance.f1371ff5e7f410d3df6a2e71ff0a814e_2" ; -"f#B#instance.f1371ff5e7f410d3df6a2e71ff0a814e_4" [label="4: Message Call: foo:and: \n n$4=*&self:B* [line 23, column 10]\n n$5=*n$4.h:int [line 23, column 10]\n n$2=*&self:B* const [line 24, column 11]\n n$6=_fun_B.foo:and:(n$5:int,(_fun_objc_blockB.f_1,([by ref]n$2 &self:B* const )):_fn_(*)) block_params [line 23, column 3]\n " shape="box"] +"f#B#instance.f1371ff5e7f410d3df6a2e71ff0a814e_4" [label="4: Message Call: foo:and: \n n$4=*&self:B* [line 23, column 10]\n n$5=*n$4.h:int [line 23, column 10]\n n$2=*&self:B* const [line 24, column 11]\n n$6=_fun_B.foo:and:[objc_blockB.f_1](n$5:int,n$2:B* const ) block_params [line 23, column 3]\n " shape="box"] "f#B#instance.f1371ff5e7f410d3df6a2e71ff0a814e_4" -> "f#B#instance.f1371ff5e7f410d3df6a2e71ff0a814e_3" ; diff --git a/infer/tests/codetoanalyze/objc/shared/block/block-it.m.dot b/infer/tests/codetoanalyze/objc/shared/block/block-it.m.dot index 904242de0..a4b7e7ec3 100644 --- a/infer/tests/codetoanalyze/objc/shared/block/block-it.m.dot +++ b/infer/tests/codetoanalyze/objc/shared/block/block-it.m.dot @@ -63,7 +63,7 @@ digraph cfg { "array#MyBlock#instance.8be6e5b5e968d186440e1931c9eb40de_2" [label="2: Exit MyBlock.array \n " color=yellow style=filled] -"array#MyBlock#instance.8be6e5b5e968d186440e1931c9eb40de_3" [label="3: Message Call: enumerateObjectsUsingBlock: \n n$5=*&a:NSArray* [line 19, column 4]\n n$6=_fun_NSArray.enumerateObjectsUsingBlock:(n$5:NSArray*,(_fun_objc_blockMyBlock.array_1):_fn_(*)) block_params virtual [line 19, column 3]\n " shape="box"] +"array#MyBlock#instance.8be6e5b5e968d186440e1931c9eb40de_3" [label="3: Message Call: enumerateObjectsUsingBlock: \n n$5=*&a:NSArray* [line 19, column 4]\n n$6=_fun_NSArray.enumerateObjectsUsingBlock:[objc_blockMyBlock.array_1](n$5:NSArray*) block_params virtual [line 19, column 3]\n " shape="box"] "array#MyBlock#instance.8be6e5b5e968d186440e1931c9eb40de_3" -> "array#MyBlock#instance.8be6e5b5e968d186440e1931c9eb40de_2" ; diff --git a/infer/tests/codetoanalyze/objc/shared/block/dispatch.m.dot b/infer/tests/codetoanalyze/objc/shared/block/dispatch.m.dot index 6cf11277e..6ba52ce77 100644 --- a/infer/tests/codetoanalyze/objc/shared/block/dispatch.m.dot +++ b/infer/tests/codetoanalyze/objc/shared/block/dispatch.m.dot @@ -110,7 +110,7 @@ digraph cfg { "block_attribute#DispatchA#class.df997e345dbf19ec3438c667c942e14a_3" -> "block_attribute#DispatchA#class.df997e345dbf19ec3438c667c942e14a_2" ; -"block_attribute#DispatchA#class.df997e345dbf19ec3438c667c942e14a_4" [label="4: Call _fun__dispatch_once \n n$7=*&a:DispatchA* [line 37, column 24]\n n$9=_fun__dispatch_once(&#GB$DispatchA.block_attribute.once:long*,(_fun_objc_blockDispatchA.block_attribute_2,([by ref]n$7 &a:DispatchA*)):_fn_(*)) block_params [line 37, column 3]\n " shape="box"] +"block_attribute#DispatchA#class.df997e345dbf19ec3438c667c942e14a_4" [label="4: Call _fun__dispatch_once \n n$7=*&a:DispatchA* [line 37, column 24]\n n$9=_fun__dispatch_once[objc_blockDispatchA.block_attribute_2](&#GB$DispatchA.block_attribute.once:long*,n$7:DispatchA*) block_params [line 37, column 3]\n " shape="box"] "block_attribute#DispatchA#class.df997e345dbf19ec3438c667c942e14a_4" -> "block_attribute#DispatchA#class.df997e345dbf19ec3438c667c942e14a_3" ; @@ -190,7 +190,7 @@ digraph cfg { "sharedInstance#DispatchA#class.8992c6086d1ce5c225093940f62386ac_3" -> "sharedInstance#DispatchA#class.8992c6086d1ce5c225093940f62386ac_2" ; -"sharedInstance#DispatchA#class.8992c6086d1ce5c225093940f62386ac_4" [label="4: Call _fun__dispatch_once \n n$4=_fun__dispatch_once(&#GB$DispatchA.sharedInstance.once:long*,(_fun_objc_blockDispatchA.sharedInstance_1):_fn_(*)) block_params [line 28, column 3]\n " shape="box"] +"sharedInstance#DispatchA#class.8992c6086d1ce5c225093940f62386ac_4" [label="4: Call _fun__dispatch_once \n n$4=_fun__dispatch_once[objc_blockDispatchA.sharedInstance_1](&#GB$DispatchA.sharedInstance.once:long*) block_params [line 28, column 3]\n " shape="box"] "sharedInstance#DispatchA#class.8992c6086d1ce5c225093940f62386ac_4" -> "sharedInstance#DispatchA#class.8992c6086d1ce5c225093940f62386ac_3" ; diff --git a/infer/tests/codetoanalyze/objc/shared/block/dispatch_examples.m.dot b/infer/tests/codetoanalyze/objc/shared/block/dispatch_examples.m.dot index c0d058d0a..497c3143e 100644 --- a/infer/tests/codetoanalyze/objc/shared/block/dispatch_examples.m.dot +++ b/infer/tests/codetoanalyze/objc/shared/block/dispatch_examples.m.dot @@ -101,7 +101,7 @@ digraph cfg { "dispatch_after_example#DispatchEx#class.1d25856bd99eb1ef683c8f65ff46d05d_3" -> "dispatch_after_example#DispatchEx#class.1d25856bd99eb1ef683c8f65ff46d05d_2" ; -"dispatch_after_example#DispatchEx#class.1d25856bd99eb1ef683c8f65ff46d05d_4" [label="4: Call _fun_dispatch_after \n n$16=_fun_dispatch_time(0:unsigned long long,((unsigned long long)2 * 1000000000):long long) [line 46, column 18]\n n$17=_fun_dispatch_get_main_queue() [line 47, column 18]\n n$21=_fun_dispatch_after(n$16:unsigned long long,n$17:NSObject*,(_fun_objc_blockDispatchEx.dispatch_after_example_3):_fn_(*)) block_params [line 46, column 3]\n " shape="box"] +"dispatch_after_example#DispatchEx#class.1d25856bd99eb1ef683c8f65ff46d05d_4" [label="4: Call _fun_dispatch_after \n n$16=_fun_dispatch_time(0:unsigned long long,((unsigned long long)2 * 1000000000):long long) [line 46, column 18]\n n$17=_fun_dispatch_get_main_queue() [line 47, column 18]\n n$21=_fun_dispatch_after[objc_blockDispatchEx.dispatch_after_example_3](n$16:unsigned long long,n$17:NSObject*) block_params [line 46, column 3]\n " shape="box"] "dispatch_after_example#DispatchEx#class.1d25856bd99eb1ef683c8f65ff46d05d_4" -> "dispatch_after_example#DispatchEx#class.1d25856bd99eb1ef683c8f65ff46d05d_3" ; @@ -120,7 +120,7 @@ digraph cfg { "dispatch_async_example#DispatchEx#class.5c5d7347be2a9654ad7e32514189fe54_3" -> "dispatch_async_example#DispatchEx#class.5c5d7347be2a9654ad7e32514189fe54_2" ; -"dispatch_async_example#DispatchEx#class.5c5d7347be2a9654ad7e32514189fe54_4" [label="4: Call _fun_dispatch_async \n n$9=_fun_dispatch_get_global_queue(0:long,(unsigned long)0:unsigned long) [line 36, column 18]\n n$13=_fun_dispatch_async(n$9:NSObject*,(_fun_objc_blockDispatchEx.dispatch_async_example_2):_fn_(*)) block_params [line 36, column 3]\n " shape="box"] +"dispatch_async_example#DispatchEx#class.5c5d7347be2a9654ad7e32514189fe54_4" [label="4: Call _fun_dispatch_async \n n$9=_fun_dispatch_get_global_queue(0:long,(unsigned long)0:unsigned long) [line 36, column 18]\n n$13=_fun_dispatch_async[objc_blockDispatchEx.dispatch_async_example_2](n$9:NSObject*) block_params [line 36, column 3]\n " shape="box"] "dispatch_async_example#DispatchEx#class.5c5d7347be2a9654ad7e32514189fe54_4" -> "dispatch_async_example#DispatchEx#class.5c5d7347be2a9654ad7e32514189fe54_3" ; @@ -139,7 +139,7 @@ digraph cfg { "dispatch_barrier_example#DispatchEx#class.a541a40f2f04e29019c58e563f7544d8_3" -> "dispatch_barrier_example#DispatchEx#class.a541a40f2f04e29019c58e563f7544d8_2" ; -"dispatch_barrier_example#DispatchEx#class.a541a40f2f04e29019c58e563f7544d8_4" [label="4: Call _fun_dispatch_barrier_async \n n$38=_fun_dispatch_get_main_queue() [line 75, column 26]\n n$42=_fun_dispatch_barrier_async(n$38:NSObject*,(_fun_objc_blockDispatchEx.dispatch_barrier_example_6):_fn_(*)) block_params [line 75, column 3]\n " shape="box"] +"dispatch_barrier_example#DispatchEx#class.a541a40f2f04e29019c58e563f7544d8_4" [label="4: Call _fun_dispatch_barrier_async \n n$38=_fun_dispatch_get_main_queue() [line 75, column 26]\n n$42=_fun_dispatch_barrier_async[objc_blockDispatchEx.dispatch_barrier_example_6](n$38:NSObject*) block_params [line 75, column 3]\n " shape="box"] "dispatch_barrier_example#DispatchEx#class.a541a40f2f04e29019c58e563f7544d8_4" -> "dispatch_barrier_example#DispatchEx#class.a541a40f2f04e29019c58e563f7544d8_3" ; @@ -158,7 +158,7 @@ digraph cfg { "dispatch_group_example#DispatchEx#class.f420a75c58eda6d3f0e5e05fadabfc18_3" -> "dispatch_group_example#DispatchEx#class.f420a75c58eda6d3f0e5e05fadabfc18_2" ; -"dispatch_group_example#DispatchEx#class.f420a75c58eda6d3f0e5e05fadabfc18_4" [label="4: Call _fun_dispatch_group_async \n n$24=_fun_dispatch_get_main_queue() [line 57, column 30]\n n$28=_fun_dispatch_group_async(null:NSObject*,n$24:NSObject*,(_fun_objc_blockDispatchEx.dispatch_group_example_4):_fn_(*)) block_params [line 57, column 3]\n " shape="box"] +"dispatch_group_example#DispatchEx#class.f420a75c58eda6d3f0e5e05fadabfc18_4" [label="4: Call _fun_dispatch_group_async \n n$24=_fun_dispatch_get_main_queue() [line 57, column 30]\n n$28=_fun_dispatch_group_async[objc_blockDispatchEx.dispatch_group_example_4](n$24:NSObject*,null:NSObject*) block_params [line 57, column 3]\n " shape="box"] "dispatch_group_example#DispatchEx#class.f420a75c58eda6d3f0e5e05fadabfc18_4" -> "dispatch_group_example#DispatchEx#class.f420a75c58eda6d3f0e5e05fadabfc18_3" ; @@ -177,7 +177,7 @@ digraph cfg { "dispatch_group_notify_example#DispatchEx#class.f5cf54b07621c319cf7ead3b217760ed_3" -> "dispatch_group_notify_example#DispatchEx#class.f5cf54b07621c319cf7ead3b217760ed_2" ; -"dispatch_group_notify_example#DispatchEx#class.f5cf54b07621c319cf7ead3b217760ed_4" [label="4: Call _fun_dispatch_group_async \n n$31=_fun_dispatch_get_main_queue() [line 66, column 30]\n n$35=_fun_dispatch_group_async(null:NSObject*,n$31:NSObject*,(_fun_objc_blockDispatchEx.dispatch_group_notify_example_5):_fn_(*)) block_params [line 66, column 3]\n " shape="box"] +"dispatch_group_notify_example#DispatchEx#class.f5cf54b07621c319cf7ead3b217760ed_4" [label="4: Call _fun_dispatch_group_async \n n$31=_fun_dispatch_get_main_queue() [line 66, column 30]\n n$35=_fun_dispatch_group_async[objc_blockDispatchEx.dispatch_group_notify_example_5](n$31:NSObject*,null:NSObject*) block_params [line 66, column 3]\n " shape="box"] "dispatch_group_notify_example#DispatchEx#class.f5cf54b07621c319cf7ead3b217760ed_4" -> "dispatch_group_notify_example#DispatchEx#class.f5cf54b07621c319cf7ead3b217760ed_3" ; @@ -196,7 +196,7 @@ digraph cfg { "dispatch_once_example#DispatchEx#class.d3456446b1a2d5355c1767887cc8b62c_3" -> "dispatch_once_example#DispatchEx#class.d3456446b1a2d5355c1767887cc8b62c_2" ; -"dispatch_once_example#DispatchEx#class.d3456446b1a2d5355c1767887cc8b62c_4" [label="4: Call _fun__dispatch_once \n n$6=_fun__dispatch_once(&#GB$DispatchEx.dispatch_once_example.onceToken:long*,(_fun_objc_blockDispatchEx.dispatch_once_example_1):_fn_(*)) block_params [line 27, column 3]\n " shape="box"] +"dispatch_once_example#DispatchEx#class.d3456446b1a2d5355c1767887cc8b62c_4" [label="4: Call _fun__dispatch_once \n n$6=_fun__dispatch_once[objc_blockDispatchEx.dispatch_once_example_1](&#GB$DispatchEx.dispatch_once_example.onceToken:long*) block_params [line 27, column 3]\n " shape="box"] "dispatch_once_example#DispatchEx#class.d3456446b1a2d5355c1767887cc8b62c_4" -> "dispatch_once_example#DispatchEx#class.d3456446b1a2d5355c1767887cc8b62c_3" ; diff --git a/infer/tests/codetoanalyze/objc/shared/block/dispatch_in_macro.m.dot b/infer/tests/codetoanalyze/objc/shared/block/dispatch_in_macro.m.dot index bcc5d8c5f..e655ae81d 100644 --- a/infer/tests/codetoanalyze/objc/shared/block/dispatch_in_macro.m.dot +++ b/infer/tests/codetoanalyze/objc/shared/block/dispatch_in_macro.m.dot @@ -11,7 +11,7 @@ digraph cfg { "DispatchInMacroTest.f5d56763274a479d06265a2f9562bef1_3" -> "DispatchInMacroTest.f5d56763274a479d06265a2f9562bef1_5" ; -"DispatchInMacroTest.f5d56763274a479d06265a2f9562bef1_4" [label="4: Call _fun__dispatch_once \n n$3=_fun__dispatch_once(&#GB$DispatchInMacroTest.once_token:long*,(_fun_objc_blockDispatchInMacroTest_1):_fn_(*)) block_params [line 21, column 10]\n " shape="box"] +"DispatchInMacroTest.f5d56763274a479d06265a2f9562bef1_4" [label="4: Call _fun__dispatch_once \n n$3=_fun__dispatch_once[objc_blockDispatchInMacroTest_1](&#GB$DispatchInMacroTest.once_token:long*) block_params [line 21, column 10]\n " shape="box"] "DispatchInMacroTest.f5d56763274a479d06265a2f9562bef1_4" -> "DispatchInMacroTest.f5d56763274a479d06265a2f9562bef1_3" ;