From c5890238f002f77ced93ccf44a17233125c8cee8 Mon Sep 17 00:00:00 2001 From: David Lively Date: Tue, 5 Feb 2019 10:50:42 -0800 Subject: [PATCH] [Config] support arbitrary named symbol lists Reviewed By: jvillard Differential Revision: D13903005 fbshipit-source-id: b1cf9b4e5 --- infer/man/man1/infer-analyze.txt | 3 ++ infer/man/man1/infer-full.txt | 4 ++ infer/man/man1/infer.txt | 4 ++ infer/src/base/Config.ml | 46 +++++++++++++++++++ infer/src/base/Config.mli | 5 +- infer/src/clang/cPredicates.ml | 8 ++++ infer/src/clang/cPredicates.mli | 5 ++ infer/src/clang/cTL.ml | 6 +++ .../cpp/linters-for-test-only/Makefile | 4 +- .../cpp/linters-for-test-only/issues.exp | 2 + .../linters-for-test-only/linters_example.al | 5 ++ .../test_symbol_lists.cpp | 16 +++++++ 12 files changed, 105 insertions(+), 3 deletions(-) create mode 100644 infer/tests/codetoanalyze/cpp/linters-for-test-only/test_symbol_lists.cpp diff --git a/infer/man/man1/infer-analyze.txt b/infer/man/man1/infer-analyze.txt index 8639961bd..12c09519e 100644 --- a/infer/man/man1/infer-analyze.txt +++ b/infer/man/man1/infer-analyze.txt @@ -68,6 +68,9 @@ OPTIONS Activates: Enable --cost and disable all other checkers (Conversely: --no-cost-only) + --custom-symbols json + Specify named lists of symbols available to rules (default: []) + --debug,-g Activates: Debug mode (also sets --debug-level 2, --developer-mode, --no-filtering, --print-buckets, --print-types, diff --git a/infer/man/man1/infer-full.txt b/infer/man/man1/infer-full.txt index 877404740..9087760ff 100644 --- a/infer/man/man1/infer-full.txt +++ b/infer/man/man1/infer-full.txt @@ -186,6 +186,10 @@ OPTIONS compare against, assuming we are on the current version already. See also infer-diff(1). + --custom-symbols json + Specify named lists of symbols available to rules (default: []) + See also infer-analyze(1). + --no-cxx Deactivates: Analyze C++ methods (Conversely: --cxx) See also infer-capture(1). diff --git a/infer/man/man1/infer.txt b/infer/man/man1/infer.txt index 6381289a1..e2421ce77 100644 --- a/infer/man/man1/infer.txt +++ b/infer/man/man1/infer.txt @@ -186,6 +186,10 @@ OPTIONS compare against, assuming we are on the current version already. See also infer-diff(1). + --custom-symbols json + Specify named lists of symbols available to rules (default: []) + See also infer-analyze(1). + --no-cxx Deactivates: Analyze C++ methods (Conversely: --cxx) See also infer-capture(1). diff --git a/infer/src/base/Config.ml b/infer/src/base/Config.ml index 29f42f35a..afb6fe940 100644 --- a/infer/src/base/Config.ml +++ b/infer/src/base/Config.ml @@ -469,6 +469,25 @@ let exe_usage = (Option.value_map ~default:"" ~f:(( ^ ) " ") exe_command_name) +let get_symbol_string json_obj = + match json_obj with + | `String sym_regexp_str -> + sym_regexp_str + | _ -> + L.(die UserError) "each --custom-symbols element should be list of symbol *strings*" + + +let get_symbols_regexp json_obj = + let sym_regexp_strs = + match json_obj with + | `List json_objs -> + List.map ~f:get_symbol_string json_objs + | _ -> + L.(die UserError) "each --custom-symbols element should be a *list* of strings" + in + Str.regexp ("\\(" ^ String.concat ~sep:"\\|" sym_regexp_strs ^ "\\)") + + (** Command Line options *) (* HOWTO define a new command line and config file option. @@ -968,6 +987,12 @@ and cxx = "Analyze C++ methods" +and custom_symbols = + CLOpt.mk_json ~long:"custom-symbols" + ~in_help:InferCommand.[(Analyze, manual_generic)] + "Specify named lists of symbols available to rules" + + and ( bo_debug , developer_mode , debug @@ -2917,6 +2942,19 @@ and stats_report = !stats_report and subtype_multirange = !subtype_multirange +and custom_symbols = + (* Convert symbol lists to regexps just once, here *) + match !custom_symbols with + | `Assoc sym_lists -> + List.Assoc.map ~f:get_symbols_regexp sym_lists + | `List [] -> + [] + | _ -> + L.(die UserError) + "--custom-symbols must be dictionary of symbol lists not %s" + (Yojson.Basic.to_string !custom_symbols) + + and symops_per_iteration = !symops_per_iteration and keep_going = !keep_going @@ -3015,3 +3053,11 @@ let java_package_is_external package = | _ -> List.exists external_java_packages ~f:(fun (prefix : string) -> String.is_prefix package ~prefix ) + + +let is_in_custom_symbols list_name symbol = + match List.Assoc.find ~equal:String.equal custom_symbols list_name with + | Some regexp -> + Str.string_match regexp symbol 0 + | None -> + false diff --git a/infer/src/base/Config.mli b/infer/src/base/Config.mli index 765bf7c75..c0857a7d2 100644 --- a/infer/src/base/Config.mli +++ b/infer/src/base/Config.mli @@ -702,4 +702,7 @@ val java_package_is_external : string -> bool (** Check if a Java package is external to the repository *) val quandaryBO_filtered_issues : IssueType.t list -(* List of issues that are enabled by QuandaryBO but should not be in the final report.json *) +(** List of issues that are enabled by QuandaryBO but should not be in the final report.json *) + +val is_in_custom_symbols : string -> string -> bool +(** Does named symbol match any prefix in the named custom symbol list? *) diff --git a/infer/src/clang/cPredicates.ml b/infer/src/clang/cPredicates.ml index 50df28592..fbec15548 100644 --- a/infer/src/clang/cPredicates.ml +++ b/infer/src/clang/cPredicates.ml @@ -1420,6 +1420,14 @@ let has_cxx_fully_qualified_name an qual_name_re = ALVar.compare_str_with_alexp fully_qualified_name qual_name_re +let has_cxx_fully_qualified_name_in_custom_symbols an list_name = + match Ctl_parser_types.ast_node_cxx_fully_qualified_name an with + | "" -> + false + | fully_qualified_name -> + Config.is_in_custom_symbols list_name fully_qualified_name + + 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 diff --git a/infer/src/clang/cPredicates.mli b/infer/src/clang/cPredicates.mli index c5cd93aec..fa971dd3a 100644 --- a/infer/src/clang/cPredicates.mli +++ b/infer/src/clang/cPredicates.mli @@ -492,6 +492,11 @@ val has_cxx_fully_qualified_name : Ctl_parser_types.ast_node -> ALVar.alexp -> b * matching the given regexp *) +val has_cxx_fully_qualified_name_in_custom_symbols : Ctl_parser_types.ast_node -> string -> bool +(** true iff node has C++ fully qualified name (w/class and namespace) + * matching a prefix on the given named custom symbol list + *) + val is_in_source_file : Ctl_parser_types.ast_node -> ALVar.alexp -> bool (** * True iff the source file path of the given node matches the given regexp or string. diff --git a/infer/src/clang/cTL.ml b/infer/src/clang/cTL.ml index a93c44d8b..1fc0c0b89 100644 --- a/infer/src/clang/cTL.ml +++ b/infer/src/clang/cTL.ml @@ -975,6 +975,12 @@ let rec eval_Atomic pred_name_ args an lcxt = CPredicates.declaration_has_name an decl_name | "has_cxx_fully_qualified_name", [qual_name_re], an -> CPredicates.has_cxx_fully_qualified_name an qual_name_re + | "has_cxx_fully_qualified_name_in_custom_symbols", [list_name], an -> ( + match list_name with + | ALVar.Const s -> + CPredicates.has_cxx_fully_qualified_name_in_custom_symbols an s + | _ -> + assert false ) | "declaration_ref_name", [decl_name], an -> CPredicates.declaration_ref_name an decl_name | "decl_unavailable_in_supported_ios_sdk", [], an -> diff --git a/infer/tests/codetoanalyze/cpp/linters-for-test-only/Makefile b/infer/tests/codetoanalyze/cpp/linters-for-test-only/Makefile index 2fd217ca6..b40123d22 100644 --- a/infer/tests/codetoanalyze/cpp/linters-for-test-only/Makefile +++ b/infer/tests/codetoanalyze/cpp/linters-for-test-only/Makefile @@ -5,8 +5,8 @@ TESTS_DIR = ../../.. -CLANG_OPTIONS = -std=c++11 -c -INFER_OPTIONS = --no-capture --linters-only --cxx --linters-def-file linters_example.al --project-root $(TESTS_DIR) +CLANG_OPTIONS = -std=c++11 -c +INFER_OPTIONS = --no-capture --linters-only --cxx --linters-def-file linters_example.al --project-root $(TESTS_DIR) --custom-symbols '{ "test": [ "::AllowedSym" ] }' INFERPRINT_OPTIONS = --issues-tests SOURCES = \ 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 46e357ca3..d99c6be16 100644 --- a/infer/tests/codetoanalyze/cpp/linters-for-test-only/issues.exp +++ b/infer/tests/codetoanalyze/cpp/linters-for-test-only/issues.exp @@ -26,3 +26,5 @@ codetoanalyze/cpp/linters-for-test-only/test_overrides.cpp, Linters_dummy_method codetoanalyze/cpp/linters-for-test-only/test_partial_spec_template.cpp, Foo::is_negative_impl_type-parameter-0-0,_false__check, 16, FIND_NODES_WITH_CXX_FULL_NAME, no_bucket, WARNING, [] codetoanalyze/cpp/linters-for-test-only/test_partial_spec_template.cpp, Linters_dummy_method, 9, FIND_NODES_WITH_CXX_FULL_NAME, no_bucket, WARNING, [] codetoanalyze/cpp/linters-for-test-only/test_partial_spec_template.cpp, Linters_dummy_method, 14, FIND_NODES_WITH_CXX_FULL_NAME, no_bucket, WARNING, [] +codetoanalyze/cpp/linters-for-test-only/test_symbol_lists.cpp, foo, 13, FIND_LISTED_SYMBOLS, no_bucket, WARNING, [] +codetoanalyze/cpp/linters-for-test-only/test_symbol_lists.cpp, foo, 14, FIND_LISTED_SYMBOLS, 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 d2aaea2ef..95d632e2c 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 @@ -48,3 +48,8 @@ DEFINE-CHECKER FIND_CXX_METHODS_FROM_HEADER_FILE = { HOLDS-IN-NODE CXXMethodDecl; SET message = "found C++ method %name% in %source_file%"; }; + +DEFINE-CHECKER FIND_LISTED_SYMBOLS = { + SET report_when = NOT is_decl() AND has_cxx_fully_qualified_name_in_custom_symbols("test"); + SET message = "found usage of %cxx_fully_qualified_name%"; +}; diff --git a/infer/tests/codetoanalyze/cpp/linters-for-test-only/test_symbol_lists.cpp b/infer/tests/codetoanalyze/cpp/linters-for-test-only/test_symbol_lists.cpp new file mode 100644 index 000000000..7dd0cc4fa --- /dev/null +++ b/infer/tests/codetoanalyze/cpp/linters-for-test-only/test_symbol_lists.cpp @@ -0,0 +1,16 @@ +/* + * 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. + */ + +extern void AllowedSymbol1(); +extern void AllowedSymbol2(); +extern void DisallowedSymbol(); + +void foo() { + AllowedSymbol1(); + AllowedSymbol2(); + DisallowedSymbol(); +}