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.
171 lines
8.4 KiB
171 lines
8.4 KiB
(*
|
|
* 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.
|
|
*)
|
|
|
|
(** Process methods or functions declarations by adding them to the cfg. *)
|
|
|
|
open Utils
|
|
open CFrontend_utils
|
|
open Clang_ast_t
|
|
open CContext
|
|
|
|
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 -> 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
|
|
|
|
module CMethod_decl_funct(T: CModule_type.CTranslation) : CMethod_decl =
|
|
struct
|
|
|
|
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
|
|
|
|
let model_exists procname =
|
|
Specs.summary_exists_in_models procname && not !CFrontend_config.models_mode
|
|
|
|
let rec add_assume_not_null_calls param_decls attributes =
|
|
match param_decls with
|
|
| [] -> []
|
|
| decl:: rest ->
|
|
let rest_assume_calls = add_assume_not_null_calls rest attributes in
|
|
(match decl with
|
|
| ParmVarDecl(decl_info, name_info, qtype, var_decl_info)
|
|
when CFrontend_utils.Ast_utils.is_type_nonnull qtype attributes ->
|
|
let name = name_info.Clang_ast_t.ni_name in
|
|
let assume_call = Ast_expressions.create_assume_not_null_call decl_info name qtype in
|
|
assume_call:: rest_assume_calls
|
|
| _ -> rest_assume_calls)
|
|
|
|
(* 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 param_decls attributes =
|
|
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 body of function: '%s' ---------<<\n@."
|
|
(Procname.to_string procname);
|
|
let nonnull_assume_calls = add_assume_not_null_calls param_decls in
|
|
let instrs' = instrs@nonnull_assume_calls attributes in
|
|
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 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 *)
|
|
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_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
|
|
|
|
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;
|
|
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] 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
|
|
| 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;
|
|
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 _ -> ()
|
|
| _ ->
|
|
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 =
|
|
list_iter (process_one_method_decl tenv cg cfg curr_class namespace) decl_list
|
|
|
|
let process_getter_setter context procname =
|
|
let class_name = Procname.c_get_class procname in
|
|
let cls = CContext.create_curr_class context.tenv class_name in
|
|
let method_name = Procname.c_get_method procname in
|
|
match ObjcProperty_decl.method_is_property_accesor cls method_name with
|
|
| Some (property_name, property_type, is_getter) when
|
|
CMethod_trans.should_create_procdesc context.cfg procname true true ->
|
|
(match property_type with qt, atts, decl_info, _, _, ivar_opt ->
|
|
let ivar_name = ObjcProperty_decl.get_ivar_name property_name ivar_opt in
|
|
let field = CField_decl.build_sil_field_property cls context.tenv ivar_name qt (Some atts) in
|
|
ignore (CField_decl.add_missing_fields context.tenv class_name [field]);
|
|
let accessor =
|
|
if is_getter then
|
|
ObjcProperty_decl.make_getter cls property_name property_type
|
|
else ObjcProperty_decl.make_setter cls property_name property_type in
|
|
list_iter (process_one_method_decl context.tenv context.cg context.cfg cls context.namespace) accessor;
|
|
true)
|
|
| _ -> false
|
|
|
|
end
|