diff --git a/infer/src/clang/cPredicates.ml b/infer/src/clang/cPredicates.ml index 618c7b396..096e1861f 100644 --- a/infer/src/clang/cPredicates.ml +++ b/infer/src/clang/cPredicates.ml @@ -1412,6 +1412,14 @@ let is_cxx_copy_constructor an = false +let is_cxx_method_overriding an = + match an with + | Ctl_parser_types.Decl (Clang_ast_t.CXXMethodDecl (_, _, _, _, mdi)) -> + not (List.is_empty mdi.xmdi_overriden_methods) + | _ -> + false + + let is_init_expr_cxx11_constant an = let open Clang_ast_t in match an with diff --git a/infer/src/clang/cPredicates.mli b/infer/src/clang/cPredicates.mli index 4e60ddde9..e99b94eec 100644 --- a/infer/src/clang/cPredicates.mli +++ b/infer/src/clang/cPredicates.mli @@ -228,7 +228,7 @@ val is_objc_constructor : CLintersContext.context -> bool val objc_class_has_only_one_constructor_method_named : Ctl_parser_types.ast_node -> ALVar.alexp -> bool -(** true if an ObjC class has only one class method and is a constructor +(** true if an ObjC class has only one class method and is a constructor whose name matches the provided REGEXP *) val is_objc_dealloc : CLintersContext.context -> bool @@ -487,6 +487,12 @@ val is_method_called_by_superclass : Ctl_parser_types.ast_node -> bool val is_cxx_copy_constructor : Ctl_parser_types.ast_node -> bool (** true if the current node is a C++ copy constructor *) +val is_cxx_method_overriding : Ctl_parser_types.ast_node -> bool +(** + * Checks if the current node is a CXXMethodDecl node and is overriding a + * method in a superclass. + *) + val is_init_expr_cxx11_constant : Ctl_parser_types.ast_node -> bool (** true if the current node is classified as C++11 constant expression by the AST. It works only for VarDecl init expr *) diff --git a/infer/src/clang/cTL.ml b/infer/src/clang/cTL.ml index d2dcb465c..1591b21ea 100644 --- a/infer/src/clang/cTL.ml +++ b/infer/src/clang/cTL.ml @@ -1153,6 +1153,8 @@ let rec eval_Atomic pred_name_ args an lcxt = CPredicates.is_method_called_by_superclass an | "is_cxx_copy_constructor", [], an -> CPredicates.is_cxx_copy_constructor an + | "is_cxx_method_overriding", [], an -> + CPredicates.is_cxx_method_overriding an | "is_init_expr_cxx11_constant", [], an -> CPredicates.is_init_expr_cxx11_constant an | "cxx_construct_expr_has_no_parameters", [], an -> diff --git a/infer/tests/codetoanalyze/cpp/linters-for-test-only/issues.exp b/infer/tests/codetoanalyze/cpp/linters-for-test-only/issues.exp index 1a5e20035..b12899728 100644 --- a/infer/tests/codetoanalyze/cpp/linters-for-test-only/issues.exp +++ b/infer/tests/codetoanalyze/cpp/linters-for-test-only/issues.exp @@ -1,2 +1,4 @@ codetoanalyze/cpp/linters-for-test-only/test_constructor.cpp, f, 12, FIND_STATIC_LOCAL_VAR, no_bucket, WARNING, [] codetoanalyze/cpp/linters-for-test-only/test_constructor.cpp, g, 17, FIND_CXX_COPY_CONSTRUCTOR, no_bucket, WARNING, [] +codetoanalyze/cpp/linters-for-test-only/test_overrides.cpp, B_bar, 16, FIND_CXX_METHOD_OVERRIDES, no_bucket, WARNING, [] +codetoanalyze/cpp/linters-for-test-only/test_overrides.cpp, B_foo, 14, FIND_CXX_METHOD_OVERRIDES, no_bucket, WARNING, [] diff --git a/infer/tests/codetoanalyze/cpp/linters-for-test-only/linters_example.al b/infer/tests/codetoanalyze/cpp/linters-for-test-only/linters_example.al index 8b8abf920..7175a9bce 100644 --- a/infer/tests/codetoanalyze/cpp/linters-for-test-only/linters_example.al +++ b/infer/tests/codetoanalyze/cpp/linters-for-test-only/linters_example.al @@ -26,4 +26,8 @@ SET report_when = SET message = "Found static local var"; }; - + +DEFINE-CHECKER FIND_CXX_METHOD_OVERRIDES = { + SET report_when = is_cxx_method_overriding; + SET message = "%decl_name% overrides"; +}; diff --git a/infer/tests/codetoanalyze/cpp/linters-for-test-only/test_overrides.cpp b/infer/tests/codetoanalyze/cpp/linters-for-test-only/test_overrides.cpp new file mode 100644 index 000000000..0a7cc51cf --- /dev/null +++ b/infer/tests/codetoanalyze/cpp/linters-for-test-only/test_overrides.cpp @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2018-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. + */ +struct A { + virtual void foo(); + virtual void bar(); + void bazoo(); +}; + +struct B : public A { + void foo() override; + void bar(int i); + void bar() /* override */; + void bazoo(); +};