Add new ObjC predicates, mostly related to categories

Reviewed By: dulmarod

Differential Revision: D7809653

fbshipit-source-id: c21f721
master
Brandon Kieft 7 years ago committed by Facebook Github Bot
parent eea5b4c97e
commit d7cf002461

@ -19,11 +19,13 @@ type context =
; current_method: Clang_ast_t.decl option ; current_method: Clang_ast_t.decl option
; parent_methods: Clang_ast_t.decl list ; parent_methods: Clang_ast_t.decl list
; in_synchronized_block: bool ; in_synchronized_block: bool
(** True if the translation unit contains an ObjC class impl that's a subclass
of CKComponent or CKComponentController. *)
; is_ck_translation_unit: bool ; is_ck_translation_unit: bool
(** If inside an objc class, contains the objc class (impl or interface) decl. *) (** True if the translation unit contains an ObjC class impl that's a subclass
of CKComponent or CKComponentController. *)
; current_objc_class: Clang_ast_t.decl option ; current_objc_class: Clang_ast_t.decl option
(** If inside an objc class, contains the objc class (impl or interface) decl. *)
; current_objc_category: Clang_ast_t.decl option
(** If inside an objc category, contains the objc category (impl or interface) decl. *)
; et_evaluation_node: string option ; et_evaluation_node: string option
; if_context: if_context option ; if_context: if_context option
; in_for_loop_declaration: bool } ; in_for_loop_declaration: bool }
@ -35,6 +37,7 @@ let empty translation_unit_context =
; in_synchronized_block= false ; in_synchronized_block= false
; is_ck_translation_unit= false ; is_ck_translation_unit= false
; current_objc_class= None ; current_objc_class= None
; current_objc_category= None
; et_evaluation_node= None ; et_evaluation_node= None
; if_context= None ; if_context= None
; in_for_loop_declaration= false } ; in_for_loop_declaration= false }

@ -19,11 +19,13 @@ type context =
; current_method: Clang_ast_t.decl option ; current_method: Clang_ast_t.decl option
; parent_methods: Clang_ast_t.decl list ; parent_methods: Clang_ast_t.decl list
; in_synchronized_block: bool ; in_synchronized_block: bool
(** True if the translation unit contains an ObjC class impl that's a subclass
of CKComponent or CKComponentController. *)
; is_ck_translation_unit: bool ; is_ck_translation_unit: bool
(** If inside an objc class, contains the objc class (impl or interface) decl. *) (** True if the translation unit contains an ObjC class impl that's a subclass
of CKComponent or CKComponentController. *)
; current_objc_class: Clang_ast_t.decl option ; current_objc_class: Clang_ast_t.decl option
(** If inside an objc class, contains the objc class (impl or interface) decl. *)
; current_objc_category: Clang_ast_t.decl option
(** If inside an objc category, contains the objc category (impl or interface) decl. *)
; et_evaluation_node: string option ; et_evaluation_node: string option
; if_context: if_context option ; if_context: if_context option
; in_for_loop_declaration: bool } ; in_for_loop_declaration: bool }

@ -338,6 +338,11 @@ and do_frontend_checks_decl (context: CLintersContext.context)
let context' = {context with current_objc_class= Some decl} in let context' = {context with current_objc_class= Some decl} in
List.iter ~f:(do_frontend_checks_decl context' map_active) decls ; List.iter ~f:(do_frontend_checks_decl context' map_active) decls ;
call_tableaux context' an map_active call_tableaux context' an map_active
| ObjCCategoryImplDecl (_, _, decls, _, _) | ObjCCategoryDecl (_, _, decls, _, _) ->
CFrontend_errors.invoke_set_of_checkers_on_node context an ;
let context' = {context with current_objc_category= Some decl} in
List.iter ~f:(do_frontend_checks_decl context' map_active) decls ;
call_tableaux context' an map_active
| _ -> | _ ->
CFrontend_errors.invoke_set_of_checkers_on_node context an ; CFrontend_errors.invoke_set_of_checkers_on_node context an ;
( match Clang_ast_proj.get_decl_context_tuple decl with ( match Clang_ast_proj.get_decl_context_tuple decl with

@ -148,16 +148,148 @@ let pp_predicate fmt (name_, arglist_) =
Format.fprintf fmt "%s(%a)" name (Pp.comma_seq Format.pp_print_string) arglist 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 *) (* is an objc interface with name expected_name *)
let is_objc_interface_named an expected_name = let is_objc_interface_named an expected_name =
match an with match an with
| Ctl_parser_types.Decl (Clang_ast_t.ObjCInterfaceDecl (_, ni, _, _, _)) -> | Ctl_parser_types.Decl (Clang_ast_t.ObjCInterfaceDecl _) ->
ALVar.compare_str_with_alexp ni.ni_name expected_name 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 false
(* checkes whether an object is of a certain class *) (* 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_method_named an name =
match an with
| Ctl_parser_types.Decl (Clang_ast_t.ObjCMethodDecl _) ->
declaration_has_name an name
| _ ->
false
(* checks whether an object is of a certain class *)
let is_object_of_class_named receiver cname = let is_object_of_class_named receiver cname =
let open Clang_ast_t in let open Clang_ast_t in
match receiver with match receiver with
@ -459,22 +591,6 @@ let is_in_block context =
match context.CLintersContext.current_method with Some (BlockDecl _) -> true | _ -> false match context.CLintersContext.current_method with Some (BlockDecl _) -> true | _ -> 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
let is_in_objc_subclass_of context name = let is_in_objc_subclass_of context name =
match context.CLintersContext.current_objc_class with match context.CLintersContext.current_objc_class with
| Some cls -> | Some cls ->
@ -486,7 +602,31 @@ let is_in_objc_subclass_of context name =
let is_in_objc_class_named context name = let is_in_objc_class_named context name =
match context.CLintersContext.current_objc_class with match context.CLintersContext.current_objc_class with
| Some cls -> | Some cls ->
is_objc_interface_named (Decl cls) name is_objc_class_named (Decl cls) 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_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_named context name =
match context.CLintersContext.current_objc_category with
| Some cat ->
is_objc_category_named (Decl cat) name
| None -> | None ->
false false
@ -573,17 +713,7 @@ let isa an classname =
false false
(* an is a declaration whose name contains a regexp defined by re *) let is_class an re = is_objc_class_named an re
let declaration_has_name an name =
match an with
| Ctl_parser_types.Decl d -> (
match Clang_ast_proj.get_named_decl_tuple d with
| Some (_, ndi) ->
ALVar.compare_str_with_alexp ndi.ni_name name
| _ ->
false )
| _ ->
false
(* an is an expression @selector with whose name in the language of re *) (* an is an expression @selector with whose name in the language of re *)
@ -595,15 +725,6 @@ let is_at_selector_with_name an re =
false false
let is_class an re =
match an with
| Ctl_parser_types.Decl (Clang_ast_t.ObjCInterfaceDecl _)
| Ctl_parser_types.Decl (Clang_ast_t.ObjCImplementationDecl _) ->
declaration_has_name an re
| _ ->
false
let iphoneos_target_sdk_version_by_path (cxt: CLintersContext.context) = let iphoneos_target_sdk_version_by_path (cxt: CLintersContext.context) =
let source_file = cxt.translation_unit_context.source_file in let source_file = cxt.translation_unit_context.source_file in
let regex_version_opt = let regex_version_opt =

@ -20,11 +20,11 @@ val call_method : Ctl_parser_types.ast_node -> ALVar.alexp -> bool
(** 'call_method an m an' is true iff node an is a call to an ObjC method with name containing string m *) (** 'call_method an m an' is true iff node an is a call to an ObjC method with name containing string m *)
val call_class_method : Ctl_parser_types.ast_node -> ALVar.alexp -> ALVar.alexp -> bool val call_class_method : Ctl_parser_types.ast_node -> ALVar.alexp -> ALVar.alexp -> bool
(** 'call_class_method an cname mname' is true iff node an is a call to an ObjC method of class cname (** 'call_class_method an cname mname' is true iff node an is a call to an ObjC method of class cname
and the name of the method contains mname *) and the name of the method contains mname *)
val call_instance_method : Ctl_parser_types.ast_node -> ALVar.alexp -> ALVar.alexp -> bool val call_instance_method : Ctl_parser_types.ast_node -> ALVar.alexp -> ALVar.alexp -> bool
(** 'call_instance_method an cname mname' is true iff an is a node calling an ObjC method of an (** 'call_instance_method an cname mname' is true iff an is a node calling an ObjC method of an
object of class cname and the method name contains mname object of class cname and the method name contains mname
*) *)
@ -36,11 +36,6 @@ val is_enum_constant : Ctl_parser_types.ast_node -> ALVar.alexp -> bool
val is_enum_constant_of_enum : Ctl_parser_types.ast_node -> ALVar.alexp -> bool val is_enum_constant_of_enum : Ctl_parser_types.ast_node -> ALVar.alexp -> bool
val is_objc_interface_named : Ctl_parser_types.ast_node -> ALVar.alexp -> bool
(** 'is_objc_interface_named an expected_name' is true iff an is an objc interface with name expected_name *)
val is_objc_extension : CLintersContext.context -> bool
val is_global_var : Ctl_parser_types.ast_node -> bool val is_global_var : Ctl_parser_types.ast_node -> bool
(** 'is_global_var an' is true iff an is a global variable (but not a static local) *) (** 'is_global_var an' is true iff an is a global variable (but not a static local) *)
@ -89,8 +84,114 @@ val is_in_cxx_method : CLintersContext.context -> ALVar.alexp -> bool
val is_in_function : CLintersContext.context -> ALVar.alexp -> bool val is_in_function : CLintersContext.context -> ALVar.alexp -> bool
(** 'is_in_function context name' is true if the curent node is within a function whose name contains 'name' *) (** 'is_in_function context name' is true if the curent node is within a function whose name contains 'name' *)
val is_in_objc_method : CLintersContext.context -> ALVar.alexp -> bool val is_objc_extension : CLintersContext.context -> bool
(** 'is_in_objc_method context name' is true if the curent node is within an ObjC method whose name contains 'name' *) (**
* Checks if the current file has an ObjC file extension (I.E. '.m' or '.mm')
*)
val is_objc_class_named : Ctl_parser_types.ast_node -> ALVar.alexp -> bool
(**
* Checks if the current node is an ObjCInterfaceDecl or ObjCImplementationDecl
* node whose name matches the provided REGEXP
*
* Matches on MyClass in:
* @interface MyClass
* @implementation MyClass
*)
val is_objc_interface_named : Ctl_parser_types.ast_node -> ALVar.alexp -> bool
(**
* Checks if the current node is an ObjCInterfaceDecl node
* whose name matches the provided REGEXP
*
* Matches on MyClass in @interface MyClass
*)
val is_objc_implementation_named : Ctl_parser_types.ast_node -> ALVar.alexp -> bool
(**
* Checks if the current node is an ObjCImplementationDecl node
* whose name matches the provided REGEXP
*
* Matches on MyClass in @implementation MyClass
*)
val is_objc_category_named : Ctl_parser_types.ast_node -> ALVar.alexp -> bool
(**
* Checks if the current node is an ObjCCategoryDecl or ObjCCategoryImplDecl
* node whose name matches the provided REGEXP
*
* Matches on MyCategory in:
* @interface MyClass (MyCategory)
* @implementation MyClass (MyCategory)
*)
val is_objc_category_interface_named : Ctl_parser_types.ast_node -> ALVar.alexp -> bool
(**
* Checks if the current node is an ObjCCategoryDecl node
* whose name matches the provided REGEXP
*
* Matches on MyCategory in @interface MyClass (MyCategory)
*)
val is_objc_category_implementation_named : Ctl_parser_types.ast_node -> ALVar.alexp -> bool
(**
* Checks if the current node is an ObjCCategoryImplDecl node
* whose name matches the provided REGEXP
*
* Matches on MyCategory in @implementation MyClass (MyCategory)
*)
val is_objc_category_on_class_named : Ctl_parser_types.ast_node -> ALVar.alexp -> bool
(**
* Checks if the current node is an ObjCCategoryDecl or ObjCCategoryImplDecl
* node whose class's name matches the provided REGEXP
*
* Matches on MyClass in:
* @interface MyClass (MyCategory)
* @implementation MyClass (MyCategory)
*)
val is_objc_category_interface_on_class_named : Ctl_parser_types.ast_node -> ALVar.alexp -> bool
(**
* Checks if the current node is an ObjCCategoryDecl node
* whose class's name matches the provided REGEXP
*
* Matches on MyClass in @interface MyClass (MyCategory)
*)
val is_objc_category_implementation_on_class_named :
Ctl_parser_types.ast_node -> ALVar.alexp -> bool
(**
* Checks if the current node is an ObjCCategoryImplDecl node
* whose class's name matches the provided REGEXP
*
* Matches on MyClass in @implementation MyClass (MyCategory)
*)
val is_objc_category_on_subclass_of : Ctl_parser_types.ast_node -> ALVar.alexp -> bool
(**
* Checks if the current node is an ObjCCategoryDecl or ObjCCategoryImplDecl
* node whose class inherits from a class whose name matches the provided REGEXP
*)
val is_objc_category_interface_on_subclass_of : Ctl_parser_types.ast_node -> ALVar.alexp -> bool
(**
* Checks if the current node is an ObjCCategoryDecl node whose class
* inherits from a class whose name matches the provided REGEXP
*)
val is_objc_category_implementation_on_subclass_of :
Ctl_parser_types.ast_node -> ALVar.alexp -> bool
(**
* Checks if the current node is an ObjCCategoryImplDecl node whose class
* inherits from a class whose name matches the provided REGEXP
*)
val is_objc_method_named : Ctl_parser_types.ast_node -> ALVar.alexp -> bool
(**
* Checks if the current node is an ObjCMethodDecl node
* whose name matches the provided REGEXP
*)
val is_objc_constructor : CLintersContext.context -> bool val is_objc_constructor : CLintersContext.context -> bool
(** 'is_in_objc_constructor context' is true if the curent node is within an ObjC constructor *) (** 'is_in_objc_constructor context' is true if the curent node is within an ObjC constructor *)
@ -99,10 +200,42 @@ val is_objc_dealloc : CLintersContext.context -> bool
(** 'is_in_objc_dealloc context' is true if the curent node is within an ObjC dealloc method *) (** 'is_in_objc_dealloc context' is true if the curent node is within an ObjC dealloc method *)
val is_in_objc_subclass_of : CLintersContext.context -> ALVar.alexp -> bool val is_in_objc_subclass_of : CLintersContext.context -> ALVar.alexp -> bool
(** 'is_in_objc_subclass_of context cname' is true if the current node is within the context of a subclass of class cname*) (**
* Checks if the current node is a subnode of an ObjCInterfaceDecl or
* ObjCImplementationDecl node which inherits from a class whose
* name matches the provided REGEXP
*)
val is_in_objc_class_named : CLintersContext.context -> ALVar.alexp -> bool val is_in_objc_class_named : CLintersContext.context -> ALVar.alexp -> bool
(** 'is_in_objc_class_named context cname' is true if the current node is within the context of a of class cname*) (**
* Checks if the current node is a subnode of an ObjCInterfaceDecl or
* ObjCImplementationDecl node whose name matches the provided REGEXP
*)
val is_in_objc_category_on_class_named : CLintersContext.context -> ALVar.alexp -> bool
(**
* Checks if the current node is a subnode of an ObjCCategoryDecl or
* ObjCCategoryImplDecl node whose class's name matches the provided REGEXP
*)
val is_in_objc_category_on_subclass_of : CLintersContext.context -> ALVar.alexp -> bool
(**
* Checks if the current node is a subnode of an ObjCCategoryDecl or
* ObjCCategoryImplDecl node whose class inherits from a class whose
* name matches the provided REGEXP
*)
val is_in_objc_category_named : CLintersContext.context -> ALVar.alexp -> bool
(**
* Checks if the current node is a subnode of an ObjCCategoryDecl or
* ObjCCategoryImplDecl node whose name matches the provided REGEXP
*)
val is_in_objc_method : CLintersContext.context -> ALVar.alexp -> bool
(**
* Checks if the current node, or a parent node, is an ObjCMethodDecl node
* whose name matches the provided REGEXP
*)
val captures_cxx_references : Ctl_parser_types.ast_node -> bool val captures_cxx_references : Ctl_parser_types.ast_node -> bool
(** 'captures_cxx_references an' is true iff the node an captures some CXX references *) (** 'captures_cxx_references an' is true iff the node an captures some CXX references *)
@ -126,7 +259,7 @@ val declaration_has_name : Ctl_parser_types.ast_node -> ALVar.alexp -> bool
val declaration_ref_name : val declaration_ref_name :
?kind:Clang_ast_t.decl_kind -> Ctl_parser_types.ast_node -> ALVar.alexp -> bool ?kind:Clang_ast_t.decl_kind -> Ctl_parser_types.ast_node -> ALVar.alexp -> bool
(** 'declaration_ref_has_name an n' is true iff node an is a DeclRefExpr with name containing string n. The optional parameter kind (** 'declaration_ref_has_name an n' is true iff node an is a DeclRefExpr with name containing string n. The optional parameter kind
allow to distinguish between special kind of decl_ref_exprs like 'is_enum_constant'. *) allow to distinguish between special kind of decl_ref_exprs like 'is_enum_constant'. *)
val is_class : Ctl_parser_types.ast_node -> ALVar.alexp -> bool val is_class : Ctl_parser_types.ast_node -> ALVar.alexp -> bool

@ -1022,6 +1022,12 @@ let rec eval_Atomic pred_name_ args an lcxt =
CPredicates.is_in_objc_class_named lcxt name CPredicates.is_in_objc_class_named lcxt name
| "is_in_objc_subclass_of", [name], _ -> | "is_in_objc_subclass_of", [name], _ ->
CPredicates.is_in_objc_subclass_of lcxt name CPredicates.is_in_objc_subclass_of lcxt name
| "is_in_objc_category_on_class_named", [name], _ ->
CPredicates.is_in_objc_category_on_class_named lcxt name
| "is_in_objc_category_on_subclass_of", [name], _ ->
CPredicates.is_in_objc_category_on_subclass_of lcxt name
| "is_in_objc_category_named", [name], _ ->
CPredicates.is_in_objc_category_named lcxt name
| "is_ivar_atomic", [], an -> | "is_ivar_atomic", [], an ->
CPredicates.is_ivar_atomic an CPredicates.is_ivar_atomic an
| "is_method_property_accessor_of_ivar", [], an -> | "is_method_property_accessor_of_ivar", [], an ->
@ -1036,6 +1042,30 @@ let rec eval_Atomic pred_name_ args an lcxt =
CPredicates.is_objc_extension lcxt CPredicates.is_objc_extension lcxt
| "is_objc_interface_named", [name], an -> | "is_objc_interface_named", [name], an ->
CPredicates.is_objc_interface_named an name CPredicates.is_objc_interface_named an name
| "is_objc_implementation_named", [name], an ->
CPredicates.is_objc_implementation_named an name
| "is_objc_class_named", [name], an ->
CPredicates.is_objc_class_named an name
| "is_objc_category_interface_on_class_named", [name], an ->
CPredicates.is_objc_category_interface_on_class_named an name
| "is_objc_category_implementation_on_class_named", [name], an ->
CPredicates.is_objc_category_implementation_on_class_named an name
| "is_objc_category_on_class_named", [cname], an ->
CPredicates.is_objc_category_on_class_named an cname
| "is_objc_category_interface_named", [name], an ->
CPredicates.is_objc_category_interface_named an name
| "is_objc_category_implementation_named", [name], an ->
CPredicates.is_objc_category_implementation_named an name
| "is_objc_category_named", [cname], an ->
CPredicates.is_objc_category_named an cname
| "is_objc_category_interface_on_subclass_of", [name], an ->
CPredicates.is_objc_category_interface_on_subclass_of an name
| "is_objc_category_implementation_on_subclass_of", [name], an ->
CPredicates.is_objc_category_implementation_on_subclass_of an name
| "is_objc_category_on_subclass_of", [name], an ->
CPredicates.is_objc_category_on_subclass_of an name
| "is_objc_method_named", [name], an ->
CPredicates.is_objc_method_named an name
| "is_property_pointer_type", [], an -> | "is_property_pointer_type", [], an ->
CPredicates.is_property_pointer_type an CPredicates.is_property_pointer_type an
| "is_strong_property", [], an -> | "is_strong_property", [], an ->

@ -0,0 +1,145 @@
// Copyright 2004-present Facebook. All Rights Reserved.
#import <Foundation/Foundation.h>
/* ======== My Base Class ======== */
@protocol MyBaseClassProtocol
@required
- (void)myBaseClassProtocolRequiredMethod;
@optional
- (void)myBaseClassProtocolOptionalMethod;
@end
@interface MyBaseClass : NSObject<MyBaseClassProtocol>
@property int myBaseClassProperty;
- (void)myBaseClassMethod;
@end
@interface MyBaseClass ()
- (void)myBaseClassInterfaceExtensionMethod;
@end
@implementation MyBaseClass
- (void)myBaseClassMethod {
}
- (void)myBaseClassInterfaceExtensionMethod {
}
- (void)myBaseClassProtocolRequiredMethod {
}
- (void)myBaseClassProtocolOptionalMethod {
}
- (int)myBaseClassProperty {
return 0;
}
- (void)setMyBaseClassProperty:(int)value {
}
@end
@interface MyBaseClass (MyBaseClassCategory)
- (void)myBaseClassCategoryMethod;
@end
@implementation MyBaseClass (MyBaseClassCategory)
- (void)myBaseClassCategoryMethod {
}
@end
/* ======== My Subclass ======== */
@protocol MySubclassProtocol
@required
- (void)mySubclassProtocolRequiredMethod;
@optional
- (void)mySubclassProtocolOptionalMethod;
@end
@protocol MySubclassProtocol2
@required
- (void)mySubclassProtocol2RequiredMethod;
@optional
- (void)mySubclassProtocol2OptionalMethod;
@end
@protocol MySubclassSubprotocol<MySubclassProtocol>
@required
- (void)mySubclassSubprotocol2RequiredMethod;
@optional
- (void)mySubclassSubprotocol2OptionalMethod;
@end
@interface MySubclass : MyBaseClass<MySubclassSubprotocol, MySubclassProtocol2>
- (void)mySubclassMethod;
@end
@implementation MySubclass
- (void)myBaseClassMethod {
[super myBaseClassMethod];
}
- (void)myBaseClassInterfaceExtensionMethod {
[super myBaseClassInterfaceExtensionMethod];
}
- (void)myBaseClassProtocolRequiredMethod {
[super myBaseClassProtocolRequiredMethod];
}
- (void)myBaseClassProtocolOptionalMethod {
[super myBaseClassProtocolOptionalMethod];
}
- (int)myBaseClassProperty {
return [super myBaseClassProperty];
}
- (void)setMyBaseClassProperty:(int)value {
[super setMyBaseClassProperty:value];
}
- (void)myBaseClassCategoryMethod {
[super myBaseClassCategoryMethod];
}
- (void)mySubclassMethod {
}
- (void)mySubclassProtocolRequiredMethod {
}
- (void)mySubclassProtocolOptionalMethod {
}
- (void)mySubclassProtocol2RequiredMethod {
}
- (void)mySubclassProtocol2OptionalMethod {
}
- (void)mySubclassSubprotocol2RequiredMethod {
}
- (void)mySubclassSubprotocol2OptionalMethod {
}
@end
@interface MySubclass (MySubclassCategory)
- (void)mySubclassCategoryMethod;
@end
@implementation MySubclass (MySubclassCategory)
- (void)mySubclassCategoryMethod {
}
@end

@ -128,7 +128,7 @@ DEFINE-CHECKER TEST_BUILTIN_TYPE = {
SET report_when = SET report_when =
WHEN WHEN
is_in_objc_class_named("TestType") AND is_in_objc_class_named("TestType") AND
(method_return_type("void") (method_return_type("void")
OR method_return_type("bool") OR method_return_type("bool")
OR method_return_type("char") OR method_return_type("char")
@ -443,3 +443,145 @@ DEFINE-CHECKER TEST_PARAMETER_SEL_TYPE = {
SET message = "Method %name% is not called with super."; SET message = "Method %name% is not called with super.";
}; };
DEFINE-CHECKER TEST_IF_METHOD_IS_IN_CATEGORY_NAMED = {
SET report_when =
WHEN
is_in_objc_category_named("MyBaseClassCategory")
HOLDS-IN-NODE ObjCMethodDecl;
SET message = "Method %name% is in the category named MyBaseClassCategory.";
};
DEFINE-CHECKER TEST_IF_METHOD_IS_IN_CATEGORY_ON_CLASS_NAMED = {
SET report_when =
WHEN
is_in_objc_category_on_class_named("MyBaseClass")
HOLDS-IN-NODE ObjCMethodDecl;
SET message = "Method %name% is in the category on a class named MyBaseClass.";
};
DEFINE-CHECKER TEST_IF_METHOD_IS_IN_CATEGORY_ON_SUBCLASS_OF = {
SET report_when =
WHEN
is_in_objc_category_on_subclass_of("MyBaseClass")
HOLDS-IN-NODE ObjCMethodDecl;
SET message = "Method %name% is in the category on a subclass of MyBaseClass.";
};
DEFINE-CHECKER TEST_IF_IS_CATEGORY_INTERFACE_NAMED = {
SET report_when =
is_objc_category_interface_named("MyBaseClassCategory");
SET message = "Node is a category interface named MyBaseClassCategory.";
};
DEFINE-CHECKER TEST_IF_IS_CATEGORY_IMPLEMENTATION_NAMED = {
SET report_when =
is_objc_category_implementation_named("MyBaseClassCategory");
SET message = "Node is a category implementation named MyBaseClassCategory.";
};
DEFINE-CHECKER TEST_IF_IS_CATEGORY_NAMED = {
SET report_when =
is_objc_category_named("MyBaseClassCategory");
SET message = "Node is a category named MyBaseClassCategory.";
};
DEFINE-CHECKER TEST_IF_IS_CATEGORY_INTERFACE_ON_CLASS_NAMED = {
SET report_when =
is_objc_category_interface_on_class_named("MyBaseClass");
SET message = "Node is a category interface on a class named MyBaseClass.";
};
DEFINE-CHECKER TEST_IF_IS_CATEGORY_IMPLEMENTATION_ON_CLASS_NAMED = {
SET report_when =
is_objc_category_implementation_on_class_named("MyBaseClass");
SET message = "Node is a category implementation on a class named MyBaseClass.";
};
DEFINE-CHECKER TEST_IF_IS_CATEGORY_ON_CLASS_NAMED = {
SET report_when =
is_objc_category_on_class_named("MyBaseClass");
SET message = "Node is a category on a class named MyBaseClass.";
};
DEFINE-CHECKER TEST_IF_IS_CATEGORY_INTERFACE_ON_SUBCLASS_OF = {
SET report_when =
is_objc_category_interface_on_subclass_of("MyBaseClass");
SET message = "Node is a category interface on a subclass of MyBaseClass.";
};
DEFINE-CHECKER TEST_IF_IS_CATEGORY_IMPLEMENTATION_ON_SUBCLASS_OF = {
SET report_when =
is_objc_category_implementation_on_subclass_of("MyBaseClass");
SET message = "Node is a category implementation on a subclass of MyBaseClass.";
};
DEFINE-CHECKER TEST_IF_IS_CATEGORY_ON_SUBCLASS_OF = {
SET report_when =
is_objc_category_on_subclass_of("MyBaseClass");
SET message = "Node is a category on a subclass of MyBaseClass.";
};
DEFINE-CHECKER TEST_IF_IS_IMPLEMENTATION_NAMED = {
SET report_when =
is_objc_implementation_named("MyBaseClass");
SET message = "Node is an implementation named MyBaseClass.";
};
DEFINE-CHECKER TEST_IF_IS_CLASS_NAMED = {
SET report_when =
is_objc_class_named("MyBaseClass");
SET message = "Node is a class named MyBaseClass.";
};
DEFINE-CHECKER TEST_IF_IS_METHOD_NAMED = {
SET report_when =
is_objc_method_named("mySubclassMethod");
SET message = "Node is a method named mySubclassMethod.";
};

@ -1,6 +1,36 @@
codetoanalyze/objc/linters-for-test-only/CallingAMethodWithSelf.m, CallingAMethodWithSelfBase_testView, 17, TEST_VAR_TYPE_CHECK, WARNING, [] codetoanalyze/objc/linters-for-test-only/CallingAMethodWithSelf.m, CallingAMethodWithSelfBase_testView, 17, TEST_VAR_TYPE_CHECK, WARNING, []
codetoanalyze/objc/linters-for-test-only/CallingAMethodWithSelf.m, CallingAMethodWithSelf_methodThatShallComplain, 41, TEST_IF_VIEW_METHOD_IS_NOT_CALLED_WITH_SUPER, WARNING, [] codetoanalyze/objc/linters-for-test-only/CallingAMethodWithSelf.m, CallingAMethodWithSelf_methodThatShallComplain, 41, TEST_IF_VIEW_METHOD_IS_NOT_CALLED_WITH_SUPER, WARNING, []
codetoanalyze/objc/linters-for-test-only/CallingAMethodWithSelf.m, CallingAMethodWithSelf_testView, 45, TEST_VAR_TYPE_CHECK, WARNING, [] codetoanalyze/objc/linters-for-test-only/CallingAMethodWithSelf.m, CallingAMethodWithSelf_testView, 45, TEST_VAR_TYPE_CHECK, WARNING, []
codetoanalyze/objc/linters-for-test-only/GenericTestClass.m, Linters_dummy_method, 14, TEST_IF_IS_CLASS_NAMED, WARNING, []
codetoanalyze/objc/linters-for-test-only/GenericTestClass.m, Linters_dummy_method, 21, TEST_IF_IS_CATEGORY_INTERFACE_ON_CLASS_NAMED, WARNING, []
codetoanalyze/objc/linters-for-test-only/GenericTestClass.m, Linters_dummy_method, 21, TEST_IF_IS_CATEGORY_ON_CLASS_NAMED, WARNING, []
codetoanalyze/objc/linters-for-test-only/GenericTestClass.m, Linters_dummy_method, 27, TEST_IF_IS_CLASS_NAMED, WARNING, []
codetoanalyze/objc/linters-for-test-only/GenericTestClass.m, Linters_dummy_method, 27, TEST_IF_IS_IMPLEMENTATION_NAMED, WARNING, []
codetoanalyze/objc/linters-for-test-only/GenericTestClass.m, Linters_dummy_method, 45, TEST_IF_IS_CATEGORY_INTERFACE_NAMED, WARNING, []
codetoanalyze/objc/linters-for-test-only/GenericTestClass.m, Linters_dummy_method, 45, TEST_IF_IS_CATEGORY_INTERFACE_ON_CLASS_NAMED, WARNING, []
codetoanalyze/objc/linters-for-test-only/GenericTestClass.m, Linters_dummy_method, 45, TEST_IF_IS_CATEGORY_NAMED, WARNING, []
codetoanalyze/objc/linters-for-test-only/GenericTestClass.m, Linters_dummy_method, 45, TEST_IF_IS_CATEGORY_ON_CLASS_NAMED, WARNING, []
codetoanalyze/objc/linters-for-test-only/GenericTestClass.m, Linters_dummy_method, 51, TEST_IF_IS_CATEGORY_IMPLEMENTATION_NAMED, WARNING, []
codetoanalyze/objc/linters-for-test-only/GenericTestClass.m, Linters_dummy_method, 51, TEST_IF_IS_CATEGORY_IMPLEMENTATION_ON_CLASS_NAMED, WARNING, []
codetoanalyze/objc/linters-for-test-only/GenericTestClass.m, Linters_dummy_method, 51, TEST_IF_IS_CATEGORY_NAMED, WARNING, []
codetoanalyze/objc/linters-for-test-only/GenericTestClass.m, Linters_dummy_method, 51, TEST_IF_IS_CATEGORY_ON_CLASS_NAMED, WARNING, []
codetoanalyze/objc/linters-for-test-only/GenericTestClass.m, Linters_dummy_method, 134, TEST_IF_IS_CATEGORY_INTERFACE_ON_SUBCLASS_OF, WARNING, []
codetoanalyze/objc/linters-for-test-only/GenericTestClass.m, Linters_dummy_method, 134, TEST_IF_IS_CATEGORY_ON_SUBCLASS_OF, WARNING, []
codetoanalyze/objc/linters-for-test-only/GenericTestClass.m, Linters_dummy_method, 140, TEST_IF_IS_CATEGORY_IMPLEMENTATION_ON_SUBCLASS_OF, WARNING, []
codetoanalyze/objc/linters-for-test-only/GenericTestClass.m, Linters_dummy_method, 140, TEST_IF_IS_CATEGORY_ON_SUBCLASS_OF, WARNING, []
codetoanalyze/objc/linters-for-test-only/GenericTestClass.m, MyBaseClass_myBaseClassCategoryMethod, 47, TEST_IF_METHOD_IS_IN_CATEGORY_NAMED, WARNING, []
codetoanalyze/objc/linters-for-test-only/GenericTestClass.m, MyBaseClass_myBaseClassCategoryMethod, 47, TEST_IF_METHOD_IS_IN_CATEGORY_ON_CLASS_NAMED, WARNING, []
codetoanalyze/objc/linters-for-test-only/GenericTestClass.m, MyBaseClass_myBaseClassCategoryMethod, 53, TEST_IF_METHOD_IS_IN_CATEGORY_NAMED, WARNING, []
codetoanalyze/objc/linters-for-test-only/GenericTestClass.m, MyBaseClass_myBaseClassCategoryMethod, 53, TEST_IF_METHOD_IS_IN_CATEGORY_ON_CLASS_NAMED, WARNING, []
codetoanalyze/objc/linters-for-test-only/GenericTestClass.m, MyBaseClass_myBaseClassInterfaceExtensionMethod, 23, TEST_IF_METHOD_IS_IN_CATEGORY_ON_CLASS_NAMED, WARNING, []
codetoanalyze/objc/linters-for-test-only/GenericTestClass.m, MyBaseClass_myBaseClassProperty, 37, TEST_RETURN_METHOD, WARNING, []
codetoanalyze/objc/linters-for-test-only/GenericTestClass.m, MyBaseClass_setMyBaseClassProperty, 40, TEST_PARAM_TYPE_CHECK2, WARNING, []
codetoanalyze/objc/linters-for-test-only/GenericTestClass.m, MySubclass_myBaseClassProperty, 105, TEST_RETURN_METHOD, WARNING, []
codetoanalyze/objc/linters-for-test-only/GenericTestClass.m, MySubclass_mySubclassCategoryMethod, 136, TEST_IF_METHOD_IS_IN_CATEGORY_ON_SUBCLASS_OF, WARNING, []
codetoanalyze/objc/linters-for-test-only/GenericTestClass.m, MySubclass_mySubclassCategoryMethod, 142, TEST_IF_METHOD_IS_IN_CATEGORY_ON_SUBCLASS_OF, WARNING, []
codetoanalyze/objc/linters-for-test-only/GenericTestClass.m, MySubclass_mySubclassMethod, 83, TEST_IF_IS_METHOD_NAMED, WARNING, []
codetoanalyze/objc/linters-for-test-only/GenericTestClass.m, MySubclass_mySubclassMethod, 117, TEST_IF_IS_METHOD_NAMED, WARNING, []
codetoanalyze/objc/linters-for-test-only/GenericTestClass.m, MySubclass_setMyBaseClassProperty, 109, TEST_PARAM_TYPE_CHECK2, WARNING, []
codetoanalyze/objc/linters-for-test-only/InContextOfMethodsTest.m, InContextOfMethodsTest_method, 16, TEST_IN_METHOD_CONTEXT, WARNING, [] codetoanalyze/objc/linters-for-test-only/InContextOfMethodsTest.m, InContextOfMethodsTest_method, 16, TEST_IN_METHOD_CONTEXT, WARNING, []
codetoanalyze/objc/linters-for-test-only/InContextOfMethodsTest.m, InContextOfMethodsTest_method, 16, TEST_VAR_TYPE_CHECK, WARNING, [] codetoanalyze/objc/linters-for-test-only/InContextOfMethodsTest.m, InContextOfMethodsTest_method, 16, TEST_VAR_TYPE_CHECK, WARNING, []
codetoanalyze/objc/linters-for-test-only/InContextOfMethodsTest.m, function, 27, TEST_IN_FUNCTION_CONTEXT, WARNING, [] codetoanalyze/objc/linters-for-test-only/InContextOfMethodsTest.m, function, 27, TEST_IN_FUNCTION_CONTEXT, WARNING, []

Loading…
Cancel
Save