diff --git a/infer/src/clang/cMethod_trans.ml b/infer/src/clang/cMethod_trans.ml index 18e2e565f..69c3f3d13 100644 --- a/infer/src/clang/cMethod_trans.ml +++ b/infer/src/clang/cMethod_trans.ml @@ -121,13 +121,19 @@ let get_objc_method_data obj_c_message_expr_info = (selector, MCStatic) -let should_create_procdesc cfg procname ~defined ~set_objc_accessor_attr = +let should_create_procdesc ?(captured_vars = []) cfg procname ~defined ~set_objc_accessor_attr = match Procname.Hash.find cfg procname with | previous_procdesc -> let is_defined_previous = Procdesc.is_defined previous_procdesc in if (defined || set_objc_accessor_attr) && not is_defined_previous then ( Procname.Hash.remove cfg procname ; true ) + else if is_defined_previous && not (List.is_empty captured_vars) then ( + let new_attributes = + {(Procdesc.get_attributes previous_procdesc) with captured= captured_vars} + in + Procdesc.set_attributes previous_procdesc new_attributes ; + false ) else false | exception Caml.Not_found -> true @@ -189,8 +195,8 @@ let find_sentinel_attribute attrs = (** Creates a procedure description. *) -let create_local_procdesc ?(set_objc_accessor_attr = false) trans_unit_ctx cfg tenv ms fbody - captured = +let create_local_procdesc ?(set_objc_accessor_attr = false) ?(update_lambda_captured = false) + trans_unit_ctx cfg tenv ms fbody captured = let defined = not (List.is_empty fbody) in let proc_name = ms.CMethodSignature.name in let clang_method_kind = ms.CMethodSignature.method_kind in @@ -205,6 +211,9 @@ let create_local_procdesc ?(set_objc_accessor_attr = false) trans_unit_ctx cfg t | `Public -> PredSymb.Protected in + let captured_mangled = + List.map ~f:(fun (var, t, mode) -> (Pvar.get_name var, t, mode)) captured + in let create_new_procdesc () = let all_params = Option.to_list ms.CMethodSignature.class_param @ ms.CMethodSignature.params in let has_added_return_param = ms.CMethodSignature.has_added_return_param in @@ -216,10 +225,10 @@ let create_local_procdesc ?(set_objc_accessor_attr = false) trans_unit_ctx cfg t let formals = List.map ~f:(fun ({name; typ} : CMethodSignature.param_type) -> (name, typ)) all_params in - let captured_mangled = - List.map ~f:(fun (var, t, mode) -> (Pvar.get_name var, t, mode)) captured - in - (* Captured variables for blocks are treated as parameters *) + (* Captured variables for blocks are treated as parameters + Captured variables will not be added to formals for lambdas' `operator()` as procdesc for + `operator()` is created before captured variables are translated + *) let captured_as_formals = List.map ~f:(fun (var, t, _) -> (var, t)) captured_mangled in let formals = captured_as_formals @ formals in let const_formals = @@ -269,7 +278,8 @@ let create_local_procdesc ?(set_objc_accessor_attr = false) trans_unit_ctx cfg t Procdesc.set_start_node procdesc start_node ; Procdesc.set_exit_node procdesc exit_node ) in - if should_create_procdesc cfg proc_name ~defined ~set_objc_accessor_attr then ( + let captured_vars = if update_lambda_captured then captured_mangled else [] in + if should_create_procdesc cfg proc_name ~defined ~set_objc_accessor_attr ~captured_vars then ( create_new_procdesc () ; true ) else false @@ -294,13 +304,14 @@ let create_external_procdesc trans_unit_ctx cfg proc_name clang_method_kind type ignore (Cfg.create_proc_desc cfg proc_attributes) -let create_procdesc_with_pointer context pointer class_name_opt name = +let create_procdesc_with_pointer ?(captured_vars = []) context pointer class_name_opt name = let open CContext in match method_signature_of_pointer context.tenv pointer with | Some callee_ms -> ignore (create_local_procdesc context.translation_unit_context context.cfg context.tenv callee_ms - [] []) ; + [] captured_vars + ~update_lambda_captured:(not (List.is_empty captured_vars))) ; callee_ms.CMethodSignature.name | None -> let callee_name, method_kind = @@ -317,13 +328,13 @@ let create_procdesc_with_pointer context pointer class_name_opt name = callee_name -let get_procname_from_cpp_lambda context dec = +let get_procname_from_cpp_lambda context dec captured_vars = match dec with | Clang_ast_t.CXXRecordDecl (_, _, _, _, _, _, _, cxx_rdi) -> ( match cxx_rdi.xrdi_lambda_call_operator with | Some dr -> let name_info, decl_ptr, _ = CAst_utils.get_info_from_decl_ref dr in - create_procdesc_with_pointer context decl_ptr None name_info.ni_name + create_procdesc_with_pointer context decl_ptr None name_info.ni_name ~captured_vars | _ -> assert false ) | _ -> diff --git a/infer/src/clang/cMethod_trans.mli b/infer/src/clang/cMethod_trans.mli index 952a62a82..bdb383ccc 100644 --- a/infer/src/clang/cMethod_trans.mli +++ b/infer/src/clang/cMethod_trans.mli @@ -19,13 +19,19 @@ type method_call_type = MCVirtual | MCNoVirtual | MCStatic [@@deriving compare] val equal_method_call_type : method_call_type -> method_call_type -> bool val should_create_procdesc : - Cfg.t -> Procname.t -> defined:bool -> set_objc_accessor_attr:bool -> bool + ?captured_vars:(Mangled.t * Typ.typ * Pvar.capture_mode) list + -> Cfg.t + -> Procname.t + -> defined:bool + -> set_objc_accessor_attr:bool + -> bool (** Return if a procdesc should be added or not. It returns [false] when the same name of procdesc was added previously. [defined] represents if the function body is non-empty. [set_objc_accessor_attr] represents if the function is a getter/setter in Obj-C. *) val create_local_procdesc : ?set_objc_accessor_attr:bool + -> ?update_lambda_captured:bool -> CFrontend_config.translation_unit_context -> Cfg.t -> Tenv.t @@ -55,8 +61,14 @@ val method_signature_of_pointer : Tenv.t -> Clang_ast_t.pointer -> CMethodSignat val get_method_name_from_clang : Tenv.t -> CMethodSignature.t option -> Procname.t option val create_procdesc_with_pointer : - CContext.t -> Clang_ast_t.pointer -> Typ.Name.t option -> string -> Procname.t + ?captured_vars:(Pvar.t * Typ.t * Pvar.capture_mode) list + -> CContext.t + -> Clang_ast_t.pointer + -> Typ.Name.t option + -> string + -> Procname.t -val get_procname_from_cpp_lambda : CContext.t -> Clang_ast_t.decl -> Procname.t +val get_procname_from_cpp_lambda : + CContext.t -> Clang_ast_t.decl -> (Pvar.t * Typ.t * Pvar.capture_mode) list -> Procname.t val get_captures_from_cpp_lambda : Clang_ast_t.decl -> Clang_ast_t.lambda_capture_info list diff --git a/infer/src/clang/cTrans.ml b/infer/src/clang/cTrans.ml index 5bc1de34a..ae4b8f906 100644 --- a/infer/src/clang/cTrans.ml +++ b/infer/src/clang/cTrans.ml @@ -2860,7 +2860,6 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s let context = trans_state.context in call_translation context lei_lambda_decl ; let procname = Procdesc.get_proc_name context.procdesc in - let lambda_pname = CMethod_trans.get_procname_from_cpp_lambda context lei_lambda_decl in let typ = CType_decl.qual_type_to_sil_type context.tenv qual_type in let get_captured_pvar_typ decl_ref = CVar_decl.sil_var_of_captured_var context stmt_info.Clang_ast_t.si_source_range procname @@ -2936,6 +2935,12 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s let trans_results, captured_vars = List.fold_right ~f:translate_captured ~init:([], []) lei_captures in + let captured_var_names = + List.map ~f:(fun (_, var, typ, mode) -> (var, typ, mode)) captured_vars + in + let lambda_pname = + CMethod_trans.get_procname_from_cpp_lambda context lei_lambda_decl captured_var_names + in let closure = Exp.Closure {name= lambda_pname; captured_vars} in collect_trans_results context.procdesc ~return:(closure, typ) trans_results diff --git a/infer/tests/codetoanalyze/cpp/shared/lambda/lambda1.cpp.dot b/infer/tests/codetoanalyze/cpp/shared/lambda/lambda1.cpp.dot index cd8a63ff7..1899b20b4 100644 --- a/infer/tests/codetoanalyze/cpp/shared/lambda/lambda1.cpp.dot +++ b/infer/tests/codetoanalyze/cpp/shared/lambda/lambda1.cpp.dot @@ -302,7 +302,7 @@ digraph cfg { "#lambda_shared_lambda_lambda1.cpp:24:12#fooOK#{12805486487749307717|constexpr}.5e8e5a47f663bbae0aeb80a4152608e7_2" [label="2: Exit fooOK::lambda_shared_lambda_lambda1.cpp:24:12:: \n " color=yellow style=filled] -"operator()#lambda_shared_lambda_lambda1.cpp:31:10#normal_capture#(3336792892144266867).563aa24976a73c4ea364dbb5afa3f73f_1" [label="1: Start normal_capture::lambda_shared_lambda_lambda1.cpp:31:10::operator()\nFormals: this:normal_capture::lambda_shared_lambda_lambda1.cpp:31:10*\nLocals: \n " color=yellow style=filled] +"operator()#lambda_shared_lambda_lambda1.cpp:31:10#normal_capture#(3336792892144266867).563aa24976a73c4ea364dbb5afa3f73f_1" [label="1: Start normal_capture::lambda_shared_lambda_lambda1.cpp:31:10::operator()\nFormals: this:normal_capture::lambda_shared_lambda_lambda1.cpp:31:10*\nLocals: \nCaptured: [by value]x:int [by value]y:int \n " color=yellow style=filled] "operator()#lambda_shared_lambda_lambda1.cpp:31:10#normal_capture#(3336792892144266867).563aa24976a73c4ea364dbb5afa3f73f_1" -> "operator()#lambda_shared_lambda_lambda1.cpp:31:10#normal_capture#(3336792892144266867).563aa24976a73c4ea364dbb5afa3f73f_3" ; @@ -313,7 +313,7 @@ digraph cfg { "operator()#lambda_shared_lambda_lambda1.cpp:31:10#normal_capture#(3336792892144266867).563aa24976a73c4ea364dbb5afa3f73f_3" -> "operator()#lambda_shared_lambda_lambda1.cpp:31:10#normal_capture#(3336792892144266867).563aa24976a73c4ea364dbb5afa3f73f_2" ; -"operator()#lambda_shared_lambda_lambda1.cpp:36:3#capture_by_ref#(17277454583786497390).328aa336808e9a777a5cd630eb1ef54f_1" [label="1: Start capture_by_ref::lambda_shared_lambda_lambda1.cpp:36:3::operator()\nFormals: this:capture_by_ref::lambda_shared_lambda_lambda1.cpp:36:3*\nLocals: \n " color=yellow style=filled] +"operator()#lambda_shared_lambda_lambda1.cpp:36:3#capture_by_ref#(17277454583786497390).328aa336808e9a777a5cd630eb1ef54f_1" [label="1: Start capture_by_ref::lambda_shared_lambda_lambda1.cpp:36:3::operator()\nFormals: this:capture_by_ref::lambda_shared_lambda_lambda1.cpp:36:3*\nLocals: \nCaptured: [by ref]x:int \n " color=yellow style=filled] "operator()#lambda_shared_lambda_lambda1.cpp:36:3#capture_by_ref#(17277454583786497390).328aa336808e9a777a5cd630eb1ef54f_1" -> "operator()#lambda_shared_lambda_lambda1.cpp:36:3#capture_by_ref#(17277454583786497390).328aa336808e9a777a5cd630eb1ef54f_3" ; @@ -324,7 +324,7 @@ digraph cfg { "operator()#lambda_shared_lambda_lambda1.cpp:36:3#capture_by_ref#(17277454583786497390).328aa336808e9a777a5cd630eb1ef54f_3" -> "operator()#lambda_shared_lambda_lambda1.cpp:36:3#capture_by_ref#(17277454583786497390).328aa336808e9a777a5cd630eb1ef54f_2" ; -"operator()#lambda_shared_lambda_lambda1.cpp:41:10#init_capture1#(11958159405823124536).c1401fcf3820489850f4deb3dab109ac_1" [label="1: Start init_capture1::lambda_shared_lambda_lambda1.cpp:41:10::operator()\nFormals: this:init_capture1::lambda_shared_lambda_lambda1.cpp:41:10*\nLocals: \n " color=yellow style=filled] +"operator()#lambda_shared_lambda_lambda1.cpp:41:10#init_capture1#(11958159405823124536).c1401fcf3820489850f4deb3dab109ac_1" [label="1: Start init_capture1::lambda_shared_lambda_lambda1.cpp:41:10::operator()\nFormals: this:init_capture1::lambda_shared_lambda_lambda1.cpp:41:10*\nLocals: \nCaptured: [by value]i:int \n " color=yellow style=filled] "operator()#lambda_shared_lambda_lambda1.cpp:41:10#init_capture1#(11958159405823124536).c1401fcf3820489850f4deb3dab109ac_1" -> "operator()#lambda_shared_lambda_lambda1.cpp:41:10#init_capture1#(11958159405823124536).c1401fcf3820489850f4deb3dab109ac_3" ; @@ -335,7 +335,7 @@ digraph cfg { "operator()#lambda_shared_lambda_lambda1.cpp:41:10#init_capture1#(11958159405823124536).c1401fcf3820489850f4deb3dab109ac_3" -> "operator()#lambda_shared_lambda_lambda1.cpp:41:10#init_capture1#(11958159405823124536).c1401fcf3820489850f4deb3dab109ac_2" ; -"operator()#lambda_shared_lambda_lambda1.cpp:46:10#init_capture2#(10943089228143620310).415a6350451062f52188b6cc908fbf46_1" [label="1: Start init_capture2::lambda_shared_lambda_lambda1.cpp:46:10::operator()\nFormals: this:init_capture2::lambda_shared_lambda_lambda1.cpp:46:10*\nLocals: \n " color=yellow style=filled] +"operator()#lambda_shared_lambda_lambda1.cpp:46:10#init_capture2#(10943089228143620310).415a6350451062f52188b6cc908fbf46_1" [label="1: Start init_capture2::lambda_shared_lambda_lambda1.cpp:46:10::operator()\nFormals: this:init_capture2::lambda_shared_lambda_lambda1.cpp:46:10*\nLocals: \nCaptured: [by value]a:int [by value]b:int [by value]c:int \n " color=yellow style=filled] "operator()#lambda_shared_lambda_lambda1.cpp:46:10#init_capture2#(10943089228143620310).415a6350451062f52188b6cc908fbf46_1" -> "operator()#lambda_shared_lambda_lambda1.cpp:46:10#init_capture2#(10943089228143620310).415a6350451062f52188b6cc908fbf46_3" ; @@ -346,7 +346,7 @@ digraph cfg { "operator()#lambda_shared_lambda_lambda1.cpp:46:10#init_capture2#(10943089228143620310).415a6350451062f52188b6cc908fbf46_3" -> "operator()#lambda_shared_lambda_lambda1.cpp:46:10#init_capture2#(10943089228143620310).415a6350451062f52188b6cc908fbf46_2" ; -"operator()#lambda_shared_lambda_lambda1.cpp:51:19#capture_this_explicit#Capture#(1084455887557995828.1d62aec1dfb3de86dac2a9a51e124083_1" [label="1: Start Capture::capture_this_explicit::lambda_shared_lambda_lambda1.cpp:51:19::operator()\nFormals: this:Capture::capture_this_explicit::lambda_shared_lambda_lambda1.cpp:51:19*\nLocals: \n " color=yellow style=filled] +"operator()#lambda_shared_lambda_lambda1.cpp:51:19#capture_this_explicit#Capture#(1084455887557995828.1d62aec1dfb3de86dac2a9a51e124083_1" [label="1: Start Capture::capture_this_explicit::lambda_shared_lambda_lambda1.cpp:51:19::operator()\nFormals: this:Capture::capture_this_explicit::lambda_shared_lambda_lambda1.cpp:51:19*\nLocals: \nCaptured: [by ref]this:Capture* \n " color=yellow style=filled] "operator()#lambda_shared_lambda_lambda1.cpp:51:19#capture_this_explicit#Capture#(1084455887557995828.1d62aec1dfb3de86dac2a9a51e124083_1" -> "operator()#lambda_shared_lambda_lambda1.cpp:51:19#capture_this_explicit#Capture#(1084455887557995828.1d62aec1dfb3de86dac2a9a51e124083_3" ; @@ -368,7 +368,7 @@ digraph cfg { "#lambda_shared_lambda_lambda1.cpp:51:19#capture_this_explicit#Capture#{15581681824770184595|constexp.7bc69d386faff7f8ffc9dc392a5988cf_3" -> "#lambda_shared_lambda_lambda1.cpp:51:19#capture_this_explicit#Capture#{15581681824770184595|constexp.7bc69d386faff7f8ffc9dc392a5988cf_2" ; -"operator()#lambda_shared_lambda_lambda1.cpp:55:19#capture_star_this#Capture#(11891233366713773989).2f1caaa7509ffca98027857cb192891f_1" [label="1: Start Capture::capture_star_this::lambda_shared_lambda_lambda1.cpp:55:19::operator()\nFormals: this:Capture::capture_star_this::lambda_shared_lambda_lambda1.cpp:55:19*\nLocals: \n " color=yellow style=filled] +"operator()#lambda_shared_lambda_lambda1.cpp:55:19#capture_star_this#Capture#(11891233366713773989).2f1caaa7509ffca98027857cb192891f_1" [label="1: Start Capture::capture_star_this::lambda_shared_lambda_lambda1.cpp:55:19::operator()\nFormals: this:Capture::capture_star_this::lambda_shared_lambda_lambda1.cpp:55:19*\nLocals: \nCaptured: [by value]this:Capture* \n " color=yellow style=filled] "operator()#lambda_shared_lambda_lambda1.cpp:55:19#capture_star_this#Capture#(11891233366713773989).2f1caaa7509ffca98027857cb192891f_1" -> "operator()#lambda_shared_lambda_lambda1.cpp:55:19#capture_star_this#Capture#(11891233366713773989).2f1caaa7509ffca98027857cb192891f_2" ; @@ -386,7 +386,7 @@ digraph cfg { "#lambda_shared_lambda_lambda1.cpp:55:19#capture_star_this#Capture#{9456129203468966420|constexpr}.524c805f606049237b74db978143df13_3" -> "#lambda_shared_lambda_lambda1.cpp:55:19#capture_star_this#Capture#{9456129203468966420|constexpr}.524c805f606049237b74db978143df13_2" ; -"operator()#lambda_shared_lambda_lambda1.cpp:61:19#capture_this_with_equal#Capture#(91082432562742530.b72f197de8f4f60c1d815523b52f3221_1" [label="1: Start Capture::capture_this_with_equal::lambda_shared_lambda_lambda1.cpp:61:19::operator()\nFormals: this:Capture::capture_this_with_equal::lambda_shared_lambda_lambda1.cpp:61:19*\nLocals: \n " color=yellow style=filled] +"operator()#lambda_shared_lambda_lambda1.cpp:61:19#capture_this_with_equal#Capture#(91082432562742530.b72f197de8f4f60c1d815523b52f3221_1" [label="1: Start Capture::capture_this_with_equal::lambda_shared_lambda_lambda1.cpp:61:19::operator()\nFormals: this:Capture::capture_this_with_equal::lambda_shared_lambda_lambda1.cpp:61:19*\nLocals: \nCaptured: [by ref]this:Capture* \n " color=yellow style=filled] "operator()#lambda_shared_lambda_lambda1.cpp:61:19#capture_this_with_equal#Capture#(91082432562742530.b72f197de8f4f60c1d815523b52f3221_1" -> "operator()#lambda_shared_lambda_lambda1.cpp:61:19#capture_this_with_equal#Capture#(91082432562742530.b72f197de8f4f60c1d815523b52f3221_3" ; @@ -408,7 +408,7 @@ digraph cfg { "#lambda_shared_lambda_lambda1.cpp:61:19#capture_this_with_equal#Capture#{16013381636753347826|conste.5c764d68be3baa1f6ef1128e1dbea59f_3" -> "#lambda_shared_lambda_lambda1.cpp:61:19#capture_this_with_equal#Capture#{16013381636753347826|conste.5c764d68be3baa1f6ef1128e1dbea59f_2" ; -"operator()#lambda_shared_lambda_lambda1.cpp:65:19#capture_this_with_auto#Capture#(476955214552649307.449a23f73c844f26ba0d7a54aef5727e_1" [label="1: Start Capture::capture_this_with_auto::lambda_shared_lambda_lambda1.cpp:65:19::operator()\nFormals: this:Capture::capture_this_with_auto::lambda_shared_lambda_lambda1.cpp:65:19*\nLocals: \n " color=yellow style=filled] +"operator()#lambda_shared_lambda_lambda1.cpp:65:19#capture_this_with_auto#Capture#(476955214552649307.449a23f73c844f26ba0d7a54aef5727e_1" [label="1: Start Capture::capture_this_with_auto::lambda_shared_lambda_lambda1.cpp:65:19::operator()\nFormals: this:Capture::capture_this_with_auto::lambda_shared_lambda_lambda1.cpp:65:19*\nLocals: \nCaptured: [by ref]this:Capture* \n " color=yellow style=filled] "operator()#lambda_shared_lambda_lambda1.cpp:65:19#capture_this_with_auto#Capture#(476955214552649307.449a23f73c844f26ba0d7a54aef5727e_1" -> "operator()#lambda_shared_lambda_lambda1.cpp:65:19#capture_this_with_auto#Capture#(476955214552649307.449a23f73c844f26ba0d7a54aef5727e_3" ; @@ -430,7 +430,7 @@ digraph cfg { "#lambda_shared_lambda_lambda1.cpp:65:19#capture_this_with_auto#Capture#{10854495330849287568|constex.920289afd6e5ecdf220f6692ec06788a_3" -> "#lambda_shared_lambda_lambda1.cpp:65:19#capture_this_with_auto#Capture#{10854495330849287568|constex.920289afd6e5ecdf220f6692ec06788a_2" ; -"operator()#lambda_shared_lambda_lambda1.cpp:77:12#struct_capture#(3957024350029978205).24bdda6ed01a44c4f20e0211a02e4440_1" [label="1: Start struct_capture::lambda_shared_lambda_lambda1.cpp:77:12::operator()\nFormals: this:struct_capture::lambda_shared_lambda_lambda1.cpp:77:12*\nLocals: \n " color=yellow style=filled] +"operator()#lambda_shared_lambda_lambda1.cpp:77:12#struct_capture#(3957024350029978205).24bdda6ed01a44c4f20e0211a02e4440_1" [label="1: Start struct_capture::lambda_shared_lambda_lambda1.cpp:77:12::operator()\nFormals: this:struct_capture::lambda_shared_lambda_lambda1.cpp:77:12*\nLocals: \nCaptured: [by value]x:SomeStruct [by value]y:SomeStruct \n " color=yellow style=filled] "operator()#lambda_shared_lambda_lambda1.cpp:77:12#struct_capture#(3957024350029978205).24bdda6ed01a44c4f20e0211a02e4440_1" -> "operator()#lambda_shared_lambda_lambda1.cpp:77:12#struct_capture#(3957024350029978205).24bdda6ed01a44c4f20e0211a02e4440_3" ;