diff --git a/infer/src/clang/cPredicates.ml b/infer/src/clang/cPredicates.ml index 9b38800a8..46df3e56a 100644 --- a/infer/src/clang/cPredicates.ml +++ b/infer/src/clang/cPredicates.ml @@ -330,34 +330,64 @@ let is_method_property_accessor_of_ivar an context = | _ -> 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.is_objc_constructor (get_method_name_from_context context) + +let is_objc_dealloc context = Typ.Procname.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_method context name = match context.CLintersContext.current_method with - | Some method_decl - -> let method_name = - match Clang_ast_proj.get_named_decl_tuple method_decl with - | Some (_, mnd) - -> mnd.Clang_ast_t.ni_name - | _ - -> "" - in - Typ.Procname.is_objc_constructor method_name + | Some ObjCMethodDecl _ + -> is_in_method context name | _ -> false -let is_objc_dealloc context = +let is_in_function context name = match context.CLintersContext.current_method with - | Some method_decl - -> let method_name = - match Clang_ast_proj.get_named_decl_tuple method_decl with - | Some (_, mnd) - -> mnd.Clang_ast_t.ni_name - | _ - -> "" - in - Typ.Procname.is_objc_dealloc method_name + | 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 captures_cxx_references an = List.length (captured_variables_cxx_ref an) > 0 let is_binop_with_kind an alexp_kind = diff --git a/infer/src/clang/cPredicates.mli b/infer/src/clang/cPredicates.mli index bf66a378d..45b4d2a4d 100644 --- a/infer/src/clang/cPredicates.mli +++ b/infer/src/clang/cPredicates.mli @@ -48,6 +48,18 @@ val is_ivar_atomic : Ctl_parser_types.ast_node -> bool val is_method_property_accessor_of_ivar : Ctl_parser_types.ast_node -> CLintersContext.context -> bool +val is_in_block : CLintersContext.context -> bool + +val is_in_cxx_constructor : CLintersContext.context -> ALVar.alexp -> bool + +val is_in_cxx_destructor : CLintersContext.context -> ALVar.alexp -> bool + +val is_in_cxx_method : CLintersContext.context -> ALVar.alexp -> bool + +val is_in_function : CLintersContext.context -> ALVar.alexp -> bool + +val is_in_objc_method : CLintersContext.context -> ALVar.alexp -> bool + val is_objc_constructor : CLintersContext.context -> bool val is_objc_dealloc : CLintersContext.context -> bool diff --git a/infer/src/clang/cTL.ml b/infer/src/clang/cTL.ml index 48b263806..05d12b69d 100644 --- a/infer/src/clang/cTL.ml +++ b/infer/src/clang/cTL.ml @@ -764,6 +764,18 @@ let rec eval_Atomic _pred_name args an lcxt = -> CPredicates.is_enum_constant an cname | "is_global_var", [], an -> CPredicates.is_syntactically_global_var an + | "is_in_block", [], _ + -> CPredicates.is_in_block lcxt + | "is_in_cxx_constructor", [name], _ + -> CPredicates.is_in_cxx_constructor lcxt name + | "is_in_cxx_destructor", [name], _ + -> CPredicates.is_in_cxx_destructor lcxt name + | "is_in_cxx_method", [name], _ + -> CPredicates.is_in_cxx_method lcxt name + | "is_in_function", [name], _ + -> CPredicates.is_in_function lcxt name + | "is_in_objc_method", [name], _ + -> CPredicates.is_in_objc_method lcxt name | "is_ivar_atomic", [], an -> CPredicates.is_ivar_atomic an | "is_method_property_accessor_of_ivar", [], an diff --git a/infer/tests/codetoanalyze/objc/linters-for-test-only/InContextOfMethodsTest.m b/infer/tests/codetoanalyze/objc/linters-for-test-only/InContextOfMethodsTest.m new file mode 100644 index 000000000..231258278 --- /dev/null +++ b/infer/tests/codetoanalyze/objc/linters-for-test-only/InContextOfMethodsTest.m @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2017 - present Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ +@interface InContextOfMethodsTest + +@end + +@implementation InContextOfMethodsTest + +- (void)method { + int x = 0; +} + +- (void)method_with_block { + ^{ + int x = 0; + }(); +} + +@end + +void function() { int x = 0; } 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 bb97b103b..4a28438d3 100644 --- a/infer/tests/codetoanalyze/objc/linters-for-test-only/issues.exp +++ b/infer/tests/codetoanalyze/objc/linters-for-test-only/issues.exp @@ -1,3 +1,11 @@ +codetoanalyze/objc/linters-for-test-only/InContextOfMethodsTest.m, InContextOfMethodsTest_method, 15, TEST_BUILTIN_TYPE, [] +codetoanalyze/objc/linters-for-test-only/InContextOfMethodsTest.m, InContextOfMethodsTest_method, 16, TEST_IN_METHOD_CONTEXT, [] +codetoanalyze/objc/linters-for-test-only/InContextOfMethodsTest.m, InContextOfMethodsTest_method, 16, TEST_VAR_TYPE_CHECK, [] +codetoanalyze/objc/linters-for-test-only/InContextOfMethodsTest.m, InContextOfMethodsTest_method_with_block, 19, TEST_BUILTIN_TYPE, [] +codetoanalyze/objc/linters-for-test-only/InContextOfMethodsTest.m, __objc_anonymous_block_______1, 21, TEST_VAR_TYPE_CHECK, [] +codetoanalyze/objc/linters-for-test-only/InContextOfMethodsTest.m, __objc_anonymous_block_______2, 21, TEST_IN_BLOCK_CONTEXT, [] +codetoanalyze/objc/linters-for-test-only/InContextOfMethodsTest.m, function, 27, TEST_IN_FUNCTION_CONTEXT, [] +codetoanalyze/objc/linters-for-test-only/InContextOfMethodsTest.m, function, 27, TEST_VAR_TYPE_CHECK, [] codetoanalyze/objc/linters-for-test-only/PrivateAPIChecker.m, TestView_methodd, 16, TEST_BUILTIN_TYPE, [] codetoanalyze/objc/linters-for-test-only/PrivateAPIChecker.m, TestView_methoddd, 20, TEST_BUILTIN_TYPE, [] codetoanalyze/objc/linters-for-test-only/PrivateAPIChecker.m, TestView_methoddd, 21, TEST_SELECTOR, [] diff --git a/infer/tests/codetoanalyze/objc/linters-for-test-only/linters_example.al b/infer/tests/codetoanalyze/objc/linters-for-test-only/linters_example.al index 910a1ccb4..da9ac92b3 100644 --- a/infer/tests/codetoanalyze/objc/linters-for-test-only/linters_example.al +++ b/infer/tests/codetoanalyze/objc/linters-for-test-only/linters_example.al @@ -376,3 +376,24 @@ DEFINE-CHECKER ENUM_CONSTANTS = { HOLDS-IN-NODE CallExpr; SET message = "%name% has default visibility and used attribute"; }; + + DEFINE-CHECKER TEST_IN_METHOD_CONTEXT = { + SET report_when = + WHEN declaration_has_name("x") AND is_in_objc_method("method") + HOLDS-IN-NODE VarDecl; + SET message = "var %name% declared in ObjC method"; + }; + + DEFINE-CHECKER TEST_IN_BLOCK_CONTEXT = { + SET report_when = + WHEN declaration_has_name("x") AND is_in_block() + HOLDS-IN-NODE VarDecl; + SET message = "var %name% declared in block"; + }; + + DEFINE-CHECKER TEST_IN_FUNCTION_CONTEXT = { + SET report_when = + WHEN declaration_has_name("x") AND is_in_function(REGEXP("funct.*")) + HOLDS-IN-NODE VarDecl; + SET message = "var %name% declared in function"; + };