diff --git a/infer/src/clang/cPredicates.ml b/infer/src/clang/cPredicates.ml index 5f6cb8151..13b698ce5 100644 --- a/infer/src/clang/cPredicates.ml +++ b/infer/src/clang/cPredicates.ml @@ -593,13 +593,16 @@ let has_init_list_const_expr an = false -let decl_ref_name ?kind name st = +let decl_ref_name qualified ?kind name st = match st with | Clang_ast_t.DeclRefExpr (_, _, _, drti) -> ( match drti.drti_decl_ref with | Some dr -> ( let ndi, _, _ = CAst_utils.get_info_from_decl_ref dr in - let has_right_name = ALVar.compare_str_with_alexp ndi.ni_name name in + let qname = + if qualified then String.concat ~sep:"::" (List.rev ndi.ni_qual_name) else ndi.ni_name + in + let has_right_name = ALVar.compare_str_with_alexp qname name in match kind with | Some decl_kind -> has_right_name && PolyVariantEqual.( = ) dr.Clang_ast_t.dr_kind decl_kind @@ -612,13 +615,21 @@ let decl_ref_name ?kind name st = let declaration_ref_name ?kind an name = - match an with Ctl_parser_types.Stmt st -> decl_ref_name ?kind name st | _ -> false + match an with Ctl_parser_types.Stmt st -> decl_ref_name false ?kind name st | _ -> false let call_function an name = match an with | Ctl_parser_types.Stmt st -> - CAst_utils.exists_eventually_st (decl_ref_name ~kind:`Function) name st + CAst_utils.exists_eventually_st (decl_ref_name false ~kind:`Function) name st + | _ -> + false + + +let call_qualified_function an name = + match an with + | Ctl_parser_types.Stmt st -> + CAst_utils.exists_eventually_st (decl_ref_name true ~kind:`Function) name st | _ -> false @@ -626,7 +637,7 @@ let call_function an name = let is_enum_constant an name = match an with | Ctl_parser_types.Stmt st -> - decl_ref_name ~kind:`EnumConstant name st + decl_ref_name false ~kind:`EnumConstant name st | _ -> false @@ -984,7 +995,7 @@ let is_receiver_self an = match an with | Ctl_parser_types.Stmt (Clang_ast_t.ObjCMessageExpr (_, fst_param :: _, _, _)) -> CAst_utils.exists_eventually_st - (decl_ref_name ~kind:`ImplicitParam) + (decl_ref_name false ~kind:`ImplicitParam) (ALVar.Const CFrontend_config.self) fst_param | _ -> false diff --git a/infer/src/clang/cPredicates.mli b/infer/src/clang/cPredicates.mli index c5b64a991..c4fc24e09 100644 --- a/infer/src/clang/cPredicates.mli +++ b/infer/src/clang/cPredicates.mli @@ -54,6 +54,9 @@ val has_init_list_const_expr : Ctl_parser_types.ast_node -> bool val call_function : Ctl_parser_types.ast_node -> ALVar.alexp -> bool (** 'call_function an name' is true iff an is a call to a function whose name contains 'name' *) +val call_qualified_function : Ctl_parser_types.ast_node -> ALVar.alexp -> bool +(** 'call_function an name' is true iff an is a call to a function whose fully qualified name contains 'name' *) + val is_strong_property : Ctl_parser_types.ast_node -> bool (** 'is_strong_property an' is true iff an denotes a objc property declaration with 'strong' attribute *) diff --git a/infer/src/clang/cTL.ml b/infer/src/clang/cTL.ml index ec9335727..cc59c0109 100644 --- a/infer/src/clang/cTL.ml +++ b/infer/src/clang/cTL.ml @@ -961,6 +961,8 @@ let rec eval_Atomic pred_name_ args an lcxt = CPredicates.call_class_method an m | "call_function", [m], an -> CPredicates.call_function an m + | "call_qualified_function", [m], an -> + CPredicates.call_qualified_function an m | "call_instance_method", [m], an -> CPredicates.call_instance_method an m | "call_method", [m], an -> diff --git a/infer/tests/codetoanalyze/cpp/linters/Makefile b/infer/tests/codetoanalyze/cpp/linters/Makefile index 19786a812..e1aa932e4 100644 --- a/infer/tests/codetoanalyze/cpp/linters/Makefile +++ b/infer/tests/codetoanalyze/cpp/linters/Makefile @@ -6,7 +6,7 @@ TESTS_DIR = ../../.. CLANG_OPTIONS = -std=c++11 -c -INFER_OPTIONS = --no-capture --linters-only --linters-def-file extracopy.al --no-filtering --debug-exceptions --project-root $(TESTS_DIR) \ +INFER_OPTIONS = --no-capture --linters-only --linters-def-file extracopy.al --linters-def-file call_function.al --no-filtering --debug-exceptions --project-root $(TESTS_DIR) \ --enable-issue-type GLOBAL_VARIABLE_INITIALIZED_WITH_FUNCTION_OR_METHOD_CALL INFERPRINT_OPTIONS = --issues-tests diff --git a/infer/tests/codetoanalyze/cpp/linters/call_function.al b/infer/tests/codetoanalyze/cpp/linters/call_function.al new file mode 100644 index 000000000..1a884db42 --- /dev/null +++ b/infer/tests/codetoanalyze/cpp/linters/call_function.al @@ -0,0 +1,15 @@ +// 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. +DEFINE-CHECKER CALL_FUNCTION = { + SET report_when = + WHEN call_qualified_function("anamespace::the_function") OR call_function("the_other_function") + HOLDS-IN-NODE CallExpr; + + SET message = "the_function and the_other_function are not to be called"; + SET suggestion = "Call something else."; + SET severity = "WARNING"; + SET mode = "ON"; + +}; diff --git a/infer/tests/codetoanalyze/cpp/linters/call_function.cpp b/infer/tests/codetoanalyze/cpp/linters/call_function.cpp new file mode 100644 index 000000000..04edef8cb --- /dev/null +++ b/infer/tests/codetoanalyze/cpp/linters/call_function.cpp @@ -0,0 +1,35 @@ +/* + * 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. + */ +namespace anamespace { +void the_function() {} + +void the_other_function() {} +} // namespace anamespace + +namespace anothernamespace { +void the_function() {} + +void the_other_function() {} +} // namespace anothernamespace + +int main() { + anamespace::the_function(); + anothernamespace::the_function(); + anamespace::the_other_function(); + anothernamespace::the_other_function(); + { + using namespace anamespace; + the_function(); + the_other_function(); + } + { + using namespace anothernamespace; + the_function(); + the_other_function(); + } + return 0; +} diff --git a/infer/tests/codetoanalyze/cpp/linters/issues.exp b/infer/tests/codetoanalyze/cpp/linters/issues.exp index 4c07cc210..b7ba4d903 100644 --- a/infer/tests/codetoanalyze/cpp/linters/issues.exp +++ b/infer/tests/codetoanalyze/cpp/linters/issues.exp @@ -1,3 +1,9 @@ +codetoanalyze/cpp/linters/call_function.cpp, main, 18, CALL_FUNCTION, no_bucket, WARNING, [] +codetoanalyze/cpp/linters/call_function.cpp, main, 20, CALL_FUNCTION, no_bucket, WARNING, [] +codetoanalyze/cpp/linters/call_function.cpp, main, 21, CALL_FUNCTION, no_bucket, WARNING, [] +codetoanalyze/cpp/linters/call_function.cpp, main, 24, CALL_FUNCTION, no_bucket, WARNING, [] +codetoanalyze/cpp/linters/call_function.cpp, main, 25, CALL_FUNCTION, no_bucket, WARNING, [] +codetoanalyze/cpp/linters/call_function.cpp, main, 30, CALL_FUNCTION, no_bucket, WARNING, [] codetoanalyze/cpp/linters/cxxconst.cpp, test, 28, CONSTANT_EXPR, no_bucket, WARNING, [] codetoanalyze/cpp/linters/cxxconst.cpp, test, 31, CONSTANT_EXPR, no_bucket, WARNING, [] codetoanalyze/cpp/linters/cxxconst.cpp, test, 33, CONSTANT_EXPR, no_bucket, WARNING, []