From 2f3b37699681ff0b5d706592cab5a57123d334ca Mon Sep 17 00:00:00 2001 From: Dino Distefano Date: Thu, 23 May 2019 02:58:03 -0700 Subject: [PATCH] Added is_optional_objc_method predicate Reviewed By: martintrojer Differential Revision: D15468063 fbshipit-source-id: d3525082a --- infer/src/clang/cPredicates.ml | 8 ++++++ infer/src/clang/cPredicates.mli | 3 ++ infer/src/clang/cTL.ml | 2 ++ .../al_definitions/linters_example.al | 11 ++++++++ .../objc/linters-for-test-only/issues.exp | 6 ++++ .../objc/linters-for-test-only/optional.m | 28 +++++++++++++++++++ 6 files changed, 58 insertions(+) create mode 100644 infer/tests/codetoanalyze/objc/linters-for-test-only/optional.m diff --git a/infer/src/clang/cPredicates.ml b/infer/src/clang/cPredicates.ml index 34986a4ec..a88ad7b0e 100644 --- a/infer/src/clang/cPredicates.ml +++ b/infer/src/clang/cPredicates.ml @@ -858,6 +858,14 @@ let cxx_construct_expr_has_name an name = false +let is_optional_objc_method an = + match an with + | Ctl_parser_types.Decl (Clang_ast_t.ObjCMethodDecl (_, _, omdi)) -> + omdi.omdi_is_optional + | _ -> + false + + let is_in_block context = match context.CLintersContext.current_method with Some (BlockDecl _) -> true | _ -> false diff --git a/infer/src/clang/cPredicates.mli b/infer/src/clang/cPredicates.mli index e8f29953a..3bbd7bf0b 100644 --- a/infer/src/clang/cPredicates.mli +++ b/infer/src/clang/cPredicates.mli @@ -90,6 +90,9 @@ val is_method_property_accessor_of_ivar : val is_in_block : CLintersContext.context -> bool (** true if the current node is in the context of an objc block *) +val is_optional_objc_method : Ctl_parser_types.ast_node -> bool +(** true if the current node is an objc method declaration which is declared with @optional *) + val is_in_cxx_constructor : CLintersContext.context -> ALVar.alexp -> bool (** 'is_in_cxx_constructor context name' is true if the curent node is within a CXX constructor whose name contains 'name' *) diff --git a/infer/src/clang/cTL.ml b/infer/src/clang/cTL.ml index ac5026dd9..5da9a7f44 100644 --- a/infer/src/clang/cTL.ml +++ b/infer/src/clang/cTL.ml @@ -1049,6 +1049,8 @@ let rec eval_Atomic pred_name_ args an lcxt = CPredicates.adhere_to_protocol an | "is_in_block", [], _ -> CPredicates.is_in_block lcxt + | "is_optional_objc_method", [], an -> + CPredicates.is_optional_objc_method an | "is_in_cxx_constructor", [name], _ -> CPredicates.is_in_cxx_constructor lcxt name | "is_in_cxx_destructor", [name], _ -> 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 268b0253f..c5931cbf0 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 @@ -866,3 +866,14 @@ DEFINE-CHECKER TEST_UNAVAILABLE_ATTR = { SET message = "This node has unavailable attribute"; }; + +DEFINE-CHECKER TEST_IS_OPTIONAL_METHOD = { + + SET report_when = + WHEN + is_optional_objc_method + HOLDS-IN-NODE ObjCMethodDecl; + + SET message = "This is an optional method"; + +}; 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 41b50577d..4e760e4eb 100644 --- a/infer/tests/codetoanalyze/objc/linters-for-test-only/issues.exp +++ b/infer/tests/codetoanalyze/objc/linters-for-test-only/issues.exp @@ -113,6 +113,7 @@ codetoanalyze/objc/linters-for-test-only/GenericTestClass.m, MyBaseClass::setMyB codetoanalyze/objc/linters-for-test-only/GenericTestClass.m, MyBaseClass::setMyBaseClassProperty, 56, TEST_IS_METHOD_EXPOSED, no_bucket, WARNING, [] codetoanalyze/objc/linters-for-test-only/GenericTestClass.m, MyBaseClass::setMyBaseClassProperty, 56, TEST_PARAM_TYPE_CHECK2, no_bucket, WARNING, [] codetoanalyze/objc/linters-for-test-only/GenericTestClass.m, MyBaseClassProtocol::myBaseClassProtocolOptionalMethod, 16, TEST_IF_METHOD_IS_IN_PROTOCOL_NAMED, no_bucket, WARNING, [] +codetoanalyze/objc/linters-for-test-only/GenericTestClass.m, MyBaseClassProtocol::myBaseClassProtocolOptionalMethod, 16, TEST_IS_OPTIONAL_METHOD, no_bucket, WARNING, [] codetoanalyze/objc/linters-for-test-only/GenericTestClass.m, MyBaseClassProtocol::myBaseClassProtocolRequiredMethod, 14, TEST_IF_METHOD_IS_IN_PROTOCOL_NAMED, no_bucket, WARNING, [] codetoanalyze/objc/linters-for-test-only/GenericTestClass.m, MySubclass::myBaseClassCategoryMethod, 148, TEST_IS_METHOD_EXPOSED, no_bucket, WARNING, [] codetoanalyze/objc/linters-for-test-only/GenericTestClass.m, MySubclass::myBaseClassCategoryMethod, 148, TEST_IS_OVERRIDING_METHOD, no_bucket, WARNING, [] @@ -196,6 +197,9 @@ codetoanalyze/objc/linters-for-test-only/GenericTestClass.m, MySubclass::setMyBa codetoanalyze/objc/linters-for-test-only/GenericTestClass.m, MySubclass::setMyBaseClassProperty, 144, TEST_PARAM_TYPE_CHECK2, no_bucket, WARNING, [] codetoanalyze/objc/linters-for-test-only/GenericTestClass.m, MySubclass::setMyBaseClassProperty, 145, TEST_IS_RECEIVER_CLASS_NAMED, no_bucket, WARNING, [] codetoanalyze/objc/linters-for-test-only/GenericTestClass.m, MySubclass::setMyBaseClassProperty, 145, TEST_IS_RECEIVER_SUPER, no_bucket, WARNING, [] +codetoanalyze/objc/linters-for-test-only/GenericTestClass.m, MySubclassProtocol2::mySubclassProtocol2OptionalMethod, 102, TEST_IS_OPTIONAL_METHOD, no_bucket, WARNING, [] +codetoanalyze/objc/linters-for-test-only/GenericTestClass.m, MySubclassProtocol::mySubclassProtocolOptionalMethod, 95, TEST_IS_OPTIONAL_METHOD, no_bucket, WARNING, [] +codetoanalyze/objc/linters-for-test-only/GenericTestClass.m, MySubclassSubprotocol::mySubclassSubprotocol2OptionalMethod, 109, TEST_IS_OPTIONAL_METHOD, no_bucket, WARNING, [] codetoanalyze/objc/linters-for-test-only/InContextOfMethodsTest.m, InContextOfMethodsTest::method, 14, TEST_IN_METHOD_CONTEXT, no_bucket, WARNING, [] codetoanalyze/objc/linters-for-test-only/InContextOfMethodsTest.m, InContextOfMethodsTest::method, 14, TEST_VAR_TYPE_CHECK, no_bucket, WARNING, [] codetoanalyze/objc/linters-for-test-only/InContextOfMethodsTest.m, function, 25, TEST_IN_FUNCTION_CONTEXT, no_bucket, WARNING, [] @@ -244,6 +248,8 @@ codetoanalyze/objc/linters-for-test-only/namespace.mm, Linters_dummy_method, 15, codetoanalyze/objc/linters-for-test-only/ns_assume_nonnull.m, Blah::someMethod, 14, TEST_INSTANCE_TYPE, no_bucket, WARNING, [] codetoanalyze/objc/linters-for-test-only/ns_assume_nonnull.m, Blah::someMethod, 20, TEST_INSTANCE_TYPE, no_bucket, WARNING, [] codetoanalyze/objc/linters-for-test-only/ns_assume_nonnull.m, Blah::someMethod, 20, TEST_IS_METHOD_EXPOSED, no_bucket, WARNING, [] +codetoanalyze/objc/linters-for-test-only/optional.m, BarDelegate::optionalFunction, 16, TEST_IS_OPTIONAL_METHOD, no_bucket, WARNING, [] +codetoanalyze/objc/linters-for-test-only/optional.m, Linters_dummy_method, 20, STRONG_DELEGATE_WARNING, no_bucket, WARNING, [] codetoanalyze/objc/linters-for-test-only/protocols.m, Foo::newWithA, 22, TEST_INSTANCE_TYPE, no_bucket, WARNING, [] codetoanalyze/objc/linters-for-test-only/protocols.m, Foo::newWithA, 22, TEST_PROTOCOL_TYPE_INHERITANCE, no_bucket, WARNING, [] codetoanalyze/objc/linters-for-test-only/protocols.m, Foo::newWithB, 23, TEST_INSTANCE_TYPE, no_bucket, WARNING, [] diff --git a/infer/tests/codetoanalyze/objc/linters-for-test-only/optional.m b/infer/tests/codetoanalyze/objc/linters-for-test-only/optional.m new file mode 100644 index 000000000..70413f062 --- /dev/null +++ b/infer/tests/codetoanalyze/objc/linters-for-test-only/optional.m @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2019-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. + */ + +@interface NSObject +@end + +@protocol NSObject +@end + +@protocol BarDelegate +@optional +- (void)optionalFunction; +@end + +@interface Bar : NSObject +@property(nonatomic) id delegate; +@end + +@implementation Bar +- (void)unsafeAction { + [self.delegate optionalFunction]; +} + +@end