From e46cddb52b29e991104e3b3b53e64678e1142103 Mon Sep 17 00:00:00 2001 From: Andrzej Kotulski Date: Mon, 4 Jul 2016 09:38:42 -0700 Subject: [PATCH] Use mangling in function parameters to encode its position Summary: When clang instantiates template function with argument pack, it will give the same name to all parameters coming from the pack. To avoid name collisions, always add index of argument's position to mangled part of the variable. Seemingly unrelated changes are to make existing tests pass (don't use simple variable name where it matters) Reviewed By: dulmarod Differential Revision: D3503608 fbshipit-source-id: 794093a --- infer/src/clang/ast_expressions.ml | 18 +- infer/src/clang/cFrontend_utils.ml | 19 +- infer/src/clang/cFrontend_utils.mli | 3 +- infer/src/clang/cMethod_signature.ml | 4 +- infer/src/clang/cMethod_signature.mli | 4 +- infer/src/clang/cMethod_trans.ml | 20 +- infer/src/clang/cTrans_models.ml | 13 +- .../cpp/frontend/templates/function_pack.cpp | 26 +++ .../frontend/templates/function_pack.cpp.dot | 201 ++++++++++++++++++ .../cpp/TemplateFunctionPackTest.java | 68 ++++++ infer/tests/frontend/cpp/TemplatesTest.java | 7 + 11 files changed, 349 insertions(+), 34 deletions(-) create mode 100644 infer/tests/codetoanalyze/cpp/frontend/templates/function_pack.cpp create mode 100644 infer/tests/codetoanalyze/cpp/frontend/templates/function_pack.cpp.dot create mode 100644 infer/tests/endtoend/cpp/TemplateFunctionPackTest.java 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"); + } }