You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
177 lines
8.8 KiB
177 lines
8.8 KiB
(*
|
|
* Copyright (c) 2013 - Facebook.
|
|
* All rights reserved.
|
|
*)
|
|
|
|
(** Process methods or functions declarations by adding them to the cfg. *)
|
|
|
|
open Utils
|
|
open CFrontend_utils
|
|
open Clang_ast_t
|
|
|
|
module L = Logging
|
|
|
|
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 create_function_signature : Clang_ast_t.decl_info -> Clang_ast_t.function_decl_info -> string ->
|
|
Clang_ast_t.qual_type -> bool -> Procname.t option -> Clang_ast_t.stmt option * CMethod_signature.method_signature
|
|
end
|
|
|
|
module CMethod_decl_funct(T: CModule_type.CTranslation) : CMethod_decl =
|
|
struct
|
|
|
|
let method_body_to_translate di 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, qtype, var_decl_info) ->
|
|
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)
|
|
| _ -> 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):: 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 =
|
|
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
|
|
CMethod_signature.make_ms procname parameters qt source_range is_instance_method
|
|
|
|
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 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
|
|
|
|
(* Translates the method/function's body into nodes of the cfg. *)
|
|
let add_method tenv cg cfg class_decl_opt procname namespace instrs is_objc_method is_instance
|
|
captured_vars is_anonym_block =
|
|
Printing.log_out
|
|
"\n\n>>---------- ADDING METHOD: '%s' ---------<<\n" (Procname.to_string procname);
|
|
try
|
|
(match Cfg.Procdesc.find_from_name cfg procname with
|
|
| Some procdesc ->
|
|
if (Cfg.Procdesc.is_defined procdesc && not (model_exists procname)) then
|
|
(let context =
|
|
CContext.create_context tenv cg cfg procdesc namespace class_decl_opt
|
|
is_objc_method captured_vars is_instance in
|
|
CVar_decl.get_fun_locals context instrs;
|
|
let local_vars = list_map (fun (n, t, _) -> n, t) context.CContext.local_vars in
|
|
let start_node = Cfg.Procdesc.get_start_node procdesc in
|
|
let exit_node = Cfg.Procdesc.get_exit_node procdesc in
|
|
Cfg.Procdesc.append_locals procdesc local_vars;
|
|
Cfg.Node.add_locals_ret_declaration start_node local_vars;
|
|
Printing.log_out
|
|
"\n\n>>---------- Start translating the function: '%s' ---------<<"
|
|
(Procname.to_string procname);
|
|
let meth_body_nodes = T.instructions_trans context instrs exit_node in
|
|
if (not is_anonym_block) then CContext.LocalVars.reset_block ();
|
|
Cfg.Node.set_succs_exn start_node meth_body_nodes [];
|
|
Cg.add_node (CContext.get_cg context) (Cfg.Procdesc.get_proc_name procdesc))
|
|
| None -> ())
|
|
with
|
|
| Not_found -> ()
|
|
| CTrans_utils.Self.SelfClassException _ ->
|
|
assert false (* this shouldn't happen, because self or [a class] should always be arguments of functions. This is to make sure I'm not wrong. *)
|
|
| Assert_failure (file, line, column) ->
|
|
print_endline ("Fatal error: exception Assert_failure("^
|
|
file^", "^(string_of_int line)^", "^(string_of_int column)^")");
|
|
Cfg.Procdesc.remove cfg procname true;
|
|
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;
|
|
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 procname = CMethod_signature.ms_get_name ms in
|
|
CMethod_trans.create_local_procdesc cfg tenv ms [body] captured_vars false;
|
|
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
|
|
add_method tenv cg cfg curr_class procname namespace [body] is_objc_method is_instance
|
|
captured_vars is_anonym_block
|
|
| None, ms -> CMethod_signature.add ms
|
|
|
|
let process_objc_method_decl tenv cg cfg namespace curr_class decl_info method_name method_decl_info =
|
|
let class_name = CContext.get_curr_class_name curr_class in
|
|
let procname = CMethod_trans.mk_procname_from_method class_name method_name in
|
|
let method_decl = Meth_decl_info (method_decl_info, class_name) in
|
|
let ms = build_method_signature decl_info procname method_decl false false in
|
|
Printing.log_out " ....Processing implementation for method '%s'\n" (Procname.to_string procname);
|
|
(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
|
|
CMethod_trans.create_local_procdesc cfg tenv ms [body] [] is_instance;
|
|
add_method tenv cg cfg curr_class procname namespace [body] true is_instance [] false
|
|
| None ->
|
|
CMethod_signature.add ms)
|
|
|
|
let rec process_one_method_decl tenv cg cfg curr_class namespace dec =
|
|
match dec with
|
|
| ObjCMethodDecl(decl_info, method_name, method_decl_info) ->
|
|
process_objc_method_decl tenv cg cfg namespace curr_class decl_info method_name method_decl_info
|
|
|
|
| ObjCPropertyImplDecl(decl_info, property_impl_decl_info) ->
|
|
let prop_methods = ObjcProperty_decl.make_getter_setter cfg curr_class decl_info property_impl_decl_info in
|
|
list_iter (process_one_method_decl tenv cg cfg curr_class namespace) prop_methods
|
|
|
|
| EmptyDecl _ | ObjCIvarDecl _ -> ()
|
|
| d -> Printing.log_err
|
|
"\nWARNING: found Method Declaration '%s' skipped. NEED TO BE FIXED\n\n" (Ast_utils.string_of_decl d);
|
|
()
|
|
|
|
let process_methods tenv cg cfg curr_class namespace decl_list =
|
|
list_iter (process_one_method_decl tenv cg cfg curr_class namespace) decl_list
|
|
|
|
end
|