From 5a531ac755627ec408a7a97d934a67a7bb29c236 Mon Sep 17 00:00:00 2001 From: David Lively Date: Wed, 12 Dec 2018 07:16:41 -0800 Subject: [PATCH] Make is_cxx_method_overriding predicate take regex matching class/name Reviewed By: jvillard Differential Revision: D13419974 fbshipit-source-id: c63ad011e --- infer/src/clang/cPredicates.ml | 27 ++++++++++++-- infer/src/clang/cPredicates.mli | 7 ++-- infer/src/clang/cTL.ml | 4 ++- .../cpp/linters-for-test-only/issues.exp | 8 +++++ .../linters-for-test-only/linters_example.al | 6 ++++ .../linters-for-test-only/test_overrides.cpp | 35 +++++++++++++++++++ 6 files changed, 80 insertions(+), 7 deletions(-) diff --git a/infer/src/clang/cPredicates.ml b/infer/src/clang/cPredicates.ml index 096e1861f..cc6f2d6da 100644 --- a/infer/src/clang/cPredicates.ml +++ b/infer/src/clang/cPredicates.ml @@ -1412,10 +1412,31 @@ let is_cxx_copy_constructor an = false -let is_cxx_method_overriding an = +let is_cxx_method_overriding an qual_name_re = + let rec overrides_named (decl_refs : Clang_ast_t.decl_ref list) (qnre : ALVar.alexp) = + List.exists + ~f:(fun (decl_ref : Clang_ast_t.decl_ref) -> + match CAst_utils.get_decl decl_ref.dr_decl_pointer with + | None -> + false + | Some decl -> ( + match decl with + | Clang_ast_t.CXXMethodDecl (_, ndi, _, _, mdi) -> + ALVar.compare_str_with_alexp + (String.concat ~sep:"::" (List.rev ndi.ni_qual_name)) + qnre + || overrides_named mdi.xmdi_overriden_methods qnre + | _ -> + false ) ) + decl_refs + in match an with - | Ctl_parser_types.Decl (Clang_ast_t.CXXMethodDecl (_, _, _, _, mdi)) -> - not (List.is_empty mdi.xmdi_overriden_methods) + | Ctl_parser_types.Decl (Clang_ast_t.CXXMethodDecl (_, _, _, _, mdi)) -> ( + match qual_name_re with + | None -> + not (List.is_empty mdi.xmdi_overriden_methods) + | Some qnre -> + overrides_named mdi.xmdi_overriden_methods qnre ) | _ -> false diff --git a/infer/src/clang/cPredicates.mli b/infer/src/clang/cPredicates.mli index e99b94eec..45bd99d85 100644 --- a/infer/src/clang/cPredicates.mli +++ b/infer/src/clang/cPredicates.mli @@ -487,10 +487,11 @@ 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 +val is_cxx_method_overriding : Ctl_parser_types.ast_node -> ALVar.alexp option -> bool (** - * Checks if the current node is a CXXMethodDecl node and is overriding a - * method in a superclass. + * True iff the current node is a CXXMethodDecl node and is overriding a + * method whose fully-qualified name (with class and namespace) matches + * the given regexp (if given, otherwise any overriding method satisfies). *) val is_init_expr_cxx11_constant : Ctl_parser_types.ast_node -> bool diff --git a/infer/src/clang/cTL.ml b/infer/src/clang/cTL.ml index 1591b21ea..4227683c1 100644 --- a/infer/src/clang/cTL.ml +++ b/infer/src/clang/cTL.ml @@ -1154,7 +1154,9 @@ let rec eval_Atomic pred_name_ args an lcxt = | "is_cxx_copy_constructor", [], an -> CPredicates.is_cxx_copy_constructor an | "is_cxx_method_overriding", [], an -> - CPredicates.is_cxx_method_overriding an + CPredicates.is_cxx_method_overriding an None + | "is_cxx_method_overriding", [qual_name_re], an -> + CPredicates.is_cxx_method_overriding an (Some qual_name_re) | "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 b12899728..a6d7c141c 100644 --- a/infer/tests/codetoanalyze/cpp/linters-for-test-only/issues.exp +++ b/infer/tests/codetoanalyze/cpp/linters-for-test-only/issues.exp @@ -2,3 +2,11 @@ codetoanalyze/cpp/linters-for-test-only/test_constructor.cpp, f, 12, FIND_STATIC 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, [] +codetoanalyze/cpp/linters-for-test-only/test_overrides.cpp, Foo::Bar::SvIf_async_tm_poke, 36, FIND_CXX_METHOD_OVERRIDES, no_bucket, WARNING, [] +codetoanalyze/cpp/linters-for-test-only/test_overrides.cpp, Foo::Bar::SvIf_future_poke, 37, FIND_CXX_METHOD_OVERRIDES, no_bucket, WARNING, [] +codetoanalyze/cpp/linters-for-test-only/test_overrides.cpp, Foo::Bar::SvIf_semifuture_poke, 38, FIND_CXX_METHOD_OVERRIDES, no_bucket, WARNING, [] +codetoanalyze/cpp/linters-for-test-only/test_overrides.cpp, FooBarService_async_tm_poke, 50, FIND_CXX_METHOD_OVERRIDES, no_bucket, WARNING, [] +codetoanalyze/cpp/linters-for-test-only/test_overrides.cpp, FooBarService_future_poke, 51, FIND_CXX_METHOD_OVERRIDES, no_bucket, WARNING, [] +codetoanalyze/cpp/linters-for-test-only/test_overrides.cpp, FooBarService_future_poke, 51, FIND_CXX_METHOD_OVERRIDES_MATCHING, no_bucket, WARNING, [] +codetoanalyze/cpp/linters-for-test-only/test_overrides.cpp, FooBarService_poke, 49, FIND_CXX_METHOD_OVERRIDES, no_bucket, WARNING, [] +codetoanalyze/cpp/linters-for-test-only/test_overrides.cpp, FooBarService_semifuture_poke, 52, 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 7175a9bce..9b0ade99a 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 @@ -31,3 +31,9 @@ DEFINE-CHECKER FIND_CXX_METHOD_OVERRIDES = { SET report_when = is_cxx_method_overriding; SET message = "%decl_name% overrides"; }; + +DEFINE-CHECKER FIND_CXX_METHOD_OVERRIDES_MATCHING = { + SET report_when = WHEN is_cxx_method_overriding(REGEXP("oo::.*::SvIf::future")) + HOLDS-IN-NODE CXXMethodDecl; + SET message = "%decl_name% overriding matching method"; +}; 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 index 0a7cc51cf..1fa7d263c 100644 --- a/infer/tests/codetoanalyze/cpp/linters-for-test-only/test_overrides.cpp +++ b/infer/tests/codetoanalyze/cpp/linters-for-test-only/test_overrides.cpp @@ -16,3 +16,38 @@ struct B : public A { void bar() /* override */; void bazoo(); }; + +namespace Foo { + +class SvIf { + public: + virtual ~SvIf() {} + virtual void async_tm_poke() {} + virtual void future_poke() {} + virtual void semifuture_poke() {} +}; + +namespace Bar { + +class SvIf : public Foo::SvIf { + public: + virtual ~SvIf() {} + virtual void poke() {} + virtual void async_tm_poke() override {} + virtual void future_poke() override {} + virtual void semifuture_poke() override {} +}; + +} // namespace Bar +} // namespace Foo + +class ServiceBase {}; + +class FooBarService : public ServiceBase, public Foo::Bar::SvIf { + public: + explicit FooBarService() {} + virtual void poke() override {} + virtual void async_tm_poke() override {} + virtual void future_poke() override {} + virtual void semifuture_poke() override {} +};