diff --git a/infer/models/cpp/src/type_info.cpp b/infer/models/cpp/src/type_info.cpp new file mode 100644 index 000000000..e0d1a810f --- /dev/null +++ b/infer/models/cpp/src/type_info.cpp @@ -0,0 +1,35 @@ +/* + * 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. + */ + +namespace std { + +class type_info { + + type_info& operator=(const type_info&); + type_info(const type_info&); + + protected: + const char* __type_name; + + explicit type_info(const char* __n) : __type_name(__n) {} + + public: + virtual ~type_info(); + + const char* name() const noexcept { return __type_name; } + + bool operator==(const type_info& __arg) const noexcept { + return __type_name == __arg.__type_name; + } + + bool operator!=(const type_info& __arg) const noexcept { + return !operator==(__arg); + } +}; +} diff --git a/infer/src/backend/symExec.ml b/infer/src/backend/symExec.ml index 8279fc544..cfface97b 100644 --- a/infer/src/backend/symExec.ml +++ b/infer/src/backend/symExec.ml @@ -2445,6 +2445,30 @@ module ModelBuiltins = struct [(prop_alloc, path); (prop_null, path)] else [(prop_alloc, path)] + let execute___cxx_typeid ({ Builtin.pdesc; tenv; prop_; args; loc} as r) + : Builtin.ret_typ = + match args with + | type_info_exp :: rest -> + (let res = execute_alloc Sil.Mnew false { r with args = [type_info_exp] } in + match rest with + | [(field_exp, _); (lexp, typ)] -> + let pname = Cfg.Procdesc.get_proc_name pdesc in + let n_lexp, prop = exp_norm_check_arith pname prop_ lexp in + let typ = + try + let hpred = IList.find (function + | Sil.Hpointsto (e, _, _) -> Sil.exp_equal e n_lexp + | _ -> false) (Prop.get_sigma prop) in + match hpred with + | Sil.Hpointsto (_, _, Sil.Sizeof (dynamic_type, _)) -> dynamic_type + | _ -> typ + with Not_found -> typ in + let typ_string = Sil.typ_to_string typ in + let set_instr = Sil.Set (field_exp, Sil.Tvoid, Sil.Const (Sil.Cstr typ_string), loc) in + sym_exec_generated true tenv pdesc [set_instr] res + | _ -> res) + | _ -> raise (Exceptions.Wrong_argument_number __POS__) + let execute_pthread_create { Builtin.pdesc; tenv; prop_; path; ret_ids; args; loc; } : Builtin.ret_typ = match args with @@ -2671,6 +2695,9 @@ module ModelBuiltins = struct "__objc_retain" execute___objc_retain let __objc_retain_cf = Builtin.register "__objc_retain_cf" execute___objc_retain_cf + let __cxx_typeid = Builtin.register + (* C++ "typeid" *) + "__cxx_typeid" execute___cxx_typeid let __placement_delete = Builtin.register (* placement delete is skip *) "__placement_delete" execute_skip diff --git a/infer/src/backend/symExec.mli b/infer/src/backend/symExec.mli index 90231c0e5..c18d44242 100644 --- a/infer/src/backend/symExec.mli +++ b/infer/src/backend/symExec.mli @@ -58,5 +58,6 @@ module ModelBuiltins : sig val __objc_release_autorelease_pool : Procname.t val __objc_cast : Procname.t val __objc_dictionary_literal : Procname.t + val __cxx_typeid : Procname.t val malloc_no_fail : Procname.t end diff --git a/infer/src/clang/cTrans.ml b/infer/src/clang/cTrans.ml index 7799f4023..654c33608 100644 --- a/infer/src/clang/cTrans.ml +++ b/infer/src/clang/cTrans.ml @@ -2018,6 +2018,36 @@ struct let fun_name = Procname.from_string_c_fun CFrontend_config.infer_skip_fun in { empty_res_trans with exps = [(Sil.Const (Sil.Cfun fun_name), Sil.Tvoid)] } + and cxxTypeidExpr_trans trans_state stmt_info stmts expr_info = + let tenv = trans_state.context.CContext.tenv in + let typ = CTypes_decl.get_type_from_expr_info expr_info tenv in + let sil_loc = CLocation.get_sil_location stmt_info trans_state.context in + let trans_state_pri = PriorityNode.try_claim_priority_node trans_state stmt_info in + let res_trans_subexpr = + match stmts with + | [stmt] -> + let trans_state_param = { trans_state_pri with succ_nodes = [] } in + instruction trans_state_param stmt + | _ -> empty_res_trans in + let fun_name = SymExec.ModelBuiltins.__cxx_typeid in + let sil_fun = Sil.Const (Sil.Cfun fun_name) in + let ret_id = Ident.create_fresh Ident.knormal in + let type_info_objc = (Sil.Sizeof (typ, Sil.Subtype.exact), Sil.Tvoid) in + let field_name_decl = Ast_utils.make_qual_name_decl ["type_info"; "std"] "__type_name" in + let field_name = General_utils.mk_class_field_name field_name_decl in + let ret_exp = Sil.Var ret_id in + let field_exp = Sil.Lfield (ret_exp, field_name, typ) in + let args = [type_info_objc; (field_exp, Sil.Tvoid)] @ res_trans_subexpr.exps in + let call_instr = Sil.Call ([ret_id], sil_fun, args, sil_loc, Sil.cf_default) in + let res_trans_call = { empty_res_trans with + ids = [ret_id]; + instrs = [call_instr]; + exps = [(ret_exp, typ)]; } in + let all_res_trans = [res_trans_subexpr; res_trans_call] in + let res_trans_to_parent = PriorityNode.compute_results_to_parent trans_state_pri sil_loc + "CXXTypeidExpr" stmt_info all_res_trans in + { res_trans_to_parent with exps = res_trans_call.exps } + (* Translates a clang instruction into SIL instructions. It takes a *) (* a trans_state containing current info on the translation and it returns *) (* a result_state.*) @@ -2286,6 +2316,9 @@ struct | CXXPseudoDestructorExpr _ -> cxxPseudoDestructorExpr_trans () + | CXXTypeidExpr (stmt_info, stmts, expr_info) -> + cxxTypeidExpr_trans trans_state stmt_info stmts expr_info + | s -> (Printing.log_stats "\n!!!!WARNING: found statement %s. \nACTION REQUIRED: Translation need to be defined. Statement ignored.... \n" (Ast_utils.string_of_stmt s); diff --git a/infer/tests/codetoanalyze/cpp/frontend/types/typeid_expr.cpp b/infer/tests/codetoanalyze/cpp/frontend/types/typeid_expr.cpp new file mode 100644 index 000000000..01f654272 --- /dev/null +++ b/infer/tests/codetoanalyze/cpp/frontend/types/typeid_expr.cpp @@ -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. + */ + +#include + +class Person { + public: + virtual ~Person() {} +}; + +class Employee : public Person {}; + +int person_typeid() { + Person person; + int t = 3; + if (typeid(t) == typeid(person)) + return 1; + else + return 1 / 0; +} + +int person_typeid_name() { + Person person; + int t = 3; + const char* t_type_info = typeid(t).name(); + const char* person_type_info = typeid(person).name(); + if (t_type_info == person_type_info) + return 0; + else + return 1 / 0; +} + +int employee_typeid() { + Employee employee; + Person* ptr = &employee; + if (typeid(employee) == typeid(*ptr)) + return 1 / 0; + else + return 0; +} + +int person_ptr_typeid(Person* ptr) { + Person person; + if (typeid(*ptr).name() == typeid(person).name()) + return 1 / 0; + else + return 0; +} + +template +const char* template_typeid(const Tgt& value) { + Tgt result = Tgt(value); + return typeid(Tgt).name(); +} + +int template_type_id_person() { + Person person; + if (template_typeid(person) == typeid(person).name()) + return 1; + else + return 1 / 0; +} diff --git a/infer/tests/codetoanalyze/cpp/frontend/types/typeid_expr.cpp.dot b/infer/tests/codetoanalyze/cpp/frontend/types/typeid_expr.cpp.dot new file mode 100644 index 000000000..9eda0cbd7 --- /dev/null +++ b/infer/tests/codetoanalyze/cpp/frontend/types/typeid_expr.cpp.dot @@ -0,0 +1,256 @@ +digraph iCFG { +65 [label="65: DeclStmt \n _fun_Person_Person(&person:class Person *) [line 63]\n " shape="box"] + + + 65 -> 60 ; +64 [label="64: Return Stmt \n *&return:int =(1 / 0) [line 67]\n NULLIFY(&person,false); [line 67]\n APPLY_ABSTRACTION; [line 67]\n " shape="box"] + + + 64 -> 58 ; +63 [label="63: Return Stmt \n *&return:int =1 [line 65]\n NULLIFY(&person,false); [line 65]\n APPLY_ABSTRACTION; [line 65]\n " shape="box"] + + + 63 -> 58 ; +62 [label="62: Prune (false branch) \n PRUNE(((n$0 == n$3) == 0), false); [line 64]\n REMOVE_TEMPS(n$0,n$1,n$2,n$3); [line 64]\n " shape="invhouse"] + + + 62 -> 64 ; +61 [label="61: Prune (true branch) \n PRUNE(((n$0 == n$3) != 0), true); [line 64]\n REMOVE_TEMPS(n$0,n$1,n$2,n$3); [line 64]\n " shape="invhouse"] + + + 61 -> 63 ; +60 [label="60: BinaryOperatorStmt: EQ \n n$0=_fun_template_typeid(&person:class Person &) [line 64]\n n$1=_fun___cxx_typeid(sizeof(class std::type_info ):void ,n$1.__type_name:void ,&person:class Person ) [line 64]\n n$2=*n$1:class std::type_info [line 64]\n n$3=_fun_std::type_info_name(n$1:class std::type_info &) [line 64]\n " shape="box"] + + + 60 -> 61 ; + 60 -> 62 ; +59 [label="59: + \n NULLIFY(&person,false); [line 64]\n " ] + + + 59 -> 58 ; +58 [label="58: Exit template_type_id_person \n " color=yellow style=filled] + + +57 [label="57: Start template_type_id_person\nFormals: \nLocals: person:class Person \n DECLARE_LOCALS(&return,&person); [line 62]\n " color=yellow style=filled] + + + 57 -> 65 ; +56 [label="56: DeclStmt \n n$4=*&value:class Person & [line 58]\n _fun_Person_Person(&SIL_materialize_temp__n$3:class Person *,n$4:class Person &) [line 58]\n _fun_Person_Person(&result:class Person *,&SIL_materialize_temp__n$3:class Person &) [line 58]\n REMOVE_TEMPS(n$4); [line 58]\n NULLIFY(&value,false); [line 58]\n " shape="box"] + + + 56 -> 55 ; +55 [label="55: Return Stmt \n n$0=_fun___cxx_typeid(sizeof(class std::type_info ):void ,n$0.__type_name:void ) [line 59]\n n$1=*n$0:class std::type_info [line 59]\n n$2=_fun_std::type_info_name(n$0:class std::type_info &) [line 59]\n *&return:char *=n$2 [line 59]\n REMOVE_TEMPS(n$0,n$1,n$2); [line 59]\n NULLIFY(&SIL_materialize_temp__n$3,false); [line 59]\n NULLIFY(&result,false); [line 59]\n APPLY_ABSTRACTION; [line 59]\n " shape="box"] + + + 55 -> 54 ; +54 [label="54: Exit template_typeid \n " color=yellow style=filled] + + +53 [label="53: Start template_typeid\nFormals: value:class Person &\nLocals: result:class Person SIL_materialize_temp__n$3:class Person \n DECLARE_LOCALS(&return,&result,&SIL_materialize_temp__n$3); [line 57]\n " color=yellow style=filled] + + + 53 -> 56 ; +52 [label="52: DeclStmt \n _fun_Person_Person(&person:class Person *) [line 49]\n " shape="box"] + + + 52 -> 47 ; +51 [label="51: Return Stmt \n *&return:int =0 [line 53]\n NULLIFY(&person,false); [line 53]\n APPLY_ABSTRACTION; [line 53]\n " shape="box"] + + + 51 -> 45 ; +50 [label="50: Return Stmt \n *&return:int =(1 / 0) [line 51]\n NULLIFY(&person,false); [line 51]\n APPLY_ABSTRACTION; [line 51]\n " shape="box"] + + + 50 -> 45 ; +49 [label="49: Prune (false branch) \n PRUNE(((n$3 == n$6) == 0), false); [line 50]\n REMOVE_TEMPS(n$0,n$1,n$2,n$3,n$4,n$5,n$6); [line 50]\n " shape="invhouse"] + + + 49 -> 51 ; +48 [label="48: Prune (true branch) \n PRUNE(((n$3 == n$6) != 0), true); [line 50]\n REMOVE_TEMPS(n$0,n$1,n$2,n$3,n$4,n$5,n$6); [line 50]\n " shape="invhouse"] + + + 48 -> 50 ; +47 [label="47: BinaryOperatorStmt: EQ \n n$0=*&ptr:class Person * [line 50]\n n$1=_fun___cxx_typeid(sizeof(class std::type_info ):void ,n$1.__type_name:void ,n$0:class Person ) [line 50]\n n$2=*n$1:class std::type_info [line 50]\n n$3=_fun_std::type_info_name(n$1:class std::type_info &) [line 50]\n n$4=_fun___cxx_typeid(sizeof(class std::type_info ):void ,n$4.__type_name:void ,&person:class Person ) [line 50]\n n$5=*n$4:class std::type_info [line 50]\n n$6=_fun_std::type_info_name(n$4:class std::type_info &) [line 50]\n NULLIFY(&ptr,false); [line 50]\n " shape="box"] + + + 47 -> 48 ; + 47 -> 49 ; +46 [label="46: + \n NULLIFY(&ptr,false); [line 50]\n NULLIFY(&person,false); [line 50]\n " ] + + + 46 -> 45 ; +45 [label="45: Exit person_ptr_typeid \n " color=yellow style=filled] + + +44 [label="44: Start person_ptr_typeid\nFormals: ptr:class Person *\nLocals: person:class Person \n DECLARE_LOCALS(&return,&person); [line 48]\n " color=yellow style=filled] + + + 44 -> 52 ; +43 [label="43: DeclStmt \n _fun_Employee_Employee(&employee:class Employee *) [line 40]\n " shape="box"] + + + 43 -> 42 ; +42 [label="42: DeclStmt \n *&ptr:class Employee *=&employee [line 41]\n " shape="box"] + + + 42 -> 37 ; +41 [label="41: Return Stmt \n *&return:int =0 [line 45]\n NULLIFY(&employee,false); [line 45]\n APPLY_ABSTRACTION; [line 45]\n " shape="box"] + + + 41 -> 35 ; +40 [label="40: Return Stmt \n *&return:int =(1 / 0) [line 43]\n NULLIFY(&employee,false); [line 43]\n APPLY_ABSTRACTION; [line 43]\n " shape="box"] + + + 40 -> 35 ; +39 [label="39: Prune (false branch) \n PRUNE((n$3 == 0), false); [line 42]\n REMOVE_TEMPS(n$0,n$1,n$2,n$3); [line 42]\n " shape="invhouse"] + + + 39 -> 41 ; +38 [label="38: Prune (true branch) \n PRUNE((n$3 != 0), true); [line 42]\n REMOVE_TEMPS(n$0,n$1,n$2,n$3); [line 42]\n " shape="invhouse"] + + + 38 -> 40 ; +37 [label="37: Call _fun_std::type_info_operator== \n n$0=_fun___cxx_typeid(sizeof(class std::type_info ):void ,n$0.__type_name:void ,&employee:class Employee ) [line 42]\n n$1=*&ptr:class Person * [line 42]\n n$2=_fun___cxx_typeid(sizeof(class std::type_info ):void ,n$2.__type_name:void ,n$1:class Person ) [line 42]\n n$3=_fun_std::type_info_operator==(n$0:class std::type_info &,n$2:class std::type_info &) [line 42]\n NULLIFY(&ptr,false); [line 42]\n " shape="box"] + + + 37 -> 38 ; + 37 -> 39 ; +36 [label="36: + \n NULLIFY(&ptr,false); [line 42]\n NULLIFY(&employee,false); [line 42]\n " ] + + + 36 -> 35 ; +35 [label="35: Exit employee_typeid \n " color=yellow style=filled] + + +34 [label="34: Start employee_typeid\nFormals: \nLocals: ptr:class Person * employee:class Employee \n DECLARE_LOCALS(&return,&ptr,&employee); [line 39]\n NULLIFY(&ptr,false); [line 39]\n " color=yellow style=filled] + + + 34 -> 43 ; +33 [label="33: DeclStmt \n _fun_Person_Person(&person:class Person *) [line 29]\n " shape="box"] + + + 33 -> 32 ; +32 [label="32: DeclStmt \n *&t:int =3 [line 30]\n " shape="box"] + + + 32 -> 31 ; +31 [label="31: DeclStmt \n n$5=_fun___cxx_typeid(sizeof(class std::type_info ):void ,n$5.__type_name:void ,&t:int ) [line 31]\n n$6=*n$5:class std::type_info [line 31]\n n$7=_fun_std::type_info_name(n$5:class std::type_info &) [line 31]\n *&t_type_info:char *=n$7 [line 31]\n REMOVE_TEMPS(n$5,n$6,n$7); [line 31]\n " shape="box"] + + + 31 -> 30 ; +30 [label="30: DeclStmt \n n$2=_fun___cxx_typeid(sizeof(class std::type_info ):void ,n$2.__type_name:void ,&person:class Person ) [line 32]\n n$3=*n$2:class std::type_info [line 32]\n n$4=_fun_std::type_info_name(n$2:class std::type_info &) [line 32]\n *&person_type_info:char *=n$4 [line 32]\n REMOVE_TEMPS(n$2,n$3,n$4); [line 32]\n " shape="box"] + + + 30 -> 25 ; +29 [label="29: Return Stmt \n *&return:int =(1 / 0) [line 36]\n NULLIFY(&person,false); [line 36]\n NULLIFY(&t,false); [line 36]\n APPLY_ABSTRACTION; [line 36]\n " shape="box"] + + + 29 -> 23 ; +28 [label="28: Return Stmt \n *&return:int =0 [line 34]\n NULLIFY(&person,false); [line 34]\n NULLIFY(&t,false); [line 34]\n APPLY_ABSTRACTION; [line 34]\n " shape="box"] + + + 28 -> 23 ; +27 [label="27: Prune (false branch) \n PRUNE(((n$0 == n$1) == 0), false); [line 33]\n REMOVE_TEMPS(n$0,n$1); [line 33]\n " shape="invhouse"] + + + 27 -> 29 ; +26 [label="26: Prune (true branch) \n PRUNE(((n$0 == n$1) != 0), true); [line 33]\n REMOVE_TEMPS(n$0,n$1); [line 33]\n " shape="invhouse"] + + + 26 -> 28 ; +25 [label="25: BinaryOperatorStmt: EQ \n n$0=*&t_type_info:char * [line 33]\n n$1=*&person_type_info:char * [line 33]\n NULLIFY(&person_type_info,false); [line 33]\n NULLIFY(&t_type_info,false); [line 33]\n " shape="box"] + + + 25 -> 26 ; + 25 -> 27 ; +24 [label="24: + \n NULLIFY(&person_type_info,false); [line 33]\n NULLIFY(&t_type_info,false); [line 33]\n NULLIFY(&person,false); [line 33]\n NULLIFY(&t,false); [line 33]\n " ] + + + 24 -> 23 ; +23 [label="23: Exit person_typeid_name \n " color=yellow style=filled] + + +22 [label="22: Start person_typeid_name\nFormals: \nLocals: person_type_info:char * t_type_info:char * t:int person:class Person \n DECLARE_LOCALS(&return,&person_type_info,&t_type_info,&t,&person); [line 28]\n NULLIFY(&person_type_info,false); [line 28]\n NULLIFY(&t_type_info,false); [line 28]\n " color=yellow style=filled] + + + 22 -> 33 ; +21 [label="21: DeclStmt \n _fun_Person_Person(&person:class Person *) [line 20]\n " shape="box"] + + + 21 -> 20 ; +20 [label="20: DeclStmt \n *&t:int =3 [line 21]\n " shape="box"] + + + 20 -> 15 ; +19 [label="19: Return Stmt \n *&return:int =(1 / 0) [line 25]\n NULLIFY(&person,false); [line 25]\n NULLIFY(&t,false); [line 25]\n APPLY_ABSTRACTION; [line 25]\n " shape="box"] + + + 19 -> 13 ; +18 [label="18: Return Stmt \n *&return:int =1 [line 23]\n NULLIFY(&person,false); [line 23]\n NULLIFY(&t,false); [line 23]\n APPLY_ABSTRACTION; [line 23]\n " shape="box"] + + + 18 -> 13 ; +17 [label="17: Prune (false branch) \n PRUNE((n$2 == 0), false); [line 22]\n REMOVE_TEMPS(n$0,n$1,n$2); [line 22]\n " shape="invhouse"] + + + 17 -> 19 ; +16 [label="16: Prune (true branch) \n PRUNE((n$2 != 0), true); [line 22]\n REMOVE_TEMPS(n$0,n$1,n$2); [line 22]\n " shape="invhouse"] + + + 16 -> 18 ; +15 [label="15: Call _fun_std::type_info_operator== \n n$0=_fun___cxx_typeid(sizeof(class std::type_info ):void ,n$0.__type_name:void ,&t:int ) [line 22]\n n$1=_fun___cxx_typeid(sizeof(class std::type_info ):void ,n$1.__type_name:void ,&person:class Person ) [line 22]\n n$2=_fun_std::type_info_operator==(n$0:class std::type_info &,n$1:class std::type_info &) [line 22]\n " shape="box"] + + + 15 -> 16 ; + 15 -> 17 ; +14 [label="14: + \n NULLIFY(&person,false); [line 22]\n NULLIFY(&t,false); [line 22]\n " ] + + + 14 -> 13 ; +13 [label="13: Exit person_typeid \n " color=yellow style=filled] + + +12 [label="12: Start person_typeid\nFormals: \nLocals: t:int person:class Person \n DECLARE_LOCALS(&return,&t,&person); [line 19]\n " color=yellow style=filled] + + + 12 -> 21 ; +11 [label="11: Constructor Init \n n$0=*&this:class Employee * [line 17]\n _fun_Person_Person(n$0:class Employee *) [line 17]\n REMOVE_TEMPS(n$0); [line 17]\n NULLIFY(&this,false); [line 17]\n APPLY_ABSTRACTION; [line 17]\n " shape="box"] + + + 11 -> 10 ; +10 [label="10: Exit Employee_Employee \n " color=yellow style=filled] + + +9 [label="9: Start Employee_Employee\nFormals: this:class Employee *\nLocals: \n DECLARE_LOCALS(&return); [line 17]\n " color=yellow style=filled] + + + 9 -> 11 ; +8 [label="8: Exit Employee_~Employee \n " color=yellow style=filled] + + +7 [label="7: Start Employee_~Employee\nFormals: this:class Employee *\nLocals: \n DECLARE_LOCALS(&return); [line 17]\n NULLIFY(&this,false); [line 17]\n " color=yellow style=filled] + + + 7 -> 8 ; +6 [label="6: Exit Person_Person \n " color=yellow style=filled] + + +5 [label="5: Start Person_Person\nFormals: this:class Person *\nLocals: \n DECLARE_LOCALS(&return); [line 12]\n NULLIFY(&this,false); [line 12]\n " color=yellow style=filled] + + + 5 -> 6 ; +4 [label="4: Exit Person_Person \n " color=yellow style=filled] + + +3 [label="3: Start Person_Person\nFormals: this:class Person * __param_0:class Person &\nLocals: \n DECLARE_LOCALS(&return); [line 12]\n NULLIFY(&__param_0,false); [line 12]\n NULLIFY(&this,false); [line 12]\n " color=yellow style=filled] + + + 3 -> 4 ; +2 [label="2: Exit Person_~Person \n " color=yellow style=filled] + + +1 [label="1: Start Person_~Person\nFormals: this:class Person *\nLocals: \n DECLARE_LOCALS(&return); [line 14]\n NULLIFY(&this,false); [line 14]\n " color=yellow style=filled] + + + 1 -> 2 ; +} diff --git a/infer/tests/endtoend/cpp/TypeIdExprTest.java b/infer/tests/endtoend/cpp/TypeIdExprTest.java new file mode 100644 index 000000000..950976d56 --- /dev/null +++ b/infer/tests/endtoend/cpp/TypeIdExprTest.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2015 - 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 TypeIdExprTest { + + public static final String FILE = + "infer/tests/codetoanalyze/cpp/frontend/types/typeid_expr.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 whenInferRunsOnMethodsDivideByZeroIsFound() + throws InterruptedException, IOException, InferException { + InferResults inferResults = InferRunner.runInferCPP(inferCmd); + String[] procedures = { + "person_typeid", + "person_typeid_name", + "employee_typeid", + "person_ptr_typeid", + "template_type_id_person" + }; + assertThat( + "Results should contain the no null dereference", + inferResults, + containsExactly( + DIVIDE_BY_ZERO, + FILE, + procedures + ) + ); + } +} diff --git a/infer/tests/frontend/cpp/TypesTest.java b/infer/tests/frontend/cpp/TypesTest.java new file mode 100644 index 000000000..6d8b770d8 --- /dev/null +++ b/infer/tests/frontend/cpp/TypesTest.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2013 - 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 frontend.cpp; + +import org.junit.Rule; +import org.junit.Test; + +import java.io.IOException; + +import utils.DebuggableTemporaryFolder; +import utils.InferException; +import utils.ClangFrontendUtils; + +public class TypesTest { + + String basePath = "infer/tests/codetoanalyze/cpp/frontend/types/"; + + @Rule + public DebuggableTemporaryFolder folder = new DebuggableTemporaryFolder(); + + void frontendTest(String fileRelative) throws InterruptedException, IOException, InferException { + ClangFrontendUtils.createAndCompareCppDotFiles(folder, basePath + fileRelative); + } + + @Test + public void typeidExprDotFilesMatch() + throws InterruptedException, IOException, InferException { + frontendTest("typeid_expr.cpp"); + } +}