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.

1302 lines
39 KiB

(*
* Copyright (c) 2016-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*)
open! IStd
open Types_lexer
module L = Logging
let parsed_type_map : Ctl_parser_types.abs_ctype String.Map.t ref = ref String.Map.empty
let rec objc_class_of_pointer_type type_ptr =
match CAst_utils.get_type type_ptr with
| Some (ObjCInterfaceType (_, decl_ptr)) ->
CAst_utils.get_decl decl_ptr
| Some (ObjCObjectPointerType (_, inner_qual_type)) ->
objc_class_of_pointer_type inner_qual_type.qt_type_ptr
| Some (AttributedType (type_info, _)) -> (
match type_info.ti_desugared_type with
| Some type_ptr ->
objc_class_of_pointer_type type_ptr
| None ->
None )
| _ ->
None
let receiver_class_method_call an =
match an with
| Ctl_parser_types.Stmt (ObjCMessageExpr (_, _, _, obj_c_message_expr_info)) -> (
match obj_c_message_expr_info.omei_receiver_kind with
| `Class qt ->
CAst_utils.get_decl_from_typ_ptr qt.qt_type_ptr
| _ ->
None )
| _ ->
None
let receiver_instance_method_call an =
match an with
| Ctl_parser_types.Stmt (ObjCMessageExpr (_, args, _, obj_c_message_expr_info)) -> (
match obj_c_message_expr_info.omei_receiver_kind with
| `Instance -> (
match args with
| receiver :: _ -> (
match Clang_ast_proj.get_expr_tuple receiver with
| Some (_, _, expr_info) ->
objc_class_of_pointer_type expr_info.ei_qual_type.qt_type_ptr
| None ->
None )
| [] ->
None )
| _ ->
None )
| _ ->
None
let receiver_method_call an =
match receiver_class_method_call an with
| Some decl ->
Some decl
| None ->
receiver_instance_method_call an
let declaration_name decl =
match Clang_ast_proj.get_named_decl_tuple decl with
| Some (_, ndi) ->
Some ndi.ni_name
| None ->
None
let get_available_attr_ios_sdk an =
let open Clang_ast_t in
let rec get_available_attr attrs =
match attrs with
| [] ->
None
| AvailabilityAttr attr_info :: rest -> (
match attr_info.ai_parameters with
| "ios" :: version :: _ ->
Some
(String.Search_pattern.replace_all
(String.Search_pattern.create "_")
~in_:version ~with_:".")
| _ ->
get_available_attr rest )
| _ :: rest ->
get_available_attr rest
in
match an with
| Ctl_parser_types.Decl decl ->
let decl_info = Clang_ast_proj.get_decl_tuple decl in
get_available_attr decl_info.di_attributes
| _ ->
None
let get_ivar_attributes ivar_decl =
let open Clang_ast_t in
match ivar_decl with
| ObjCIvarDecl (ivar_decl_info, _, _, _, _) -> (
match CAst_utils.get_property_of_ivar ivar_decl_info.Clang_ast_t.di_pointer with
| Some (ObjCPropertyDecl (_, _, obj_c_property_decl_info)) ->
obj_c_property_decl_info.Clang_ast_t.opdi_property_attributes
| _ ->
[] )
| _ ->
[]
(* list of cxx references captured by decl *)
let captured_variables_cxx_ref an =
let open Clang_ast_t in
let capture_var_is_cxx_ref reference_captured_vars captured_var =
let decl_ref_opt = captured_var.Clang_ast_t.bcv_variable in
match CAst_utils.get_decl_opt_with_decl_ref decl_ref_opt with
| Some (VarDecl (_, named_decl_info, qual_type, _))
| Some (ParmVarDecl (_, named_decl_info, qual_type, _))
| Some (ImplicitParamDecl (_, named_decl_info, qual_type, _)) -> (
match CAst_utils.get_desugared_type qual_type.Clang_ast_t.qt_type_ptr with
| Some (RValueReferenceType _) | Some (LValueReferenceType _) ->
named_decl_info :: reference_captured_vars
| _ ->
reference_captured_vars )
| _ ->
reference_captured_vars
in
match an with
| Ctl_parser_types.Decl (BlockDecl (_, bdi)) ->
List.fold ~f:capture_var_is_cxx_ref ~init:[] bdi.bdi_captured_variables
| _ ->
[]
type t = ALVar.formula_id * (* (name, [param1,...,paramK]) *) ALVar.alexp list [@@deriving compare]
let pp_predicate fmt (name_, arglist_) =
let name = ALVar.formula_id_to_string name_ in
let arglist = List.map ~f:ALVar.alexp_to_string arglist_ in
Format.fprintf fmt "%s(%a)" name (Pp.comma_seq Format.pp_print_string) arglist
(* an is a declaration whose name contains a regexp defined by re *)
let declaration_has_name an name =
match an with
| Ctl_parser_types.Decl d -> (
match declaration_name d with
| Some decl_name ->
ALVar.compare_str_with_alexp decl_name name
| _ ->
false )
| _ ->
false
let rec is_subclass_of decl name =
match CAst_utils.get_superclass_curr_class_objc_from_decl decl with
| Some super_ref
-> (
let ndi = match super_ref.Clang_ast_t.dr_name with Some ni -> ni | _ -> assert false in
if ALVar.compare_str_with_alexp ndi.ni_name name then true
else
match CAst_utils.get_decl_opt_with_decl_ref (Some super_ref) with
| Some decl ->
is_subclass_of decl name
| None ->
false )
| None ->
false
(* is an objc interface with name expected_name *)
let is_objc_interface_named an expected_name =
match an with
| Ctl_parser_types.Decl (Clang_ast_t.ObjCInterfaceDecl _) ->
declaration_has_name an expected_name
| _ ->
false
(* is an objc implementation with name expected_name *)
let is_objc_implementation_named an expected_name =
match an with
| Ctl_parser_types.Decl (Clang_ast_t.ObjCImplementationDecl _) ->
declaration_has_name an expected_name
| _ ->
false
let is_objc_class_named an re = is_objc_interface_named an re || is_objc_implementation_named an re
(* is an objc category interface with class name expected_name *)
let is_objc_category_interface_on_class_named an expected_name =
match an with
| Ctl_parser_types.Decl (Clang_ast_t.ObjCCategoryDecl (_, _, _, _, ocdi)) -> (
match CAst_utils.get_decl_opt_with_decl_ref ocdi.odi_class_interface with
| Some decl_ref ->
is_objc_interface_named (Decl decl_ref) expected_name
| _ ->
false )
| _ ->
false
(* is an objc category implementation with class name expected_name *)
let is_objc_category_implementation_on_class_named an expected_name =
match an with
| Ctl_parser_types.Decl (Clang_ast_t.ObjCCategoryImplDecl (_, _, _, _, ocidi)) -> (
match CAst_utils.get_decl_opt_with_decl_ref ocidi.ocidi_class_interface with
| Some decl_ref ->
is_objc_interface_named (Decl decl_ref) expected_name
| _ ->
false )
| _ ->
false
let is_objc_category_on_class_named an re =
is_objc_category_interface_on_class_named an re
|| is_objc_category_implementation_on_class_named an re
(* is an objc category interface with superclass name expected_name *)
let is_objc_category_interface_on_subclass_of an expected_name =
match an with
| Ctl_parser_types.Decl (Clang_ast_t.ObjCCategoryDecl (_, _, _, _, ocdi)) -> (
match CAst_utils.get_decl_opt_with_decl_ref ocdi.odi_class_interface with
| Some decl_ref ->
is_subclass_of decl_ref expected_name
| _ ->
false )
| _ ->
false
(* is an objc category implementation with superclass name expected_name *)
let is_objc_category_implementation_on_subclass_of an expected_name =
match an with
| Ctl_parser_types.Decl (Clang_ast_t.ObjCCategoryImplDecl (_, _, _, _, ocidi)) -> (
match CAst_utils.get_decl_opt_with_decl_ref ocidi.ocidi_class_interface with
| Some decl_ref ->
is_subclass_of decl_ref expected_name
| _ ->
false )
| _ ->
false
let is_objc_category_on_subclass_of an expected_name =
is_objc_category_interface_on_subclass_of an expected_name
|| is_objc_category_implementation_on_subclass_of an expected_name
(* is an objc category interface with name expected_name *)
let is_objc_category_interface_named an expected_name =
match an with
| Ctl_parser_types.Decl (Clang_ast_t.ObjCCategoryDecl _) ->
declaration_has_name an expected_name
| _ ->
false
(* is an objc category implementation with name expected_name *)
let is_objc_category_implementation_named an expected_name =
match an with
| Ctl_parser_types.Decl (Clang_ast_t.ObjCCategoryImplDecl _) ->
declaration_has_name an expected_name
| _ ->
false
let is_objc_category_named an re =
is_objc_category_interface_named an re || is_objc_category_implementation_named an re
let is_objc_protocol_named an re =
match an with
| Ctl_parser_types.Decl (Clang_ast_t.ObjCProtocolDecl _) ->
declaration_has_name an re
| _ ->
false
let is_objc_class_method_named an name =
match an with
| Ctl_parser_types.Decl (Clang_ast_t.ObjCMethodDecl (_, _, omdi)) ->
declaration_has_name an name && not omdi.omdi_is_instance_method
| _ ->
false
let is_objc_instance_method_named an name =
match an with
| Ctl_parser_types.Decl (Clang_ast_t.ObjCMethodDecl (_, _, omdi)) ->
declaration_has_name an name && omdi.omdi_is_instance_method
| _ ->
false
let is_objc_method_named an name =
match an with
| Ctl_parser_types.Decl (Clang_ast_t.ObjCMethodDecl _) ->
declaration_has_name an name
| _ ->
false
let is_objc_method_overriding an =
match an with
| Ctl_parser_types.Decl (Clang_ast_t.ObjCMethodDecl (_, _, mdi)) ->
mdi.omdi_is_overriding
| _ ->
false
let decl_list_has_objc_method decl_list method_name is_instance_method =
List.exists
~f:(fun decl ->
match decl with
| Clang_ast_t.ObjCMethodDecl (_, ni, omdi) ->
Bool.equal omdi.omdi_is_instance_method is_instance_method
&& String.equal ni.ni_name method_name
| _ ->
false )
decl_list
let current_objc_container context =
let open CLintersContext in
let current_objc_class = context.current_objc_class in
let current_objc_category = context.current_objc_category in
let current_objc_protocol = context.current_objc_protocol in
if not (Option.is_none current_objc_class) then current_objc_class
else if not (Option.is_none current_objc_category) then current_objc_category
else if not (Option.is_none current_objc_protocol) then current_objc_protocol
else None
let is_objc_method_exposed context an =
let open Clang_ast_t in
if is_objc_method_overriding an then true
else
match an with
| Ctl_parser_types.Decl (ObjCMethodDecl (_, ndi, mdi))
-> (
let method_name = ndi.ni_name in
let is_instance_method = mdi.omdi_is_instance_method in
match current_objc_container context with
| Some (ObjCImplementationDecl (_, _, _, _, oidi)) -> (
match CAst_utils.get_decl_opt_with_decl_ref oidi.oidi_class_interface with
| Some (ObjCInterfaceDecl (_, _, decl_list, _, otdi)) ->
decl_list_has_objc_method decl_list method_name is_instance_method
|| List.exists
~f:(fun decl_ref ->
match CAst_utils.get_decl decl_ref.dr_decl_pointer with
| Some (ObjCCategoryDecl (_, ni, decl_list, _, _)) ->
String.equal ni.ni_name ""
&& decl_list_has_objc_method decl_list method_name is_instance_method
| _ ->
false )
otdi.otdi_known_categories
| _ ->
false )
| Some (ObjCCategoryImplDecl (_, _, _, _, ocidi)) -> (
match CAst_utils.get_decl_opt_with_decl_ref ocidi.ocidi_category_decl with
| Some (ObjCCategoryDecl (_, _, decl_list, _, _)) ->
decl_list_has_objc_method decl_list method_name is_instance_method
| _ ->
false )
| _ ->
false )
| _ ->
false
let get_selector an =
match an with
| Ctl_parser_types.Stmt (Clang_ast_t.ObjCMessageExpr (_, _, _, omei)) ->
Some omei.omei_selector
| _ ->
None
let receiver_objc_type_name an =
match an with
| Ctl_parser_types.Stmt (ObjCMessageExpr (_, receiver :: _, _, {omei_receiver_kind= `Instance})) ->
Clang_ast_proj.get_expr_tuple receiver
|> Option.bind ~f:(fun (_, _, expr_info) ->
CAst_utils.name_opt_of_typedef_qual_type expr_info.Clang_ast_t.ei_qual_type )
|> Option.map ~f:QualifiedCppName.to_qual_string
| _ ->
None
let is_receiver_objc_class_type an =
match receiver_objc_type_name an with
| Some type_name ->
String.equal type_name "Class"
| None ->
false
let is_receiver_objc_id_type an =
match receiver_objc_type_name an with
| Some type_name ->
String.equal type_name "id"
| None ->
false
let objc_message_receiver context an =
match an with
| Ctl_parser_types.Stmt (ObjCMessageExpr (_, args, _, omei)) -> (
match omei.omei_receiver_kind with
| `SuperClass | `SuperInstance -> (
match current_objc_container context with
| Some container ->
let decl_ref_opt = CAst_utils.get_superclass_curr_class_objc_from_decl container in
CAst_utils.get_decl_opt_with_decl_ref decl_ref_opt
| _ ->
None )
| `Class qt ->
CAst_utils.get_decl_from_typ_ptr qt.qt_type_ptr
| `Instance ->
match args with
| receiver :: _ -> (
match receiver with
| ObjCMessageExpr (_, _, _, sub_omei) -> (
match CAst_utils.get_decl_opt sub_omei.omei_decl_pointer with
| Some (ObjCMethodDecl (_, _, omdi)) ->
CAst_utils.qual_type_to_objc_interface omdi.omdi_result_type
| _ ->
None )
| PseudoObjectExpr (_, _, ei) | ImplicitCastExpr (_, _, ei, _) | ParenExpr (_, _, ei) ->
CAst_utils.qual_type_to_objc_interface ei.ei_qual_type
| _ ->
None )
| [] ->
None )
| _ ->
None
(* an |= call_method(m) where the name must be exactly m *)
let call_method an m =
match get_selector an with
| Some selector ->
ALVar.compare_str_with_alexp selector m
| _ ->
false
let call_class_method an mname =
match an with
| Ctl_parser_types.Stmt (Clang_ast_t.ObjCMessageExpr (_, _, _, omei)) -> (
match omei.omei_receiver_kind with
| `SuperClass | `Class _ ->
ALVar.compare_str_with_alexp omei.omei_selector mname
| `Instance ->
(* The ObjC class type, 'Class', is treated as an instance receiver kind.
We need to check if the receiver is the class type to catch cases like
[[self class] myClassMethod] *)
ALVar.compare_str_with_alexp omei.omei_selector mname && is_receiver_objc_class_type an
| _ ->
false )
| _ ->
false
(* an is a node calling method whose name contains mname of a class. *)
let call_instance_method an mname =
match an with
| Ctl_parser_types.Stmt (Clang_ast_t.ObjCMessageExpr (_, _, _, omei)) -> (
match omei.omei_receiver_kind with
| `SuperInstance ->
ALVar.compare_str_with_alexp omei.omei_selector mname
| `Instance ->
(* The ObjC class type, 'Class', is treated as an instance receiver kind.
We need to verify the receiver is not the class type to avoid cases like
[[self class] myClassMethod] *)
ALVar.compare_str_with_alexp omei.omei_selector mname
&& not (is_receiver_objc_class_type an)
| _ ->
false )
| _ ->
false
let is_objc_extension lcxt =
CGeneral_utils.is_objc_extension lcxt.CLintersContext.translation_unit_context
let is_global_var an =
match an with Ctl_parser_types.Decl d -> CAst_utils.is_syntactically_global_var d | _ -> false
let is_const_expr_var an =
match an with Ctl_parser_types.Decl d -> CAst_utils.is_const_expr_var d | _ -> false
let decl_ref_name ?kind name st =
match st with
| Clang_ast_t.DeclRefExpr (_, _, _, drti) -> (
match drti.drti_decl_ref with
| Some dr
-> (
let ndi, _, _ = CAst_utils.get_info_from_decl_ref dr in
let has_right_name = ALVar.compare_str_with_alexp ndi.ni_name name in
match kind with
| Some decl_kind ->
has_right_name && PolyVariantEqual.( = ) dr.Clang_ast_t.dr_kind decl_kind
| None ->
has_right_name )
| _ ->
false )
| _ ->
false
let declaration_ref_name ?kind an name =
match an with Ctl_parser_types.Stmt st -> decl_ref_name ?kind name st | _ -> false
let call_function an name =
match an with
| Ctl_parser_types.Stmt st ->
CAst_utils.exists_eventually_st (decl_ref_name ~kind:`Function) name st
| _ ->
false
let is_enum_constant an name =
match an with
| Ctl_parser_types.Stmt st ->
decl_ref_name ~kind:`EnumConstant name st
| _ ->
false
let is_enum_constant_of_enum an name =
match an with
| Ctl_parser_types.Stmt (Clang_ast_t.DeclRefExpr (_, _, _, drti)) -> (
match drti.drti_decl_ref with
| Some dr
-> (
let ndi, _, _ = CAst_utils.get_info_from_decl_ref dr in
let qual_name = CAst_utils.get_qualified_name ndi in
match QualifiedCppName.extract_last qual_name with
| Some (_, stripped_qual_name) -> (
match QualifiedCppName.extract_last stripped_qual_name with
| Some (enum_name, _) ->
PolyVariantEqual.( = ) dr.Clang_ast_t.dr_kind `EnumConstant
&& ALVar.compare_str_with_alexp enum_name name
| _ ->
false )
| _ ->
false )
| _ ->
false )
| _ ->
false
let is_strong_property an =
match an with
| Ctl_parser_types.Decl (Clang_ast_t.ObjCPropertyDecl (_, _, pdi)) ->
ObjcProperty_decl.is_strong_property pdi
| _ ->
false
let is_weak_property an =
match an with
| Ctl_parser_types.Decl (Clang_ast_t.ObjCPropertyDecl (_, _, pdi)) ->
ObjcProperty_decl.is_weak_property pdi
| _ ->
false
let is_assign_property an =
match an with
| Ctl_parser_types.Decl (Clang_ast_t.ObjCPropertyDecl (_, _, pdi)) ->
ObjcProperty_decl.is_assign_property pdi
| _ ->
false
let is_property_pointer_type an =
let open Clang_ast_t in
match an with
| Ctl_parser_types.Decl (ObjCPropertyDecl (_, _, pdi)) -> (
match CAst_utils.get_desugared_type pdi.opdi_qual_type.Clang_ast_t.qt_type_ptr with
| Some (MemberPointerType _) | Some (ObjCObjectPointerType _) | Some (BlockPointerType _) ->
true
| Some (TypedefType (_, tti)) ->
let typedef_str =
CAst_utils.name_of_typedef_type_info tti |> QualifiedCppName.to_qual_string
in
String.equal typedef_str CFrontend_config.id_cl
| exception Caml.Not_found ->
false
| _ ->
false )
| _ ->
false
let context_in_synchronized_block context = context.CLintersContext.in_synchronized_block
(* checks if ivar is defined among a set of fields and if it is atomic *)
let is_ivar_atomic an =
match an with
| Ctl_parser_types.Stmt (Clang_ast_t.ObjCIvarRefExpr (_, _, _, irei))
-> (
let dr_ref = irei.Clang_ast_t.ovrei_decl_ref in
let ivar_pointer = dr_ref.Clang_ast_t.dr_decl_pointer in
match CAst_utils.get_decl ivar_pointer with
| Some d ->
let attributes = get_ivar_attributes d in
List.exists ~f:(PolyVariantEqual.( = ) `Atomic) attributes
| _ ->
false )
| _ ->
false
let is_method_property_accessor_of_ivar an context =
let open Clang_ast_t in
match an with
| Ctl_parser_types.Stmt (ObjCIvarRefExpr (_, _, _, irei))
-> (
let dr_ref = irei.Clang_ast_t.ovrei_decl_ref in
let ivar_pointer = dr_ref.Clang_ast_t.dr_decl_pointer in
match context.CLintersContext.current_method with
| Some (ObjCMethodDecl (_, _, mdi)) ->
if mdi.omdi_is_property_accessor then
let property_opt = mdi.omdi_property_decl in
match CAst_utils.get_decl_opt_with_decl_ref property_opt with
| Some (ObjCPropertyDecl (_, _, pdi)) -> (
match pdi.opdi_ivar_decl with
| Some decl_ref ->
Int.equal decl_ref.dr_decl_pointer ivar_pointer
| None ->
false )
| _ ->
false
else false
| _ ->
false )
| _ ->
false
let get_method_name_from_context context =
match context.CLintersContext.current_method with
| Some method_decl -> (
match Clang_ast_proj.get_named_decl_tuple method_decl with
| Some (_, mnd) ->
mnd.Clang_ast_t.ni_name
| _ ->
"" )
| _ ->
""
let is_objc_constructor context =
Typ.Procname.ObjC_Cpp.is_objc_constructor (get_method_name_from_context context)
let is_objc_dealloc context =
Typ.Procname.ObjC_Cpp.is_objc_dealloc (get_method_name_from_context context)
let is_in_method context name =
let current_method_name = get_method_name_from_context context in
ALVar.compare_str_with_alexp current_method_name name
let is_in_objc_class_method context name =
match context.CLintersContext.current_method with
| Some (ObjCMethodDecl (_, _, omdi) as objc_method) ->
declaration_has_name (Decl objc_method) name && not omdi.omdi_is_instance_method
| _ ->
false
let is_in_objc_instance_method context name =
match context.CLintersContext.current_method with
| Some (ObjCMethodDecl (_, _, omdi) as objc_method) ->
declaration_has_name (Decl objc_method) name && omdi.omdi_is_instance_method
| _ ->
false
let is_in_objc_method context name =
is_in_objc_class_method context name || is_in_objc_instance_method context name
let is_in_function context name =
match context.CLintersContext.current_method with
| Some (FunctionDecl _) ->
is_in_method context name
| _ ->
false
let is_in_cxx_method context name =
match context.CLintersContext.current_method with
| Some (CXXMethodDecl _) ->
is_in_method context name
| _ ->
false
let is_in_cxx_constructor context name =
match context.CLintersContext.current_method with
| Some (CXXConstructorDecl _) ->
is_in_method context name
| _ ->
false
let is_in_cxx_destructor context name =
match context.CLintersContext.current_method with
| Some (CXXDestructorDecl _) ->
is_in_method context name
| _ ->
false
let is_in_block context =
match context.CLintersContext.current_method with Some (BlockDecl _) -> true | _ -> false
let is_in_objc_subclass_of context name =
match context.CLintersContext.current_objc_class with
| Some cls ->
is_subclass_of cls name
| None ->
false
let is_in_objc_interface_named context name =
match context.CLintersContext.current_objc_class with
| Some cls ->
is_objc_interface_named (Decl cls) name
| None ->
false
let is_in_objc_implementation_named context name =
match context.CLintersContext.current_objc_class with
| Some cls ->
is_objc_implementation_named (Decl cls) name
| None ->
false
let is_in_objc_class_named context name =
match context.CLintersContext.current_objc_class with
| Some cls ->
is_objc_class_named (Decl cls) name
| None ->
false
let is_in_objc_category_interface_on_class_named context name =
match context.CLintersContext.current_objc_category with
| Some cat ->
is_objc_category_interface_on_class_named (Decl cat) name
| None ->
false
let is_in_objc_category_implementation_on_class_named context name =
match context.CLintersContext.current_objc_category with
| Some cat ->
is_objc_category_implementation_on_class_named (Decl cat) name
| None ->
false
let is_in_objc_category_on_class_named context name =
match context.CLintersContext.current_objc_category with
| Some cat ->
is_objc_category_on_class_named (Decl cat) name
| None ->
false
let is_in_objc_category_interface_on_subclass_of context name =
match context.CLintersContext.current_objc_category with
| Some cat ->
is_objc_category_interface_on_subclass_of (Decl cat) name
| None ->
false
let is_in_objc_category_implementation_on_subclass_of context name =
match context.CLintersContext.current_objc_category with
| Some cat ->
is_objc_category_implementation_on_subclass_of (Decl cat) name
| None ->
false
let is_in_objc_category_on_subclass_of context name =
match context.CLintersContext.current_objc_category with
| Some cat ->
is_objc_category_on_subclass_of (Decl cat) name
| None ->
false
let is_in_objc_category_interface_named context name =
match context.CLintersContext.current_objc_category with
| Some cat ->
is_objc_category_interface_named (Decl cat) name
| None ->
false
let is_in_objc_category_implementation_named context name =
match context.CLintersContext.current_objc_category with
| Some cat ->
is_objc_category_implementation_named (Decl cat) name
| None ->
false
let is_in_objc_category_named context name =
match context.CLintersContext.current_objc_category with
| Some cat ->
is_objc_category_named (Decl cat) name
| None ->
false
let is_in_objc_protocol_named context name =
match context.CLintersContext.current_objc_protocol with
| Some protocol ->
is_objc_protocol_named (Decl protocol) name
| None ->
false
let is_receiver_subclass_of context an cname =
match objc_message_receiver context an with
| Some receiver ->
is_subclass_of receiver cname
| _ ->
false
let is_receiver_class_named context an cname =
match objc_message_receiver context an with
| Some receiver ->
declaration_has_name (Decl receiver) cname
| _ ->
false
let is_receiver_super an =
match an with
| Ctl_parser_types.Stmt
(ObjCMessageExpr (_, _, _, {omei_receiver_kind= `SuperClass | `SuperInstance})) ->
true
| _ ->
false
let captures_cxx_references an = List.length (captured_variables_cxx_ref an) > 0
let is_binop_with_kind an alexp_kind =
let str_kind = ALVar.alexp_to_string alexp_kind in
if not (Clang_ast_proj.is_valid_binop_kind_name str_kind) then
L.(die ExternalError) "Binary operator kind '%s' is not valid" str_kind ;
match an with
| Ctl_parser_types.Stmt (Clang_ast_t.BinaryOperator (_, _, _, boi)) ->
ALVar.compare_str_with_alexp (Clang_ast_proj.string_of_binop_kind boi.boi_kind) alexp_kind
| _ ->
false
let is_unop_with_kind an alexp_kind =
let str_kind = ALVar.alexp_to_string alexp_kind in
if not (Clang_ast_proj.is_valid_unop_kind_name str_kind) then
L.(die ExternalError) "Unary operator kind '%s' is not valid" str_kind ;
match an with
| Ctl_parser_types.Stmt (Clang_ast_t.UnaryOperator (_, _, _, uoi)) ->
ALVar.compare_str_with_alexp (Clang_ast_proj.string_of_unop_kind uoi.uoi_kind) alexp_kind
| _ ->
false
let has_cast_kind an alexp_kind =
match an with
| Ctl_parser_types.Decl _ ->
false
| Ctl_parser_types.Stmt stmt ->
let str_kind = ALVar.alexp_to_string alexp_kind in
match Clang_ast_proj.get_cast_kind stmt with
| Some cast_kind ->
let cast_kind_str = Clang_ast_proj.string_of_cast_kind cast_kind in
String.equal cast_kind_str str_kind
| None ->
false
let is_node an nodename =
let nodename_str = ALVar.alexp_to_string nodename in
if not (Clang_ast_proj.is_valid_astnode_kind nodename_str) then
L.(die ExternalError) "Node '%s' is not a valid AST node" nodename_str ;
let an_str =
match an with
| Ctl_parser_types.Stmt s ->
Clang_ast_proj.get_stmt_kind_string s
| Ctl_parser_types.Decl d ->
Clang_ast_proj.get_decl_kind_string d
in
ALVar.compare_str_with_alexp an_str nodename
let is_ptr_to_objc_class typ class_name =
match typ with
| Some (Clang_ast_t.ObjCObjectPointerType (_, {Clang_ast_t.qt_type_ptr})) -> (
match CAst_utils.get_desugared_type qt_type_ptr with
| Some (ObjCInterfaceType (_, ptr)) -> (
match CAst_utils.get_decl ptr with
| Some (ObjCInterfaceDecl (_, ndi, _, _, _)) ->
ALVar.compare_str_with_alexp ndi.ni_name class_name
| _ ->
false )
| _ ->
false )
| _ ->
false
(* node an is of class classname *)
let isa an classname =
match an with
| Ctl_parser_types.Stmt stmt -> (
match Clang_ast_proj.get_expr_tuple stmt with
| Some (_, _, expr_info) ->
let typ = CAst_utils.get_desugared_type expr_info.ei_qual_type.qt_type_ptr in
is_ptr_to_objc_class typ classname
| _ ->
false )
| _ ->
false
let is_class an re = is_objc_class_named an re
(* an is an expression @selector with whose name in the language of re *)
let is_at_selector_with_name an re =
match an with
| Ctl_parser_types.Stmt (ObjCSelectorExpr (_, _, _, s)) ->
ALVar.compare_str_with_alexp s re
| _ ->
false
let iphoneos_target_sdk_version_by_path (cxt: CLintersContext.context) =
let source_file = cxt.translation_unit_context.source_file in
let regex_version_opt =
List.find Config.iphoneos_target_sdk_version_path_regex ~f:
(fun (version_path_regex: Config.iphoneos_target_sdk_version_path_regex) ->
ALVar.str_match_forward (SourceFile.to_rel_path source_file) version_path_regex.path )
in
match regex_version_opt with
| Some version_by_regex ->
Some version_by_regex.version
| None (* no version by path specified, use default version *) ->
Config.iphoneos_target_sdk_version
let iphoneos_target_sdk_version_greater_or_equal (cxt: CLintersContext.context) version =
match iphoneos_target_sdk_version_by_path cxt with
| Some target_version ->
Utils.compare_versions target_version version >= 0
| None ->
false
let decl_unavailable_in_supported_ios_sdk (cxt: CLintersContext.context) an =
let config_iphoneos_target_sdk_version = iphoneos_target_sdk_version_by_path cxt in
let allowed_os_versions =
match
(config_iphoneos_target_sdk_version, (cxt.if_context : CLintersContext.if_context option))
with
| Some iphoneos_target_sdk_version, Some if_context ->
iphoneos_target_sdk_version :: if_context.ios_version_guard
| Some iphoneos_target_sdk_version, None ->
[iphoneos_target_sdk_version]
| _ ->
[]
in
let max_allowed_version_opt = List.max_elt allowed_os_versions ~compare:Utils.compare_versions in
let available_attr_ios_sdk = get_available_attr_ios_sdk an in
match (available_attr_ios_sdk, max_allowed_version_opt) with
| Some available_attr_ios_sdk, Some max_allowed_version ->
Utils.compare_versions available_attr_ios_sdk max_allowed_version > 0
| _ ->
false
let class_unavailable_in_supported_ios_sdk (cxt: CLintersContext.context) an =
match receiver_method_call an with
| Some decl ->
decl_unavailable_in_supported_ios_sdk cxt (Ctl_parser_types.Decl decl)
| None ->
false
(* Check whether a type_ptr and a string denote the same type *)
let type_ptr_equal_type type_ptr type_str =
let parse_type_string str =
L.(debug Linters Medium) "Starting parsing type string '%s'@\n" str ;
let lexbuf = Lexing.from_string str in
try Types_parser.abs_ctype token lexbuf with
| CTLExceptions.ALParserInvariantViolationException s ->
raise
CTLExceptions.(
ALFileException (create_exc_info ("Syntax Error when defining type " ^ s) lexbuf))
| SyntaxError _ | Types_parser.Error ->
raise CTLExceptions.(ALFileException (create_exc_info "SYNTAX ERROR" lexbuf))
in
let abs_ctype =
match String.Map.find !parsed_type_map type_str with
| Some abs_ctype' ->
abs_ctype'
| None ->
let abs_ctype' = parse_type_string type_str in
parsed_type_map := String.Map.set !parsed_type_map ~key:type_str ~data:abs_ctype' ;
abs_ctype'
in
match CAst_utils.get_type type_ptr with
| Some c_type' ->
Ctl_parser_types.c_type_equal c_type' abs_ctype
| _ ->
L.(debug Linters Medium) "Couldn't find type....@\n" ;
false
let get_ast_node_type_ptr an =
match an with
| Ctl_parser_types.Stmt stmt -> (
match Clang_ast_proj.get_expr_tuple stmt with
| Some (_, _, expr_info) ->
Some expr_info.ei_qual_type.qt_type_ptr
| _ ->
None )
| Ctl_parser_types.Decl decl ->
CAst_utils.type_of_decl decl
let has_type an typ_ =
match (get_ast_node_type_ptr an, typ_) with
| Some pt, ALVar.Const typ ->
type_ptr_equal_type pt typ
| _ ->
false
let has_type_const_ptr_to_objc_class node =
let open Clang_ast_t in
match get_ast_node_type_ptr node with
| Some type_ptr -> (
match CAst_utils.get_desugared_type type_ptr with
| Some (ObjCObjectPointerType (_, qt)) ->
qt.qt_is_const
| _ ->
false )
| None ->
false
(* Return the lifetime of the pointer of an expression if it is of type AttributedType *)
(* This is useful to check the lifetime of ivars *)
(* @returns objc_lifetime_attr *)
let get_ivar_lifetime an =
match get_ast_node_type_ptr an with
| Some pt -> (
match CAst_utils.get_type pt with
| Some c_type
-> (
L.(debug Linters Medium) "@\nChecking type: `%s`\n" (Clang_ast_j.string_of_c_type c_type) ;
let open Clang_ast_t in
match c_type with
| AttributedType (_, attr_info) ->
Some attr_info.Clang_ast_t.ati_lifetime
| ObjCObjectPointerType _ ->
Some `OCL_Strong
| _ ->
L.(debug Linters Medium) "Pointer is not of type AttributedType...@\n" ;
None )
| _ ->
L.(debug Linters Medium) "Couldn't find type....\n" ;
None )
| _ ->
L.(debug Linters Medium) "Couldn't find pointer...@\n" ;
None
let is_strong_ivar an =
match get_ivar_lifetime an with
| Some lifetime -> (
match lifetime with `OCL_Strong | `OCL_Autoreleasing | `OCL_None -> true | _ -> false )
| _ ->
false
let is_decl node =
match node with Ctl_parser_types.Decl _ -> true | Ctl_parser_types.Stmt _ -> false
let method_return_type an typ_ =
L.(debug Linters Verbose) "@\n Executing method_return_type..." ;
match (an, typ_) with
| Ctl_parser_types.Decl (Clang_ast_t.ObjCMethodDecl (_, _, mdi)), ALVar.Const typ ->
L.(debug Linters Verbose) "@\n with parameter `%s`...." typ ;
let qual_type = mdi.Clang_ast_t.omdi_result_type in
type_ptr_equal_type qual_type.Clang_ast_t.qt_type_ptr typ
| _ ->
false
let rec check_protocol_hiearachy decls_ptr prot_name_ =
let open Clang_ast_t in
let is_this_protocol di_opt =
match di_opt with Some di -> ALVar.compare_str_with_alexp di.ni_name prot_name_ | _ -> false
in
match decls_ptr with
| [] ->
false
| pt :: decls' ->
let di, protocols =
match CAst_utils.get_decl pt with
| Some (ObjCProtocolDecl (_, di, _, _, opcdi)) ->
(Some di, opcdi.opcdi_protocols)
| _ ->
(None, [])
in
if is_this_protocol di || List.exists ~f:(fun dr -> is_this_protocol dr.dr_name) protocols
then true
else
let super_prot = List.map ~f:(fun dr -> dr.dr_decl_pointer) protocols in
check_protocol_hiearachy (super_prot @ decls') prot_name_
let has_type_subprotocol_of an prot_name_ =
let open Clang_ast_t in
let rec check_subprotocol t =
match t with
| Some (ObjCObjectPointerType (_, qt)) ->
check_subprotocol (CAst_utils.get_type qt.qt_type_ptr)
| Some (ObjCObjectType (_, ooti)) ->
if List.length ooti.ooti_protocol_decls_ptr > 0 then
check_protocol_hiearachy ooti.ooti_protocol_decls_ptr prot_name_
else
List.exists
~f:(fun qt -> check_subprotocol (CAst_utils.get_type qt.qt_type_ptr))
ooti.ooti_type_args
| Some (ObjCInterfaceType (_, pt)) ->
check_protocol_hiearachy [pt] prot_name_
| _ ->
false
in
match get_ast_node_type_ptr an with
| Some tp ->
check_subprotocol (CAst_utils.get_type tp)
| _ ->
false
let within_responds_to_selector_block (cxt: CLintersContext.context) an =
let open Clang_ast_t in
match an with
| Ctl_parser_types.Decl (ObjCMethodDecl (_, named_decl_info, _)) -> (
match cxt.if_context with
| Some if_context ->
let in_selector_block = if_context.within_responds_to_selector_block in
List.mem ~equal:String.equal in_selector_block named_decl_info.ni_name
| None ->
false )
| _ ->
false
let within_available_class_block (cxt: CLintersContext.context) an =
match (receiver_method_call an, cxt.if_context) with
| Some receiver, Some if_context
-> (
let in_available_class_block = if_context.within_available_class_block in
match declaration_name receiver with
| Some receiver_name ->
List.mem ~equal:String.equal in_available_class_block receiver_name
| None ->
false )
| _ ->
false
let using_namespace an namespace =
let open Clang_ast_t in
match an with
| Ctl_parser_types.Decl (UsingDirectiveDecl (_, _, uddi)) -> (
match uddi.uddi_nominated_namespace with
| Some dr -> (
match (dr.dr_kind, dr.dr_name) with
| `Namespace, Some ni ->
ALVar.compare_str_with_alexp ni.ni_name namespace
| _ ->
false )
| None ->
false )
| _ ->
false
let rec get_decl_attributes_for_callexpr an =
let open Clang_ast_t in
let open Ctl_parser_types in
match an with
| Stmt (CallExpr (_, func :: _, _)) ->
get_decl_attributes_for_callexpr (Stmt func)
| Stmt (ImplicitCastExpr (_, [stmt], _, _)) ->
get_decl_attributes_for_callexpr (Stmt stmt)
| Stmt (DeclRefExpr (_, _, _, drti)) -> (
match CAst_utils.get_decl_opt_with_decl_ref drti.drti_decl_ref with
| Some decl ->
let decl_info = Clang_ast_proj.get_decl_tuple decl in
decl_info.di_attributes
| None ->
[] )
| _ ->
[]
let has_visibility_attribute an visibility =
let open Clang_ast_t in
let rec has_visibility_attr attrs param =
match attrs with
| [] ->
false
| VisibilityAttr attr_info :: rest ->
if List.exists ~f:(fun s -> String.equal param (String.strip s)) attr_info.ai_parameters
then true
else has_visibility_attr rest param
| _ :: rest ->
has_visibility_attr rest param
in
let attributes = get_decl_attributes_for_callexpr an in
match visibility with ALVar.Const vis -> has_visibility_attr attributes vis | _ -> false
let has_used_attribute an =
let open Clang_ast_t in
let attributes = get_decl_attributes_for_callexpr an in
List.exists ~f:(fun attr -> match attr with UsedAttr _ -> true | _ -> false) attributes
let has_value an al_exp =
let open Clang_ast_t in
let open Ctl_parser_types in
match an with
| Stmt (IntegerLiteral (_, _, _, integer_literal_info)) ->
let value = integer_literal_info.Clang_ast_t.ili_value in
ALVar.compare_str_with_alexp value al_exp
| Stmt (StringLiteral (_, _, _, l)) ->
ALVar.compare_str_with_alexp (String.concat ~sep:"" l) al_exp
| _ ->
false
(* check if method is called on superclass *)
let is_method_called_by_superclass an =
let open Clang_ast_t in
let open Ctl_parser_types in
match an with
| Stmt (ObjCMessageExpr (_, _, _, obj_c_message_expr_info)) -> (
match obj_c_message_expr_info.omei_receiver_kind with `SuperInstance -> true | _ -> false )
| _ ->
false
let is_cxx_copy_constructor an =
let open Clang_ast_t in
match an with
| Ctl_parser_types.Stmt (CXXConstructExpr (_, _, _, xcei)) ->
xcei.xcei_is_copy_constructor
| _ ->
false