[clang] Refactor building method signatures

Reviewed By: da319

Differential Revision: D8139862

fbshipit-source-id: ea79568
master
Dulma Churchill 7 years ago committed by Facebook Github Bot
parent 6769248f9b
commit 6ad971c875

@ -184,6 +184,8 @@ let mk_array ?default ?quals ?length ?stride elt : t =
mk ?default ?quals (Tarray {elt; length; stride})
let void = mk Tvoid
let void_star = mk (Tptr (mk Tvoid, Pk_pointer))
let merge_quals quals1 quals2 =

@ -112,6 +112,9 @@ val mk : ?default:t -> ?quals:type_quals -> desc -> t
val mk_array : ?default:t -> ?quals:type_quals -> ?length:IntLit.t -> ?stride:IntLit.t -> t -> t
(** Create an array type from a given element type. If [length] or [stride] value is given, use them as static length and size. *)
val void : t
(** void type *)
val void_star : t
(** void* type *)

@ -0,0 +1,147 @@
(*
* Copyright (c) 2018 - 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.
*)
open! IStd
(** Functions for extracting properties of functions or method declarations *)
let get_method_kind meth_decl =
let open Clang_ast_t in
match meth_decl with
| FunctionDecl _ ->
ProcAttributes.C_FUNCTION
| CXXMethodDecl (_, _, _, _, method_decl_info)
| CXXConstructorDecl (_, _, _, _, method_decl_info)
| CXXConversionDecl (_, _, _, _, method_decl_info)
| CXXDestructorDecl (_, _, _, _, method_decl_info) ->
if method_decl_info.Clang_ast_t.xmdi_is_static then ProcAttributes.CPP_CLASS
else ProcAttributes.CPP_INSTANCE
| ObjCMethodDecl (_, _, method_decl_info) ->
if method_decl_info.Clang_ast_t.omdi_is_instance_method then ProcAttributes.OBJC_INSTANCE
else ProcAttributes.OBJC_CLASS
| BlockDecl _ ->
ProcAttributes.BLOCK
| _ ->
raise CFrontend_config.Invalid_declaration
let get_return_type method_decl =
let open Clang_ast_t in
match method_decl with
| FunctionDecl (_, _, qt, _)
| CXXMethodDecl (_, _, qt, _, _)
| CXXConstructorDecl (_, _, qt, _, _)
| CXXConversionDecl (_, _, qt, _, _)
| CXXDestructorDecl (_, _, qt, _, _) ->
CType.return_type_of_function_type qt
| ObjCMethodDecl (_, _, omdi) ->
omdi.omdi_result_type
| _ ->
raise CFrontend_config.Invalid_declaration
let get_param_decls method_decl =
let open Clang_ast_t in
match method_decl with
| FunctionDecl (_, _, _, function_decl_info)
| CXXMethodDecl (_, _, _, function_decl_info, _)
| CXXConstructorDecl (_, _, _, function_decl_info, _)
| CXXConversionDecl (_, _, _, function_decl_info, _)
| CXXDestructorDecl (_, _, _, function_decl_info, _) ->
function_decl_info.fdi_parameters
| ObjCMethodDecl (_, _, method_decl_info) ->
method_decl_info.omdi_parameters
| BlockDecl (_, block_decl_info) ->
block_decl_info.bdi_parameters
| _ ->
raise CFrontend_config.Invalid_declaration
let get_method_body method_decl =
let open Clang_ast_t in
match method_decl with
| FunctionDecl (_, _, _, function_decl_info)
| CXXMethodDecl (_, _, _, function_decl_info, _)
| CXXConstructorDecl (_, _, _, function_decl_info, _)
| CXXConversionDecl (_, _, _, function_decl_info, _)
| CXXDestructorDecl (_, _, _, function_decl_info, _) ->
function_decl_info.fdi_body
| ObjCMethodDecl (_, _, method_decl_info) ->
method_decl_info.omdi_body
| BlockDecl (_, block_decl_info) ->
block_decl_info.bdi_body
| _ ->
raise CFrontend_config.Invalid_declaration
let get_language ~is_cpp method_decl =
let open Clang_ast_t in
match method_decl with
| FunctionDecl _ ->
if is_cpp then CFrontend_config.CPP else CFrontend_config.ObjC
| CXXMethodDecl _ | CXXConstructorDecl _ | CXXConversionDecl _ | CXXDestructorDecl _ ->
CFrontend_config.CPP
| ObjCMethodDecl _ | BlockDecl _ ->
CFrontend_config.ObjC
| _ ->
raise CFrontend_config.Invalid_declaration
let is_cpp_virtual method_decl =
let open Clang_ast_t in
match method_decl with
| CXXMethodDecl (_, _, _, _, mdi)
| CXXConstructorDecl (_, _, _, _, mdi)
| CXXConversionDecl (_, _, _, _, mdi)
| CXXDestructorDecl (_, _, _, _, mdi) ->
mdi.xmdi_is_virtual
| _ ->
false
let is_cpp_nothrow method_decl =
let open Clang_ast_t in
match method_decl with
| FunctionDecl (_, _, _, fdi)
| CXXMethodDecl (_, _, _, fdi, _)
| CXXConstructorDecl (_, _, _, fdi, _)
| CXXConversionDecl (_, _, _, fdi, _)
| CXXDestructorDecl (_, _, _, fdi, _) ->
fdi.fdi_is_no_throw
| _ ->
false
let get_init_list_instrs method_decl =
let open Clang_ast_t in
match method_decl with
| CXXMethodDecl (_, _, _, _, mdi)
| CXXConstructorDecl (_, _, _, _, mdi)
| CXXConversionDecl (_, _, _, _, mdi)
| CXXDestructorDecl (_, _, _, _, mdi) ->
let create_custom_instr construct_instr = `CXXConstructorInit construct_instr in
List.map ~f:create_custom_instr mdi.xmdi_cxx_ctor_initializers
| _ ->
[]
let get_pointer_to_property method_decl =
let open Clang_ast_t in
match method_decl with
| ObjCMethodDecl (_, _, mdi) -> (
match mdi.Clang_ast_t.omdi_property_decl with
| Some decl_ref ->
Some decl_ref.Clang_ast_t.dr_decl_pointer
| None ->
None )
| _ ->
None
let is_objc_method method_decl =
match method_decl with Clang_ast_t.ObjCMethodDecl _ -> true | _ -> false

@ -0,0 +1,33 @@
(*
* Copyright (c) 2018 - 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.
*)
open! IStd
(** Functions for extracting properties of functions or method declarations *)
val get_method_kind : Clang_ast_t.decl -> ProcAttributes.clang_method_kind
val get_return_type : Clang_ast_t.decl -> Clang_ast_t.qual_type
val get_param_decls : Clang_ast_t.decl -> Clang_ast_t.decl list
val get_method_body : Clang_ast_t.decl -> Clang_ast_t.stmt option
val get_language : is_cpp:bool -> Clang_ast_t.decl -> CFrontend_config.clang_lang
val is_cpp_virtual : Clang_ast_t.decl -> bool
val is_cpp_nothrow : Clang_ast_t.decl -> bool
val get_init_list_instrs :
Clang_ast_t.decl -> [> `CXXConstructorInit of Clang_ast_t.cxx_ctor_initializer] list
val get_pointer_to_property : Clang_ast_t.decl -> Clang_ast_t.pointer option
val is_objc_method : Clang_ast_t.decl -> bool

@ -11,6 +11,169 @@ open! IStd
(** Processes types and record declarations by adding them to the tenv *)
module BuildMethodSignature = struct
let get_class_parameter_name method_kind =
match method_kind with
| ProcAttributes.CPP_INSTANCE ->
Some (Mangled.from_string CFrontend_config.this)
| ProcAttributes.OBJC_INSTANCE ->
Some (Mangled.from_string CFrontend_config.self)
| _ ->
None
let param_type_of_qual_type qual_type_to_sil_type tenv name qual_type =
let typ = qual_type_to_sil_type tenv qual_type in
let is_value = CType.is_value qual_type in
let is_pointer_to_const = CType.is_pointer_to_const qual_type in
let annot = CAst_utils.sil_annot_of_type qual_type in
Some (CMethodSignature.mk_param_type ~is_value ~is_pointer_to_const ~annot name typ)
let get_class_param qual_type_to_sil_type tenv method_decl =
let open Clang_ast_t in
match method_decl with
| FunctionDecl _ | BlockDecl _ ->
None
| CXXMethodDecl (decl_info, _, _, _, _)
| CXXConstructorDecl (decl_info, _, _, _, _)
| CXXConversionDecl (decl_info, _, _, _, _)
| CXXDestructorDecl (decl_info, _, _, _, _)
| ObjCMethodDecl (decl_info, _, _)
-> (
let method_kind = CMethodProperties.get_method_kind method_decl in
match method_kind with
| ProcAttributes.CPP_INSTANCE | ProcAttributes.OBJC_INSTANCE -> (
match (get_class_parameter_name method_kind, decl_info.di_parent_pointer) with
| Some name, Some parent_pointer ->
let qual_type = CAst_utils.qual_type_of_decl_ptr parent_pointer in
let pointer_qual_type = Ast_expressions.create_pointer_qual_type qual_type in
param_type_of_qual_type qual_type_to_sil_type tenv name pointer_qual_type
| _ ->
None )
| _ ->
None )
| _ ->
raise CFrontend_config.Invalid_declaration
let should_add_return_param return_type ~is_objc_method =
match return_type.Typ.desc with Tstruct _ -> not is_objc_method | _ -> false
let get_return_param qual_type_to_sil_type tenv ~block_return_type method_decl =
let is_objc_method = CMethodProperties.is_objc_method method_decl in
let return_qual_type =
match block_return_type with
| Some return_type ->
CType.return_type_of_function_type return_type
| None ->
CMethodProperties.get_return_type method_decl
in
let return_typ = qual_type_to_sil_type tenv return_qual_type in
if should_add_return_param return_typ ~is_objc_method then
let name = Mangled.from_string CFrontend_config.return_param in
let return_qual_type = Ast_expressions.create_pointer_qual_type return_qual_type in
param_type_of_qual_type qual_type_to_sil_type tenv name return_qual_type
else None
(** Returns parameters of a function/method. They will have following order:
1. normal parameters
2. return parameter (optional) *)
let get_parameters qual_type_to_sil_type ~is_cpp tenv ~block_return_type method_decl =
let par_to_ms_par par =
match par with
| Clang_ast_t.ParmVarDecl (_, name_info, qt, var_decl_info) ->
let method_decl_info = Clang_ast_proj.get_decl_tuple method_decl in
let _, name =
CGeneral_utils.get_var_name_mangled method_decl_info name_info var_decl_info
in
let param_typ = qual_type_to_sil_type tenv qt in
let typ =
match param_typ.Typ.desc with
| Tstruct _ when is_cpp ->
qual_type_to_sil_type tenv (Ast_expressions.create_reference_qual_type qt)
| _ ->
param_typ
in
let is_pointer_to_const = CType.is_pointer_to_const qt in
let is_value = CType.is_value qt in
let annot = CAst_utils.sil_annot_of_type qt in
CMethodSignature.mk_param_type name typ ~is_value ~is_pointer_to_const ~annot
| _ ->
raise CFrontend_config.Invalid_declaration
in
let params = List.map ~f:par_to_ms_par (CMethodProperties.get_param_decls method_decl) in
let return_param =
Option.to_list (get_return_param qual_type_to_sil_type tenv ~block_return_type method_decl)
in
params @ return_param
(** get return type of the function and optionally type of function's return parameter *)
let get_return_val_and_param_types qual_type_to_sil_type tenv ~block_return_type method_decl =
let return_qual_type =
match block_return_type with
| Some return_type ->
CType.return_type_of_function_type return_type
| None ->
CMethodProperties.get_return_type method_decl
in
let return_typ = qual_type_to_sil_type tenv return_qual_type in
let return_typ_annot = CAst_utils.sil_annot_of_type return_qual_type in
let is_objc_method = CMethodProperties.is_objc_method method_decl in
if should_add_return_param return_typ ~is_objc_method then
(Typ.void, Some (CType.add_pointer_to_typ return_typ), Annot.Item.empty)
else (return_typ, None, return_typ_annot)
let method_signature_of_decl qual_type_to_sil_type ~is_cpp tenv method_decl ?block_return_type
procname =
let decl_info = Clang_ast_proj.get_decl_tuple method_decl in
let loc = decl_info.Clang_ast_t.di_source_range in
let ret_type, return_param_typ, ret_typ_annot =
get_return_val_and_param_types qual_type_to_sil_type tenv ~block_return_type method_decl
in
let method_kind = CMethodProperties.get_method_kind method_decl in
let pointer_to_parent = decl_info.di_parent_pointer in
let class_param = get_class_param qual_type_to_sil_type tenv method_decl in
let params =
get_parameters qual_type_to_sil_type ~is_cpp tenv ~block_return_type method_decl
in
let attributes = decl_info.Clang_ast_t.di_attributes in
let lang = CMethodProperties.get_language ~is_cpp method_decl in
let is_cpp_virtual = CMethodProperties.is_cpp_virtual method_decl in
let is_cpp_nothrow = CMethodProperties.is_cpp_nothrow method_decl in
let access = decl_info.Clang_ast_t.di_access in
let pointer_to_property_opt = CMethodProperties.get_pointer_to_property method_decl in
{ CMethodSignature.name= procname
; access
; class_param
; params
; ret_type= (ret_type, ret_typ_annot)
; attributes
; loc
; method_kind
; is_cpp_virtual
; is_cpp_nothrow
; lang
; pointer_to_parent
; pointer_to_property_opt
; return_param_typ }
let method_signature_body_of_decl qual_type_to_sil_type ~is_cpp tenv method_decl
?block_return_type procname =
let body = CMethodProperties.get_method_body method_decl in
let init_list_instrs = CMethodProperties.get_init_list_instrs method_decl in
let ms =
method_signature_of_decl qual_type_to_sil_type ~is_cpp tenv method_decl ?block_return_type
procname
in
(ms, body, init_list_instrs)
end
let get_struct_decls decl =
let open Clang_ast_t in
match decl with
@ -356,8 +519,8 @@ and mk_c_function ?tenv ~is_cpp name function_decl_info_opt =
match function_decl_info.Clang_ast_t.fdi_storage_class with
| Some "static"
(* when we model static functions, we cannot take the file into account to
create a mangled name because the file of the model is different to the real file,
thus the model won't work *)
create a mangled name because the file of the model is different to the real file,
thus the model won't work *)
when not (CTrans_models.is_modelled_static_function (QualifiedCppName.to_qual_string name)) ->
let file_opt =
(fst decl_info.Clang_ast_t.di_source_range).Clang_ast_t.sl_file
@ -444,6 +607,7 @@ and objc_block_procname outer_proc_opt =
Typ.Procname.mangled_objc_block name
(* TODO: get the parameters from BuildMethodSignature.get_parameters and pass it to the method names *)
and from_decl ?tenv ~is_cpp ?outer_proc meth_decl =
let open Clang_ast_t in
match meth_decl with
@ -526,6 +690,14 @@ and get_record_struct_type tenv definition_decl : Typ.desc =
assert false
let method_signature_body_of_decl =
BuildMethodSignature.method_signature_body_of_decl qual_type_to_sil_type
let method_signature_of_decl = BuildMethodSignature.method_signature_of_decl qual_type_to_sil_type
let should_add_return_param = BuildMethodSignature.should_add_return_param
module CProcname = struct
let from_decl = from_decl

@ -47,3 +47,16 @@ val qual_type_to_sil_type : Tenv.t -> Clang_ast_t.qual_type -> Typ.t
val class_from_pointer_type : Tenv.t -> Clang_ast_t.qual_type -> Typ.Name.t
val get_type_from_expr_info : Clang_ast_t.expr_info -> Tenv.t -> Typ.t
val method_signature_of_decl :
is_cpp:bool -> Tenv.t -> Clang_ast_t.decl -> ?block_return_type:Clang_ast_t.qual_type
-> Typ.Procname.t -> CMethodSignature.t
val method_signature_body_of_decl :
is_cpp:bool -> Tenv.t -> Clang_ast_t.decl -> ?block_return_type:Clang_ast_t.qual_type
-> Typ.Procname.t
-> CMethodSignature.t
* Clang_ast_t.stmt option
* [> `CXXConstructorInit of Clang_ast_t.cxx_ctor_initializer] list
val should_add_return_param : Typ.typ -> is_objc_method:bool -> bool

@ -43,8 +43,6 @@ let create_char_type = builtin_to_qual_type `Char_S
let create_char_star_type ?quals () = create_pointer_qual_type ?quals create_char_type
let create_BOOL_type = builtin_to_qual_type `SChar
let create_class_qual_type ?quals typename =
create_qual_type ?quals (Clang_ast_extend.ClassType typename)

@ -12,20 +12,12 @@ open Clang_ast_t
(** This module creates extra ast constructs that are needed for the translation *)
val create_class_qual_type : ?quals:Typ.type_quals -> Typ.Name.t -> qual_type
val create_pointer_qual_type : ?quals:Typ.type_quals -> qual_type -> qual_type
val create_reference_qual_type : ?quals:Typ.type_quals -> qual_type -> qual_type
val create_char_star_type : ?quals:Typ.type_quals -> unit -> qual_type
val create_id_type : qual_type
val create_void_type : qual_type
val create_BOOL_type : qual_type
val make_next_object_exp :
stmt_info -> stmt -> Clang_ast_t.stmt -> Clang_ast_t.stmt * Clang_ast_t.stmt

@ -200,12 +200,6 @@ let name_opt_of_typedef_qual_type qual_type =
None
let string_of_qual_type {Clang_ast_t.qt_type_ptr; qt_is_const} =
Printf.sprintf "%s%s"
(if qt_is_const then "is_const " else "")
(Clang_ast_extend.type_ptr_to_string qt_type_ptr)
let qual_type_of_decl_ptr decl_ptr =
{ (* This function needs to be in this module - CAst_utils can't depend on
Ast_expressions *)

@ -64,8 +64,6 @@ val name_of_typedef_type_info : Clang_ast_t.typedef_type_info -> QualifiedCppNam
val name_opt_of_typedef_qual_type : Clang_ast_t.qual_type -> QualifiedCppName.t option
val string_of_qual_type : Clang_ast_t.qual_type -> string
type qual_type_to_sil_type = Tenv.t -> Clang_ast_t.qual_type -> Typ.t
val qual_type_of_decl_ptr : Clang_ast_t.pointer -> Clang_ast_t.qual_type

@ -40,6 +40,8 @@ let incorrect_assumption position source_range ?ast_node fmt =
type translation_unit_context = {lang: clang_lang; source_file: SourceFile.t}
exception Invalid_declaration
(** Constants *)
let alloc = "alloc"

@ -41,6 +41,8 @@ val incorrect_assumption :
type translation_unit_context = {lang: clang_lang; source_file: SourceFile.t}
exception Invalid_declaration
(** Constants *)
val alloc : string

@ -106,13 +106,20 @@ module CFrontend_decl_funct (T : CModule_type.CTranslation) : CModule_type.CFron
| None ->
([], None)
in
let is_cpp = CGeneral_utils.is_cpp_translation trans_unit_ctx in
let procname, block_return_type =
match block_data_opt with
| Some (_, block_return_type, procname, _) ->
(procname, Some block_return_type)
| _ ->
(CType_decl.CProcname.from_decl ~is_cpp ~tenv func_decl, None)
in
let ms, body_opt, extra_instrs =
CMethod_trans.method_signature_of_decl trans_unit_ctx tenv func_decl block_data_opt
CType_decl.method_signature_body_of_decl ~is_cpp tenv func_decl ?block_return_type procname
in
match body_opt with
| Some body ->
(* Only in the case the function declaration has a defined body we create a procdesc *)
let procname = ms.CMethodSignature.name in
let return_param_typ_opt = ms.CMethodSignature.return_param_typ in
if CMethod_trans.create_local_procdesc trans_unit_ctx cfg tenv ms [body] captured_vars
then
@ -127,9 +134,11 @@ module CFrontend_decl_funct (T : CModule_type.CTranslation) : CModule_type.CFron
let process_method_decl ?(set_objc_accessor_attr= false) ?(is_destructor= false) trans_unit_ctx
tenv cfg curr_class meth_decl ~is_objc =
let is_cpp = CGeneral_utils.is_cpp_translation trans_unit_ctx in
try
let ms, body_opt, extra_instrs =
CMethod_trans.method_signature_of_decl trans_unit_ctx tenv meth_decl None
let procname = CType_decl.CProcname.from_decl ~is_cpp ~tenv meth_decl in
CType_decl.method_signature_body_of_decl ~is_cpp tenv meth_decl procname
in
match body_opt with
| Some body ->
@ -407,7 +416,7 @@ module CFrontend_decl_funct (T : CModule_type.CTranslation) : CModule_type.CFron
Option.value_exn (Pvar.get_initializer_pname global)
in
let ms =
CMethodSignature.mk procname [] Ast_expressions.create_void_type []
CMethodSignature.mk procname None [] (Typ.void, Annot.Item.empty) []
decl_info.Clang_ast_t.di_source_range ProcAttributes.C_FUNCTION
trans_unit_ctx.CFrontend_config.lang None None None `None
in

@ -14,11 +14,20 @@ open! IStd
module F = Format
type param_type =
{name: Mangled.t; typ: Typ.t; is_pointer_to_const: bool; is_value: bool; annot: Annot.Item.t}
let mk_param_type ?(is_value= false) ?(is_pointer_to_const= false) ?(annot= Annot.Item.empty) name
typ =
{name; typ; is_value; is_pointer_to_const; annot}
type t =
{ name: Typ.Procname.t
; access: Clang_ast_t.access_specifier
; args: (Mangled.t * Clang_ast_t.qual_type) list
; ret_type: Clang_ast_t.qual_type
; class_param: param_type option
; params: param_type list
; ret_type: Typ.t * Annot.Item.t
; attributes: Clang_ast_t.attribute list
; loc: Clang_ast_t.source_range
; method_kind: ProcAttributes.clang_method_kind
@ -31,24 +40,25 @@ type t =
return_param_typ: Typ.t option }
(* A method is a getter if it has a link to a property and *)
(* it has 1 argument (this includes self) *)
let is_getter {pointer_to_property_opt; args} =
Option.is_some pointer_to_property_opt && Int.equal (List.length args) 1
(* it has 0 arguments *)
let is_getter {pointer_to_property_opt; params} =
Option.is_some pointer_to_property_opt && Int.equal (List.length params) 0
(* A method is a setter if it has a link to a property and *)
(* it has 2 argument (this includes self) *)
let is_setter {pointer_to_property_opt; args} =
Option.is_some pointer_to_property_opt && Int.equal (List.length args) 2
(* it has 1 argument *)
let is_setter {pointer_to_property_opt; params} =
Option.is_some pointer_to_property_opt && Int.equal (List.length params) 1
let mk name args ret_type attributes loc method_kind ?is_cpp_virtual ?is_cpp_nothrow lang
pointer_to_parent pointer_to_property_opt return_param_typ access =
let mk name class_param params ret_type attributes loc method_kind ?is_cpp_virtual ?is_cpp_nothrow
lang pointer_to_parent pointer_to_property_opt return_param_typ access =
let is_cpp_virtual = Option.value is_cpp_virtual ~default:false in
let is_cpp_nothrow = Option.value is_cpp_nothrow ~default:false in
{ name
; access
; args
; class_param
; params
; ret_type
; attributes
; loc
@ -62,15 +72,9 @@ let mk name args ret_type attributes loc method_kind ?is_cpp_virtual ?is_cpp_not
let pp fmt ms =
let pp_arg fmt (mangled, qual_type) =
F.fprintf fmt "%a, %a" Mangled.pp mangled
(Pp.to_string ~f:CAst_utils.string_of_qual_type)
qual_type
in
let pp_param fmt {name; typ} = F.fprintf fmt "%a, %a" Mangled.pp name (Typ.pp Pp.text) typ in
Format.fprintf fmt "Method %a [%a]->%a %a"
(Pp.to_string ~f:Typ.Procname.to_string)
ms.name (Pp.comma_seq pp_arg) ms.args
(Pp.to_string ~f:Clang_ast_extend.type_ptr_to_string)
ms.ret_type.Clang_ast_t.qt_type_ptr
ms.name (Pp.comma_seq pp_param) ms.params (Typ.pp Pp.text) (fst ms.ret_type)
(Pp.to_string ~f:Clang_ast_j.string_of_source_range)
ms.loc

@ -12,11 +12,15 @@ open! IStd
(** Define the signature of a method consisting of its name, its arguments, return type, location
and whether its an instance method. *)
type param_type =
{name: Mangled.t; typ: Typ.t; is_pointer_to_const: bool; is_value: bool; annot: Annot.Item.t}
type t =
{ name: Typ.Procname.t
; access: Clang_ast_t.access_specifier
; args: (Mangled.t * Clang_ast_t.qual_type) list
; ret_type: Clang_ast_t.qual_type
; class_param: param_type option
; params: param_type list
; ret_type: Typ.t * Annot.Item.t
; attributes: Clang_ast_t.attribute list
; loc: Clang_ast_t.source_range
; method_kind: ProcAttributes.clang_method_kind
@ -33,10 +37,14 @@ val is_getter : t -> bool
val is_setter : t -> bool
val mk :
Typ.Procname.t -> (Mangled.t * Clang_ast_t.qual_type) list -> Clang_ast_t.qual_type
Typ.Procname.t -> param_type option -> param_type list -> Typ.t * Annot.Item.t
-> Clang_ast_t.attribute list -> Clang_ast_t.source_range -> ProcAttributes.clang_method_kind
-> ?is_cpp_virtual:bool -> ?is_cpp_nothrow:bool -> CFrontend_config.clang_lang
-> Clang_ast_t.pointer option -> Clang_ast_t.pointer option -> Typ.t option
-> Clang_ast_t.access_specifier -> t
val pp : Format.formatter -> t -> unit
val mk_param_type :
?is_value:bool -> ?is_pointer_to_const:bool -> ?annot:Annot.Item.t -> Mangled.t -> Typ.t
-> param_type

@ -14,8 +14,6 @@ open! IStd
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 it means that it is an instance method but that the method to be
@ -24,224 +22,17 @@ type method_call_type = MCVirtual | MCNoVirtual | MCStatic [@@deriving compare]
let equal_method_call_type = [%compare.equal : method_call_type]
type function_method_decl_info =
| Func_decl_info of Clang_ast_t.function_decl_info * Clang_ast_t.qual_type
| Cpp_Meth_decl_info of
Clang_ast_t.function_decl_info
* Clang_ast_t.cxx_method_decl_info
* Clang_ast_t.pointer
* Clang_ast_t.qual_type
| ObjC_Meth_decl_info of Clang_ast_t.obj_c_method_decl_info * Clang_ast_t.pointer
| Block_decl_info of Clang_ast_t.block_decl_info * Clang_ast_t.qual_type * CContext.t
let get_method_kind function_method_decl_info =
match function_method_decl_info with
| Func_decl_info _ ->
ProcAttributes.C_FUNCTION
| Block_decl_info _ ->
ProcAttributes.BLOCK
| Cpp_Meth_decl_info (_, method_decl_info, _, _) ->
if method_decl_info.Clang_ast_t.xmdi_is_static then ProcAttributes.CPP_CLASS
else ProcAttributes.CPP_INSTANCE
| ObjC_Meth_decl_info (method_decl_info, _) ->
if method_decl_info.Clang_ast_t.omdi_is_instance_method then ProcAttributes.OBJC_INSTANCE
else ProcAttributes.OBJC_CLASS
let get_original_return_type function_method_decl_info =
match function_method_decl_info with
| Func_decl_info (_, typ) | Cpp_Meth_decl_info (_, _, _, typ) | Block_decl_info (_, typ, _) ->
CType.return_type_of_function_type typ
| ObjC_Meth_decl_info (method_decl_info, _) ->
method_decl_info.Clang_ast_t.omdi_result_type
let get_class_param function_method_decl_info =
match get_method_kind function_method_decl_info with
| ProcAttributes.CPP_INSTANCE | ProcAttributes.OBJC_INSTANCE -> (
match function_method_decl_info with
| Cpp_Meth_decl_info (_, _, class_decl_ptr, _) ->
let class_type = CAst_utils.qual_type_of_decl_ptr class_decl_ptr in
[(Mangled.from_string CFrontend_config.this, class_type)]
| ObjC_Meth_decl_info (_, class_decl_ptr) ->
let class_type = CAst_utils.qual_type_of_decl_ptr class_decl_ptr in
[(Mangled.from_string CFrontend_config.self, class_type)]
| _ ->
[] )
| _ ->
[]
let should_add_return_param return_type ~is_objc_method =
match return_type.Typ.desc with Tstruct _ -> not is_objc_method | _ -> false
let is_objc_method function_method_decl_info =
match function_method_decl_info with ObjC_Meth_decl_info _ -> true | _ -> false
let get_return_param tenv function_method_decl_info =
let is_objc_method = is_objc_method function_method_decl_info in
let return_qual_type = get_original_return_type function_method_decl_info in
let return_typ = CType_decl.qual_type_to_sil_type tenv return_qual_type in
if should_add_return_param return_typ ~is_objc_method then
[ ( Mangled.from_string CFrontend_config.return_param
, Ast_expressions.create_pointer_qual_type return_qual_type ) ]
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
| ObjC_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_language trans_unit_ctx function_method_decl_info =
match function_method_decl_info with
| Func_decl_info (_, _) ->
trans_unit_ctx.CFrontend_config.lang
| Cpp_Meth_decl_info _ ->
CFrontend_config.CPP
| ObjC_Meth_decl_info _ ->
CFrontend_config.ObjC
| Block_decl_info _ ->
CFrontend_config.ObjC
let is_cpp_virtual function_method_decl_info =
match function_method_decl_info with
| Cpp_Meth_decl_info (_, mdi, _, _) ->
mdi.Clang_ast_t.xmdi_is_virtual
| _ ->
false
let is_cpp_nothrow function_method_decl_info =
match function_method_decl_info with
| Func_decl_info (fdi, _) | Cpp_Meth_decl_info (fdi, _, _, _) ->
fdi.Clang_ast_t.fdi_is_no_throw
| _ ->
false
(** Returns parameters of a function/method. They will have following order:
1. self/this parameter (optional, only for methods)
2. normal parameters
3. return parameter (optional) *)
let get_parameters trans_unit_ctx tenv decl_info function_method_decl_info =
let par_to_ms_par par =
match par with
| Clang_ast_t.ParmVarDecl (_, name_info, qt, var_decl_info) ->
let _, mangled = CGeneral_utils.get_var_name_mangled decl_info name_info var_decl_info in
let param_typ = CType_decl.qual_type_to_sil_type tenv qt in
let new_qt =
match param_typ.Typ.desc with
| Tstruct _ when CGeneral_utils.is_cpp_translation trans_unit_ctx ->
Ast_expressions.create_reference_qual_type qt
| _ ->
qt
in
(mangled, new_qt)
| _ ->
assert false
in
let pars = List.map ~f:par_to_ms_par (get_param_decls function_method_decl_info) in
get_class_param function_method_decl_info @ pars
@ get_return_param tenv function_method_decl_info
(** get return type of the function and optionally type of function's return parameter *)
let get_return_val_and_param_types tenv function_method_decl_info =
let return_qual_type = get_original_return_type function_method_decl_info in
let return_typ = CType_decl.qual_type_to_sil_type tenv return_qual_type in
let is_objc_method = is_objc_method function_method_decl_info in
if should_add_return_param return_typ ~is_objc_method then
(Ast_expressions.create_void_type, Some (CType.add_pointer_to_typ return_typ))
else (return_qual_type, None)
let build_method_signature trans_unit_ctx tenv decl_info procname function_method_decl_info
parent_pointer pointer_to_property_opt =
let source_range = decl_info.Clang_ast_t.di_source_range in
let tp, return_param_type_opt = get_return_val_and_param_types tenv function_method_decl_info in
let method_kind = get_method_kind function_method_decl_info in
let parameters = get_parameters trans_unit_ctx tenv decl_info function_method_decl_info in
let attributes = decl_info.Clang_ast_t.di_attributes in
let lang = get_language trans_unit_ctx function_method_decl_info in
let is_cpp_virtual = is_cpp_virtual function_method_decl_info in
let is_cpp_nothrow = is_cpp_nothrow function_method_decl_info in
let access = decl_info.Clang_ast_t.di_access in
CMethodSignature.mk procname parameters tp attributes source_range method_kind ~is_cpp_virtual
~is_cpp_nothrow lang parent_pointer pointer_to_property_opt return_param_type_opt access
let get_init_list_instrs method_decl_info =
let create_custom_instr construct_instr = `CXXConstructorInit construct_instr in
List.map ~f:create_custom_instr method_decl_info.Clang_ast_t.xmdi_cxx_ctor_initializers
let method_signature_of_decl trans_unit_ctx tenv meth_decl block_data_opt =
let open Clang_ast_t in
let is_cpp = CGeneral_utils.is_cpp_translation trans_unit_ctx in
match (meth_decl, block_data_opt) with
| FunctionDecl (decl_info, _, qt, fdi), _ ->
let func_decl = Func_decl_info (fdi, qt) in
let procname = CType_decl.CProcname.from_decl ~is_cpp ~tenv meth_decl in
let ms = build_method_signature trans_unit_ctx tenv decl_info procname func_decl None None in
(ms, fdi.Clang_ast_t.fdi_body, [])
| CXXMethodDecl (decl_info, _, qt, fdi, mdi), _
| CXXConstructorDecl (decl_info, _, qt, fdi, mdi), _
| CXXConversionDecl (decl_info, _, qt, fdi, mdi), _
| CXXDestructorDecl (decl_info, _, qt, fdi, mdi), _ ->
let procname = CType_decl.CProcname.from_decl ~is_cpp ~tenv meth_decl in
let parent_ptr = Option.value_exn decl_info.di_parent_pointer in
let method_decl = Cpp_Meth_decl_info (fdi, mdi, parent_ptr, qt) in
let parent_pointer = decl_info.Clang_ast_t.di_parent_pointer in
let ms =
build_method_signature trans_unit_ctx tenv decl_info procname method_decl parent_pointer
None
in
let init_list_instrs = get_init_list_instrs mdi in
(* it will be empty for methods *)
(ms, fdi.Clang_ast_t.fdi_body, init_list_instrs)
| ObjCMethodDecl (decl_info, _, mdi), _ ->
let procname = CType_decl.CProcname.from_decl ~is_cpp ~tenv meth_decl in
let parent_ptr = Option.value_exn decl_info.di_parent_pointer in
let method_decl = ObjC_Meth_decl_info (mdi, parent_ptr) in
let parent_pointer = decl_info.Clang_ast_t.di_parent_pointer in
let pointer_to_property_opt =
match mdi.Clang_ast_t.omdi_property_decl with
| Some decl_ref ->
Some decl_ref.Clang_ast_t.dr_decl_pointer
| None ->
None
in
let ms =
build_method_signature trans_unit_ctx tenv decl_info procname method_decl parent_pointer
pointer_to_property_opt
in
(ms, mdi.omdi_body, [])
| BlockDecl (decl_info, bdi), Some (outer_context, tp, procname, _) ->
let func_decl = Block_decl_info (bdi, tp, outer_context) in
let ms = build_method_signature trans_unit_ctx tenv decl_info procname func_decl None None in
(ms, bdi.bdi_body, [])
| _ ->
raise Invalid_declaration
let method_signature_of_pointer trans_unit_ctx tenv pointer =
let is_cpp = CGeneral_utils.is_cpp_translation trans_unit_ctx in
try
match CAst_utils.get_decl pointer with
| Some meth_decl ->
let ms, _, _ = method_signature_of_decl trans_unit_ctx tenv meth_decl None in
let procname = CType_decl.CProcname.from_decl ~is_cpp ~tenv meth_decl in
let ms = CType_decl.method_signature_of_decl ~is_cpp tenv meth_decl procname in
Some ms
| None ->
None
with Invalid_declaration -> None
with CFrontend_config.Invalid_declaration -> None
let get_method_name_from_clang tenv ms_opt =
@ -335,42 +126,6 @@ let get_objc_method_data obj_c_message_expr_info =
(selector, pointer, MCStatic)
let get_formal_parameters tenv ms =
let rec defined_parameters pl =
match pl with
| [] ->
[]
| (mangled, qual_type) :: pl' ->
let should_add_pointer name ms =
let is_objc_self =
String.equal name CFrontend_config.self
&& CFrontend_config.equal_clang_lang ms.CMethodSignature.lang CFrontend_config.ObjC
in
let is_cxx_this =
String.equal name CFrontend_config.this
&& CFrontend_config.equal_clang_lang ms.CMethodSignature.lang CFrontend_config.CPP
in
is_objc_self
&& ProcAttributes.equal_clang_method_kind ms.CMethodSignature.method_kind
ProcAttributes.OBJC_INSTANCE
|| is_cxx_this
in
let qt =
if should_add_pointer (Mangled.to_string mangled) ms then
Ast_expressions.create_pointer_qual_type qual_type
else qual_type
in
let typ = CType_decl.qual_type_to_sil_type tenv qt in
(mangled, typ) :: defined_parameters pl'
in
defined_parameters ms.CMethodSignature.args
let get_return_type tenv ms =
let return_type = ms.CMethodSignature.ret_type in
CType_decl.qual_type_to_sil_type tenv return_type
let sil_func_attributes_of_attributes attrs =
let rec do_translation acc al =
match al with
@ -403,31 +158,24 @@ let should_create_procdesc cfg procname defined set_objc_accessor_attr =
true
let sil_method_annotation_of_args args method_type : Annot.Method.t =
let args_types = List.map ~f:snd args in
let param_annots = List.map ~f:CAst_utils.sil_annot_of_type args_types in
let retval_annot = CAst_utils.sil_annot_of_type method_type in
(retval_annot, param_annots)
(** Returns a list of the indices of expressions in [args] which point to const-typed values. Each
index is offset by [shift]. *)
let get_const_args_indices ~shift args =
let get_const_params_indices ~shift params =
let i = ref shift in
let rec aux result = function
| [] ->
List.rev result
| (_, qual_type) :: tl ->
| ({is_pointer_to_const}: CMethodSignature.param_type) :: tl ->
incr i ;
if CType.is_pointer_to_const qual_type then aux (!i - 1 :: result) tl else aux result tl
if is_pointer_to_const then aux (!i - 1 :: result) tl else aux result tl
in
aux [] args
aux [] params
let get_byval_args_indices ~shift args =
List.filter_mapi args ~f:(fun index (_, qual_type) ->
let get_byval_params_indices ~shift params =
List.filter_mapi params ~f:(fun index ({is_value}: CMethodSignature.param_type) ->
let index' = index + shift in
Option.some_if (CType.is_value qual_type) index' )
Option.some_if is_value index' )
let get_objc_property_accessor tenv ms =
@ -473,8 +221,6 @@ let create_local_procdesc ?(set_objc_accessor_attr= false) trans_unit_ctx cfg te
let proc_name = ms.CMethodSignature.name in
let pname = Typ.Procname.to_string proc_name in
let attributes = sil_func_attributes_of_attributes ms.CMethodSignature.attributes in
let method_ret_type = ms.CMethodSignature.ret_type in
let method_annotation = sil_method_annotation_of_args ms.CMethodSignature.args method_ret_type in
let clang_method_kind = ms.CMethodSignature.method_kind in
let is_cpp_nothrow = ms.CMethodSignature.is_cpp_nothrow in
let access =
@ -489,16 +235,22 @@ let create_local_procdesc ?(set_objc_accessor_attr= false) trans_unit_ctx cfg te
PredSymb.Protected
in
let create_new_procdesc () =
let formals = get_formal_parameters tenv ms in
let all_params = Option.to_list ms.CMethodSignature.class_param @ ms.CMethodSignature.params in
let params_annots =
List.map ~f:(fun ({annot}: CMethodSignature.param_type) -> annot) all_params
in
let return_annot = snd ms.CMethodSignature.ret_type in
let method_annotation = (return_annot, params_annots) in
let formals =
List.map ~f:(fun ({name; typ}: CMethodSignature.param_type) -> (name, typ)) all_params
in
let captured_mangled = List.map ~f:(fun (var, t) -> (Pvar.get_name var, t)) captured in
(* Captured variables for blocks are treated as parameters *)
let formals = captured_mangled @ formals in
let const_formals =
get_const_args_indices ~shift:(List.length captured_mangled) ms.CMethodSignature.args
in
let by_vals =
get_byval_args_indices ~shift:(List.length captured_mangled) ms.CMethodSignature.args
get_const_params_indices ~shift:(List.length captured_mangled) all_params
in
let by_vals = get_byval_params_indices ~shift:(List.length captured_mangled) all_params in
let source_range = ms.CMethodSignature.loc in
L.(debug Capture Verbose) "@\nCreating a new procdesc for function: '%s'@\n@." pname ;
L.(debug Capture Verbose) "@\nms = %a@\n@." CMethodSignature.pp ms ;
@ -512,7 +264,7 @@ let create_local_procdesc ?(set_objc_accessor_attr= false) trans_unit_ctx cfg te
CLocation.location_of_source_range ~pick_location:`End
trans_unit_ctx.CFrontend_config.source_file source_range
in
let ret_type = get_return_type tenv ms in
let ret_type = fst ms.CMethodSignature.ret_type in
let objc_property_accessor =
if set_objc_accessor_attr then get_objc_property_accessor tenv ms else None
in

@ -20,8 +20,6 @@ type method_call_type = MCVirtual | MCNoVirtual | MCStatic [@@deriving compare]
val equal_method_call_type : method_call_type -> method_call_type -> bool
val should_add_return_param : Typ.t -> is_objc_method:bool -> bool
val create_local_procdesc :
?set_objc_accessor_attr:bool -> CFrontend_config.translation_unit_context -> Cfg.t -> Tenv.t
-> CMethodSignature.t -> Clang_ast_t.stmt list -> (Pvar.t * Typ.t) list -> bool
@ -40,11 +38,6 @@ val get_class_name_method_call_from_clang :
CFrontend_config.translation_unit_context -> Tenv.t -> Clang_ast_t.obj_c_message_expr_info
-> Typ.Name.t option
val method_signature_of_decl :
CFrontend_config.translation_unit_context -> Tenv.t -> Clang_ast_t.decl
-> CModule_type.block_data option
-> CMethodSignature.t * Clang_ast_t.stmt option * CModule_type.instr_type list
val method_signature_of_pointer :
CFrontend_config.translation_unit_context -> Tenv.t -> Clang_ast_t.pointer
-> CMethodSignature.t option

@ -239,7 +239,7 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s
let ret_id_typ = (Ident.create_fresh Ident.knormal, return_type) in
let ret_id', params, initd_exps, ret_exps =
(* Assumption: should_add_return_param will return true only for struct types *)
if CMethod_trans.should_add_return_param return_type ~is_objc_method then
if CType_decl.should_add_return_param return_type ~is_objc_method then
let param_type = Typ.mk (Typ.Tptr (return_type, Typ.Pk_pointer)) in
let var_exp =
match trans_state.var_exp_typ with

@ -75,7 +75,7 @@ let get_predefined_ms_method condition class_name method_name method_kind mk_pro
mk_procname class_name method_name method_kind
in
let ms =
CMethodSignature.mk procname arguments return_type attributes
CMethodSignature.mk procname None arguments return_type attributes
(CAst_utils.dummy_source_range ())
ProcAttributes.C_FUNCTION lang None None None `None
in
@ -88,21 +88,25 @@ let get_predefined_ms_stringWithUTF8String class_name method_name mk_procname la
class_equal class_name CFrontend_config.nsstring_cl
&& String.equal method_name CFrontend_config.string_with_utf8_m
in
let id_type = Ast_expressions.create_id_type in
let id_type = CType_to_sil_type.type_of_builtin_type_kind `ObjCId in
let char_star_type =
Ast_expressions.create_char_star_type ~quals:(Typ.mk_type_quals ~is_const:true ()) ()
let char_type = CType_to_sil_type.type_of_builtin_type_kind ~is_const:true `Char_S in
Typ.Tptr (char_type, Typ.Pk_pointer) |> Typ.mk ~quals:(Typ.mk_type_quals ())
in
let args = [(Mangled.from_string "x", char_star_type)] in
let param_name = Mangled.from_string "x" in
let params = [CMethodSignature.mk_param_type param_name char_star_type] in
get_predefined_ms_method condition class_name method_name Typ.Procname.ObjC_Cpp.ObjCClassMethod
mk_procname lang args id_type [] None
mk_procname lang params (id_type, Annot.Item.empty) [] None
let get_predefined_ms_is_kind_of_class class_name method_name mk_procname lang =
let condition = String.equal method_name CFrontend_config.is_kind_of_class in
let class_type = Ast_expressions.create_class_qual_type class_name in
let args = [(Mangled.from_string CFrontend_config.self, class_type)] in
let class_type = CType_to_sil_type.type_of_builtin_type_kind `ObjCClass in
let name = Mangled.from_string CFrontend_config.self in
let params = [CMethodSignature.mk_param_type name class_type] in
let bool_type = CType_to_sil_type.type_of_builtin_type_kind `Bool in
get_predefined_ms_method condition class_name method_name
Typ.Procname.ObjC_Cpp.ObjCInstanceMethod mk_procname lang args Ast_expressions.create_BOOL_type
Typ.Procname.ObjC_Cpp.ObjCInstanceMethod mk_procname lang params (bool_type, Annot.Item.empty)
[] (Some BuiltinDecl.__instanceof)

@ -75,6 +75,12 @@ let type_desc_of_builtin_type_kind builtin_type_kind =
Typ.Tvoid
let type_of_builtin_type_kind ?(is_const= false) builtin_type_kind =
let desc = type_desc_of_builtin_type_kind builtin_type_kind in
let quals = Typ.mk_type_quals ~is_const () in
Typ.mk ~quals desc
let pointer_attribute_of_objc_attribute attr_info =
match attr_info.Clang_ast_t.ati_lifetime with
| `OCL_None | `OCL_Strong ->

@ -11,5 +11,7 @@ open! IStd
val get_builtin_objc_typename : [< `ObjCClass | `ObjCId] -> Typ.Name.t
val type_of_builtin_type_kind : ?is_const:bool -> Clang_ast_t.builtin_type_kind -> Typ.t
val qual_type_to_sil_type :
(Tenv.t -> Clang_ast_t.decl -> Typ.desc) -> Tenv.t -> Clang_ast_t.qual_type -> Typ.t

Loading…
Cancel
Save