diff --git a/infer/src/clang/cFrontend.ml b/infer/src/clang/cFrontend.ml index baef74369..0f93f3561 100644 --- a/infer/src/clang/cFrontend.ml +++ b/infer/src/clang/cFrontend.ml @@ -29,8 +29,7 @@ let rec translate_one_declaration tenv cg cfg namespace dec = let should_translate_enum = CLocation.should_translate_enum source_range in match dec with | FunctionDecl(di, name_info, qt, fdecl_info) -> - let name = name_info.Clang_ast_t.ni_name in - CMethod_declImpl.function_decl tenv cfg cg namespace false di name qt fdecl_info [] None CContext.ContextNoCls + CMethod_declImpl.function_decl tenv cfg cg namespace dec None CContext.ContextNoCls | TypedefDecl (decl_info, name_info, opt_type, _, typedef_decl_info) -> let name = name_info.Clang_ast_t.ni_name in CTypes_decl.do_typedef_declaration tenv namespace @@ -94,8 +93,8 @@ let rec translate_one_declaration tenv cg cfg namespace dec = (* Translates a file by translating the ast into a cfg. *) let compute_icfg tenv source_file ast = match ast with - | TranslationUnitDecl(_, decl_list, _, _) -> - CFrontend_config.global_translation_unit_decls:= decl_list; + | Clang_ast_t.TranslationUnitDecl(_, decl_list, _, _) -> + CFrontend_config.global_translation_unit_decls := decl_list; Printing.log_out "\n Start creating icfg\n"; let cg = Cg.create () in let cfg = Cfg.Node.create_cfg () in diff --git a/infer/src/clang/cMethod_decl.ml b/infer/src/clang/cMethod_decl.ml index 809c1ba6a..9fba244d9 100644 --- a/infer/src/clang/cMethod_decl.ml +++ b/infer/src/clang/cMethod_decl.ml @@ -20,8 +20,9 @@ module type CMethod_decl = sig val process_methods : Sil.tenv -> Cg.t -> Cfg.cfg -> CContext.curr_class -> string option -> Clang_ast_t.decl list -> unit - val function_decl : Sil.tenv -> Cfg.cfg -> Cg.t -> string option -> bool -> Clang_ast_t.decl_info -> - string -> Clang_ast_t.qual_type -> Clang_ast_t.function_decl_info -> (Mangled.t * Sil.typ * bool) list -> Procname.t option -> CContext.curr_class -> unit + val function_decl : Sil.tenv -> Cfg.cfg -> Cg.t -> string option -> Clang_ast_t.decl -> + (Clang_ast_t.qual_type * bool * Procname.t * (Mangled.t * Sil.typ * bool) list) option -> + CContext.curr_class -> unit val process_getter_setter : CContext.t -> Procname.t -> bool end @@ -29,68 +30,13 @@ end module CMethod_decl_funct(T: CModule_type.CTranslation) : CMethod_decl = struct - let method_body_to_translate di ms body = + let method_body_to_translate ms body = match body with | Some body -> if not (CLocation.should_translate_lib (CMethod_signature.ms_get_loc ms)) then None else Some body | None -> body - type function_method_decl_info = - | Func_decl_info of Clang_ast_t.function_decl_info * string - | Meth_decl_info of Clang_ast_t.obj_c_method_decl_info * string - - let is_instance_method function_method_decl_info is_instance is_anonym_block = - if is_anonym_block then is_instance - else ( - match function_method_decl_info with - | Func_decl_info (function_decl_info, _) -> false - | Meth_decl_info (method_decl_info, _) -> - method_decl_info.Clang_ast_t.omdi_is_instance_method) - - let get_parameters function_method_decl_info = - let par_to_ms_par par = - match par with - | ParmVarDecl(decl_info, name_info, qtype, var_decl_info) -> - let name = name_info.Clang_ast_t.ni_name in - Printing.log_out "Adding param '%s' " name; - 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 false) then - ("self", class_name, None):: pars - else pars - - let get_return_type function_method_decl_info = - match function_method_decl_info with - | Func_decl_info (_, qt) -> qt - | Meth_decl_info (method_decl_info, _) -> - let qt = method_decl_info.Clang_ast_t.omdi_result_type in - CTypes.get_type 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 - let qt = get_return_type function_method_decl_info in - let is_instance_method = is_instance_method function_method_decl_info is_instance is_anonym_block in - let parameters = get_parameters function_method_decl_info in - 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 create_function_signature di fdecl_info name qt is_instance anonym_block_opt = - let procname, is_anonym_block = - match anonym_block_opt with - | Some block -> block, true - | None -> CMethod_trans.mk_procname_from_function name (CTypes.get_type qt), false in - let ms = build_method_signature di procname - (Func_decl_info (fdecl_info, CTypes.get_type qt)) is_instance is_anonym_block false in - (match method_body_to_translate di ms fdecl_info.Clang_ast_t.fdi_body with - | Some body -> Some body, ms - | None -> None, ms) let model_exists procname = Specs.summary_exists_in_models procname && not !CFrontend_config.models_mode @@ -147,58 +93,55 @@ struct CMethod_trans.create_external_procdesc cfg procname is_objc_method None; () - let function_decl tenv cfg cg namespace is_instance di name qt fdecl_info captured_vars anonym_block_opt curr_class = - Printing.log_out "\nFound FunctionDecl '%s'. Processing...\n" name; + let function_decl tenv cfg cg namespace func_decl block_data_opt curr_class = Printing.log_out "\nResetting the goto_labels hashmap...\n"; CTrans_utils.GotoLabel.reset_all_labels (); (* C Language Std 6.8.6.1-1 *) - match create_function_signature di fdecl_info name qt is_instance anonym_block_opt with - | Some body, ms -> (* Only in the case the function declaration has a defined body we create a procdesc *) + let ms, body_opt, param_decls = + CMethod_trans.method_signature_of_decl curr_class func_decl block_data_opt in + match method_body_to_translate ms body_opt with + | Some body -> (* Only in the case the function declaration has a defined body we create a procdesc *) let procname = CMethod_signature.ms_get_name ms in + let is_anonym_block, captured_vars = + match block_data_opt with + | Some (_, _, _, captured_vars) -> true, captured_vars + | None -> false, [] in if CMethod_trans.create_local_procdesc cfg tenv ms [body] captured_vars false then let is_instance = CMethod_signature.ms_is_instance ms in - let is_anonym_block = Option.is_some anonym_block_opt in let is_objc_method = is_anonym_block in let curr_class = if is_anonym_block then curr_class else CContext.ContextNoCls in let attributes = CMethod_signature.ms_get_attributes ms in CMethod_signature.add ms; add_method tenv cg cfg curr_class procname namespace [body] is_objc_method is_instance - captured_vars is_anonym_block fdecl_info.Clang_ast_t.fdi_parameters attributes - | None, ms -> CMethod_signature.add ms - - let process_objc_method_decl tenv cg cfg namespace curr_class decl_info name_info method_decl_info = - 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 = method_decl_info.Clang_ast_t.omdi_is_instance_method in - let method_kind = Procname.objc_method_kind_of_bool is_instance in - let procname = CMethod_trans.mk_procname_from_method class_name method_name method_kind in - let method_decl = Meth_decl_info (method_decl_info, 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 - Printing.log_out " ....Processing implementation for method '%s'\n" (Procname.to_string procname); + 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 ms, body_opt, param_decls = + CMethod_trans.method_signature_of_decl curr_class meth_decl None in CMethod_signature.add ms; - (match method_body_to_translate decl_info ms method_decl_info.Clang_ast_t.omdi_body with - | Some body -> - let is_instance = CMethod_signature.ms_is_instance ms in - let attributes = CMethod_signature.ms_get_attributes 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 - method_decl_info.Clang_ast_t.omdi_parameters attributes - | None -> ()) + match method_body_to_translate ms body_opt with + | Some body -> + let is_instance = CMethod_signature.ms_is_instance ms in + 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 + 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 decl_info name_info method_decl_info - - | ObjCPropertyImplDecl(decl_info, property_impl_decl_info) -> + | ObjCMethodDecl (decl_info, name_info, method_decl_info) -> + process_objc_method_decl tenv cg cfg namespace curr_class dec + | 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; let getter_setter = ObjcProperty_decl.make_getter_setter curr_class decl_info pname in list_iter (process_one_method_decl tenv cg cfg curr_class namespace) getter_setter - | EmptyDecl _ | ObjCIvarDecl _ | ObjCPropertyDecl _ -> () - | d -> Printing.log_err - "\nWARNING: found Method Declaration '%s' skipped. NEED TO BE FIXED\n\n" (Ast_utils.string_of_decl d); + | _ -> + Printing.log_stats + "\nWARNING: found Method Declaration '%s' skipped. NEED TO BE FIXED\n\n" (Ast_utils.string_of_decl dec); () let process_methods tenv cg cfg curr_class namespace decl_list = diff --git a/infer/src/clang/cMethod_decl.mli b/infer/src/clang/cMethod_decl.mli index e5161dbe9..0c4a623a3 100644 --- a/infer/src/clang/cMethod_decl.mli +++ b/infer/src/clang/cMethod_decl.mli @@ -13,8 +13,9 @@ module CMethod_decl_funct(T: CModule_type.CTranslation) : sig val process_methods : Sil.tenv -> Cg.t -> Cfg.cfg -> CContext.curr_class -> string option -> Clang_ast_t.decl list -> unit - val function_decl : Sil.tenv -> Cfg.cfg -> Cg.t -> string option -> bool -> Clang_ast_t.decl_info -> - string -> Clang_ast_t.qual_type -> Clang_ast_t.function_decl_info -> (Mangled.t * Sil.typ * bool) list -> Procname.t option -> CContext.curr_class -> unit + val function_decl : Sil.tenv -> Cfg.cfg -> Cg.t -> string option -> Clang_ast_t.decl -> + (Clang_ast_t.qual_type * bool * Procname.t * (Mangled.t * Sil.typ * bool) list) option -> + CContext.curr_class -> unit val process_getter_setter : CContext.t -> Procname.t -> bool @@ -24,8 +25,9 @@ module type CMethod_decl = sig val process_methods : Sil.tenv -> Cg.t -> Cfg.cfg -> CContext.curr_class -> string option -> Clang_ast_t.decl list -> unit - val function_decl : Sil.tenv -> Cfg.cfg -> Cg.t -> string option -> bool -> Clang_ast_t.decl_info -> - string -> Clang_ast_t.qual_type -> Clang_ast_t.function_decl_info -> (Mangled.t * Sil.typ * bool) list -> Procname.t option -> CContext.curr_class -> unit + val function_decl : Sil.tenv -> Cfg.cfg -> Cg.t -> string option -> Clang_ast_t.decl -> + (Clang_ast_t.qual_type * bool * Procname.t * (Mangled.t * Sil.typ * bool) list) option -> + CContext.curr_class -> unit val process_getter_setter : CContext.t -> Procname.t -> bool end diff --git a/infer/src/clang/cMethod_trans.ml b/infer/src/clang/cMethod_trans.ml index db963908b..6cff4ea84 100644 --- a/infer/src/clang/cMethod_trans.ml +++ b/infer/src/clang/cMethod_trans.ml @@ -13,9 +13,19 @@ open Utils open CFrontend_utils open CContext +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 *) @@ -26,13 +36,79 @@ type method_call_type = | MCNoVirtual | MCStatic -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 +type function_method_decl_info = + | Func_decl_info of Clang_ast_t.function_decl_info * string + | 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 + | 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_parameters function_method_decl_info = + let par_to_ms_par par = + match par with + | ParmVarDecl(decl_info, name_info, qtype, var_decl_info) -> + let name = name_info.Clang_ast_t.ni_name in + Printing.log_out "Adding param '%s' " name; + 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 get_return_type function_method_decl_info = + match function_method_decl_info with + | Func_decl_info (_, qt) -> qt + | 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 + let qt = get_return_type function_method_decl_info in + let is_instance_method = is_instance_method function_method_decl_info is_instance in + let parameters = get_parameters function_method_decl_info in + 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 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 + | 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 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 + ms, mdi.Clang_ast_t.omdi_body, mdi.Clang_ast_t.omdi_parameters + | BlockDecl(decl_info, decl_list, decl_context_info, bdi), Some (qt, is_instance, procname, _) -> + let func_decl = Block_decl_info (bdi, CTypes.get_type qt) in + let ms = build_method_signature decl_info procname func_decl is_instance true false in + ms, bdi.Clang_ast_t.bdi_body, bdi.Clang_ast_t.bdi_parameters + |_ -> assert false -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 get_superclass_curr_class context = let retrive_super cname super_opt = diff --git a/infer/src/clang/cMethod_trans.mli b/infer/src/clang/cMethod_trans.mli index 5fb6fd30d..86de15b83 100644 --- a/infer/src/clang/cMethod_trans.mli +++ b/infer/src/clang/cMethod_trans.mli @@ -35,3 +35,7 @@ val get_class_selector_instance : CContext.t -> Clang_ast_t.obj_c_message_expr_i -> (string * string * method_call_type) val should_create_procdesc : Cfg.cfg -> Procname.t -> bool -> bool -> bool + +val method_signature_of_decl : CContext.curr_class -> Clang_ast_t.decl -> + (Clang_ast_t.qual_type * bool * Procname.t * 'a list) option -> + CMethod_signature.method_signature * Clang_ast_t.stmt option * Clang_ast_t.decl list diff --git a/infer/src/clang/cModule_type.ml b/infer/src/clang/cModule_type.ml index 6c64374f5..f4839c680 100644 --- a/infer/src/clang/cModule_type.ml +++ b/infer/src/clang/cModule_type.ml @@ -14,8 +14,9 @@ end module type CMethod_declaration = sig - val function_decl : Sil.tenv -> Cfg.cfg -> Cg.t -> string option -> bool -> Clang_ast_t.decl_info -> - string -> Clang_ast_t.qual_type -> Clang_ast_t.function_decl_info -> (Mangled.t * Sil.typ * bool) list -> Procname.t option -> CContext.curr_class -> unit + val function_decl : Sil.tenv -> Cfg.cfg -> Cg.t -> string option -> Clang_ast_t.decl -> + (Clang_ast_t.qual_type * bool * Procname.t * (Mangled.t * Sil.typ * bool) list) option -> + CContext.curr_class -> unit val process_getter_setter : CContext.t -> Procname.t -> bool end diff --git a/infer/src/clang/cTrans.ml b/infer/src/clang/cTrans.ml index 17180c7b7..63660c499 100644 --- a/infer/src/clang/cTrans.ml +++ b/infer/src/clang/cTrans.ml @@ -1617,33 +1617,33 @@ struct let id = Ident.create_fresh Ident.knormal in let instr = Sil.Letderef (id, Sil.Lvar (Sil.mk_pvar cvar procname), typ, loc) in (id, instr) in - (match decl with - | BlockDecl(decl_info, decl_list, decl_context_info, block_decl_info) -> - let qual_type = expr_info.Clang_ast_t.ei_qual_type in - let block_pname = CFrontend_utils.General_utils.mk_fresh_block_procname procname in - let typ = CTypes_decl.qual_type_to_sil_type context.tenv qual_type in - (* We need to set the explicit dependency between the newly created block and the *) - (* defining procedure. We add an edge in the call graph.*) - Cg.add_edge context.cg procname block_pname; - let function_decl_info = CFrontend_utils.General_utils.mk_function_decl_info_from_block block_decl_info in - let static_locals = list_filter (fun (v, t, s) -> s = true) context.local_vars in - (*list_iter (fun (v, _, _) -> L.err "Static Locals %s@." (Mangled.to_string v)) static_locals;*) - let static_formals = list_filter (fun (v, t, s) -> s = true) context.captured_vars in - (*list_iter (fun (v, _, _) -> L.err "Formal Static %s@." (Mangled.to_string v)) static_formals;*) - let static_vars = static_locals @ static_formals in - let captured_vars = - (CMethod_trans.captured_vars_from_block_info context block_decl_info.Clang_ast_t.bdi_captured_variables) in - let all_captured_vars = captured_vars @ static_vars in - let ids_instrs = list_map assign_captured_var all_captured_vars in - let ids, instrs = list_split ids_instrs in - M.function_decl context.tenv context.cfg context.cg context.namespace context.is_instance decl_info - (Procname.to_string block_pname) qual_type function_decl_info all_captured_vars (Some block_pname) context.curr_class; - Cfg.set_procname_priority context.cfg block_pname; - let captured_exps = list_map (fun id -> Sil.Var id) ids in - let tu = Sil.Ctuple ((Sil.Const (Sil.Cfun block_pname)):: captured_exps) in - let alloc_block_instr, ids_block = allocate_block trans_state (Procname.to_string block_pname) all_captured_vars loc in - { empty_res_trans with ids = ids_block @ ids; instrs = alloc_block_instr @ instrs; exps = [(Sil.Const tu, typ)]} - | _ -> assert false) + match decl with + | BlockDecl(decl_info, decl_list, decl_context_info, block_decl_info) -> + let qual_type = expr_info.Clang_ast_t.ei_qual_type in + let block_pname = CFrontend_utils.General_utils.mk_fresh_block_procname procname in + let typ = CTypes_decl.qual_type_to_sil_type context.tenv qual_type in + (* We need to set the explicit dependency between the newly created block and the *) + (* defining procedure. We add an edge in the call graph.*) + Cg.add_edge context.cg procname block_pname; + let static_locals = list_filter (fun (v, t, s) -> s = true) context.local_vars in + (*list_iter (fun (v, _, _) -> L.err "Static Locals %s@." (Mangled.to_string v)) static_locals;*) + let static_formals = list_filter (fun (v, t, s) -> s = true) context.captured_vars in + (*list_iter (fun (v, _, _) -> L.err "Formal Static %s@." (Mangled.to_string v)) static_formals;*) + let static_vars = static_locals @ static_formals in + let captured_vars = + (CMethod_trans.captured_vars_from_block_info context block_decl_info.Clang_ast_t.bdi_captured_variables) in + let all_captured_vars = captured_vars @ static_vars in + let ids_instrs = list_map assign_captured_var all_captured_vars in + let ids, instrs = list_split ids_instrs in + let block_data = (qual_type, context.is_instance, block_pname, all_captured_vars) in + M.function_decl context.tenv context.cfg context.cg context.namespace decl + (Some block_data) context.curr_class; + Cfg.set_procname_priority context.cfg block_pname; + let captured_exps = list_map (fun id -> Sil.Var id) ids in + let tu = Sil.Ctuple ((Sil.Const (Sil.Cfun block_pname)):: captured_exps) in + let alloc_block_instr, ids_block = allocate_block trans_state (Procname.to_string block_pname) all_captured_vars loc in + { empty_res_trans with ids = ids_block @ ids; instrs = alloc_block_instr @ instrs; exps = [(Sil.Const tu, typ)]} + | _ -> assert false and cxxNewExpr_trans trans_state stmt_info expr_info = let context = trans_state.context in