diff --git a/Makefile b/Makefile index 6884c7751..b1c7a1edd 100644 --- a/Makefile +++ b/Makefile @@ -49,7 +49,9 @@ endif ifneq ($(XCODE_SELECT),no) BUILD_SYSTEMS_TESTS += xcodebuild_no_xcpretty DIRECT_TESTS += \ - objc_frontend objc_errors objc_linters objc_ioslints objcpp_frontend objcpp_linters objc_linters-for-test-only + objc_frontend objc_errors objc_linters objc_ioslints \ + objcpp_frontend objcpp_linters objc_linters-for-test-only \ + objc_linters-def-folder ifneq ($(XCPRETTY),no) BUILD_SYSTEMS_TESTS += xcodebuild endif diff --git a/infer/src/base/Config.ml b/infer/src/base/Config.ml index 246c222d5..314f38029 100644 --- a/infer/src/base/Config.ml +++ b/infer/src/base/Config.ml @@ -1109,6 +1109,11 @@ and linters_def_file = ~long:"linters-def-file" ~in_help:CLOpt.[Capture, manual_clang_linters] ~meta:"file" "Specify the file containing linters definition (e.g. 'linters.al')" +and linters_def_folder = + CLOpt.mk_path_list ~default:[] ~long:"linters-def-folder" + ~in_help:CLOpt.[Capture, manual_clang_linters] + ~meta:"dir" "Specify the folder containing linters files with extension .al" + and linters_ignore_clang_failures = CLOpt.mk_bool ~long:"linters-ignore-clang-failures" ~in_help:CLOpt.[Capture, manual_clang_linters] @@ -1820,6 +1825,7 @@ and jobs = !jobs and join_cond = !join_cond and latex = !latex and linters_def_file = !linters_def_file +and linters_def_folder = !linters_def_folder and linters_developer_mode = !linters_developer_mode and load_average = match !load_average with | None when !buck -> diff --git a/infer/src/base/Config.mli b/infer/src/base/Config.mli index 775932f6e..4205e0cbd 100644 --- a/infer/src/base/Config.mli +++ b/infer/src/base/Config.mli @@ -272,6 +272,7 @@ val join_cond : int val latex : string option val linter : string option val linters_def_file : string list +val linters_def_folder : string list val linters_developer_mode : bool val load_analysis_results : string option val log_file : string option diff --git a/infer/src/clang/cFrontend_checkers_main.ml b/infer/src/clang/cFrontend_checkers_main.ml index cb57bf2d7..113d16b9a 100644 --- a/infer/src/clang/cFrontend_checkers_main.ml +++ b/infer/src/clang/cFrontend_checkers_main.ml @@ -252,10 +252,26 @@ let store_issues source_file = DB.filename_from_string (Filename.concat lint_issues_dir (abbrev_source_file ^ ".issue")) in LintIssues.store_issues lint_issues_file !LintIssues.errLogMap +let find_linters_files () = + let rec find_aux init dir_path = + let aux base_path files rel_path = + let full_path = Filename.concat base_path rel_path in + match (Unix.stat full_path).Unix.st_kind with + | Unix.S_REG when String.is_suffix ~suffix:".al" full_path -> full_path :: files + | Unix.S_DIR -> find_aux files full_path + | _ -> files in + Sys.fold_dir ~init ~f:(aux dir_path) dir_path in + List.concat (List.map ~f:(fun folder -> find_aux [] folder) Config.linters_def_folder) + +let linters_files = + List.dedup ~compare:String.compare (find_linters_files () @ Config.linters_def_file) + let do_frontend_checks (trans_unit_ctx: CFrontend_config.translation_unit_context) ast = + Logging.out "Loading the following linters files: %a\n" + (Pp.comma_seq Format.pp_print_string) linters_files; CTL.create_ctl_evaluation_tracker trans_unit_ctx.source_file; try - let parsed_linters = parse_ctl_files Config.linters_def_file in + let parsed_linters = parse_ctl_files linters_files in let filtered_parsed_linters = CFrontend_errors.filter_parsed_linters parsed_linters trans_unit_ctx.source_file in CFrontend_errors.parsed_linters := filtered_parsed_linters; diff --git a/infer/tests/codetoanalyze/objc/linters-def-folder/Makefile b/infer/tests/codetoanalyze/objc/linters-def-folder/Makefile new file mode 100644 index 000000000..9a9385b9e --- /dev/null +++ b/infer/tests/codetoanalyze/objc/linters-def-folder/Makefile @@ -0,0 +1,17 @@ +# 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. + +TESTS_DIR = ../../.. + +ANALYZER = linters +CLANG_OPTIONS = -c +INFER_OPTIONS = --linters-def-folder checks --project-root $(TESTS_DIR) --no-failures-allowed +INFERPRINT_OPTIONS = --issues-tests + +SOURCES = file.m + +include $(TESTS_DIR)/clang.make diff --git a/infer/tests/codetoanalyze/objc/linters-def-folder/checks/dummy_check.al b/infer/tests/codetoanalyze/objc/linters-def-folder/checks/dummy_check.al new file mode 100644 index 000000000..943f320f4 --- /dev/null +++ b/infer/tests/codetoanalyze/objc/linters-def-folder/checks/dummy_check.al @@ -0,0 +1,11 @@ +// 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. + +DEFINE-CHECKER FORBIDDEN_NAME_EXAMPLE = { + SET report_when = WHEN is_class("ForbiddenClassName") HOLDS-IN-NODE ObjCInterfaceDecl; + SET message = "ForbiddenClassName is forbidden, please use another name"; +}; diff --git a/infer/tests/codetoanalyze/objc/linters-def-folder/checks/not_an_al_file.al.txt b/infer/tests/codetoanalyze/objc/linters-def-folder/checks/not_an_al_file.al.txt new file mode 100644 index 000000000..334ba6807 --- /dev/null +++ b/infer/tests/codetoanalyze/objc/linters-def-folder/checks/not_an_al_file.al.txt @@ -0,0 +1,10 @@ +/* + * 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. + */ + +not_an_al_file.al.txt is not an AL file. diff --git a/infer/tests/codetoanalyze/objc/linters-def-folder/checks/subfolder_with_checks/simple_check.al b/infer/tests/codetoanalyze/objc/linters-def-folder/checks/subfolder_with_checks/simple_check.al new file mode 100644 index 000000000..730cf3790 --- /dev/null +++ b/infer/tests/codetoanalyze/objc/linters-def-folder/checks/subfolder_with_checks/simple_check.al @@ -0,0 +1,11 @@ +// 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. + +DEFINE-CHECKER SUBCLASSING_TEST_EXAMPLE = { + SET report_when = is_class("A") HOLDS-IN-SOME-SUPERCLASS-OF ObjCInterfaceDecl; + SET message = "This is subclassing A. Class A should not be subclassed."; +}; diff --git a/infer/tests/codetoanalyze/objc/linters-def-folder/checks/subfolder_with_checks/unrelated_file.al.txt b/infer/tests/codetoanalyze/objc/linters-def-folder/checks/subfolder_with_checks/unrelated_file.al.txt new file mode 100644 index 000000000..aba0a67fb --- /dev/null +++ b/infer/tests/codetoanalyze/objc/linters-def-folder/checks/subfolder_with_checks/unrelated_file.al.txt @@ -0,0 +1,10 @@ +/* + * 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. + */ + +unrelated_file.al.txt is not an AL file. diff --git a/infer/tests/codetoanalyze/objc/linters-def-folder/file.m b/infer/tests/codetoanalyze/objc/linters-def-folder/file.m new file mode 100644 index 000000000..436fe3472 --- /dev/null +++ b/infer/tests/codetoanalyze/objc/linters-def-folder/file.m @@ -0,0 +1,36 @@ +/* + * 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. + */ + +// Test the functionality of the --linters-def-folder flag + +#import + +@interface A : NSObject +@end + +@implementation A +@end + +@interface B : A +@end + +@implementation B +@end + +@interface ForbiddenClassName : NSObject +@end + +@implementation ForbiddenClassName +@end + +@interface C : NSObject +@end + +@implementation C +@end diff --git a/infer/tests/codetoanalyze/objc/linters-def-folder/issues.exp b/infer/tests/codetoanalyze/objc/linters-def-folder/issues.exp new file mode 100644 index 000000000..f668b2d80 --- /dev/null +++ b/infer/tests/codetoanalyze/objc/linters-def-folder/issues.exp @@ -0,0 +1,2 @@ +codetoanalyze/objc/linters-def-folder/file.m, Linters_dummy_method, 20, SUBCLASSING_TEST_EXAMPLE, [] +codetoanalyze/objc/linters-def-folder/file.m, Linters_dummy_method, 26, FORBIDDEN_NAME_EXAMPLE, []