[clang] Use the map of pointers to find method declarations and build method signatures

Summary:
Use the map of pointers to find method declarations and build method signatures.
Remove the need for having an extra map for method signatures (and remove that map).
master
Dulma Rodriguez 9 years ago
parent 001e6a7c8f
commit 3cddd0489c

@ -29,7 +29,7 @@ let rec translate_one_declaration tenv cg cfg namespace parent_dec dec =
let open Clang_ast_t in
match dec with
| FunctionDecl(di, name_info, qt, fdecl_info) ->
CMethod_declImpl.function_decl tenv cfg cg namespace dec None CContext.ContextNoCls
CMethod_declImpl.function_decl tenv cfg cg namespace dec None
| 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
@ -124,7 +124,6 @@ let init_global_state source_file =
DB.current_source := source_file;
DB.Results_dir.init ();
Ident.reset_name_generator ();
CMethod_signature.reset_map ();
CGlobal_vars.reset_map ();
CFrontend_config.global_translation_unit_decls := [];
ObjcProperty_decl.reset_property_table ();

@ -19,8 +19,7 @@ module type CMethod_decl = sig
Clang_ast_t.decl list -> 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
CModule_type.block_data option -> unit
val process_getter_setter : CContext.t -> Procname.t -> bool
end
@ -90,32 +89,32 @@ struct
CMethod_trans.create_external_procdesc cfg procname is_objc_method None;
()
let function_decl tenv cfg cg namespace func_decl block_data_opt curr_class =
let function_decl tenv cfg cg namespace func_decl block_data_opt =
Printing.log_out "\nResetting the goto_labels hashmap...\n";
CTrans_utils.GotoLabel.reset_all_labels (); (* C Language Std 6.8.6.1-1 *)
let is_anonym_block, captured_vars, curr_class =
match block_data_opt with
| Some (_, _, _, captured_vars, curr_class) -> true, captured_vars, curr_class
| None -> false, [], CContext.ContextNoCls in
let class_name =
if curr_class = CContext.ContextNoCls then None else Some (CContext.get_curr_class_name curr_class) in
let ms, body_opt, param_decls =
CMethod_trans.method_signature_of_decl curr_class func_decl block_data_opt in
CMethod_trans.method_signature_of_decl class_name 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_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 param_decls attributes
| None -> CMethod_signature.add ms
| None -> ()
let process_method_decl tenv cg cfg namespace curr_class meth_decl ~is_objc =
let class_name = Some (CContext.get_curr_class_name curr_class) in
let ms, body_opt, param_decls =
CMethod_trans.method_signature_of_decl curr_class meth_decl None in
CMethod_signature.add ms;
CMethod_trans.method_signature_of_decl class_name meth_decl None in
match method_body_to_translate ms body_opt with
| Some body ->
let is_instance = CMethod_signature.ms_is_instance ms in

@ -14,8 +14,7 @@ module CMethod_decl_funct(T: CModule_type.CTranslation) : sig
Clang_ast_t.decl list -> 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
CModule_type.block_data option -> unit
val process_getter_setter : CContext.t -> Procname.t -> bool
@ -26,8 +25,7 @@ module type CMethod_decl = sig
Clang_ast_t.decl list -> 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
CModule_type.block_data option -> unit
val process_getter_setter : CContext.t -> Procname.t -> bool
end

@ -41,10 +41,6 @@ let ms_is_instance ms =
let ms_is_generated ms =
ms._is_generated
type methodMap = method_signature Procname.Map.t
let methodMap = ref Procname.Map.empty
let make_ms procname args ret_type attributes loc is_instance is_generated =
let meth_signature = {
_name = procname;
@ -64,13 +60,3 @@ let ms_to_string ms =
"Method "^(Procname.to_string ms._name)^gen^" "^
(Utils.list_to_string (fun (s1, s2, _) -> s1^", "^s2) ms._args)^"->"^ms._ret_type^" "^
Clang_ast_j.string_of_source_range ms._loc
let find ms =
Procname.Map.find ms !methodMap
let add ms =
try ignore (find ms._name)
with Not_found -> methodMap := Procname.Map.add ms._name ms !methodMap
let reset_map () =
methodMap := Procname.Map.empty

@ -12,12 +12,6 @@
type method_signature
val add : method_signature -> unit
val find : Procname.t -> method_signature
val reset_map : unit -> unit
val ms_get_name : method_signature -> Procname.t
val ms_get_args : method_signature -> (string * string * Clang_ast_t.stmt option) list

@ -15,6 +15,8 @@ open CFrontend_utils
module L = Logging
exception Invalid_declaration
(** 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 *)
@ -84,25 +86,23 @@ 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 =
let method_signature_of_decl class_name_opt meth_decl block_data_opt =
let open Clang_ast_t in
match meth_decl, block_data_opt with
| FunctionDecl (decl_info, name_info, qt, fdi), _ ->
match meth_decl, block_data_opt, class_name_opt with
| FunctionDecl (decl_info, name_info, qt, fdi), _, _ ->
let name = name_info.ni_name in
let func_decl = Func_decl_info (fdi, 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
| CXXMethodDecl (decl_info, name_info, qt, fdi), _, Some class_name ->
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
| ObjCMethodDecl (decl_info, name_info, mdi), _, Some class_name ->
let method_name = name_info.ni_name in
let is_instance = mdi.omdi_is_instance_method in
let method_kind = Procname.objc_method_kind_of_bool is_instance in
@ -112,11 +112,20 @@ let method_signature_of_decl curr_class meth_decl block_data_opt =
let ms = build_method_signature decl_info procname method_decl false false is_generated in
ms, mdi.omdi_body, mdi.omdi_parameters
| BlockDecl (decl_info, decl_list, decl_context_info, bdi),
Some (qt, is_instance, procname, _) ->
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.bdi_body, bdi.bdi_parameters
|_ -> assert false
| _ -> raise Invalid_declaration
let method_signature_of_pointer class_name_opt pointer =
try
match Ast_utils.get_decl pointer with
| Some meth_decl ->
let ms, _, _ = method_signature_of_decl class_name_opt meth_decl None in
Some ms
| None -> None
with Invalid_declaration -> None
let get_superclass_curr_class context =
let retrive_super cname super_opt =
@ -140,20 +149,21 @@ let get_superclass_curr_class context =
let get_class_selector_instance context obj_c_message_expr_info act_params =
let selector = obj_c_message_expr_info.Clang_ast_t.omei_selector in
let pointer = obj_c_message_expr_info.Clang_ast_t.omei_decl_pointer in
match obj_c_message_expr_info.Clang_ast_t.omei_receiver_kind with
| `Class qt -> (CTypes.get_type qt, selector, MCStatic)
| `Class qt -> (CTypes.get_type qt, selector, pointer, MCStatic)
| `Instance ->
(match act_params with
| (instance_obj, Sil.Tptr(t, _)):: _
| (instance_obj, t):: _ ->
(CTypes.classname_of_type t, selector, MCVirtual)
(CTypes.classname_of_type t, selector, pointer, MCVirtual)
| _ -> assert false)
| `SuperInstance ->
let superclass = get_superclass_curr_class context in
(superclass, selector, MCNoVirtual)
(superclass, selector, pointer, MCNoVirtual)
| `SuperClass ->
let superclass = get_superclass_curr_class context in
(superclass, selector, MCStatic)
(superclass, selector, pointer, MCStatic)
let get_formal_parameters tenv ms =
let rec defined_parameters pl =

@ -28,10 +28,11 @@ 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 get_class_selector_instance : CContext.t -> Clang_ast_t.obj_c_message_expr_info -> (Sil.exp * Sil.typ) list
-> (string * string * method_call_type)
-> (string * string * Clang_ast_t.pointer option * 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 ->
val method_signature_of_decl : string option -> Clang_ast_t.decl -> CModule_type.block_data option ->
CMethod_signature.method_signature * Clang_ast_t.stmt option * Clang_ast_t.decl list
val method_signature_of_pointer : string option -> Clang_ast_t.pointer -> CMethod_signature.method_signature option

@ -7,6 +7,8 @@
* of patent rights can be found in the PATENTS file in the same directory.
*)
type block_data = Clang_ast_t.qual_type * bool * Procname.t * (Mangled.t * Sil.typ * bool) list * CContext.curr_class
module type CTranslation =
sig
val instructions_trans : CContext.t -> Clang_ast_t.stmt list -> Cfg.Node.t -> Cfg.Node.t list
@ -15,8 +17,7 @@ end
module type CMethod_declaration =
sig
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
block_data option -> unit
val process_getter_setter : CContext.t -> Procname.t -> bool
end

@ -35,10 +35,11 @@ struct
(*Returns the procname and whether is instance, according to the selector *)
(* information and according to the method signature *)
let get_callee_objc_method context obj_c_message_expr_info act_params =
let (class_name, method_name, mc_type) =
let (class_name, method_name, method_pointer_opt, mc_type) =
CMethod_trans.get_class_selector_instance context obj_c_message_expr_info act_params in
let is_instance = mc_type != CMethod_trans.MCStatic in
let method_kind = Procname.objc_method_kind_of_bool is_instance in
let callee_pn = General_utils.mk_procname_from_objc_method class_name method_name method_kind in
let open CContext in
match CTrans_models.get_predefined_model_method_signature class_name method_name
General_utils.mk_procname_from_objc_method with
@ -46,16 +47,19 @@ struct
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 = General_utils.mk_procname_from_objc_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 = General_utils.mk_procname_from_objc_method class_name method_name method_kind in
let found_method =
match method_pointer_opt with
| Some pointer ->
(match CMethod_trans.method_signature_of_pointer (Some class_name) pointer with
| Some callee_ms ->
if not (M.process_getter_setter context callee_pn) then
(ignore (CMethod_trans.create_local_procdesc context.cfg context.tenv callee_ms [] [] is_instance));
true
| None -> false)
| None -> false in
if not found_method then
CMethod_trans.create_external_procdesc context.cfg callee_pn is_instance None;
callee_pn, mc_type
callee_pn, mc_type
let add_autorelease_call context exp typ sil_loc =
let method_name = Procname.c_get_method (Cfg.Procdesc.get_proc_name context.CContext.procdesc) in
@ -295,6 +299,7 @@ struct
let typ = CTypes_decl.qual_type_to_sil_type context.tenv expr_info.Clang_ast_t.ei_qual_type in
let name = get_name_decl_ref_exp_info decl_ref_expr_info stmt_info in
let procname = Cfg.Procdesc.get_proc_name context.procdesc in
let pointer = CTrans_utils.get_decl_pointer decl_ref_expr_info in
let is_function =
match get_decl_kind decl_ref_expr_info with
| `Function -> true
@ -320,6 +325,11 @@ struct
| Some v ->
(General_utils.mk_procname_from_function name v, CTypes_decl.parse_func_type name v)
| None -> (Procname.from_string_c_fun name, None) in
(match CMethod_trans.method_signature_of_pointer None pointer with
| Some callee_ms ->
ignore (CMethod_trans.create_local_procdesc context.cfg context.tenv callee_ms [] [] false)
| None ->
CMethod_trans.create_external_procdesc context.cfg pname false None);
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.*)
(* As e.g. in fun_ptr = foo; *)
@ -557,7 +567,7 @@ struct
(Procname.to_string pn) <> CFrontend_config.builtin_object_size
| _ -> true in
let params_stmt = if should_translate_args then
CTrans_utils.assign_default_params params_stmt callee_pname_opt ~is_cxx_method:false
CTrans_utils.assign_default_params params_stmt None fun_exp_stmt ~is_cxx_method:false
else [] in
let res_trans_par =
let l = list_map (fun i -> exec_with_self_exception instruction trans_state_param i) params_stmt in
@ -602,11 +612,6 @@ struct
if not (SymExec.function_is_builtin callee_pname) then
begin
Cg.add_edge context.cg procname callee_pname;
try
let callee_ms = CMethod_signature.find callee_pname in
ignore (CMethod_trans.create_local_procdesc context.cfg context.tenv callee_ms [] [] false)
with Not_found ->
CMethod_trans.create_external_procdesc context.cfg callee_pname false None
end
| None -> ());
(match ret_id with
@ -638,8 +643,8 @@ struct
let callee_pname = match sil_method with
| Sil.Const (Sil.Cfun pn) -> pn
| _ -> assert false (* method pointer not implemented, this shouldn't happen *) in
let params_stmt = CTrans_utils.assign_default_params params_stmt (Some callee_pname) ~is_cxx_method:true in
let class_name_opt = Some (Procname.c_get_class callee_pname) in
let params_stmt = CTrans_utils.assign_default_params params_stmt class_name_opt fun_exp_stmt ~is_cxx_method:true in
(* As we may have nodes coming from different parameters we need to *)
(* call instruction for each parameter and collect the results *)
(* afterwards. The 'instructions' function does not do that *)
@ -668,12 +673,6 @@ struct
let result_trans_to_parent =
PriorityNode.compute_results_to_parent trans_state_pri sil_loc nname si res_trans_tmp in
Cg.add_edge context.CContext.cg procname callee_pname;
let cfg = context.CContext.cfg in
(try
let callee_ms = CMethod_signature.find callee_pname in
ignore (CMethod_trans.create_local_procdesc cfg context.CContext.tenv callee_ms [] [] false)
with Not_found ->
CMethod_trans.create_external_procdesc cfg callee_pname false None);
match ret_id with
| [] -> { result_trans_to_parent with exps = [] }
| [ret_id'] -> { result_trans_to_parent with exps = [(Sil.Var ret_id', function_type)] }
@ -709,7 +708,7 @@ struct
let l = list_map (fun i -> exec_with_self_exception instruction trans_state_param i) rest in
obj_c_message_expr_info, collect_res_trans (fst_res_trans :: l)
| [] -> obj_c_message_expr_info, empty_res_trans) in
let (class_type, _, _) = CMethod_trans.get_class_selector_instance context obj_c_message_expr_info res_trans_par.exps in
let (class_type, _, _, _) = CMethod_trans.get_class_selector_instance context obj_c_message_expr_info res_trans_par.exps in
if (selector = CFrontend_config.class_method && CTypes.is_class method_type) then
raise (Self.SelfClassException class_type)
else if is_alloc_or_new then
@ -1764,9 +1763,8 @@ struct
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;
let block_data = (qual_type, context.is_instance, block_pname, all_captured_vars, context.curr_class) in
M.function_decl context.tenv context.cfg context.cg context.namespace decl (Some block_data);
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

@ -571,6 +571,11 @@ let get_decl_kind decl_ref_expr_info =
| Some decl_ref -> decl_ref.Clang_ast_t.dr_kind
| None -> assert false
let get_decl_pointer decl_ref_expr_info =
match decl_ref_expr_info.Clang_ast_t.drti_decl_ref with
| Some decl_ref -> decl_ref.Clang_ast_t.dr_decl_pointer
| None -> assert false
(* From the manual: A selector is in a certain selector family if, ignoring any leading underscores, *)
(* the first component of the selector either consists entirely of the name of *)
(* the method family or it begins with that followed by character other than lower case letter.*)
@ -678,27 +683,43 @@ let is_dispatch_function stmt_list =
| _ -> None))
| _ -> None
let assign_default_params params_stmt callee_pname_opt ~is_cxx_method =
match callee_pname_opt with
let rec pointer_of_call_expr stmt =
let open Clang_ast_t in
match stmt with
| DeclRefExpr(_, _, _, decl_ref_expr_info) ->
Some (get_decl_pointer decl_ref_expr_info)
| MemberExpr(_, _, _, member_expr_info) ->
let decl_ref = member_expr_info.Clang_ast_t.mei_decl_ref in
Some decl_ref.Clang_ast_t.dr_decl_pointer
| _ ->
match snd (Clang_ast_proj.get_stmt_tuple stmt) with
| [stmt] -> pointer_of_call_expr stmt
| _ -> None
let assign_default_params params_stmt class_name_opt stmt ~is_cxx_method =
match pointer_of_call_expr stmt with
| Some pointer ->
(match CMethod_trans.method_signature_of_pointer class_name_opt pointer with
| Some callee_ms ->
(let args = CMethod_signature.ms_get_args callee_ms in
let args = if is_cxx_method then match args with _::tl -> tl | _ -> assert false
else args in
let replace_default_arg param =
match param with
| Clang_ast_t.CXXDefaultArgExpr _, (_, _, Some default_instr) ->
default_instr
| instr, _ -> instr in
try
let params_args = list_combine params_stmt args in
list_map replace_default_arg params_args
with Invalid_argument _ ->
(* list_combine failed because of different list lengths *)
Printing.log_err "Param count doesn't match %s\n"
(Procname.to_string (CMethod_signature.ms_get_name callee_ms));
params_stmt)
| None -> params_stmt)
| None -> params_stmt
| Some callee_pname ->
try
let callee_ms = CMethod_signature.find callee_pname in
let args = CMethod_signature.ms_get_args callee_ms in
let args = if is_cxx_method then match args with _::tl -> tl | _ -> assert false
else args in
let params_args = list_combine params_stmt args in
let replace_default_arg param =
match param with
| Clang_ast_t.CXXDefaultArgExpr _, (_, _, Some default_instr) -> default_instr
| instr, _ -> instr in
list_map replace_default_arg params_args
with
| Invalid_argument _ ->
(* list_combine failed because of different list lengths *)
Printing.log_err "Param count doesn't match %s\n" (Procname.to_string callee_pname);
params_stmt
| Not_found -> params_stmt
let is_block_enumerate_function mei =
mei.Clang_ast_t.omei_selector = CFrontend_config.enumerateObjectsUsingBlock

@ -70,6 +70,8 @@ val get_name_decl_ref_exp_info : Clang_ast_t.decl_ref_expr_info -> Clang_ast_t.s
val get_decl_kind : Clang_ast_t.decl_ref_expr_info -> Clang_ast_t.decl_kind
val get_decl_pointer : Clang_ast_t.decl_ref_expr_info -> Clang_ast_t.pointer
val is_enumeration_constant : Clang_ast_t.stmt -> bool
val is_member_exp : Clang_ast_t.stmt -> bool
@ -203,7 +205,7 @@ val is_logical_negation_of_int : Sil.tenv -> Clang_ast_t.expr_info -> Clang_ast_
val is_dispatch_function : Clang_ast_t.stmt list -> int option
val assign_default_params : Clang_ast_t.stmt list -> Procname.t option ->
val assign_default_params : Clang_ast_t.stmt list -> string option -> Clang_ast_t.stmt ->
is_cxx_method:bool -> Clang_ast_t.stmt list
val is_block_enumerate_function : Clang_ast_t.obj_c_message_expr_info -> bool

Loading…
Cancel
Save