diff --git a/infer/src/clang/ast_expressions.ml b/infer/src/clang/ast_expressions.ml index d2f58c6e6..8f63d9e27 100644 --- a/infer/src/clang/ast_expressions.ml +++ b/infer/src/clang/ast_expressions.ml @@ -308,13 +308,13 @@ let translate_dispatch_function stmt_info stmt_list n = | _ -> assert false (* Create declaration statement: tp vname = iexp *) -let make_DeclStmt stmt_info di tp vname iexp = +let make_DeclStmt stmt_info di tp vname old_vdi iexp = let init_expr_opt, init_expr_l = match iexp with | Some iexp' -> let ie = create_implicit_cast_expr stmt_info [iexp'] tp `IntegralCast in Some ie, [ie] | None -> None, [] in - let var_decl_info = { empty_var_decl_info with Clang_ast_t.vdi_init_expr = init_expr_opt } in + let var_decl_info = { old_vdi with Clang_ast_t.vdi_init_expr = init_expr_opt } in let di = fresh_decl_info di in let var_decl = Clang_ast_t.VarDecl (di, vname, tp, var_decl_info) in Clang_ast_t.DeclStmt (stmt_info, init_expr_l, [var_decl]) @@ -393,16 +393,18 @@ let translate_block_enumerate block_name stmt_info stmt_list ei = let build_idx_decl pidx = match pidx with - | Clang_ast_t.ParmVarDecl (di_idx, name_idx, tp_idx, _) -> + | Clang_ast_t.ParmVarDecl (di_idx, name_idx, tp_idx, vdi) -> let zero = create_integer_literal "0" in (* tp_idx idx = 0; *) - let idx_decl_stmt = make_DeclStmt (fresh_stmt_info stmt_info) di_idx tp_idx name_idx (Some zero) in + let idx_decl_stmt = make_DeclStmt (fresh_stmt_info stmt_info) di_idx tp_idx + name_idx vdi (Some zero) in let idx_ei = make_expr_info tp_idx in let pointer = di_idx.Clang_ast_t.di_pointer in let idx_decl_ref = make_decl_ref_tp `Var pointer name_idx false tp_idx in let idx_drei = make_decl_ref_expr_info idx_decl_ref in let idx_decl_ref_exp = make_decl_ref_exp stmt_info idx_ei idx_drei in - let idx_cast = create_implicit_cast_expr (fresh_stmt_info stmt_info) [idx_decl_ref_exp] tp_idx `LValueToRValue in + let idx_cast = create_implicit_cast_expr (fresh_stmt_info stmt_info) [idx_decl_ref_exp] + tp_idx `LValueToRValue in idx_decl_stmt, idx_decl_ref_exp, idx_cast, tp_idx | _ -> assert false in @@ -415,7 +417,7 @@ let translate_block_enumerate block_name stmt_info stmt_list ei = (* build statement BOOL *stop = malloc(sizeof(BOOL)); *) let build_stop pstop = match pstop with - | Clang_ast_t.ParmVarDecl (di, name, tp, _) -> + | Clang_ast_t.ParmVarDecl (di, name, tp, vdi) -> let tp_fun = create_void_unsigned_long_type in let type_opt = Some create_BOOL_type in let parameter = Clang_ast_t.UnaryExprOrTypeTraitExpr @@ -427,7 +429,7 @@ let translate_block_enumerate block_name stmt_info stmt_list ei = let malloc_name = Ast_utils.make_name_decl CFrontend_config.malloc in let malloc = create_call stmt_info pointer malloc_name tp_fun [parameter] in let init_exp = create_implicit_cast_expr (fresh_stmt_info stmt_info) [malloc] tp `BitCast in - make_DeclStmt (fresh_stmt_info stmt_info) di tp name (Some init_exp) + make_DeclStmt (fresh_stmt_info stmt_info) di tp name vdi (Some init_exp) | _ -> assert false in (* BOOL *stop =NO; *) @@ -588,7 +590,7 @@ let trans_negation_with_conditional stmt_info expr_info stmt_list = let create_assume_not_null_call decl_info var_name var_type = let stmt_info = stmt_info_with_fresh_pointer (make_stmt_info decl_info) in let boi = { Clang_ast_t.boi_kind = `NE } in - let decl_ptr = Ast_utils.get_invalid_pointer () in + let decl_ptr = decl_info.Clang_ast_t.di_pointer in let decl_ref = make_decl_ref_tp `Var decl_ptr var_name false var_type in let stmt_info_var = dummy_stmt_info () in let decl_ref_info = make_decl_ref_expr_info decl_ref in diff --git a/infer/src/clang/cFrontend_utils.ml b/infer/src/clang/cFrontend_utils.ml index 230267cf9..4b0e8deb4 100644 --- a/infer/src/clang/cFrontend_utils.ml +++ b/infer/src/clang/cFrontend_utils.ml @@ -618,19 +618,24 @@ struct Procname.ObjC_Cpp (Procname.objc_cpp class_name method_name type_name_crc) - let get_var_name_string name_info var_decl_info = + let get_var_name_mangled name_info var_decl_info = let clang_name = Ast_utils.get_qualified_name name_info in - match clang_name, var_decl_info.Clang_ast_t.vdi_parm_index_in_function with - | "", Some index -> "__param_" ^ string_of_int index - | "", None -> assert false - | _ -> clang_name + let param_idx_opt = var_decl_info.Clang_ast_t.vdi_parm_index_in_function in + let name_string = + match clang_name, param_idx_opt with + | "", Some index -> "__param_" ^ string_of_int index + | "", None -> assert false + | _ -> clang_name in + let mangled = match param_idx_opt with + | Some index -> Mangled.mangled name_string (string_of_int index) + | None -> Mangled.from_string name_string in + name_string, mangled let mk_sil_var name decl_info_type_ptr_opt procname outer_procname = let name_string = Ast_utils.get_qualified_name name in match decl_info_type_ptr_opt with | Some (decl_info, type_ptr, var_decl_info, should_be_mangled) -> - let name_string = get_var_name_string name var_decl_info in - let simple_name = Mangled.from_string name_string in + let name_string, simple_name = get_var_name_mangled name var_decl_info in if var_decl_info.Clang_ast_t.vdi_is_global then let global_mangled_name = if var_decl_info.Clang_ast_t.vdi_is_static_local then diff --git a/infer/src/clang/cFrontend_utils.mli b/infer/src/clang/cFrontend_utils.mli index 1ab5bec24..960972c09 100644 --- a/infer/src/clang/cFrontend_utils.mli +++ b/infer/src/clang/cFrontend_utils.mli @@ -206,7 +206,8 @@ sig val mk_class_field_name : Clang_ast_t.named_decl_info -> Ident.fieldname - val get_var_name_string : Clang_ast_t.named_decl_info -> Clang_ast_t.var_decl_info -> string + val get_var_name_mangled : Clang_ast_t.named_decl_info -> Clang_ast_t.var_decl_info -> + (string * Mangled.t) val mk_sil_var : Clang_ast_t.named_decl_info -> var_info option -> Procname.t -> Procname.t -> Pvar.t diff --git a/infer/src/clang/cMethod_signature.ml b/infer/src/clang/cMethod_signature.ml index 8e52b5eac..0c33421bd 100644 --- a/infer/src/clang/cMethod_signature.ml +++ b/infer/src/clang/cMethod_signature.ml @@ -14,7 +14,7 @@ open! Utils type method_signature = { mutable name : Procname.t; - args : (string * Clang_ast_t.type_ptr) list; + args : (Mangled.t * Clang_ast_t.type_ptr) list; ret_type : Clang_ast_t.type_ptr; attributes : Clang_ast_t.attribute list; loc : Clang_ast_t.source_range; @@ -99,7 +99,7 @@ let replace_name_ms ms name = let ms_to_string ms = "Method " ^ (Procname.to_string ms.name) ^ " " ^ IList.to_string - (fun (s1, s2) -> s1 ^ ", " ^ (Clang_ast_j.string_of_type_ptr s2)) + (fun (s1, s2) -> (Mangled.to_string s1) ^ ", " ^ (Clang_ast_j.string_of_type_ptr s2)) ms.args ^ "->" ^ (Clang_ast_j.string_of_type_ptr ms.ret_type) ^ " " ^ Clang_ast_j.string_of_source_range ms.loc diff --git a/infer/src/clang/cMethod_signature.mli b/infer/src/clang/cMethod_signature.mli index 8c61d8f47..9c9817626 100644 --- a/infer/src/clang/cMethod_signature.mli +++ b/infer/src/clang/cMethod_signature.mli @@ -19,7 +19,7 @@ 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 + (Mangled.t * Clang_ast_t.type_ptr) list val ms_get_ret_type : method_signature -> Clang_ast_t.type_ptr @@ -43,7 +43,7 @@ val ms_is_getter : method_signature -> bool val ms_is_setter : method_signature -> bool -val make_ms : Procname.t -> (string * Clang_ast_t.type_ptr) list -> Clang_ast_t.type_ptr +val make_ms : Procname.t -> (Mangled.t * Clang_ast_t.type_ptr) list -> Clang_ast_t.type_ptr -> Clang_ast_t.attribute list -> Clang_ast_t.source_range -> bool -> ?is_cpp_virtual:bool -> Config.clang_lang -> Clang_ast_t.pointer option -> Clang_ast_t.pointer option -> Typ.t option -> method_signature diff --git a/infer/src/clang/cMethod_trans.ml b/infer/src/clang/cMethod_trans.ml index f4cd67fde..b9ffb1180 100644 --- a/infer/src/clang/cMethod_trans.ml +++ b/infer/src/clang/cMethod_trans.ml @@ -54,10 +54,10 @@ let get_class_param function_method_decl_info = match function_method_decl_info with | Cpp_Meth_decl_info (_, _, class_name, _) -> let class_type = Ast_expressions.create_class_type (class_name, `CPP) in - [(CFrontend_config.this, class_type)] + [(Mangled.from_string CFrontend_config.this, class_type)] | ObjC_Meth_decl_info (_, class_name) -> let class_type = Ast_expressions.create_class_type (class_name, `OBJC) in - [(CFrontend_config.self, class_type)] + [(Mangled.from_string CFrontend_config.self, class_type)] | _ -> [] else [] @@ -77,7 +77,8 @@ let get_return_param tenv function_method_decl_info = let return_type_ptr = get_original_return_type function_method_decl_info in let return_typ = CTypes_decl.type_ptr_to_sil_type tenv return_type_ptr in if should_add_return_param return_typ ~is_objc_method then - [(CFrontend_config.return_param, Ast_expressions.create_pointer_type return_type_ptr)] + [(Mangled.from_string CFrontend_config.return_param, + Ast_expressions.create_pointer_type return_type_ptr)] else [] @@ -109,13 +110,13 @@ let get_parameters tenv function_method_decl_info = let par_to_ms_par par = match par with | Clang_ast_t.ParmVarDecl (_, name_info, type_ptr, var_decl_info) -> - let name = General_utils.get_var_name_string name_info var_decl_info in + let _, mangled = General_utils.get_var_name_mangled name_info var_decl_info in let param_typ = CTypes_decl.type_ptr_to_sil_type tenv type_ptr in let type_ptr' = match param_typ with | Typ.Tstruct _ when General_utils.is_cpp_translation Config.clang_lang -> Ast_expressions.create_reference_type type_ptr | _ -> type_ptr in - (name, type_ptr') + (mangled, type_ptr') | _ -> assert false in let pars = IList.map par_to_ms_par (get_param_decls function_method_decl_info) in get_class_param function_method_decl_info @ pars @ get_return_param tenv function_method_decl_info @@ -303,18 +304,18 @@ let get_formal_parameters tenv ms = let rec defined_parameters pl = match pl with | [] -> [] - | (name, raw_type):: pl' -> + | (mangled, raw_type):: pl' -> let should_add_pointer name ms = let is_objc_self = name = CFrontend_config.self && CMethod_signature.ms_get_lang ms = Config.OBJC in let is_cxx_this = name = CFrontend_config.this && CMethod_signature.ms_get_lang ms = Config.CPP in (is_objc_self && CMethod_signature.ms_is_instance ms) || is_cxx_this in - let tp = if should_add_pointer name ms then + let tp = if should_add_pointer (Mangled.to_string mangled) ms then (Ast_expressions.create_pointer_type raw_type) else raw_type in let typ = CTypes_decl.type_ptr_to_sil_type tenv tp in - (Mangled.from_string name, typ):: defined_parameters pl' in + (mangled, typ):: defined_parameters pl' in defined_parameters (CMethod_signature.ms_get_args ms) let get_return_type tenv ms = @@ -348,7 +349,8 @@ let sil_method_annotation_of_args args : Typ.method_annotation = let mk_annot param_name annot_name = let annot = { Typ.class_name = annot_name; Typ.parameters = [param_name]; } in annot, default_visibility in - let arg_to_sil_annot (arg_name, type_ptr) acc = + let arg_to_sil_annot (arg_mangled, type_ptr) acc = + let arg_name = Mangled.to_string arg_mangled in if CFrontend_utils.Ast_utils.is_type_nullable type_ptr then [mk_annot arg_name Annotations.nullable] :: acc else Typ.item_annotation_empty::acc in diff --git a/infer/src/clang/cTrans_models.ml b/infer/src/clang/cTrans_models.ml index 2dc912894..ba7327371 100644 --- a/infer/src/clang/cTrans_models.ml +++ b/infer/src/clang/cTrans_models.ml @@ -143,8 +143,9 @@ let get_predefined_ms_stringWithUTF8String class_name method_name mk_procname la class_name = CFrontend_config.nsstring_cl && method_name = CFrontend_config.string_with_utf8_m in let id_type = Ast_expressions.create_id_type in + let args = [(Mangled.from_string "x", Ast_expressions.create_char_star_type)] in get_predefined_ms_method condition class_name method_name Procname.Class_objc_method - mk_procname lang [("x", Ast_expressions.create_char_star_type)] id_type [] None + mk_procname lang args id_type [] None let get_predefined_ms_retain_release method_name mk_procname lang = let condition = is_retain_or_release method_name in @@ -153,7 +154,7 @@ let get_predefined_ms_retain_release method_name mk_procname lang = then Ast_expressions.create_id_type else Ast_expressions.create_void_type in let class_name = CFrontend_config.nsobject_cl in let class_type = Ast_expressions.create_class_type (class_name, `OBJC) in - let args = [(CFrontend_config.self, class_type)] in + let args = [(Mangled.from_string CFrontend_config.self, class_type)] in get_predefined_ms_method condition class_name method_name Procname.Instance_objc_method mk_procname lang args return_type [] (get_builtinname method_name) @@ -163,7 +164,7 @@ let get_predefined_ms_autoreleasepool_init class_name method_name mk_procname la && class_name = CFrontend_config.nsautorelease_pool_cl in let class_type = Ast_expressions.create_class_type (class_name, `OBJC) in get_predefined_ms_method condition class_name method_name Procname.Instance_objc_method - mk_procname lang [(CFrontend_config.self, class_type)] + mk_procname lang [(Mangled.from_string CFrontend_config.self, class_type)] Ast_expressions.create_void_type [] None let get_predefined_ms_nsautoreleasepool_release class_name method_name mk_procname lang = @@ -171,15 +172,17 @@ let get_predefined_ms_nsautoreleasepool_release class_name method_name mk_procna (method_name = CFrontend_config.release || method_name = CFrontend_config.drain) && class_name = CFrontend_config.nsautorelease_pool_cl in let class_type = Ast_expressions.create_class_type (class_name, `OBJC) in + let args = [(Mangled.from_string CFrontend_config.self, class_type)] in get_predefined_ms_method condition class_name method_name Procname.Instance_objc_method - mk_procname lang [(CFrontend_config.self, class_type)] Ast_expressions.create_void_type + mk_procname lang args Ast_expressions.create_void_type [] (Some ModelBuiltins.__objc_release_autorelease_pool) let get_predefined_ms_is_kind_of_class class_name method_name mk_procname lang = let condition = method_name = CFrontend_config.is_kind_of_class in let class_type = Ast_expressions.create_class_type (class_name, `OBJC) in + let args = [(Mangled.from_string CFrontend_config.self, class_type)] in get_predefined_ms_method condition class_name method_name Procname.Instance_objc_method - mk_procname lang [(CFrontend_config.self, class_type)] Ast_expressions.create_BOOL_type + mk_procname lang args Ast_expressions.create_BOOL_type [] (Some ModelBuiltins.__instanceof) let get_predefined_model_method_signature class_name method_name mk_procname lang = diff --git a/infer/tests/codetoanalyze/cpp/frontend/templates/function_pack.cpp b/infer/tests/codetoanalyze/cpp/frontend/templates/function_pack.cpp new file mode 100644 index 000000000..c17a03a03 --- /dev/null +++ b/infer/tests/codetoanalyze/cpp/frontend/templates/function_pack.cpp @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2016 - present Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +// div(a,b,c,d) = 1/a + 1/b + 1/c + 1/d; +int div(int d) { return 1 / d; } +template +int div(int v, Args... args) { + return 1 / v + div(args...); +} + +int div0_1arg() { return div(0); } + +int div0_3args1() { return div(0, 2, 3); } +int div0_3args2() { return div(1, 0, 3); } +int div0_3args3() { return div(1, 2, 0); } +int div0_3args4() { return div(1, 0, 0); } +int div0_10args() { return div(1, 2, 3, 4, 5, 6, 7, 0, 9, 10); } + +int no_div0_3_args() { return div(1, 2, 3); } +int no_div0_10args() { return div(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); } diff --git a/infer/tests/codetoanalyze/cpp/frontend/templates/function_pack.cpp.dot b/infer/tests/codetoanalyze/cpp/frontend/templates/function_pack.cpp.dot new file mode 100644 index 000000000..fcacdb549 --- /dev/null +++ b/infer/tests/codetoanalyze/cpp/frontend/templates/function_pack.cpp.dot @@ -0,0 +1,201 @@ +/* @generated */ +digraph iCFG { +54 [label="54: Return Stmt \n n$0=_fun_div<5ae447456b906d06>(1:int ,2:int ,3:int ,4:int ,5:int ,6:int ,7:int ,8:int ,9:int ,10:int ) [line 26]\n *&return:int =n$0 [line 26]\n " shape="box"] + + + 54 -> 53 ; +53 [label="53: Exit no_div0_10args \n " color=yellow style=filled] + + +52 [label="52: Start no_div0_10args\nFormals: \nLocals: \n DECLARE_LOCALS(&return); [line 26]\n " color=yellow style=filled] + + + 52 -> 54 ; +51 [label="51: Return Stmt \n n$0=_fun_div(1:int ,2:int ,3:int ) [line 25]\n *&return:int =n$0 [line 25]\n " shape="box"] + + + 51 -> 50 ; +50 [label="50: Exit no_div0_3_args \n " color=yellow style=filled] + + +49 [label="49: Start no_div0_3_args\nFormals: \nLocals: \n DECLARE_LOCALS(&return); [line 25]\n " color=yellow style=filled] + + + 49 -> 51 ; +48 [label="48: Return Stmt \n n$0=_fun_div<5ae447456b906d06>(1:int ,2:int ,3:int ,4:int ,5:int ,6:int ,7:int ,0:int ,9:int ,10:int ) [line 23]\n *&return:int =n$0 [line 23]\n " shape="box"] + + + 48 -> 47 ; +47 [label="47: Exit div0_10args \n " color=yellow style=filled] + + +46 [label="46: Start div0_10args\nFormals: \nLocals: \n DECLARE_LOCALS(&return); [line 23]\n " color=yellow style=filled] + + + 46 -> 48 ; +45 [label="45: Return Stmt \n n$0=_fun_div(1:int ,0:int ,0:int ) [line 22]\n *&return:int =n$0 [line 22]\n " shape="box"] + + + 45 -> 44 ; +44 [label="44: Exit div0_3args4 \n " color=yellow style=filled] + + +43 [label="43: Start div0_3args4\nFormals: \nLocals: \n DECLARE_LOCALS(&return); [line 22]\n " color=yellow style=filled] + + + 43 -> 45 ; +42 [label="42: Return Stmt \n n$0=_fun_div(1:int ,2:int ,0:int ) [line 21]\n *&return:int =n$0 [line 21]\n " shape="box"] + + + 42 -> 41 ; +41 [label="41: Exit div0_3args3 \n " color=yellow style=filled] + + +40 [label="40: Start div0_3args3\nFormals: \nLocals: \n DECLARE_LOCALS(&return); [line 21]\n " color=yellow style=filled] + + + 40 -> 42 ; +39 [label="39: Return Stmt \n n$0=_fun_div(1:int ,0:int ,3:int ) [line 20]\n *&return:int =n$0 [line 20]\n " shape="box"] + + + 39 -> 38 ; +38 [label="38: Exit div0_3args2 \n " color=yellow style=filled] + + +37 [label="37: Start div0_3args2\nFormals: \nLocals: \n DECLARE_LOCALS(&return); [line 20]\n " color=yellow style=filled] + + + 37 -> 39 ; +36 [label="36: Return Stmt \n n$0=_fun_div(0:int ,2:int ,3:int ) [line 19]\n *&return:int =n$0 [line 19]\n " shape="box"] + + + 36 -> 35 ; +35 [label="35: Exit div0_3args1 \n " color=yellow style=filled] + + +34 [label="34: Start div0_3args1\nFormals: \nLocals: \n DECLARE_LOCALS(&return); [line 19]\n " color=yellow style=filled] + + + 34 -> 36 ; +33 [label="33: Return Stmt \n n$0=_fun_div(0:int ) [line 17]\n *&return:int =n$0 [line 17]\n " shape="box"] + + + 33 -> 32 ; +32 [label="32: Exit div0_1arg \n " color=yellow style=filled] + + +31 [label="31: Start div0_1arg\nFormals: \nLocals: \n DECLARE_LOCALS(&return); [line 17]\n " color=yellow style=filled] + + + 31 -> 33 ; +30 [label="30: Return Stmt \n n$0=*&v:int [line 14]\n n$1=*&args:int [line 14]\n n$2=*&args:int [line 14]\n n$3=*&args:int [line 14]\n n$4=*&args:int [line 14]\n n$5=*&args:int [line 14]\n n$6=*&args:int [line 14]\n n$7=*&args:int [line 14]\n n$8=*&args:int [line 14]\n n$9=*&args:int [line 14]\n n$10=_fun_div(n$1:int ,n$2:int ,n$3:int ,n$4:int ,n$5:int ,n$6:int ,n$7:int ,n$8:int ,n$9:int ) [line 14]\n *&return:int =((1 / n$0) + n$10) [line 14]\n " shape="box"] + + + 30 -> 11 ; +29 [label="29: Return Stmt \n n$0=*&v:int [line 14]\n n$1=*&args:int [line 14]\n n$2=*&args:int [line 14]\n n$3=*&args:int [line 14]\n n$4=*&args:int [line 14]\n n$5=*&args:int [line 14]\n n$6=*&args:int [line 14]\n n$7=*&args:int [line 14]\n n$8=*&args:int [line 14]\n n$9=_fun_div(n$1:int ,n$2:int ,n$3:int ,n$4:int ,n$5:int ,n$6:int ,n$7:int ,n$8:int ) [line 14]\n *&return:int =((1 / n$0) + n$9) [line 14]\n " shape="box"] + + + 29 -> 13 ; +28 [label="28: Return Stmt \n n$0=*&v:int [line 14]\n n$1=*&args:int [line 14]\n n$2=*&args:int [line 14]\n n$3=*&args:int [line 14]\n n$4=*&args:int [line 14]\n n$5=*&args:int [line 14]\n n$6=*&args:int [line 14]\n n$7=*&args:int [line 14]\n n$8=_fun_div(n$1:int ,n$2:int ,n$3:int ,n$4:int ,n$5:int ,n$6:int ,n$7:int ) [line 14]\n *&return:int =((1 / n$0) + n$8) [line 14]\n " shape="box"] + + + 28 -> 15 ; +27 [label="27: Return Stmt \n n$0=*&v:int [line 14]\n n$1=*&args:int [line 14]\n n$2=*&args:int [line 14]\n n$3=*&args:int [line 14]\n n$4=*&args:int [line 14]\n n$5=*&args:int [line 14]\n n$6=*&args:int [line 14]\n n$7=_fun_div(n$1:int ,n$2:int ,n$3:int ,n$4:int ,n$5:int ,n$6:int ) [line 14]\n *&return:int =((1 / n$0) + n$7) [line 14]\n " shape="box"] + + + 27 -> 17 ; +26 [label="26: Return Stmt \n n$0=*&v:int [line 14]\n n$1=*&args:int [line 14]\n n$2=*&args:int [line 14]\n n$3=*&args:int [line 14]\n n$4=*&args:int [line 14]\n n$5=*&args:int [line 14]\n n$6=_fun_div(n$1:int ,n$2:int ,n$3:int ,n$4:int ,n$5:int ) [line 14]\n *&return:int =((1 / n$0) + n$6) [line 14]\n " shape="box"] + + + 26 -> 19 ; +25 [label="25: Return Stmt \n n$0=*&v:int [line 14]\n n$1=*&args:int [line 14]\n n$2=*&args:int [line 14]\n n$3=*&args:int [line 14]\n n$4=*&args:int [line 14]\n n$5=_fun_div(n$1:int ,n$2:int ,n$3:int ,n$4:int ) [line 14]\n *&return:int =((1 / n$0) + n$5) [line 14]\n " shape="box"] + + + 25 -> 21 ; +24 [label="24: Return Stmt \n n$0=*&v:int [line 14]\n n$1=*&args:int [line 14]\n n$2=*&args:int [line 14]\n n$3=*&args:int [line 14]\n n$4=_fun_div(n$1:int ,n$2:int ,n$3:int ) [line 14]\n *&return:int =((1 / n$0) + n$4) [line 14]\n " shape="box"] + + + 24 -> 23 ; +23 [label="23: Exit div \n " color=yellow style=filled] + + +22 [label="22: Start div\nFormals: v:int args:int args:int args:int \nLocals: \n DECLARE_LOCALS(&return); [line 13]\n " color=yellow style=filled] + + + 22 -> 24 ; +21 [label="21: Exit div \n " color=yellow style=filled] + + +20 [label="20: Start div\nFormals: v:int args:int args:int args:int args:int \nLocals: \n DECLARE_LOCALS(&return); [line 13]\n " color=yellow style=filled] + + + 20 -> 25 ; +19 [label="19: Exit div \n " color=yellow style=filled] + + +18 [label="18: Start div\nFormals: v:int args:int args:int args:int args:int args:int \nLocals: \n DECLARE_LOCALS(&return); [line 13]\n " color=yellow style=filled] + + + 18 -> 26 ; +17 [label="17: Exit div \n " color=yellow style=filled] + + +16 [label="16: Start div\nFormals: v:int args:int args:int args:int args:int args:int args:int \nLocals: \n DECLARE_LOCALS(&return); [line 13]\n " color=yellow style=filled] + + + 16 -> 27 ; +15 [label="15: Exit div \n " color=yellow style=filled] + + +14 [label="14: Start div\nFormals: v:int args:int args:int args:int args:int args:int args:int args:int \nLocals: \n DECLARE_LOCALS(&return); [line 13]\n " color=yellow style=filled] + + + 14 -> 28 ; +13 [label="13: Exit div \n " color=yellow style=filled] + + +12 [label="12: Start div\nFormals: v:int args:int args:int args:int args:int args:int args:int args:int args:int \nLocals: \n DECLARE_LOCALS(&return); [line 13]\n " color=yellow style=filled] + + + 12 -> 29 ; +11 [label="11: Exit div<5ae447456b906d06> \n " color=yellow style=filled] + + +10 [label="10: Start div<5ae447456b906d06>\nFormals: v:int args:int args:int args:int args:int args:int args:int args:int args:int args:int \nLocals: \n DECLARE_LOCALS(&return); [line 13]\n " color=yellow style=filled] + + + 10 -> 30 ; +9 [label="9: Return Stmt \n n$0=*&v:int [line 14]\n n$1=*&args:int [line 14]\n n$2=*&args:int [line 14]\n n$3=_fun_div(n$1:int ,n$2:int ) [line 14]\n *&return:int =((1 / n$0) + n$3) [line 14]\n " shape="box"] + + + 9 -> 5 ; +8 [label="8: Return Stmt \n n$0=*&v:int [line 14]\n n$1=*&args:int [line 14]\n n$2=_fun_div(n$1:int ) [line 14]\n *&return:int =((1 / n$0) + n$2) [line 14]\n " shape="box"] + + + 8 -> 7 ; +7 [label="7: Exit div \n " color=yellow style=filled] + + +6 [label="6: Start div\nFormals: v:int args:int \nLocals: \n DECLARE_LOCALS(&return); [line 13]\n " color=yellow style=filled] + + + 6 -> 8 ; +5 [label="5: Exit div \n " color=yellow style=filled] + + +4 [label="4: Start div\nFormals: v:int args:int args:int \nLocals: \n DECLARE_LOCALS(&return); [line 13]\n " color=yellow style=filled] + + + 4 -> 9 ; +3 [label="3: Return Stmt \n n$0=*&d:int [line 11]\n *&return:int =(1 / n$0) [line 11]\n " shape="box"] + + + 3 -> 2 ; +2 [label="2: Exit div \n " color=yellow style=filled] + + +1 [label="1: Start div\nFormals: d:int \nLocals: \n DECLARE_LOCALS(&return); [line 11]\n " color=yellow style=filled] + + + 1 -> 3 ; +} diff --git a/infer/tests/endtoend/cpp/TemplateFunctionPackTest.java b/infer/tests/endtoend/cpp/TemplateFunctionPackTest.java new file mode 100644 index 000000000..69646561d --- /dev/null +++ b/infer/tests/endtoend/cpp/TemplateFunctionPackTest.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2016 - present Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +package endtoend.cpp; + +import static org.hamcrest.MatcherAssert.assertThat; +import static utils.matchers.ResultContainsExactly.containsExactly; + +import com.google.common.collect.ImmutableList; + +import org.junit.BeforeClass; +import org.junit.ClassRule; +import org.junit.Test; + +import java.io.IOException; + +import utils.DebuggableTemporaryFolder; +import utils.InferException; +import utils.InferResults; +import utils.InferRunner; + +public class TemplateFunctionPackTest { + + public static final String FILE = + "infer/tests/codetoanalyze/cpp/frontend/templates/function_pack.cpp"; + + private static ImmutableList inferCmd; + + public static final String DIVIDE_BY_ZERO = "DIVIDE_BY_ZERO"; + + @ClassRule + public static DebuggableTemporaryFolder folder = + new DebuggableTemporaryFolder(); + + @BeforeClass + public static void runInfer() throws InterruptedException, IOException { + inferCmd = InferRunner.createCPPInferCommand(folder, FILE); + } + + @Test + public void whenInferRunsOnDiv0MethodsErrorIsFound() + throws InterruptedException, IOException, InferException { + InferResults inferResults = InferRunner.runInferCPP(inferCmd); + String[] procedures = { + "div0_1arg", + "div0_3args1", + "div0_3args2", + "div0_3args3", + "div0_3args4", + "div0_10args", + }; + assertThat( + "Results should contain the expected divide by zero", + inferResults, + containsExactly( + DIVIDE_BY_ZERO, + FILE, + procedures + ) + ); + } +} diff --git a/infer/tests/frontend/cpp/TemplatesTest.java b/infer/tests/frontend/cpp/TemplatesTest.java index 2a79119dc..76f9b8523 100644 --- a/infer/tests/frontend/cpp/TemplatesTest.java +++ b/infer/tests/frontend/cpp/TemplatesTest.java @@ -58,4 +58,11 @@ public class TemplatesTest { throws InterruptedException, IOException, InferException { frontendTest("sizeof_pack.cpp"); } + + + @Test + public void testFunctionPackDotFilesMatch() + throws InterruptedException, IOException, InferException { + frontendTest("function_pack.cpp"); + } }