From 7ce90c6c0dc399cb807216253d466a67ffaca227 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krist=C3=B3f=20Umann?= Date: Wed, 5 Apr 2023 16:58:17 +0200 Subject: [PATCH] [analyzer] Add a new flag to demote missing checker errors to a warning Altough discouraged, if someone really insists on having a soft warning when a checker is supplied to --enable or --disable, they can use the new flag '--no-missing-checker-error', which is disabled by default. --- analyzer/codechecker_analyzer/analyzer.py | 14 +++-- analyzer/codechecker_analyzer/cmd/analyze.py | 9 ++++ analyzer/codechecker_analyzer/cmd/check.py | 9 ++++ .../tests/functional/analyze/test_analyze.py | 52 ++++++++++++++++--- 4 files changed, 73 insertions(+), 11 deletions(-) diff --git a/analyzer/codechecker_analyzer/analyzer.py b/analyzer/codechecker_analyzer/analyzer.py index 51e09d4ea4..445e3ebc9f 100644 --- a/analyzer/codechecker_analyzer/analyzer.py +++ b/analyzer/codechecker_analyzer/analyzer.py @@ -181,9 +181,17 @@ def perform_analysis(args, skip_handlers, actions, metadata_tool, missing_checkers = checkers.available(args.ordered_checkers, available_checkers) if missing_checkers: - LOG.error("No checker(s) with these names was found:\n%s", - '\n'.join(missing_checkers)) - sys.exit(1) + diag_msg = "No checker(s) with these names was found:\n{}".format( + '\n'.join(missing_checkers)) + if 'no_missing_checker_error' in args: + LOG.warning(diag_msg) + else: + LOG.error(diag_msg) + LOG.info("Although it is not reccomended, if you want to " + "suppress errors relating to unknown " + "checker names, consider using the option " + "'--no-missing-checker-error'") + sys.exit(1) if 'stats_enabled' in args: config_map[ClangSA.ANALYZER_NAME].set_checker_enabled( diff --git a/analyzer/codechecker_analyzer/cmd/analyze.py b/analyzer/codechecker_analyzer/cmd/analyze.py index 268aaefdc1..a5e92db57e 100644 --- a/analyzer/codechecker_analyzer/cmd/analyze.py +++ b/analyzer/codechecker_analyzer/cmd/analyze.py @@ -748,6 +748,15 @@ def add_arguments_to_parser(parser): "the analysis. USE WISELY AND AT YOUR " "OWN RISK!") + checkers_opts.add_argument('--no-missing-checker-error', + dest="no_missing_checker_error", + action='store_true', + required=False, + default=argparse.SUPPRESS, + help="Emit a warning instead of an error when " + "an unknown checker name is given to " + "either --enable or --disable.") + logger.add_verbose_arguments(parser) parser.set_defaults( func=main, func_process_config_file=cmd_config.process_config_file) diff --git a/analyzer/codechecker_analyzer/cmd/check.py b/analyzer/codechecker_analyzer/cmd/check.py index cf06e949d3..4df35b78ae 100644 --- a/analyzer/codechecker_analyzer/cmd/check.py +++ b/analyzer/codechecker_analyzer/cmd/check.py @@ -694,6 +694,15 @@ def add_arguments_to_parser(parser): "the analysis. USE WISELY AND AT YOUR " "OWN RISK!") + checkers_opts.add_argument('--no-missing-checker-error', + dest="no_missing_checker_error", + action='store_true', + required=False, + default=argparse.SUPPRESS, + help="Emit a warning instead of an error when " + "an unknown checker name is given to " + "either --enable or --disable.") + output_opts = parser.add_argument_group("output arguments") output_opts.add_argument('--print-steps', diff --git a/analyzer/tests/functional/analyze/test_analyze.py b/analyzer/tests/functional/analyze/test_analyze.py index 588f60c8df..62c130d7ce 100644 --- a/analyzer/tests/functional/analyze/test_analyze.py +++ b/analyzer/tests/functional/analyze/test_analyze.py @@ -764,12 +764,12 @@ def test_compile_uniqueing(self): self.assertFalse(os.path.isdir(failed_dir)) self.check_unique_compilation_db(unique_json, 3, True, True, True) - def test_invalid_enabled_checker_name(self): - """Error out in case of an invalid enabled checker.""" + def __run_with_invalid_enabled_checker_name(self, extra_args): build_json = os.path.join(self.test_workspace, "build_success.json") analyze_cmd = [self._codechecker_cmd, "analyze", build_json, "--analyzers", "clangsa", "-o", self.report_dir, "-e", "non-existing-checker-name"] + analyze_cmd.extend(extra_args) source_file = os.path.join(self.test_dir, "success.c") build_log = [{"directory": self.test_workspace, @@ -789,15 +789,33 @@ def test_invalid_enabled_checker_name(self): cwd=self.test_dir, encoding="utf-8", errors="ignore") - out, _ = process.communicate() + out, err = process.communicate() + return out, err, process.returncode + + def test_invalid_enabled_checker_name(self): + """Error out in case of an invalid enabled checker.""" + out, _, errcode = self.__run_with_invalid_enabled_checker_name([]) match = self.missing_checker_regex.search(out) self.assertIsNotNone(match) self.assertTrue("non-existing-checker-name" in out) - errcode = process.returncode self.assertEqual(errcode, 1) + def test_invalid_enabled_checker_name_warn(self): + """ + Warn in case of an invalid enabled checker when using + --no-missing-checker-error. + """ + out, _, errcode = self.__run_with_invalid_enabled_checker_name( + ['--no-missing-checker-error']) + + match = self.missing_checker_regex.search(out) + self.assertIsNotNone(match) + self.assertTrue("non-existing-checker-name" in out) + + self.assertEqual(errcode, 0) + def test_disable_all_warnings(self): """Test disabling warnings as checker groups.""" build_json = os.path.join(self.test_workspace, "build.json") @@ -830,12 +848,12 @@ def test_disable_all_warnings(self): self.assertIn("unused variable 'i' [clang-diagnostic-unused-variable]", out) - def test_invalid_disabled_checker_name(self): - """Error out in case of an invalid disabled checker.""" + def __run_with_invalid_disabled_checker_name(self, extra_args): build_json = os.path.join(self.test_workspace, "build_success.json") analyze_cmd = [self._codechecker_cmd, "analyze", build_json, "--analyzers", "clangsa", "-o", self.report_dir, "-d", "non-existing-checker-name"] + analyze_cmd.extend(extra_args) source_file = os.path.join(self.test_dir, "success.c") build_log = [{"directory": self.test_workspace, @@ -855,15 +873,33 @@ def test_invalid_disabled_checker_name(self): cwd=self.test_dir, encoding="utf-8", errors="ignore") - out, _ = process.communicate() + out, err = process.communicate() + return out, err, process.returncode + + def test_invalid_disabled_checker_name(self): + """Error out in case of an invalid disabled checker.""" + out, _, errcode = self.__run_with_invalid_disabled_checker_name([]) match = self.missing_checker_regex.search(out) self.assertIsNotNone(match) self.assertTrue("non-existing-checker-name" in out) - errcode = process.returncode self.assertEqual(errcode, 1) + def test_invalid_disabled_checker_name_warn(self): + """ + Warn in case of an invalid disabled checker when using + --no-missing-checker-error. + """ + out, _, errcode = self.__run_with_invalid_disabled_checker_name( + ['--no-missing-checker-error']) + + match = self.missing_checker_regex.search(out) + self.assertIsNotNone(match) + self.assertTrue("non-existing-checker-name" in out) + + self.assertEqual(errcode, 0) + def test_disabling_clangsa_modeling_checkers(self): """Warn in case a modeling checker is disabled from clangsa""" build_json = os.path.join(self.test_workspace, "build_success.json")