diff --git a/infer/src/clang/cTrans.ml b/infer/src/clang/cTrans.ml index c8528f586..5eddb7f41 100644 --- a/infer/src/clang/cTrans.ml +++ b/infer/src/clang/cTrans.ml @@ -838,14 +838,7 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s in let return = if Self.is_var_self pvar (CContext.is_objc_method context) && CType.is_class typ then - let class_name = CContext.get_curr_class_typename stmt_info context in - if trans_state.is_fst_arg_objc_instance_method_call then - raise - (Self.SelfClassException - {class_name; position= __POS__; source_range= stmt_info.Clang_ast_t.si_source_range}) - else - let exp_typ = sizeof_expr_class class_name in - exp_typ + sizeof_expr_class (CContext.get_curr_class_typename stmt_info context) else (var_exp, typ) in L.(debug Capture Verbose) "@\n@\n PVAR ='%s'@\n@\n" (Pvar.to_string pvar) ; @@ -1289,13 +1282,7 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s CMethod_trans.get_class_name_method_call_from_receiver_kind context obj_c_message_expr_info act_params in - if trans_state.is_fst_arg_objc_instance_method_call && is_receiver_instance receiver_kind then - raise - (Self.SelfClassException - {class_name; position= __POS__; source_range= si.Clang_ast_t.si_source_range}) - else - let exp, typ = sizeof_expr_class class_name in - Some (mk_trans_result (exp, typ) empty_control) + Some (mk_trans_result (sizeof_expr_class class_name) empty_control) else if (* alloc or new *) String.equal selector CFrontend_config.alloc @@ -1347,23 +1334,24 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s let param_trans_results = List.mapi ~f:(exec_instruction_with_trans_state trans_state_param callee_ms_opt) rest in - try - let trans_state_param' = - if is_receiver_instance obj_c_message_expr_info.Clang_ast_t.omei_receiver_kind then - {trans_state_param with is_fst_arg_objc_instance_method_call= true} - else {trans_state_param with is_fst_arg_objc_instance_method_call= false} - in - let fst_res_trans = - exec_instruction_with_trans_state trans_state_param' callee_ms_opt 0 stmt - in - (obj_c_message_expr_info, fst_res_trans :: param_trans_results) - with Self.SelfClassException e -> - 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 e.class_name pointer - in - (obj_c_message_expr_info, param_trans_results) ) + let trans_state_param' = + { trans_state_param with + is_fst_arg_objc_instance_method_call= + is_receiver_instance obj_c_message_expr_info.Clang_ast_t.omei_receiver_kind } + in + match CTrans_utils.should_remove_first_param trans_state_param' stmt with + | Some 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, param_trans_results) + | None -> + let fst_res_trans = + exec_instruction_with_trans_state trans_state_param' callee_ms_opt 0 stmt + in + (obj_c_message_expr_info, fst_res_trans :: param_trans_results) ) | [] -> (obj_c_message_expr_info, []) diff --git a/infer/src/clang/cTrans_utils.ml b/infer/src/clang/cTrans_utils.ml index 92bd2dc0e..4a11cd90e 100644 --- a/infer/src/clang/cTrans_utils.ml +++ b/infer/src/clang/cTrans_utils.ml @@ -581,10 +581,6 @@ let extract_stmt_from_singleton stmt_list source_range warning_string = module Self = struct - exception - SelfClassException of - {class_name: Typ.Name.t; position: Logging.ocaml_pos; source_range: Clang_ast_t.source_range} - let add_self_parameter_for_super_instance stmt_info context procname loc mei = if is_superinstance mei then let typ, self_expr, instrs = @@ -644,3 +640,33 @@ let last_or_mk_fresh_void_exp_typ exp_typs = last_exp_typ | None -> mk_fresh_void_exp_typ () + + +let should_remove_first_param {context= {tenv} as context; is_fst_arg_objc_instance_method_call} + stmt = + let some_class_name stmt_info = Some (CContext.get_curr_class_typename stmt_info context) in + match (stmt : Clang_ast_t.stmt) with + | ImplicitCastExpr + ( _ + , [ DeclRefExpr + ( stmt_info + , _ + , _ + , {drti_decl_ref= Some {dr_name= Some {ni_name= name}; dr_qual_type= Some qual_type}} ) + ] + , _ + , {cei_cast_kind= `LValueToRValue} ) + when is_fst_arg_objc_instance_method_call && String.equal name "self" + && CType.is_class (CType_decl.qual_type_to_sil_type tenv qual_type) -> + some_class_name stmt_info + | ObjCMessageExpr + ( _ + , [ ImplicitCastExpr + (_, [DeclRefExpr (stmt_info, _, _, _)], _, {cei_cast_kind= `LValueToRValue}) ] + , _ + , {omei_selector= selector} ) + when is_fst_arg_objc_instance_method_call && String.equal selector CFrontend_config.class_method + -> + some_class_name stmt_info + | _ -> + None diff --git a/infer/src/clang/cTrans_utils.mli b/infer/src/clang/cTrans_utils.mli index f3dabfc96..2283185e2 100644 --- a/infer/src/clang/cTrans_utils.mli +++ b/infer/src/clang/cTrans_utils.mli @@ -231,10 +231,6 @@ end (** This module handles the translation of the variable self which is challenging because self is used both as a variable in instance method calls and also as a type in class method calls. *) module Self : sig - exception - SelfClassException of - {class_name: Typ.Name.t; position: Logging.ocaml_pos; source_range: Clang_ast_t.source_range} - val add_self_parameter_for_super_instance : Clang_ast_t.stmt_info -> CContext.t @@ -256,3 +252,7 @@ val mk_fresh_void_id_typ : unit -> Ident.t * Typ.t val mk_fresh_void_return : unit -> (Ident.t * Typ.t) * (Exp.t * Typ.t) val last_or_mk_fresh_void_exp_typ : (Exp.t * Typ.t) list -> Exp.t * Typ.t + +val should_remove_first_param : trans_state -> Clang_ast_t.stmt -> Typ.name option +(** Return a class name when the first parameter should be removed according to its context, for + example, when [self] or [\[x class\]] is given as the first parameter for a class method. *) diff --git a/infer/tests/codetoanalyze/objc/frontend/self_static/Self.m.dot b/infer/tests/codetoanalyze/objc/frontend/self_static/Self.m.dot index 950cfce8a..b839c8f02 100644 --- a/infer/tests/codetoanalyze/objc/frontend/self_static/Self.m.dot +++ b/infer/tests/codetoanalyze/objc/frontend/self_static/Self.m.dot @@ -61,18 +61,18 @@ digraph cfg { "calling_super#A#class.0edc1d1d1c4ade7cd9adaa77e7322ad1_2" [label="2: Exit A.calling_super \n " color=yellow style=filled] -"calling_super#A#class.0edc1d1d1c4ade7cd9adaa77e7322ad1_3" [label="3: Message Call: test_class \n n$18=_fun_C.test_class() [line 82, column 3]\n " shape="box"] +"calling_super#A#class.0edc1d1d1c4ade7cd9adaa77e7322ad1_3" [label="3: Message Call: test_class \n n$15=_fun_C.test_class() [line 82, column 3]\n " shape="box"] "calling_super#A#class.0edc1d1d1c4ade7cd9adaa77e7322ad1_3" -> "calling_super#A#class.0edc1d1d1c4ade7cd9adaa77e7322ad1_2" ; -"class_method_fst_arg_of_class_method_inside_instance_method#A#class.7bda69c598fb7e024d776cec3122e2a6_1" [label="1: Start A.class_method_fst_arg_of_class_method_inside_instance_method\nFormals: \nLocals: 0$?%__sil_tmpSIL_temp_conditional___n$30:NSBundle* stringsBundlePath:NSString* \n " color=yellow style=filled] +"class_method_fst_arg_of_class_method_inside_instance_method#A#class.7bda69c598fb7e024d776cec3122e2a6_1" [label="1: Start A.class_method_fst_arg_of_class_method_inside_instance_method\nFormals: \nLocals: 0$?%__sil_tmpSIL_temp_conditional___n$27:NSBundle* stringsBundlePath:NSString* \n " color=yellow style=filled] "class_method_fst_arg_of_class_method_inside_instance_method#A#class.7bda69c598fb7e024d776cec3122e2a6_1" -> "class_method_fst_arg_of_class_method_inside_instance_method#A#class.7bda69c598fb7e024d776cec3122e2a6_11" ; "class_method_fst_arg_of_class_method_inside_instance_method#A#class.7bda69c598fb7e024d776cec3122e2a6_2" [label="2: Exit A.class_method_fst_arg_of_class_method_inside_instance_method \n " color=yellow style=filled] -"class_method_fst_arg_of_class_method_inside_instance_method#A#class.7bda69c598fb7e024d776cec3122e2a6_3" [label="3: Return Stmt \n n$27=*&#GB$A.class_method_fst_arg_of_class_method_inside_instance_method.bundle:NSBundle* [line 120, column 10]\n *&return:NSBundle*=n$27 [line 120, column 3]\n " shape="box"] +"class_method_fst_arg_of_class_method_inside_instance_method#A#class.7bda69c598fb7e024d776cec3122e2a6_3" [label="3: Return Stmt \n n$24=*&#GB$A.class_method_fst_arg_of_class_method_inside_instance_method.bundle:NSBundle* [line 120, column 10]\n *&return:NSBundle*=n$24 [line 120, column 3]\n " shape="box"] "class_method_fst_arg_of_class_method_inside_instance_method#A#class.7bda69c598fb7e024d776cec3122e2a6_3" -> "class_method_fst_arg_of_class_method_inside_instance_method#A#class.7bda69c598fb7e024d776cec3122e2a6_2" ; @@ -80,32 +80,32 @@ digraph cfg { "class_method_fst_arg_of_class_method_inside_instance_method#A#class.7bda69c598fb7e024d776cec3122e2a6_4" -> "class_method_fst_arg_of_class_method_inside_instance_method#A#class.7bda69c598fb7e024d776cec3122e2a6_10" ; -"class_method_fst_arg_of_class_method_inside_instance_method#A#class.7bda69c598fb7e024d776cec3122e2a6_5" [label="5: Prune (true branch, boolean exp) \n PRUNE(n$29, true); [line 119, column 12]\n " shape="invhouse"] +"class_method_fst_arg_of_class_method_inside_instance_method#A#class.7bda69c598fb7e024d776cec3122e2a6_5" [label="5: Prune (true branch, boolean exp) \n PRUNE(n$26, true); [line 119, column 12]\n " shape="invhouse"] "class_method_fst_arg_of_class_method_inside_instance_method#A#class.7bda69c598fb7e024d776cec3122e2a6_5" -> "class_method_fst_arg_of_class_method_inside_instance_method#A#class.7bda69c598fb7e024d776cec3122e2a6_7" ; -"class_method_fst_arg_of_class_method_inside_instance_method#A#class.7bda69c598fb7e024d776cec3122e2a6_6" [label="6: Prune (false branch, boolean exp) \n PRUNE(!n$29, false); [line 119, column 12]\n " shape="invhouse"] +"class_method_fst_arg_of_class_method_inside_instance_method#A#class.7bda69c598fb7e024d776cec3122e2a6_6" [label="6: Prune (false branch, boolean exp) \n PRUNE(!n$26, false); [line 119, column 12]\n " shape="invhouse"] "class_method_fst_arg_of_class_method_inside_instance_method#A#class.7bda69c598fb7e024d776cec3122e2a6_6" -> "class_method_fst_arg_of_class_method_inside_instance_method#A#class.7bda69c598fb7e024d776cec3122e2a6_8" ; -"class_method_fst_arg_of_class_method_inside_instance_method#A#class.7bda69c598fb7e024d776cec3122e2a6_7" [label="7: ConditionalStmt Branch \n *&0$?%__sil_tmpSIL_temp_conditional___n$30:NSBundle*=n$29 [line 119, column 12]\n " shape="box"] +"class_method_fst_arg_of_class_method_inside_instance_method#A#class.7bda69c598fb7e024d776cec3122e2a6_7" [label="7: ConditionalStmt Branch \n *&0$?%__sil_tmpSIL_temp_conditional___n$27:NSBundle*=n$26 [line 119, column 12]\n " shape="box"] "class_method_fst_arg_of_class_method_inside_instance_method#A#class.7bda69c598fb7e024d776cec3122e2a6_7" -> "class_method_fst_arg_of_class_method_inside_instance_method#A#class.7bda69c598fb7e024d776cec3122e2a6_4" ; -"class_method_fst_arg_of_class_method_inside_instance_method#A#class.7bda69c598fb7e024d776cec3122e2a6_8" [label="8: ConditionalStmt Branch \n n$31=_fun_NSBundle.mainBundle() [line 119, column 59]\n *&0$?%__sil_tmpSIL_temp_conditional___n$30:NSBundle*=n$31 [line 119, column 12]\n " shape="box"] +"class_method_fst_arg_of_class_method_inside_instance_method#A#class.7bda69c598fb7e024d776cec3122e2a6_8" [label="8: ConditionalStmt Branch \n n$28=_fun_NSBundle.mainBundle() [line 119, column 59]\n *&0$?%__sil_tmpSIL_temp_conditional___n$27:NSBundle*=n$28 [line 119, column 12]\n " shape="box"] "class_method_fst_arg_of_class_method_inside_instance_method#A#class.7bda69c598fb7e024d776cec3122e2a6_8" -> "class_method_fst_arg_of_class_method_inside_instance_method#A#class.7bda69c598fb7e024d776cec3122e2a6_4" ; -"class_method_fst_arg_of_class_method_inside_instance_method#A#class.7bda69c598fb7e024d776cec3122e2a6_9" [label="9: BinaryConditionalStmt Init \n n$28=*&stringsBundlePath:NSString* [line 119, column 37]\n n$29=_fun_NSBundle.bundleWithPath:(n$28:NSString*) [line 119, column 12]\n " shape="box"] +"class_method_fst_arg_of_class_method_inside_instance_method#A#class.7bda69c598fb7e024d776cec3122e2a6_9" [label="9: BinaryConditionalStmt Init \n n$25=*&stringsBundlePath:NSString* [line 119, column 37]\n n$26=_fun_NSBundle.bundleWithPath:(n$25:NSString*) [line 119, column 12]\n " shape="box"] "class_method_fst_arg_of_class_method_inside_instance_method#A#class.7bda69c598fb7e024d776cec3122e2a6_9" -> "class_method_fst_arg_of_class_method_inside_instance_method#A#class.7bda69c598fb7e024d776cec3122e2a6_5" ; "class_method_fst_arg_of_class_method_inside_instance_method#A#class.7bda69c598fb7e024d776cec3122e2a6_9" -> "class_method_fst_arg_of_class_method_inside_instance_method#A#class.7bda69c598fb7e024d776cec3122e2a6_6" ; -"class_method_fst_arg_of_class_method_inside_instance_method#A#class.7bda69c598fb7e024d776cec3122e2a6_10" [label="10: BinaryOperatorStmt: Assign \n n$32=*&0$?%__sil_tmpSIL_temp_conditional___n$30:NSBundle* [line 119, column 12]\n *&#GB$A.class_method_fst_arg_of_class_method_inside_instance_method.bundle:NSBundle*=n$32 [line 119, column 3]\n " shape="box"] +"class_method_fst_arg_of_class_method_inside_instance_method#A#class.7bda69c598fb7e024d776cec3122e2a6_10" [label="10: BinaryOperatorStmt: Assign \n n$29=*&0$?%__sil_tmpSIL_temp_conditional___n$27:NSBundle* [line 119, column 12]\n *&#GB$A.class_method_fst_arg_of_class_method_inside_instance_method.bundle:NSBundle*=n$29 [line 119, column 3]\n " shape="box"] "class_method_fst_arg_of_class_method_inside_instance_method#A#class.7bda69c598fb7e024d776cec3122e2a6_10" -> "class_method_fst_arg_of_class_method_inside_instance_method#A#class.7bda69c598fb7e024d776cec3122e2a6_3" ; -"class_method_fst_arg_of_class_method_inside_instance_method#A#class.7bda69c598fb7e024d776cec3122e2a6_11" [label="11: DeclStmt \n VARIABLE_DECLARED(stringsBundlePath:NSString*); [line 116, column 3]\n n$35=_fun_NSBundle.bundleForClass:(sizeof(t=B):unsigned long) [line 117, column 8]\n n$33=_fun_NSString.stringWithUTF8String:(\"Strings\":char* const ) [line 117, column 60]\n n$34=_fun_NSString.stringWithUTF8String:(\"bundle\":char* const ) [line 118, column 60]\n n$36=_fun_NSBundle.pathForResource:ofType:(n$35:NSBundle*,n$33:NSString*,n$34:NSString*) virtual [line 117, column 7]\n *&stringsBundlePath:NSString*=n$36 [line 116, column 3]\n " shape="box"] +"class_method_fst_arg_of_class_method_inside_instance_method#A#class.7bda69c598fb7e024d776cec3122e2a6_11" [label="11: DeclStmt \n VARIABLE_DECLARED(stringsBundlePath:NSString*); [line 116, column 3]\n n$32=_fun_NSBundle.bundleForClass:(sizeof(t=B):unsigned long) [line 117, column 8]\n n$30=_fun_NSString.stringWithUTF8String:(\"Strings\":char* const ) [line 117, column 60]\n n$31=_fun_NSString.stringWithUTF8String:(\"bundle\":char* const ) [line 118, column 60]\n n$33=_fun_NSBundle.pathForResource:ofType:(n$32:NSBundle*,n$30:NSString*,n$31:NSString*) virtual [line 117, column 7]\n *&stringsBundlePath:NSString*=n$33 [line 116, column 3]\n " shape="box"] "class_method_fst_arg_of_class_method_inside_instance_method#A#class.7bda69c598fb7e024d776cec3122e2a6_11" -> "class_method_fst_arg_of_class_method_inside_instance_method#A#class.7bda69c598fb7e024d776cec3122e2a6_9" ; @@ -131,16 +131,16 @@ digraph cfg { "used_in_binary_op:#A(struct objc_class)#class.da9fc6494d494952f5246c6cf4478263_4" -> "used_in_binary_op:#A(struct objc_class)#class.da9fc6494d494952f5246c6cf4478263_2" ; -"used_in_binary_op:#A(struct objc_class)#class.da9fc6494d494952f5246c6cf4478263_5" [label="5: BinaryOperatorStmt: NE \n n$23=*sizeof(t=A):objc_class* [line 94, column 7]\n n$24=*&c:objc_class* [line 94, column 15]\n " shape="box"] +"used_in_binary_op:#A(struct objc_class)#class.da9fc6494d494952f5246c6cf4478263_5" [label="5: BinaryOperatorStmt: NE \n n$20=*sizeof(t=A):objc_class* [line 94, column 7]\n n$21=*&c:objc_class* [line 94, column 15]\n " shape="box"] "used_in_binary_op:#A(struct objc_class)#class.da9fc6494d494952f5246c6cf4478263_5" -> "used_in_binary_op:#A(struct objc_class)#class.da9fc6494d494952f5246c6cf4478263_6" ; "used_in_binary_op:#A(struct objc_class)#class.da9fc6494d494952f5246c6cf4478263_5" -> "used_in_binary_op:#A(struct objc_class)#class.da9fc6494d494952f5246c6cf4478263_7" ; -"used_in_binary_op:#A(struct objc_class)#class.da9fc6494d494952f5246c6cf4478263_6" [label="6: Prune (true branch, if) \n PRUNE((n$23 != n$24), true); [line 94, column 7]\n " shape="invhouse"] +"used_in_binary_op:#A(struct objc_class)#class.da9fc6494d494952f5246c6cf4478263_6" [label="6: Prune (true branch, if) \n PRUNE((n$20 != n$21), true); [line 94, column 7]\n " shape="invhouse"] "used_in_binary_op:#A(struct objc_class)#class.da9fc6494d494952f5246c6cf4478263_6" -> "used_in_binary_op:#A(struct objc_class)#class.da9fc6494d494952f5246c6cf4478263_8" ; -"used_in_binary_op:#A(struct objc_class)#class.da9fc6494d494952f5246c6cf4478263_7" [label="7: Prune (false branch, if) \n PRUNE(!(n$23 != n$24), false); [line 94, column 7]\n " shape="invhouse"] +"used_in_binary_op:#A(struct objc_class)#class.da9fc6494d494952f5246c6cf4478263_7" [label="7: Prune (false branch, if) \n PRUNE(!(n$20 != n$21), false); [line 94, column 7]\n " shape="invhouse"] "used_in_binary_op:#A(struct objc_class)#class.da9fc6494d494952f5246c6cf4478263_7" -> "used_in_binary_op:#A(struct objc_class)#class.da9fc6494d494952f5246c6cf4478263_9" ; @@ -159,7 +159,7 @@ digraph cfg { "call_alloc_instance#A#instance.70a20314d55f22fb46408deb70d9aabb_2" [label="2: Exit A.call_alloc_instance \n " color=yellow style=filled] -"call_alloc_instance#A#instance.70a20314d55f22fb46408deb70d9aabb_3" [label="3: Call alloc \n n$7=_fun___objc_alloc_no_fail(sizeof(t=A):unsigned long) [line 61, column 3]\n " shape="box"] +"call_alloc_instance#A#instance.70a20314d55f22fb46408deb70d9aabb_3" [label="3: Call alloc \n n$6=_fun___objc_alloc_no_fail(sizeof(t=A):unsigned long) [line 61, column 3]\n " shape="box"] "call_alloc_instance#A#instance.70a20314d55f22fb46408deb70d9aabb_3" -> "call_alloc_instance#A#instance.70a20314d55f22fb46408deb70d9aabb_2" ; @@ -170,7 +170,7 @@ digraph cfg { "call_class_instance#A#instance.eb1ae02cd94582eb1fc7cb426794f9f0_2" [label="2: Exit A.call_class_instance \n " color=yellow style=filled] -"call_class_instance#A#instance.eb1ae02cd94582eb1fc7cb426794f9f0_3" [label="3: Message Call: test_class \n n$9=_fun_C.test_class() [line 65, column 3]\n " shape="box"] +"call_class_instance#A#instance.eb1ae02cd94582eb1fc7cb426794f9f0_3" [label="3: Message Call: test_class \n n$7=_fun_C.test_class() [line 65, column 3]\n " shape="box"] "call_class_instance#A#instance.eb1ae02cd94582eb1fc7cb426794f9f0_3" -> "call_class_instance#A#instance.eb1ae02cd94582eb1fc7cb426794f9f0_2" ; @@ -181,7 +181,7 @@ digraph cfg { "call_class_instance_with_class_name#A#instance.1baf88c0fb5549c04909fab0bed63c39_2" [label="2: Exit A.call_class_instance_with_class_name \n " color=yellow style=filled] -"call_class_instance_with_class_name#A#instance.1baf88c0fb5549c04909fab0bed63c39_3" [label="3: Message Call: test_class \n n$10=_fun_A.test_class() [line 69, column 3]\n " shape="box"] +"call_class_instance_with_class_name#A#instance.1baf88c0fb5549c04909fab0bed63c39_3" [label="3: Message Call: test_class \n n$8=_fun_A.test_class() [line 69, column 3]\n " shape="box"] "call_class_instance_with_class_name#A#instance.1baf88c0fb5549c04909fab0bed63c39_3" -> "call_class_instance_with_class_name#A#instance.1baf88c0fb5549c04909fab0bed63c39_2" ; @@ -203,7 +203,7 @@ digraph cfg { "class_method_fst_arg_of_class_method#A#instance.cf9f3087f45649c74ef1f7ca002450f2_2" [label="2: Exit A.class_method_fst_arg_of_class_method \n " color=yellow style=filled] -"class_method_fst_arg_of_class_method#A#instance.cf9f3087f45649c74ef1f7ca002450f2_3" [label="3: Return Stmt \n n$26=_fun_NSBundle.bundleForClass:(sizeof(t=A):unsigned long) [line 111, column 10]\n *&return:NSBundle*=n$26 [line 111, column 3]\n " shape="box"] +"class_method_fst_arg_of_class_method#A#instance.cf9f3087f45649c74ef1f7ca002450f2_3" [label="3: Return Stmt \n n$23=_fun_NSBundle.bundleForClass:(sizeof(t=A):unsigned long) [line 111, column 10]\n *&return:NSBundle*=n$23 [line 111, column 3]\n " shape="box"] "class_method_fst_arg_of_class_method#A#instance.cf9f3087f45649c74ef1f7ca002450f2_3" -> "class_method_fst_arg_of_class_method#A#instance.cf9f3087f45649c74ef1f7ca002450f2_2" ; @@ -225,7 +225,7 @@ digraph cfg { "init#A#instance.eee79aaaddd644404e17691a7e7d809a_2" [label="2: Exit A.init \n " color=yellow style=filled] -"init#A#instance.eee79aaaddd644404e17691a7e7d809a_3" [label="3: Message Call: init \n n$19=*&self:A* [line 86, column 3]\n n$20=_fun_NSObject.init(n$19:A*) [line 86, column 3]\n " shape="box"] +"init#A#instance.eee79aaaddd644404e17691a7e7d809a_3" [label="3: Message Call: init \n n$16=*&self:A* [line 86, column 3]\n n$17=_fun_NSObject.init(n$16:A*) [line 86, column 3]\n " shape="box"] "init#A#instance.eee79aaaddd644404e17691a7e7d809a_3" -> "init#A#instance.eee79aaaddd644404e17691a7e7d809a_2" ; @@ -236,7 +236,7 @@ digraph cfg { "loggerName#A#instance.36b9a42412bcf7d8d3f8397eb2bcb555_2" [label="2: Exit A.loggerName \n " color=yellow style=filled] -"loggerName#A#instance.36b9a42412bcf7d8d3f8397eb2bcb555_3" [label="3: Return Stmt \n n$22=_fun_NSStringFromClass(sizeof(t=A):unsigned long) [line 90, column 10]\n *&return:NSString*=n$22 [line 90, column 3]\n " shape="box"] +"loggerName#A#instance.36b9a42412bcf7d8d3f8397eb2bcb555_3" [label="3: Return Stmt \n n$19=_fun_NSStringFromClass(sizeof(t=A):unsigned long) [line 90, column 10]\n *&return:NSString*=n$19 [line 90, column 3]\n " shape="box"] "loggerName#A#instance.36b9a42412bcf7d8d3f8397eb2bcb555_3" -> "loggerName#A#instance.36b9a42412bcf7d8d3f8397eb2bcb555_2" ; @@ -247,11 +247,11 @@ digraph cfg { "t#A#instance.e31b9a7bced712626784e2860af1a31b_2" [label="2: Exit A.t \n " color=yellow style=filled] -"t#A#instance.e31b9a7bced712626784e2860af1a31b_3" [label="3: Message Call: b_m \n n$12=_fun_B.b_m() [line 74, column 3]\n " shape="box"] +"t#A#instance.e31b9a7bced712626784e2860af1a31b_3" [label="3: Message Call: b_m \n n$9=_fun_B.b_m() [line 74, column 3]\n " shape="box"] "t#A#instance.e31b9a7bced712626784e2860af1a31b_3" -> "t#A#instance.e31b9a7bced712626784e2860af1a31b_2" ; -"t#A#instance.e31b9a7bced712626784e2860af1a31b_4" [label="4: DeclStmt \n VARIABLE_DECLARED(b:B*); [line 73, column 3]\n n$13=_fun___objc_alloc_no_fail(sizeof(t=B):unsigned long) [line 73, column 10]\n n$14=_fun_NSObject.init(n$13:B*) virtual [line 73, column 10]\n *&b:B*=n$14 [line 73, column 3]\n " shape="box"] +"t#A#instance.e31b9a7bced712626784e2860af1a31b_4" [label="4: DeclStmt \n VARIABLE_DECLARED(b:B*); [line 73, column 3]\n n$10=_fun___objc_alloc_no_fail(sizeof(t=B):unsigned long) [line 73, column 10]\n n$11=_fun_NSObject.init(n$10:B*) virtual [line 73, column 10]\n *&b:B*=n$11 [line 73, column 3]\n " shape="box"] "t#A#instance.e31b9a7bced712626784e2860af1a31b_4" -> "t#A#instance.e31b9a7bced712626784e2860af1a31b_3" ; @@ -269,7 +269,7 @@ digraph cfg { "use_class_in_other_ways:#A(class B)#instance.7a96604c2c855db834d214f72f83a306_2" [label="2: Exit A.use_class_in_other_ways: \n " color=yellow style=filled] -"use_class_in_other_ways:#A(class B)#instance.7a96604c2c855db834d214f72f83a306_3" [label="3: Return Stmt \n n$16=*&object:B* [line 78, column 11]\n n$17=_fun_B.isC:(n$16:B*,sizeof(t=A):unsigned long) virtual [line 78, column 10]\n *&return:_Bool=n$17 [line 78, column 3]\n " shape="box"] +"use_class_in_other_ways:#A(class B)#instance.7a96604c2c855db834d214f72f83a306_3" [label="3: Return Stmt \n n$13=*&object:B* [line 78, column 11]\n n$14=_fun_B.isC:(n$13:B*,sizeof(t=A):unsigned long) virtual [line 78, column 10]\n *&return:_Bool=n$14 [line 78, column 3]\n " shape="box"] "use_class_in_other_ways:#A(class B)#instance.7a96604c2c855db834d214f72f83a306_3" -> "use_class_in_other_ways:#A(class B)#instance.7a96604c2c855db834d214f72f83a306_2" ; diff --git a/infer/tests/codetoanalyze/objc/performance/NSString.m b/infer/tests/codetoanalyze/objc/performance/NSString.m index ead87a3da..25be4dab7 100644 --- a/infer/tests/codetoanalyze/objc/performance/NSString.m +++ b/infer/tests/codetoanalyze/objc/performance/NSString.m @@ -123,3 +123,14 @@ NSString* string_by_appending_path_component_linear(NSString* path, bool string_has_prefix_linear(NSString* str, NSString* prefix) { return [str hasPrefix:prefix]; } + +@interface DummyClass : NSObject +@end + +@implementation DummyClass + ++ (void)call_string_by_appending_string_constant_FP { + NSString* s = [NSStringFromClass(self) stringByAppendingString:@"abc"]; +} + +@end diff --git a/infer/tests/codetoanalyze/objc/performance/cost-issues.exp b/infer/tests/codetoanalyze/objc/performance/cost-issues.exp index 8e05a1372..78dbf90b3 100644 --- a/infer/tests/codetoanalyze/objc/performance/cost-issues.exp +++ b/infer/tests/codetoanalyze/objc/performance/cost-issues.exp @@ -81,6 +81,8 @@ codetoanalyze/objc/performance/NSSet.m, nsset_init_with_array_linear, 7 + 3 ⋅ codetoanalyze/objc/performance/NSSet.m, nsset_init_with_set_constant, 6, OnUIThread:false, [] codetoanalyze/objc/performance/NSSet.m, nsset_iterate_linear, 6 + 8 ⋅ (set->elements.length.ub + 1), OnUIThread:false, [{set->elements.length.ub + 1},Loop] codetoanalyze/objc/performance/NSSet.m, nsset_next_object_linear, 5 + 5 ⋅ (set->elements.length.ub + 1), OnUIThread:false, [{set->elements.length.ub + 1},Loop] +codetoanalyze/objc/performance/NSString.m, DummyClass.call_string_by_appending_string_constant_FP, ⊤, OnUIThread:false, [Unbounded loop,Modeled call to NSString.stringByAppendingString:] +codetoanalyze/objc/performance/NSString.m, DummyClass.dealloc, 1, OnUIThread:false, [] codetoanalyze/objc/performance/NSString.m, call_component_separated_by_char_constant, 46, OnUIThread:false, [] codetoanalyze/objc/performance/NSString.m, call_init_with_string_constant, 15, OnUIThread:false, [] codetoanalyze/objc/performance/NSString.m, component_seperated_by_char_linear, 6 + m.length.ub + 3 ⋅ (-1+max(2, m.length.ub)) + 3 ⋅ (max(2, m.length.ub)), OnUIThread:false, [{max(2, m.length.ub)},Loop,{-1+max(2, m.length.ub)},Loop,{m.length.ub},Modeled call to NSString.componentsSeparatedByString:] diff --git a/infer/tests/codetoanalyze/objc/performance/issues.exp b/infer/tests/codetoanalyze/objc/performance/issues.exp index 8baaa5fbe..bbe760e79 100644 --- a/infer/tests/codetoanalyze/objc/performance/issues.exp +++ b/infer/tests/codetoanalyze/objc/performance/issues.exp @@ -12,6 +12,7 @@ codetoanalyze/objc/performance/NSMutableArray.m, nsmarray_set_linear, 2, INTEGER codetoanalyze/objc/performance/NSSet.m, nsset_enumerator_linear, 7, INTEGER_OVERFLOW_L5, no_bucket, ERROR, [,Assignment,,Assignment,Binary operation: ([0, +oo] + [1, set->elements.length.ub + 1]):signed64] codetoanalyze/objc/performance/NSSet.m, nsset_init_constant, 3, CONDITION_ALWAYS_FALSE, no_bucket, WARNING, [Here] codetoanalyze/objc/performance/NSSet.m, nsset_iterate_linear, 3, INTEGER_OVERFLOW_L5, no_bucket, ERROR, [,Assignment,,Assignment,Binary operation: ([0, +oo] + [1, set->elements.length.ub + 1]):signed64] +codetoanalyze/objc/performance/NSString.m, DummyClass.call_string_by_appending_string_constant_FP, 0, INFINITE_EXECUTION_TIME, no_bucket, ERROR, [Unbounded loop,Modeled call to NSString.stringByAppendingString:] codetoanalyze/objc/performance/NSString.m, init_string_constant, 2, CONDITION_ALWAYS_FALSE, no_bucket, WARNING, [Here] codetoanalyze/objc/performance/NSString.m, replace_linear_FP, 0, INFINITE_EXECUTION_TIME, no_bucket, ERROR, [Unbounded loop,Loop] codetoanalyze/objc/performance/NSString.m, replace_linear_FP, 2, INTEGER_OVERFLOW_U5, no_bucket, ERROR, [,Unknown value from: NSString.stringByReplacingOccurrencesOfString:withString:,Binary operation: ([0, +oo] + 1):signed32]