diff --git a/infer/src/clang/cAstProcessor.ml b/infer/src/clang/cAstProcessor.ml index 57ca91f07..6b8019118 100644 --- a/infer/src/clang/cAstProcessor.ml +++ b/infer/src/clang/cAstProcessor.ml @@ -242,19 +242,21 @@ and decl_process_locs loc_composer decl = let decl1 = Clang_ast_proj.update_decl_tuple update decl in let decl_list' = list_map (decl_process_locs loc_composer) decl_list in decl_set_sub_decls decl1 decl_list' in + let get_updated_fun_decl (decl_info', name, qt, fdecl_info) = + let fdi_decls_in_prototype_scope' = + list_map (decl_process_locs loc_composer) fdecl_info.fdi_decls_in_prototype_scope in + let fdi_parameters' = + list_map (decl_process_locs loc_composer) fdecl_info.fdi_parameters in + let body' = Option.map (stmt_process_locs loc_composer) fdecl_info.fdi_body in + let fdecl_info' = + { fdecl_info with + fdi_body = body'; + fdi_parameters = fdi_parameters'; + fdi_decls_in_prototype_scope = fdi_decls_in_prototype_scope'; } in + (decl_info', name, qt, fdecl_info') in match decl' with - | FunctionDecl (decl_info', name, qt, fdecl_info) -> - let fdi_decls_in_prototype_scope' = - list_map (decl_process_locs loc_composer) fdecl_info.fdi_decls_in_prototype_scope in - let fdi_parameters' = - list_map (decl_process_locs loc_composer) fdecl_info.fdi_parameters in - let body' = Option.map (stmt_process_locs loc_composer) fdecl_info.fdi_body in - let fdecl_info' = - { fdecl_info with - fdi_body = body'; - fdi_parameters = fdi_parameters'; - fdi_decls_in_prototype_scope = fdi_decls_in_prototype_scope'; } in - FunctionDecl (decl_info', name, qt, fdecl_info') + | FunctionDecl fun_info -> FunctionDecl (get_updated_fun_decl fun_info) + | CXXMethodDecl fun_info -> CXXMethodDecl (get_updated_fun_decl fun_info) | ObjCMethodDecl (decl_info', name, obj_c_method_decl_info) -> let body' = Option.map (stmt_process_locs loc_composer) obj_c_method_decl_info.omdi_body in diff --git a/infer/src/clang/cFrontend.ml b/infer/src/clang/cFrontend.ml index 0f93f3561..1be7edf30 100644 --- a/infer/src/clang/cFrontend.ml +++ b/infer/src/clang/cFrontend.ml @@ -21,7 +21,7 @@ open CGen_trans open Clang_ast_t (* Translate one global declaration *) -let rec translate_one_declaration tenv cg cfg namespace dec = +let rec translate_one_declaration tenv cg cfg namespace parent_dec dec = let ns_suffix = Ast_utils.namespace_to_string namespace in let info = Clang_ast_proj.get_decl_tuple dec in CLocation.update_curr_file info; @@ -39,7 +39,11 @@ let rec translate_one_declaration tenv cg cfg namespace dec = | RecordDecl (decl_info, name_info, opt_type, _, decl_list, decl_context_info, record_decl_info) -> let record_name = name_info.Clang_ast_t.ni_name in CTypes_decl.do_record_declaration tenv namespace - decl_info record_name opt_type decl_list decl_context_info record_decl_info + decl_info record_name opt_type decl_list decl_context_info record_decl_info; + let method_decls = CTypes_decl.get_method_decls dec decl_list in + let tranlate_method (parent, decl) = + translate_one_declaration tenv cg cfg namespace parent decl in + list_iter tranlate_method method_decls | VarDecl(decl_info, name_info, t, _) -> let name = name_info.Clang_ast_t.ni_name in @@ -73,6 +77,20 @@ let rec translate_one_declaration tenv cg cfg namespace dec = let curr_class = ObjcInterface_decl.interface_impl_declaration tenv name decl_list idi in CMethod_declImpl.process_methods tenv cg cfg curr_class namespace decl_list + | CXXMethodDecl(decl_info, name_info, qual_type, function_decl_info) -> + (* di_parent_pointer has pointer to lexical context such as class.*) + (* If it's not defined, then it's the same as parent in AST *) + let class_decl = match decl_info.Clang_ast_t.di_parent_pointer with + | Some ptr -> Ast_utils.get_decl ptr + | None -> Some parent_dec in + (match class_decl with + | Some CXXRecordDecl(_, _, opt_type, _, _, _, _, _) -> + let class_name = CTypes_decl.get_record_name opt_type in + let curr_class = CContext.ContextCls(class_name, None, []) in + if !CFrontend_config.testing_mode then + CMethod_declImpl.process_methods tenv cg cfg curr_class namespace [dec] + | Some dec -> Printing.log_stats "Methods of %s skipped\n" (Ast_utils.string_of_decl dec) + | None -> ()) | EnumDecl(decl_info, name_info, opt_type, _, decl_list, decl_context_info, enum_decl_info) when should_translate_enum -> @@ -81,10 +99,10 @@ let rec translate_one_declaration tenv cg cfg namespace dec = | LinkageSpecDecl(decl_info, decl_list, decl_context_info) -> Printing.log_out "ADDING: LinkageSpecDecl decl list\n"; - list_iter (translate_one_declaration tenv cg cfg namespace) decl_list + list_iter (translate_one_declaration tenv cg cfg namespace dec) decl_list | NamespaceDecl(decl_info, name_info, decl_list, decl_context_info, _) -> let name = ns_suffix^name_info.Clang_ast_t.ni_name in - list_iter (translate_one_declaration tenv cg cfg (Some name)) decl_list + list_iter (translate_one_declaration tenv cg cfg (Some name) dec) decl_list | EmptyDecl _ -> Printing.log_out "Passing from EmptyDecl. Treated as skip\n"; | dec -> @@ -98,7 +116,7 @@ let compute_icfg tenv source_file ast = Printing.log_out "\n Start creating icfg\n"; let cg = Cg.create () in let cfg = Cfg.Node.create_cfg () in - list_iter (translate_one_declaration tenv cg cfg None) decl_list; + list_iter (translate_one_declaration tenv cg cfg None ast) decl_list; Printing.log_out "\n Finished creating icfg\n"; (cg, cfg) | _ -> assert false (* NOTE: Assumes that an AST alsways starts with a TranslationUnitDecl *) diff --git a/infer/src/clang/cFrontend_config.ml b/infer/src/clang/cFrontend_config.ml index 3600a3416..b9b9d14fb 100644 --- a/infer/src/clang/cFrontend_config.ml +++ b/infer/src/clang/cFrontend_config.ml @@ -33,6 +33,8 @@ let id_cl = "id" let self = "self" +let this = "this" + let alloc = "alloc" let malloc = "malloc" diff --git a/infer/src/clang/cFrontend_config.mli b/infer/src/clang/cFrontend_config.mli index e0705ee90..f8038119a 100644 --- a/infer/src/clang/cFrontend_config.mli +++ b/infer/src/clang/cFrontend_config.mli @@ -49,6 +49,8 @@ val id_cl : string val self : string +val this : string + val nsstring_cl : string val nsobject_cl : string diff --git a/infer/src/clang/cFrontend_utils.ml b/infer/src/clang/cFrontend_utils.ml index 003726805..00ec426f5 100644 --- a/infer/src/clang/cFrontend_utils.ml +++ b/infer/src/clang/cFrontend_utils.ml @@ -258,6 +258,11 @@ struct | generated:: rest -> generated = CFrontend_config.generated_suffix | _ -> false + let get_decl decl_ptr = + try + Some (Clang_ast_main.PointerMap.find decl_ptr !CFrontend_config.pointer_decl_index) + with Not_found -> Printing.log_stats "decl with pointer %s not found\n" decl_ptr; None + end (* Global counter for anonymous block*) @@ -379,6 +384,18 @@ struct let mk_class_field_name class_name field_name = Ident.create_fieldname (Mangled.mangled field_name (class_name^"_"^field_name)) 0 + let mk_procname_from_function name type_name = + let type_name_crc = CRC.crc16 type_name in + Procname.mangled_c_fun name type_name_crc + + let mk_procname_from_method class_name method_name method_kind = + let mangled = Procname.mangled_of_objc_method_kind method_kind in + Procname.mangled_c_method class_name method_name mangled + + let mk_procname_from_cpp_method class_name method_name type_name = + let type_name_crc = Some (CRC.crc16 type_name) in + Procname.mangled_c_method class_name method_name type_name_crc + end diff --git a/infer/src/clang/cFrontend_utils.mli b/infer/src/clang/cFrontend_utils.mli index d2b7bd025..a21e62c88 100644 --- a/infer/src/clang/cFrontend_utils.mli +++ b/infer/src/clang/cFrontend_utils.mli @@ -76,6 +76,8 @@ sig val is_generated : Clang_ast_t.named_decl_info -> bool + val get_decl : Clang_ast_t.pointer -> Clang_ast_t.decl option + end module General_utils : @@ -116,6 +118,12 @@ sig val replicate: int -> 'a -> 'a list + val mk_procname_from_method : string -> string -> Procname.objc_method_kind -> Procname.t + + val mk_procname_from_function : string -> string -> Procname.t + + val mk_procname_from_cpp_method : string -> string -> string -> Procname.t + val mk_class_field_name : string -> string -> Ident.fieldname diff --git a/infer/src/clang/cMethod_decl.ml b/infer/src/clang/cMethod_decl.ml index 9fba244d9..e76435270 100644 --- a/infer/src/clang/cMethod_decl.ml +++ b/infer/src/clang/cMethod_decl.ml @@ -37,7 +37,6 @@ struct then None else Some body | None -> body - let model_exists procname = Specs.summary_exists_in_models procname && not !CFrontend_config.models_mode @@ -115,7 +114,7 @@ struct captured_vars is_anonym_block param_decls attributes | None -> CMethod_signature.add ms - let process_objc_method_decl tenv cg cfg namespace curr_class meth_decl = + let process_method_decl tenv cg cfg namespace curr_class meth_decl ~is_objc = let ms, body_opt, param_decls = CMethod_trans.method_signature_of_decl curr_class meth_decl None in CMethod_signature.add ms; @@ -125,14 +124,16 @@ struct let attributes = CMethod_signature.ms_get_attributes ms in let procname = CMethod_signature.ms_get_name ms in if CMethod_trans.create_local_procdesc cfg tenv ms [body] [] is_instance then - add_method tenv cg cfg curr_class procname namespace [body] true is_instance [] false + add_method tenv cg cfg curr_class procname namespace [body] is_objc is_instance [] false param_decls attributes | None -> () let rec process_one_method_decl tenv cg cfg curr_class namespace dec = match dec with - | ObjCMethodDecl (decl_info, name_info, method_decl_info) -> - process_objc_method_decl tenv cg cfg namespace curr_class dec + | CXXMethodDecl _ -> + process_method_decl tenv cg cfg namespace curr_class dec ~is_objc:false + | ObjCMethodDecl _ -> + process_method_decl tenv cg cfg namespace curr_class dec ~is_objc:true | ObjCPropertyImplDecl (decl_info, property_impl_decl_info) -> let pname = Ast_utils.property_name property_impl_decl_info in Printing.log_out "ADDING: ObjCPropertyImplDecl for property '%s' " pname; diff --git a/infer/src/clang/cMethod_trans.ml b/infer/src/clang/cMethod_trans.ml index 6cff4ea84..b4050f784 100644 --- a/infer/src/clang/cMethod_trans.ml +++ b/infer/src/clang/cMethod_trans.ml @@ -17,15 +17,6 @@ open Clang_ast_t module L = Logging - -let mk_procname_from_function name type_name = - let type_name_crc = CRC.crc16 type_name in - Procname.mangled_c_fun name type_name_crc - -let mk_procname_from_method class_name method_name method_kind = - let mangled = Procname.mangled_of_objc_method_kind method_kind in - Procname.mangled_c_method class_name method_name mangled - (** When the methoc call is MCStatic, means that it is a class method. *) (** When it is MCVirtual, it means that it is an instance method and that *) (** the method to be called will be determined at runtime. If it is MCNoVirtual *) @@ -38,16 +29,33 @@ type method_call_type = type function_method_decl_info = | Func_decl_info of Clang_ast_t.function_decl_info * string + | Cpp_Meth_decl_info of Clang_ast_t.function_decl_info * string (* class_name *) * string (* ret_type *) | Meth_decl_info of Clang_ast_t.obj_c_method_decl_info * string | Block_decl_info of Clang_ast_t.block_decl_info * string let is_instance_method function_method_decl_info is_instance = match function_method_decl_info with | Func_decl_info (function_decl_info, _) -> false + | Cpp_Meth_decl_info _ -> true | Meth_decl_info (method_decl_info, _) -> method_decl_info.Clang_ast_t.omdi_is_instance_method | Block_decl_info (block_decl_info, _) -> is_instance +let get_class_param function_method_decl_info = + if (is_instance_method function_method_decl_info false) then + match function_method_decl_info with + | Cpp_Meth_decl_info (_, class_name, _) -> [(CFrontend_config.this, class_name, None)] + | Meth_decl_info (_, class_name) -> [(CFrontend_config.self, class_name, None)] + | _ -> [] + else [] + +let get_param_decls function_method_decl_info = + match function_method_decl_info with + | Func_decl_info (function_decl_info, _) + | Cpp_Meth_decl_info (function_decl_info, _, _) -> function_decl_info.Clang_ast_t.fdi_parameters + | Meth_decl_info (method_decl_info, _) -> method_decl_info.Clang_ast_t.omdi_parameters + | Block_decl_info (block_decl_info, _) -> block_decl_info.Clang_ast_t.bdi_parameters + let get_parameters function_method_decl_info = let par_to_ms_par par = match par with @@ -57,24 +65,18 @@ let get_parameters function_method_decl_info = Printing.log_out "with pointer %s@." decl_info.Clang_ast_t.di_pointer; (name, CTypes.get_type qtype, var_decl_info.vdi_init_expr) | _ -> assert false in - match function_method_decl_info with - | Func_decl_info (function_decl_info, _) -> - list_map par_to_ms_par function_decl_info.Clang_ast_t.fdi_parameters - | Meth_decl_info (method_decl_info, class_name) -> - let pars = list_map par_to_ms_par method_decl_info.Clang_ast_t.omdi_parameters in - if (is_instance_method function_method_decl_info false) then - ("self", class_name, None):: pars - else pars - | Block_decl_info (block_decl_info, _) -> - list_map par_to_ms_par block_decl_info.Clang_ast_t.bdi_parameters + + let pars = list_map par_to_ms_par (get_param_decls function_method_decl_info) in + get_class_param function_method_decl_info @ pars let get_return_type function_method_decl_info = match function_method_decl_info with - | Func_decl_info (_, qt) -> qt + | Func_decl_info (_, typ) + | Cpp_Meth_decl_info (_, _, typ) + | Block_decl_info (_, typ) -> typ | Meth_decl_info (method_decl_info, _) -> let qt = method_decl_info.Clang_ast_t.omdi_result_type in CTypes.get_type qt - | Block_decl_info (_, qt) -> qt let build_method_signature decl_info procname function_method_decl_info is_instance is_anonym_block is_generated = let source_range = decl_info.Clang_ast_t.di_source_range in @@ -84,21 +86,28 @@ let build_method_signature decl_info procname function_method_decl_info is_insta let attributes = decl_info.Clang_ast_t.di_attributes in CMethod_signature.make_ms procname parameters qt attributes source_range is_instance_method is_generated - let method_signature_of_decl curr_class meth_decl block_data_opt = match meth_decl, block_data_opt with | FunctionDecl(decl_info, name_info, qt, fdi), _ -> let name = name_info.Clang_ast_t.ni_name in let func_decl = Func_decl_info (fdi, CTypes.get_type qt) in - let procname = mk_procname_from_function name (CTypes.get_type qt) in + let procname = General_utils.mk_procname_from_function name (CTypes.get_type qt) in let ms = build_method_signature decl_info procname func_decl false false false in ms, fdi.Clang_ast_t.fdi_body, fdi.Clang_ast_t.fdi_parameters + | CXXMethodDecl(decl_info, name_info, qt, fdi), _ -> + let class_name = CContext.get_curr_class_name curr_class in + let method_name = name_info.Clang_ast_t.ni_name in + let typ = CTypes.get_type qt in + let procname = General_utils.mk_procname_from_cpp_method class_name method_name typ in + let method_decl = Cpp_Meth_decl_info (fdi, class_name, typ) in + let ms = build_method_signature decl_info procname method_decl false false false in + ms, fdi.Clang_ast_t.fdi_body, fdi.Clang_ast_t.fdi_parameters | ObjCMethodDecl(decl_info, name_info, mdi), _ -> let class_name = CContext.get_curr_class_name curr_class in let method_name = name_info.Clang_ast_t.ni_name in let is_instance = mdi.Clang_ast_t.omdi_is_instance_method in let method_kind = Procname.objc_method_kind_of_bool is_instance in - let procname = mk_procname_from_method class_name method_name method_kind in + let procname = General_utils.mk_procname_from_method class_name method_name method_kind in let method_decl = Meth_decl_info (mdi, class_name) in let is_generated = Ast_utils.is_generated name_info in let ms = build_method_signature decl_info procname method_decl false false is_generated in @@ -109,7 +118,6 @@ let method_signature_of_decl curr_class meth_decl block_data_opt = ms, bdi.Clang_ast_t.bdi_body, bdi.Clang_ast_t.bdi_parameters |_ -> assert false - let get_superclass_curr_class context = let retrive_super cname super_opt = let iname = Sil.TN_csu (Sil.Class, Mangled.from_string cname) in diff --git a/infer/src/clang/cMethod_trans.mli b/infer/src/clang/cMethod_trans.mli index 86de15b83..b3c899a0d 100644 --- a/infer/src/clang/cMethod_trans.mli +++ b/infer/src/clang/cMethod_trans.mli @@ -27,10 +27,6 @@ val create_external_procdesc : Cfg.cfg -> Procname.t -> bool -> (Sil.typ * Sil.t val captured_vars_from_block_info : CContext.t -> Clang_ast_t.block_captured_variable list -> (Mangled.t * Sil.typ * bool) list -val mk_procname_from_method : string -> string -> Procname.objc_method_kind -> Procname.t - -val mk_procname_from_function : string -> string -> Procname.t - val get_class_selector_instance : CContext.t -> Clang_ast_t.obj_c_message_expr_info -> (Sil.exp * Sil.typ) list -> (string * string * method_call_type) diff --git a/infer/src/clang/cTrans.ml b/infer/src/clang/cTrans.ml index 63660c499..0b5464ddc 100644 --- a/infer/src/clang/cTrans.ml +++ b/infer/src/clang/cTrans.ml @@ -45,19 +45,19 @@ struct let is_instance = mc_type != CMethod_trans.MCStatic in let method_kind = Procname.objc_method_kind_of_bool is_instance in match CTrans_models.get_predefined_model_method_signature class_name method_name - CMethod_trans.mk_procname_from_method with + General_utils.mk_procname_from_method with | Some ms -> ignore (CMethod_trans.create_local_procdesc context.cfg context.tenv ms [] [] is_instance); CMethod_signature.ms_get_name ms, CMethod_trans.MCNoVirtual | None -> - let procname = CMethod_trans.mk_procname_from_method class_name method_name method_kind in + let procname = General_utils.mk_procname_from_method class_name method_name method_kind in try let callee_ms = CMethod_signature.find procname in if not (M.process_getter_setter context procname) then (ignore (CMethod_trans.create_local_procdesc context.cfg context.tenv callee_ms [] [] is_instance)); procname, mc_type with Not_found -> - let callee_pn = CMethod_trans.mk_procname_from_method class_name method_name method_kind in + let callee_pn = General_utils.mk_procname_from_method class_name method_name method_kind in CMethod_trans.create_external_procdesc context.cfg callee_pn is_instance None; callee_pn, mc_type @@ -317,7 +317,7 @@ struct let pname, type_opt = match qt with | Some v -> - CMethod_trans.mk_procname_from_function name v, CTypes_decl.parse_func_type name v + mk_procname_from_function name v, CTypes_decl.parse_func_type name v | None -> Procname.from_string_c_fun name, None in let address_of_function = not context.CContext.is_callee_expression in (* If we are not translating a callee expression, then the address of the function is being taken.*) diff --git a/infer/src/clang/cTrans_utils.ml b/infer/src/clang/cTrans_utils.ml index f1f30e604..23a8fcc4d 100644 --- a/infer/src/clang/cTrans_utils.ml +++ b/infer/src/clang/cTrans_utils.ml @@ -305,7 +305,7 @@ let objc_new_trans trans_state loc stmt_info cls_name function_type = let init_ret_id = Ident.create_fresh Ident.knormal in let is_instance = true in let call_flags = { Sil.cf_virtual = is_instance; Sil.cf_noreturn = false; Sil.cf_is_objc_block = false; } in - let pname = CMethod_trans.mk_procname_from_method cls_name CFrontend_config.init Procname.Instance_objc_method in + let pname = General_utils.mk_procname_from_method cls_name CFrontend_config.init Procname.Instance_objc_method in CMethod_trans.create_external_procdesc trans_state.context.cfg pname is_instance None; let args = [(Sil.Var alloc_ret_id, alloc_ret_type)] in let init_stmt_call = Sil.Call([init_ret_id], (Sil.Const (Sil.Cfun pname)), args, loc, call_flags) in diff --git a/infer/src/clang/cTypes_decl.ml b/infer/src/clang/cTypes_decl.ml index 7296d901b..6d79ed064 100644 --- a/infer/src/clang/cTypes_decl.ml +++ b/infer/src/clang/cTypes_decl.ml @@ -132,6 +132,22 @@ let parse_func_type name func_type = Printing.log_stats "\nXXXXXXX PARSE ERROR for string '%s'." func_type; None) + +(* We need to take the name out of the type as the struct can be anonymous*) +let get_record_name opt_type = match opt_type with + | `Type n' -> CTypes.cut_struct_union n' + | `NoType -> assert false + + +let get_method_decls parent decl_list = + let rec traverse_decl parent decl = match decl with + | CXXMethodDecl _ -> [(parent, decl)] + | CXXRecordDecl (_, _, _, _, decl_list', _, _, _) + | RecordDecl (_, _, _, _, decl_list', _, _) -> traverse_decl_list decl decl_list' + | _ -> [] + and traverse_decl_list parent decl_list = list_flatten (list_map (traverse_decl parent) decl_list) in + traverse_decl_list parent decl_list + (*In case of typedef like *) (* typedef struct { f1; f2; ... } s; *) (* the AST-dump splits the typedef definition from the struct definition. *) @@ -197,6 +213,17 @@ and get_struct_fields tenv record_name namespace decl_list = get_struct_fields tenv record_name namespace decl_list' | _ :: decl_list' -> get_struct_fields tenv record_name namespace decl_list' +and get_class_methods tenv class_name namespace decl_list = + let process_method_decl = function + | CXXMethodDecl (decl_info, name_info, qual_type, function_decl_info) -> + let method_name = name_info.ni_name in + Printing.log_out " ...Declaring method '%s'.\n" method_name; + let method_proc = mk_procname_from_cpp_method class_name method_name (CTypes.get_type qual_type) in + Some method_proc + | _ -> None in + (* poor mans list_filter_map *) + list_flatten_options (list_map process_method_decl decl_list) + and do_record_declaration tenv namespace decl_info name opt_type decl_list decl_context_info record_decl_info = Printing.log_out "ADDING: RecordDecl for '%s'" name; Printing.log_out " pointer= '%s'\n" decl_info.Clang_ast_t.di_pointer; @@ -206,11 +233,6 @@ and do_record_declaration tenv namespace decl_info name opt_type decl_list decl_ let typ = expand_structured_type tenv typ in add_struct_to_tenv tenv typ -(* We need to take the name out of the type as the struct can be anonymous*) -and get_record_name opt_type = match opt_type with - | `Type n' -> CTypes.cut_struct_union n' - | `NoType -> assert false - (* For a record declaration it returns/constructs the type *) and get_declaration_type tenv namespace decl_info n opt_type decl_list decl_context_info record_decl_info = let ns_suffix = Ast_utils.namespace_to_string namespace in @@ -230,8 +252,8 @@ and get_declaration_type tenv namespace decl_info n opt_type decl_list decl_cont | Sil.Tvar (Sil.TN_csu (csu, _)) -> csu | _ -> Sil.Struct) in let name = Some (Mangled.from_string name_str) in + let methods_list = get_class_methods tenv name_str namespace decl_list in (* C++ methods only *) let superclass_list = [] in (* No super class for structs *) - let methods_list = [] in (* No methods list for structs *) let item_annotation = Sil.item_annotation_empty in (* No annotations for struts *) Sil.Tstruct (non_static_fields, static_fields, csu, name, superclass_list, methods_list, item_annotation) diff --git a/infer/src/clang/cTypes_decl.mli b/infer/src/clang/cTypes_decl.mli index bdd592a15..955c6216f 100644 --- a/infer/src/clang/cTypes_decl.mli +++ b/infer/src/clang/cTypes_decl.mli @@ -15,6 +15,10 @@ val get_declaration_type : Sil.tenv -> string option -> Clang_ast_t.decl_info -> val add_struct_to_tenv : Sil.tenv -> Sil.typ -> unit +val get_record_name : Clang_ast_t.opt_type -> string + +val get_method_decls : Clang_ast_t.decl -> Clang_ast_t.decl list -> (Clang_ast_t.decl * Clang_ast_t.decl) list + val do_typedef_declaration : Sil.tenv -> string option -> Clang_ast_t.decl_info -> string -> Clang_ast_t.opt_type -> Clang_ast_t.typedef_decl_info -> unit diff --git a/infer/src/clang/objcProperty_decl.ml b/infer/src/clang/objcProperty_decl.ml index 0c6923856..c1bb818df 100644 --- a/infer/src/clang/objcProperty_decl.ml +++ b/infer/src/clang/objcProperty_decl.ml @@ -370,7 +370,7 @@ let get_methods curr_class decl_list = let method_name = name_info.Clang_ast_t.ni_name in Printing.log_out " ...Adding Method '%s' \n" (class_name^"_"^method_name); let _ = check_for_property curr_class method_name d method_decl_info.Clang_ast_t.omdi_body in - let meth_name = CMethod_trans.mk_procname_from_method class_name method_name method_kind in + let meth_name = General_utils.mk_procname_from_method class_name method_name method_kind in meth_name:: list_methods | _ -> list_methods in list_fold_right get_method decl_list [] diff --git a/infer/tests/codetoanalyze/cpp/frontend/types/methods.cpp b/infer/tests/codetoanalyze/cpp/frontend/types/methods.cpp new file mode 100644 index 000000000..71ccbfb94 --- /dev/null +++ b/infer/tests/codetoanalyze/cpp/frontend/types/methods.cpp @@ -0,0 +1,55 @@ +// commented out parts are not done yet +struct A { + public: + int member1; + float member2; + public: + int fun(int a, int b); + // overloading + int fun(int a, int b, int c); + int add(const A& other); + + struct AIn { + int fun1() { return 1;} + int fun(int a, int b); + }; + // inline definition + int def_in() { int c = 10; return c+1;} + + //static function + //static int get_fun() {return 1;} +}; + +int A::fun(int a, int b, int c) { + //using class members + //fun(a,b); +} + +int A::fun(int a, int b) { + int c = a + b + 1; + //using class members + //member1 = c; + return c*c; +} + +int A::AIn::fun(int a, int b) { + return a+b; +} + +int A::add(const A& other) { + //member1 += other.member1; + //return member1; +} + +void test() { + // constructing objects + //A a; + //a.fun(1,2); + + A *a_ptr; + // calling methods + // a_ptr->fun(10,20); + + //A::get_fun(); + //a.get_fun(); +} diff --git a/infer/tests/codetoanalyze/cpp/frontend/types/methods.dot b/infer/tests/codetoanalyze/cpp/frontend/types/methods.dot new file mode 100644 index 000000000..1c141e156 --- /dev/null +++ b/infer/tests/codetoanalyze/cpp/frontend/types/methods.dot @@ -0,0 +1,75 @@ +digraph iCFG { +20 [label="20: Exit test \n " color=yellow style=filled] + + +19 [label="19: Start test\nFormals: \nLocals: a_ptr:struct A * \n DECLARE_LOCALS(&return,&a_ptr); [line 44]\n NULLIFY(&a_ptr,false); [line 44]\n " color=yellow style=filled] + + + 19 -> 20 ; +18 [label="18: Exit A_add \n " color=yellow style=filled] + + +17 [label="17: Start A_add\nFormals: this:struct A other:struct A &\nLocals: \n DECLARE_LOCALS(&return); [line 39]\n NULLIFY(&this,false); [line 39]\n NULLIFY(&other,false); [line 39]\n " color=yellow style=filled] + + + 17 -> 18 ; +16 [label="16: Return Stmt \n n$5=*&a:int [line 36]\n n$6=*&b:int [line 36]\n *&return:int =(n$5 + n$6) [line 36]\n REMOVE_TEMPS(n$5,n$6); [line 36]\n NULLIFY(&a,false); [line 36]\n NULLIFY(&b,false); [line 36]\n APPLY_ABSTRACTION; [line 36]\n " shape="box"] + + + 16 -> 15 ; +15 [label="15: Exit A::AIn_fun \n " color=yellow style=filled] + + +14 [label="14: Start A::AIn_fun\nFormals: this:struct A::AIn a:int b:int \nLocals: \n DECLARE_LOCALS(&return); [line 35]\n NULLIFY(&this,false); [line 35]\n " color=yellow style=filled] + + + 14 -> 16 ; +13 [label="13: DeclStmt \n n$3=*&a:int [line 29]\n n$4=*&b:int [line 29]\n *&c:int =((n$3 + n$4) + 1) [line 29]\n REMOVE_TEMPS(n$3,n$4); [line 29]\n NULLIFY(&a,false); [line 29]\n NULLIFY(&b,false); [line 29]\n " shape="box"] + + + 13 -> 12 ; +12 [label="12: Return Stmt \n n$1=*&c:int [line 32]\n n$2=*&c:int [line 32]\n *&return:int =(n$1 * n$2) [line 32]\n REMOVE_TEMPS(n$1,n$2); [line 32]\n NULLIFY(&c,false); [line 32]\n APPLY_ABSTRACTION; [line 32]\n " shape="box"] + + + 12 -> 11 ; +11 [label="11: Exit A_fun \n " color=yellow style=filled] + + +10 [label="10: Start A_fun\nFormals: this:struct A a:int b:int \nLocals: c:int \n DECLARE_LOCALS(&return,&c); [line 28]\n NULLIFY(&this,false); [line 28]\n NULLIFY(&c,false); [line 28]\n " color=yellow style=filled] + + + 10 -> 13 ; +9 [label="9: Exit A_fun \n " color=yellow style=filled] + + +8 [label="8: Start A_fun\nFormals: this:struct A a:int b:int c:int \nLocals: \n DECLARE_LOCALS(&return); [line 23]\n NULLIFY(&this,false); [line 23]\n NULLIFY(&a,false); [line 23]\n NULLIFY(&b,false); [line 23]\n NULLIFY(&c,false); [line 23]\n " color=yellow style=filled] + + + 8 -> 9 ; +7 [label="7: DeclStmt \n *&c:int =10 [line 17]\n " shape="box"] + + + 7 -> 6 ; +6 [label="6: Return Stmt \n n$0=*&c:int [line 17]\n *&return:int =(n$0 + 1) [line 17]\n REMOVE_TEMPS(n$0); [line 17]\n NULLIFY(&c,false); [line 17]\n APPLY_ABSTRACTION; [line 17]\n " shape="box"] + + + 6 -> 5 ; +5 [label="5: Exit A_def_in \n " color=yellow style=filled] + + +4 [label="4: Start A_def_in\nFormals: this:struct A \nLocals: c:int \n DECLARE_LOCALS(&return,&c); [line 17]\n NULLIFY(&this,false); [line 17]\n NULLIFY(&c,false); [line 17]\n " color=yellow style=filled] + + + 4 -> 7 ; +3 [label="3: Return Stmt \n *&return:int =1 [line 13]\n APPLY_ABSTRACTION; [line 13]\n " shape="box"] + + + 3 -> 2 ; +2 [label="2: Exit A::AIn_fun1 \n " color=yellow style=filled] + + +1 [label="1: Start A::AIn_fun1\nFormals: this:struct A::AIn \nLocals: \n DECLARE_LOCALS(&return); [line 13]\n NULLIFY(&this,false); [line 13]\n " color=yellow style=filled] + + + 1 -> 3 ; +} diff --git a/infer/tests/frontend/cpp/MethodsTest.java b/infer/tests/frontend/cpp/MethodsTest.java new file mode 100644 index 000000000..9f955c5a1 --- /dev/null +++ b/infer/tests/frontend/cpp/MethodsTest.java @@ -0,0 +1,51 @@ +/* +* 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 static org.hamcrest.MatcherAssert.assertThat; +import static utils.matchers.DotFilesEqual.dotFileEqualTo; + +import com.google.common.collect.ImmutableList; + +import org.junit.Rule; +import org.junit.Test; + +import java.io.File; +import java.io.IOException; + +import utils.DebuggableTemporaryFolder; +import utils.InferException; +import utils.InferRunner; + +public class MethodsTest { + + @Rule + public DebuggableTemporaryFolder folder = new DebuggableTemporaryFolder(); + + @Test + public void whenCaptureRunCommaThenDotFilesAreTheSame() + throws InterruptedException, IOException, InferException { + String literal_src = + "infer/tests/codetoanalyze/cpp/frontend/types/methods.cpp"; + + String literal_dotty = + "infer/tests/codetoanalyze/cpp/frontend/types/methods.dot"; + + ImmutableList inferCmd = + InferRunner.createCPPInferCommandFrontend( + folder, + literal_src); + File newDotFile = InferRunner.runInferFrontend(inferCmd); + assertThat( + "In the capture of " + literal_src + + " the dotty files should be the same.", + newDotFile, dotFileEqualTo(literal_dotty)); + } +}