diff --git a/infer/src/clang/cPredicates.ml b/infer/src/clang/cPredicates.ml index 116656384..5a8e37fdc 100644 --- a/infer/src/clang/cPredicates.ml +++ b/infer/src/clang/cPredicates.ml @@ -667,6 +667,22 @@ let is_in_objc_subclass_of context name = 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 -> @@ -675,6 +691,22 @@ let is_in_objc_class_named context name = 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 -> @@ -683,6 +715,22 @@ let is_in_objc_category_on_class_named context name = 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 -> @@ -691,6 +739,22 @@ let is_in_objc_category_on_subclass_of context name = 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 -> diff --git a/infer/src/clang/cPredicates.mli b/infer/src/clang/cPredicates.mli index ca4950bee..bb571d874 100644 --- a/infer/src/clang/cPredicates.mli +++ b/infer/src/clang/cPredicates.mli @@ -206,18 +206,56 @@ val is_in_objc_subclass_of : CLintersContext.context -> ALVar.alexp -> bool * name matches the provided REGEXP *) +val is_in_objc_interface_named : CLintersContext.context -> ALVar.alexp -> bool +(** + * Checks if the current node is a subnode of an ObjCInterfaceDecl + * node whose name matches the provided REGEXP + *) + +val is_in_objc_implementation_named : CLintersContext.context -> ALVar.alexp -> bool +(** + * Checks if the current node is a subnode of an ObjCImplementationDecl + * node whose name matches the provided REGEXP + *) + val is_in_objc_class_named : CLintersContext.context -> ALVar.alexp -> bool (** * 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_interface_on_class_named : CLintersContext.context -> ALVar.alexp -> bool +(** + * Checks if the current node is a subnode of an ObjCCategoryDecl node + * whose class's name matches the provided REGEXP + *) + +val is_in_objc_category_implementation_on_class_named : + CLintersContext.context -> ALVar.alexp -> bool +(** + * Checks if the current node is a subnode of an ObjCCategoryImplDecl node + * whose class's 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_interface_on_subclass_of : CLintersContext.context -> ALVar.alexp -> bool +(** + * Checks if the current node is a subnode of an ObjCCategoryDecl node + * whose class inherits from a class whose name matches the provided REGEXP + *) + +val is_in_objc_category_implementation_on_subclass_of : + CLintersContext.context -> ALVar.alexp -> bool +(** + * Checks if the current node is a subnode of an ObjCCategoryImplDecl node + * whose class inherits from a class whose 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 @@ -225,6 +263,18 @@ val is_in_objc_category_on_subclass_of : CLintersContext.context -> ALVar.alexp * name matches the provided REGEXP *) +val is_in_objc_category_interface_named : CLintersContext.context -> ALVar.alexp -> bool +(** + * Checks if the current node is a subnode of an ObjCCategoryDecl node + * whose name matches the provided REGEXP + *) + +val is_in_objc_category_implementation_named : CLintersContext.context -> ALVar.alexp -> bool +(** + * Checks if the current node is a subnode of an ObjCCategoryImplDecl node + * 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 diff --git a/infer/src/clang/cTL.ml b/infer/src/clang/cTL.ml index 2bd064186..d92fb1975 100644 --- a/infer/src/clang/cTL.ml +++ b/infer/src/clang/cTL.ml @@ -1018,14 +1018,30 @@ let rec eval_Atomic pred_name_ args an lcxt = CPredicates.is_in_function lcxt name | "is_in_objc_method", [name], _ -> CPredicates.is_in_objc_method lcxt name + | "is_in_objc_interface_named", [name], _ -> + CPredicates.is_in_objc_interface_named lcxt name + | "is_in_objc_implementation_named", [name], _ -> + CPredicates.is_in_objc_implementation_named lcxt name | "is_in_objc_class_named", [name], _ -> CPredicates.is_in_objc_class_named lcxt name | "is_in_objc_subclass_of", [name], _ -> CPredicates.is_in_objc_subclass_of lcxt name + | "is_in_objc_category_interface_on_class_named", [name], _ -> + CPredicates.is_in_objc_category_interface_on_class_named lcxt name + | "is_in_objc_category_implementation_on_class_named", [name], _ -> + CPredicates.is_in_objc_category_implementation_on_class_named lcxt name | "is_in_objc_category_on_class_named", [name], _ -> CPredicates.is_in_objc_category_on_class_named lcxt name + | "is_in_objc_category_interface_on_subclass_of", [name], _ -> + CPredicates.is_in_objc_category_interface_on_subclass_of lcxt name + | "is_in_objc_category_implementation_on_subclass_of", [name], _ -> + CPredicates.is_in_objc_category_implementation_on_subclass_of lcxt name | "is_in_objc_category_on_subclass_of", [name], _ -> CPredicates.is_in_objc_category_on_subclass_of lcxt name + | "is_in_objc_category_interface_named", [name], _ -> + CPredicates.is_in_objc_category_interface_named lcxt name + | "is_in_objc_category_implementation_named", [name], _ -> + CPredicates.is_in_objc_category_implementation_named lcxt name | "is_in_objc_category_named", [name], _ -> CPredicates.is_in_objc_category_named lcxt name | "is_ivar_atomic", [], an -> diff --git a/infer/tests/codetoanalyze/objc/linters-for-test-only/al_definitions/linters_example.al b/infer/tests/codetoanalyze/objc/linters-for-test-only/al_definitions/linters_example.al index 2ff16e9b5..c2ac4e12e 100644 --- a/infer/tests/codetoanalyze/objc/linters-for-test-only/al_definitions/linters_example.al +++ b/infer/tests/codetoanalyze/objc/linters-for-test-only/al_definitions/linters_example.al @@ -444,6 +444,61 @@ DEFINE-CHECKER TEST_PARAMETER_SEL_TYPE = { }; +DEFINE-CHECKER TEST_IF_METHOD_IS_IN_INTERFACE_NAMED = { + + SET report_when = + WHEN + is_in_objc_interface_named("MyBaseClass") + HOLDS-IN-NODE ObjCMethodDecl; + + SET message = "Method %name% is in the interface named MyBaseClass."; + +}; + +DEFINE-CHECKER TEST_IF_METHOD_IS_IN_IMPLEMENTATION_NAMED = { + + SET report_when = + WHEN + is_in_objc_implementation_named("MyBaseClass") + HOLDS-IN-NODE ObjCMethodDecl; + + SET message = "Method %name% is in the implementation named MyBaseClass."; + +}; + +DEFINE-CHECKER TEST_IF_METHOD_IS_IN_CLASS_NAMED = { + + SET report_when = + WHEN + is_in_objc_class_named("MyBaseClass") + HOLDS-IN-NODE ObjCMethodDecl; + + SET message = "Method %name% is in the class named MyBaseClass."; + +}; + +DEFINE-CHECKER TEST_IF_METHOD_IS_IN_CATEGORY_INTERFACE_NAMED = { + + SET report_when = + WHEN + is_in_objc_category_interface_named("MyBaseClassCategory") + HOLDS-IN-NODE ObjCMethodDecl; + + SET message = "Method %name% is in the category interface named MyBaseClassCategory."; + +}; + +DEFINE-CHECKER TEST_IF_METHOD_IS_IN_CATEGORY_IMPLEMENTATION_NAMED = { + + SET report_when = + WHEN + is_in_objc_category_implementation_named("MyBaseClassCategory") + HOLDS-IN-NODE ObjCMethodDecl; + + SET message = "Method %name% is in the category implementation named MyBaseClassCategory."; + +}; + DEFINE-CHECKER TEST_IF_METHOD_IS_IN_CATEGORY_NAMED = { SET report_when = @@ -455,6 +510,28 @@ DEFINE-CHECKER TEST_IF_METHOD_IS_IN_CATEGORY_NAMED = { }; +DEFINE-CHECKER TEST_IF_METHOD_IS_IN_CATEGORY_INTERFACE_ON_CLASS_NAMED = { + + SET report_when = + WHEN + is_in_objc_category_interface_on_class_named("MyBaseClass") + HOLDS-IN-NODE ObjCMethodDecl; + + SET message = "Method %name% is in the category interface on a class named MyBaseClass."; + +}; + +DEFINE-CHECKER TEST_IF_METHOD_IS_IN_CATEGORY_IMPLEMENATION_ON_CLASS_NAMED = { + + SET report_when = + WHEN + is_in_objc_category_implementation_on_class_named("MyBaseClass") + HOLDS-IN-NODE ObjCMethodDecl; + + SET message = "Method %name% is in the category implementation on a class named MyBaseClass."; + +}; + DEFINE-CHECKER TEST_IF_METHOD_IS_IN_CATEGORY_ON_CLASS_NAMED = { SET report_when = @@ -466,6 +543,28 @@ DEFINE-CHECKER TEST_IF_METHOD_IS_IN_CATEGORY_ON_CLASS_NAMED = { }; +DEFINE-CHECKER TEST_IF_METHOD_IS_IN_CATEGORY_INTERFACE_ON_SUBCLASS_OF = { + + SET report_when = + WHEN + is_in_objc_category_interface_on_subclass_of("MyBaseClass") + HOLDS-IN-NODE ObjCMethodDecl; + + SET message = "Method %name% is in the category interface on a subclass of MyBaseClass."; + +}; + +DEFINE-CHECKER TEST_IF_METHOD_IS_IN_CATEGORY_IMPLEMENTATION_ON_SUBCLASS_OF = { + + SET report_when = + WHEN + is_in_objc_category_implementation_on_subclass_of("MyBaseClass") + HOLDS-IN-NODE ObjCMethodDecl; + + SET message = "Method %name% is in the category implementation on a subclass of MyBaseClass."; + +}; + DEFINE-CHECKER TEST_IF_METHOD_IS_IN_CATEGORY_ON_SUBCLASS_OF = { SET report_when = diff --git a/infer/tests/codetoanalyze/objc/linters-for-test-only/issues.exp b/infer/tests/codetoanalyze/objc/linters-for-test-only/issues.exp index 201a65326..5c70cbb5a 100644 --- a/infer/tests/codetoanalyze/objc/linters-for-test-only/issues.exp +++ b/infer/tests/codetoanalyze/objc/linters-for-test-only/issues.exp @@ -24,20 +24,39 @@ codetoanalyze/objc/linters-for-test-only/GenericTestClass.m, Linters_dummy_metho 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_INTERFACE_NAMED, WARNING, [] +codetoanalyze/objc/linters-for-test-only/GenericTestClass.m, MyBaseClass_myBaseClassCategoryMethod, 47, TEST_IF_METHOD_IS_IN_CATEGORY_INTERFACE_ON_CLASS_NAMED, 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_IMPLEMENATION_ON_CLASS_NAMED, WARNING, [] +codetoanalyze/objc/linters-for-test-only/GenericTestClass.m, MyBaseClass_myBaseClassCategoryMethod, 53, TEST_IF_METHOD_IS_IN_CATEGORY_IMPLEMENTATION_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_myBaseClassCategoryMethod, 53, TEST_IS_METHOD_EXPOSED, WARNING, [] +codetoanalyze/objc/linters-for-test-only/GenericTestClass.m, MyBaseClass_myBaseClassInterfaceExtensionMethod, 23, TEST_IF_METHOD_IS_IN_CATEGORY_INTERFACE_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_myBaseClassInterfaceExtensionMethod, 31, TEST_IF_METHOD_IS_IN_CLASS_NAMED, WARNING, [] +codetoanalyze/objc/linters-for-test-only/GenericTestClass.m, MyBaseClass_myBaseClassInterfaceExtensionMethod, 31, TEST_IF_METHOD_IS_IN_IMPLEMENTATION_NAMED, WARNING, [] codetoanalyze/objc/linters-for-test-only/GenericTestClass.m, MyBaseClass_myBaseClassInterfaceExtensionMethod, 31, TEST_IS_METHOD_EXPOSED, WARNING, [] +codetoanalyze/objc/linters-for-test-only/GenericTestClass.m, MyBaseClass_myBaseClassMethod, 17, TEST_IF_METHOD_IS_IN_CLASS_NAMED, WARNING, [] +codetoanalyze/objc/linters-for-test-only/GenericTestClass.m, MyBaseClass_myBaseClassMethod, 17, TEST_IF_METHOD_IS_IN_INTERFACE_NAMED, WARNING, [] +codetoanalyze/objc/linters-for-test-only/GenericTestClass.m, MyBaseClass_myBaseClassMethod, 29, TEST_IF_METHOD_IS_IN_CLASS_NAMED, WARNING, [] +codetoanalyze/objc/linters-for-test-only/GenericTestClass.m, MyBaseClass_myBaseClassMethod, 29, TEST_IF_METHOD_IS_IN_IMPLEMENTATION_NAMED, WARNING, [] codetoanalyze/objc/linters-for-test-only/GenericTestClass.m, MyBaseClass_myBaseClassMethod, 29, TEST_IS_METHOD_EXPOSED, WARNING, [] +codetoanalyze/objc/linters-for-test-only/GenericTestClass.m, MyBaseClass_myBaseClassProperty, 37, TEST_IF_METHOD_IS_IN_CLASS_NAMED, WARNING, [] +codetoanalyze/objc/linters-for-test-only/GenericTestClass.m, MyBaseClass_myBaseClassProperty, 37, TEST_IF_METHOD_IS_IN_IMPLEMENTATION_NAMED, WARNING, [] codetoanalyze/objc/linters-for-test-only/GenericTestClass.m, MyBaseClass_myBaseClassProperty, 37, TEST_IS_METHOD_EXPOSED, 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_myBaseClassProtocolOptionalMethod, 35, TEST_IF_METHOD_IS_IN_CLASS_NAMED, WARNING, [] +codetoanalyze/objc/linters-for-test-only/GenericTestClass.m, MyBaseClass_myBaseClassProtocolOptionalMethod, 35, TEST_IF_METHOD_IS_IN_IMPLEMENTATION_NAMED, WARNING, [] codetoanalyze/objc/linters-for-test-only/GenericTestClass.m, MyBaseClass_myBaseClassProtocolOptionalMethod, 35, TEST_IS_METHOD_EXPOSED, WARNING, [] codetoanalyze/objc/linters-for-test-only/GenericTestClass.m, MyBaseClass_myBaseClassProtocolOptionalMethod, 35, TEST_IS_OVERRIDING_METHOD, WARNING, [] +codetoanalyze/objc/linters-for-test-only/GenericTestClass.m, MyBaseClass_myBaseClassProtocolRequiredMethod, 33, TEST_IF_METHOD_IS_IN_CLASS_NAMED, WARNING, [] +codetoanalyze/objc/linters-for-test-only/GenericTestClass.m, MyBaseClass_myBaseClassProtocolRequiredMethod, 33, TEST_IF_METHOD_IS_IN_IMPLEMENTATION_NAMED, WARNING, [] codetoanalyze/objc/linters-for-test-only/GenericTestClass.m, MyBaseClass_myBaseClassProtocolRequiredMethod, 33, TEST_IS_METHOD_EXPOSED, WARNING, [] codetoanalyze/objc/linters-for-test-only/GenericTestClass.m, MyBaseClass_myBaseClassProtocolRequiredMethod, 33, TEST_IS_OVERRIDING_METHOD, WARNING, [] +codetoanalyze/objc/linters-for-test-only/GenericTestClass.m, MyBaseClass_setMyBaseClassProperty, 40, TEST_IF_METHOD_IS_IN_CLASS_NAMED, WARNING, [] +codetoanalyze/objc/linters-for-test-only/GenericTestClass.m, MyBaseClass_setMyBaseClassProperty, 40, TEST_IF_METHOD_IS_IN_IMPLEMENTATION_NAMED, WARNING, [] codetoanalyze/objc/linters-for-test-only/GenericTestClass.m, MyBaseClass_setMyBaseClassProperty, 40, TEST_IS_METHOD_EXPOSED, 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_myBaseClassCategoryMethod, 113, TEST_IS_METHOD_EXPOSED, WARNING, [] @@ -53,7 +72,9 @@ codetoanalyze/objc/linters-for-test-only/GenericTestClass.m, MySubclass_myBaseCl codetoanalyze/objc/linters-for-test-only/GenericTestClass.m, MySubclass_myBaseClassProtocolOptionalMethod, 101, TEST_IS_OVERRIDING_METHOD, WARNING, [] codetoanalyze/objc/linters-for-test-only/GenericTestClass.m, MySubclass_myBaseClassProtocolRequiredMethod, 97, TEST_IS_METHOD_EXPOSED, WARNING, [] codetoanalyze/objc/linters-for-test-only/GenericTestClass.m, MySubclass_myBaseClassProtocolRequiredMethod, 97, TEST_IS_OVERRIDING_METHOD, WARNING, [] +codetoanalyze/objc/linters-for-test-only/GenericTestClass.m, MySubclass_mySubclassCategoryMethod, 136, TEST_IF_METHOD_IS_IN_CATEGORY_INTERFACE_ON_SUBCLASS_OF, 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_IMPLEMENTATION_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_mySubclassCategoryMethod, 142, TEST_IS_METHOD_EXPOSED, WARNING, [] codetoanalyze/objc/linters-for-test-only/GenericTestClass.m, MySubclass_mySubclassMethod, 83, TEST_IF_IS_METHOD_NAMED, WARNING, []