|
|
|
(*
|
|
|
|
* 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.
|
|
|
|
*)
|
|
|
|
|
|
|
|
open! IStd
|
|
|
|
open Objc_models
|
|
|
|
|
|
|
|
let class_equal class_typename class_name = String.equal (Typ.Name.name class_typename) class_name
|
|
|
|
|
|
|
|
let is_cf_non_null_alloc pname =
|
|
|
|
String.equal (Typ.Procname.to_string pname) CFrontend_config.cf_non_null_alloc
|
|
|
|
|
|
|
|
let is_alloc pname = String.equal (Typ.Procname.to_string pname) CFrontend_config.cf_alloc
|
|
|
|
|
|
|
|
let is_alloc_model typ pname =
|
|
|
|
if Specs.summary_exists pname then false
|
|
|
|
else
|
|
|
|
let funct = Typ.Procname.to_string pname in
|
|
|
|
(* if (Core_foundation_model.is_core_lib_create typ funct) then
|
|
|
|
print_endline ("\nCore Foundation create not modelled "
|
|
|
|
^(Typ.to_string typ)^" "^(funct));*)
|
|
|
|
Core_foundation_model.is_core_lib_create typ funct
|
|
|
|
|
|
|
|
let is_builtin_expect pname =
|
|
|
|
String.equal (Typ.Procname.to_string pname) CFrontend_config.builtin_expect
|
|
|
|
|
|
|
|
let is_builtin_object_size pname =
|
|
|
|
String.equal (Typ.Procname.to_string pname) CFrontend_config.builtin_object_size
|
|
|
|
|
|
|
|
let is_std_addressof pname =
|
|
|
|
(* since std_addressof is a template function, matching it requires QualifiedCppName *)
|
|
|
|
QualifiedCppName.Match.match_qualifiers CFrontend_config.std_addressof
|
|
|
|
(Typ.Procname.get_qualifiers pname)
|
|
|
|
|
|
|
|
let is_replace_with_deref_first_arg pname =
|
|
|
|
String.equal (Typ.Procname.to_string pname) CFrontend_config.replace_with_deref_first_arg_attr
|
|
|
|
|
|
|
|
let is_retain_predefined_model typ pname =
|
|
|
|
let funct = Typ.Procname.to_string pname in
|
|
|
|
Core_foundation_model.is_core_lib_retain typ funct
|
|
|
|
|
|
|
|
let is_release_predefined_model typ pname =
|
|
|
|
let funct = Typ.Procname.to_string pname in
|
|
|
|
Core_foundation_model.is_core_lib_release typ funct
|
|
|
|
|| Core_foundation_model.is_core_graphics_release typ funct
|
|
|
|
|
|
|
|
let is_retain_method funct = String.equal funct CFrontend_config.retain
|
|
|
|
|
|
|
|
let is_release_method funct = String.equal funct CFrontend_config.release
|
|
|
|
|
|
|
|
let is_autorelease_method funct = String.equal funct CFrontend_config.autorelease
|
|
|
|
|
|
|
|
let get_builtinname method_name =
|
|
|
|
if is_retain_method method_name then Some BuiltinDecl.__objc_retain
|
|
|
|
else if is_autorelease_method method_name then Some BuiltinDecl.__set_autorelease_attribute
|
|
|
|
else if is_release_method method_name then Some BuiltinDecl.__objc_release
|
|
|
|
else None
|
|
|
|
|
|
|
|
let is_modeled_builtin funct = String.equal funct CFrontend_config.builtin_memset_chk
|
|
|
|
|
|
|
|
let is_modeled_attribute attr_name =
|
|
|
|
List.mem ~equal:String.equal CFrontend_config.modeled_function_attributes attr_name
|
|
|
|
|
|
|
|
let get_first_param_typedef_string_opt type_ptr =
|
|
|
|
match CAst_utils.get_desugared_type type_ptr with
|
|
|
|
| Some Clang_ast_t.FunctionProtoType (_, _, {pti_params_type= [param_ptr]})
|
|
|
|
-> CAst_utils.name_opt_of_typedef_qual_type param_ptr
|
|
|
|
|> Option.map ~f:QualifiedCppName.to_qual_string
|
|
|
|
| _
|
|
|
|
-> None
|
|
|
|
|
|
|
|
let is_release_builtin funct fun_type =
|
|
|
|
let pn = Typ.Procname.from_string_c_fun funct in
|
|
|
|
if Specs.summary_exists pn then false
|
|
|
|
else
|
|
|
|
match get_first_param_typedef_string_opt fun_type with
|
|
|
|
| Some typ
|
|
|
|
-> is_release_predefined_model typ pn
|
|
|
|
| _
|
|
|
|
-> false
|
|
|
|
|
|
|
|
let is_retain_builtin funct fun_type =
|
|
|
|
let pn = Typ.Procname.from_string_c_fun funct in
|
|
|
|
if Specs.summary_exists pn then false
|
|
|
|
else
|
|
|
|
match get_first_param_typedef_string_opt fun_type with
|
|
|
|
| Some typ
|
|
|
|
-> is_retain_predefined_model typ pn
|
|
|
|
| _
|
|
|
|
-> false
|
|
|
|
|
|
|
|
let is_assert_log_s funct =
|
|
|
|
String.equal funct CFrontend_config.assert_rtn || String.equal funct CFrontend_config.assert_fail
|
|
|
|
|| String.equal funct CFrontend_config.fbAssertWithSignalAndLogFunctionHelper
|
|
|
|
|| String.is_substring ~substring:CFrontend_config.google_MakeCheckOpString funct
|
|
|
|
|
|
|
|
let is_assert_log_method m = String.equal m CFrontend_config.google_LogMessageFatal
|
|
|
|
|
|
|
|
let is_handleFailureInMethod funct =
|
|
|
|
String.equal funct CFrontend_config.handleFailureInMethod
|
|
|
|
|| String.equal funct CFrontend_config.handleFailureInFunction
|
|
|
|
|
|
|
|
let is_retain_or_release funct =
|
|
|
|
is_retain_method funct || is_release_method funct || is_autorelease_method funct
|
|
|
|
|
|
|
|
let is_toll_free_bridging pn =
|
|
|
|
let funct = Typ.Procname.to_string pn in
|
|
|
|
String.equal funct CFrontend_config.cf_bridging_release
|
|
|
|
|| String.equal funct CFrontend_config.cf_bridging_retain
|
|
|
|
|| String.equal funct CFrontend_config.cf_autorelease
|
|
|
|
|| String.equal funct CFrontend_config.ns_make_collectable
|
|
|
|
|
|
|
|
let is_cf_retain_release pn =
|
|
|
|
Typ.Procname.equal pn BuiltinDecl.__objc_retain_cf
|
|
|
|
|| Typ.Procname.equal pn BuiltinDecl.__objc_release_cf
|
|
|
|
|
|
|
|
(** If the function is a builtin model, return the model, otherwise return the function *)
|
|
|
|
let is_assert_log pname =
|
|
|
|
match pname with
|
|
|
|
| Typ.Procname.ObjC_Cpp _
|
|
|
|
-> is_assert_log_method (Typ.Procname.to_string pname)
|
|
|
|
| Typ.Procname.C _
|
|
|
|
-> is_assert_log_s (Typ.Procname.to_string pname)
|
|
|
|
| _
|
|
|
|
-> false
|
|
|
|
|
|
|
|
let is_objc_memory_model_controlled o = Core_foundation_model.is_objc_memory_model_controlled o
|
|
|
|
|
|
|
|
let get_predefined_ms_method condition class_name method_name method_kind mk_procname lang
|
|
|
|
arguments return_type attributes builtin =
|
|
|
|
if condition then
|
|
|
|
let procname =
|
|
|
|
match builtin with
|
|
|
|
| Some procname
|
|
|
|
-> procname
|
|
|
|
| None
|
|
|
|
-> mk_procname class_name method_name method_kind
|
|
|
|
in
|
|
|
|
let ms =
|
|
|
|
CMethod_signature.make_ms procname arguments return_type attributes
|
|
|
|
(Ast_expressions.dummy_source_range ()) false lang None None None `None
|
|
|
|
in
|
|
|
|
Some ms
|
|
|
|
else None
|
|
|
|
|
|
|
|
let get_predefined_ms_stringWithUTF8String class_name method_name mk_procname lang =
|
|
|
|
let condition =
|
|
|
|
class_equal class_name CFrontend_config.nsstring_cl
|
|
|
|
&& String.equal method_name CFrontend_config.string_with_utf8_m
|
|
|
|
in
|
[clang] [2 of 3] Dealing with custom ast expressions and flow of types in the frontend.
Summary:
This is the second of 3 stack diffs to deal with replacing the parser of types.
This diff is about general changes to the frontend to make it cope with the change. There
are two main challenges:
1. We create pieces of ast in ast_expressions, such as getters and setters. For that we create
custom types.
2. We store types in cMethod_signature for parameters and return type of functions. This was
stored as strings, but that means losing the pointer information which is vital to get the
sil types.
So this diff consists mostly of dealing with these challenges. It change the signature of
cMethod_signature and update modules accordingly.
To deal with the custom types, we build methods in ast_expressions for creating those types,
with a custom type pointer, like "internal_typeint". At the beginning of the translation we save
all these custom types in the map from type pointers to sil types that we build as we compute the
types, so that they are available later.
Another custom type that we build is a type of classes or pointer of classes based on the current
class. I found a simple way to deal with it, giving it a pointer "class_name", and then we know
how to translate those. Something I tried is to save the declaration of the current class and pass
that declaration around, but somehow that lead to pref regression, so I removed it in favor of this
more lightweight version.
9 years ago
|
|
|
let id_type = Ast_expressions.create_id_type in
|
|
|
|
let char_star_type =
|
|
|
|
Ast_expressions.create_char_star_type ~quals:(Typ.mk_type_quals ~is_const:true ()) ()
|
|
|
|
in
|
|
|
|
let args = [(Mangled.from_string "x", char_star_type)] in
|
|
|
|
get_predefined_ms_method condition class_name method_name Typ.Procname.ObjCClassMethod
|
|
|
|
mk_procname lang args id_type [] None
|
|
|
|
|
|
|
|
let get_predefined_ms_retain_release method_name mk_procname lang =
|
|
|
|
let condition = is_retain_or_release method_name in
|
|
|
|
let return_type =
|
|
|
|
if is_retain_method method_name || is_autorelease_method method_name then
|
|
|
|
Ast_expressions.create_id_type
|
|
|
|
else Ast_expressions.create_void_type
|
|
|
|
in
|
|
|
|
let class_typename = Typ.Name.Objc.from_string CFrontend_config.nsobject_cl in
|
|
|
|
let class_type = Ast_expressions.create_class_qual_type class_typename in
|
|
|
|
let args = [(Mangled.from_string CFrontend_config.self, class_type)] in
|
|
|
|
get_predefined_ms_method condition class_typename method_name Typ.Procname.ObjCInstanceMethod
|
|
|
|
mk_procname lang args return_type [] (get_builtinname method_name)
|
|
|
|
|
|
|
|
let get_predefined_ms_autoreleasepool_init class_name method_name mk_procname lang =
|
|
|
|
let condition =
|
|
|
|
String.equal method_name CFrontend_config.init
|
|
|
|
&& class_equal class_name CFrontend_config.nsautorelease_pool_cl
|
|
|
|
in
|
|
|
|
let class_type = Ast_expressions.create_class_qual_type class_name in
|
|
|
|
get_predefined_ms_method condition class_name method_name Typ.Procname.ObjCInstanceMethod
|
|
|
|
mk_procname lang [(Mangled.from_string CFrontend_config.self, class_type)]
|
|
|
|
Ast_expressions.create_void_type [] None
|
|
|
|
|
|
|
|
let get_predefined_ms_nsautoreleasepool_release class_name method_name mk_procname lang =
|
|
|
|
let condition =
|
|
|
|
( String.equal method_name CFrontend_config.release
|
|
|
|
|| String.equal method_name CFrontend_config.drain )
|
|
|
|
&& class_equal class_name CFrontend_config.nsautorelease_pool_cl
|
|
|
|
in
|
|
|
|
let class_type = Ast_expressions.create_class_qual_type class_name in
|
|
|
|
let args = [(Mangled.from_string CFrontend_config.self, class_type)] in
|
|
|
|
get_predefined_ms_method condition class_name method_name Typ.Procname.ObjCInstanceMethod
|
|
|
|
mk_procname lang args Ast_expressions.create_void_type []
|
|
|
|
(Some BuiltinDecl.__objc_release_autorelease_pool)
|
|
|
|
|
|
|
|
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
|
|
|
|
get_predefined_ms_method condition class_name method_name Typ.Procname.ObjCInstanceMethod
|
|
|
|
mk_procname lang args Ast_expressions.create_BOOL_type [] (Some BuiltinDecl.__instanceof)
|
|
|
|
|
|
|
|
let get_predefined_model_method_signature class_name method_name mk_procname lang =
|
|
|
|
let next_predefined f = function Some _ as x -> x | None -> f method_name mk_procname lang in
|
|
|
|
get_predefined_ms_nsautoreleasepool_release class_name method_name mk_procname lang
|
|
|
|
|> next_predefined get_predefined_ms_retain_release
|
|
|
|
|> next_predefined (get_predefined_ms_stringWithUTF8String class_name)
|
|
|
|
|> next_predefined (get_predefined_ms_autoreleasepool_init class_name)
|
|
|
|
|> next_predefined (get_predefined_ms_is_kind_of_class class_name)
|
|
|
|
|
|
|
|
let dispatch_functions =
|
|
|
|
[ ("_dispatch_once", 1)
|
|
|
|
; ("dispatch_async", 1)
|
|
|
|
; ("dispatch_sync", 1)
|
|
|
|
; ("dispatch_after", 2)
|
|
|
|
; ("dispatch_group_async", 2)
|
|
|
|
; ("dispatch_group_notify", 2)
|
|
|
|
; ("dispatch_group_wait", 2)
|
|
|
|
; ("dispatch_barrier_async", 1)
|
|
|
|
; ("dispatch_source_set_cancel_handler", 1)
|
|
|
|
; ("dispatch_source_set_event_handler", 1) ]
|
|
|
|
|
|
|
|
let is_dispatch_function_name function_name =
|
|
|
|
let rec is_dispatch functions =
|
|
|
|
match functions with
|
|
|
|
| []
|
|
|
|
-> None
|
|
|
|
| (el, block_arg_pos) :: rest
|
|
|
|
-> if String.equal el function_name then Some (el, block_arg_pos) else is_dispatch rest
|
|
|
|
in
|
|
|
|
is_dispatch dispatch_functions
|