diff --git a/analyzer/codechecker_analyzer/analyzer.py b/analyzer/codechecker_analyzer/analyzer.py index 55b406a772..b3030dbe53 100644 --- a/analyzer/codechecker_analyzer/analyzer.py +++ b/analyzer/codechecker_analyzer/analyzer.py @@ -23,7 +23,7 @@ from . import analyzer_context, analysis_manager, pre_analysis_manager, \ checkers from .analyzers import analyzer_types -from .analyzers.config_handler import CheckerState +from .analyzers.config_handler import AnalyzerConfigHandler, CheckerState from .analyzers.clangsa.analyzer import ClangSA from .makefile import MakeFileCreator @@ -119,6 +119,15 @@ def __get_ctu_data(ctu_dir): 'ctu_temp_fnmap_folder': 'tmpExternalFnMaps'} +def __has_enabled_checker(ch: AnalyzerConfigHandler): + """ + Returns True if at least one checker is enabled in the given config + handler. + """ + return any(state == CheckerState.enabled + for _, (state, _) in ch.checks().items()) + + def perform_analysis(args, skip_handlers, actions, metadata_tool, compile_cmd_count): """ @@ -155,9 +164,16 @@ def perform_analysis(args, skip_handlers, actions, metadata_tool, "the Clang Static Analyzer.") return - actions = prepare_actions(actions, analyzers) config_map = analyzer_types.build_config_handlers(args, analyzers) + no_checker_analyzers = \ + [a for a in analyzers if not __has_enabled_checker(config_map[a])] + for analyzer in no_checker_analyzers: + LOG.info("No checkers enabled for %s", analyzer) + analyzers.remove(analyzer) + + actions = prepare_actions(actions, analyzers) + available_checkers = set() # Add profile names to the checkers list so we will not warn # if a profile is enabled but there is no checker with that name. diff --git a/analyzer/codechecker_analyzer/cmd/analyze.py b/analyzer/codechecker_analyzer/cmd/analyze.py index 5daf73858a..16303980c7 100644 --- a/analyzer/codechecker_analyzer/cmd/analyze.py +++ b/analyzer/codechecker_analyzer/cmd/analyze.py @@ -752,6 +752,15 @@ def add_arguments_to_parser(parser): "the analysis. USE WISELY AND AT YOUR " "OWN RISK!") + checkers_opts.add_argument('--disable-all', + dest="disable_all", + required=False, + default=argparse.SUPPRESS, + action='store_true', + help="Disable all checkers of all analyzers. " + "It is equivalent to using \"--disable " + "default\" as the first argument.") + checkers_opts.add_argument('--no-missing-checker-error', dest="no_missing_checker_error", action='store_true', @@ -916,6 +925,10 @@ def main(args): if 'enable_all' in args: LOG.info("'--enable-all' was supplied for this analysis.") + if 'disable_all' in args: + if 'ordered_checkers' not in args: + args.ordered_checkers = [] + args.ordered_checkers.insert(0, ('default', False)) # Enable alpha uniqueing by default if ctu analysis is used. if 'none' in args.compile_uniqueing and 'ctu_phases' in args: diff --git a/analyzer/codechecker_analyzer/cmd/check.py b/analyzer/codechecker_analyzer/cmd/check.py index 4293715147..ced027255e 100644 --- a/analyzer/codechecker_analyzer/cmd/check.py +++ b/analyzer/codechecker_analyzer/cmd/check.py @@ -698,6 +698,15 @@ def add_arguments_to_parser(parser): "the analysis. USE WISELY AND AT YOUR " "OWN RISK!") + checkers_opts.add_argument('--disable-all', + dest="disable_all", + required=False, + default=argparse.SUPPRESS, + action='store_true', + help="Disable all checkers of all analyzers. " + "It is equivalent to using \"--disable " + "default\" as the first argument.") + checkers_opts.add_argument('--no-missing-checker-error', dest="no_missing_checker_error", action='store_true', @@ -860,6 +869,7 @@ def __update_if_key_exists(source, target, key): 'stats_relevance_threshold', 'stats_min_sample_count', 'enable_all', + 'disable_all', 'ordered_checkers', # --enable and --disable. 'timeout', 'compile_uniqueing', diff --git a/analyzer/tests/functional/analyze/test_analyze.py b/analyzer/tests/functional/analyze/test_analyze.py index af37563e9a..3cc6b53ede 100644 --- a/analyzer/tests/functional/analyze/test_analyze.py +++ b/analyzer/tests/functional/analyze/test_analyze.py @@ -1095,6 +1095,47 @@ def test_makefile_generation(self): plist_files = glob.glob(os.path.join(self.report_dir, '*.plist')) self.assertEqual(len(plist_files), 4) + def test_disable_all_checkers(self): + """ + If all checkers of an analyzer are disabled then the analysis shouldn't + trigger for that analyzer. + """ + build_json = os.path.join(self.test_workspace, "build.json") + build_log = [{"directory": self.test_workspace, + "command": "gcc -c main.c", + "file": "main.c"}] + + with open(build_json, 'w', + encoding="utf-8", errors="ignore") as outfile: + json.dump(build_log, outfile) + + for analyzer in ['clangsa', 'clang-tidy']: + analyze_cmd = [self._codechecker_cmd, "check", "-l", build_json, + "--analyzers", analyzer, + "--disable", "default"] + process = subprocess.Popen( + analyze_cmd, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + encoding="utf-8", + errors="ignore") + out, _ = process.communicate() + + self.assertIn(f"No checkers enabled for {analyzer}", out) + + analyze_cmd = [self._codechecker_cmd, "check", "-l", build_json, + "--disable-all"] + process = subprocess.Popen( + analyze_cmd, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + encoding="utf-8", + errors="ignore") + out, _ = process.communicate() + + # Checkers of all 3 analyzers are disabled. + self.assertEqual(out.count("No checkers enabled for"), 3) + def test_analyzer_and_checker_config(self): """Test analyzer configuration through command line flags.""" build_json = os.path.join(self.test_workspace, "build_success.json") diff --git a/docs/analyzer/user_guide.md b/docs/analyzer/user_guide.md index 7878ffaefc..96c814995a 100644 --- a/docs/analyzer/user_guide.md +++ b/docs/analyzer/user_guide.md @@ -29,6 +29,7 @@ - [Toggling compiler warnings](#toggling-compiler-warnings) - [Checker profiles](#checker-profiles) - [`--enable-all`](#--enable-all) + - [`--disable-all`](#--disable-all) - [Cross Translation Unit (CTU) analysis mode](#cross-translation-unit-ctu-analysis-mode) - [Taint analysis configuration](#taint-analysis-configuration) - [Statistical analysis mode](#statistical-analysis-mode) @@ -145,7 +146,8 @@ usage: CodeChecker check [-h] [-o OUTPUT_DIR] [-t {plist}] [-q] [--ctu-reanalyze-on-failure] [--ctu-ast-mode {load-from-pch,parse-on-demand}] [-e checker/group/profile] [-d checker/group/profile] - [--enable-all] [--print-steps] [--suppress SUPPRESS] + [--enable-all] [--disable-all] [--print-steps] + [--suppress SUPPRESS] [--review-status [REVIEW_STATUS [REVIEW_STATUS ...]]] [--verbose {info,debug,debug_analyzer}] @@ -443,6 +445,8 @@ checker configuration: and stability, and could even result in a total failure of the analysis. USE WISELY AND AT YOUR OWN RISK! + --disable-all Disable all checkers of all analyzers. It is equivalent + to using "--disable default" as the first argument. output arguments: --print-steps Print the steps the analyzers took in finding the @@ -922,6 +926,7 @@ usage: CodeChecker analyze [-h] [-j JOBS] [--ctu-reanalyze-on-failure] [-e checker/group/profile] [-d checker/group/profile] [--enable-all] + [--disable-all] [--verbose {info,debug,debug_analyzer}] input @@ -1390,6 +1395,8 @@ checker configuration: and stability, and could even result in a total failure of the analysis. USE WISELY AND AT YOUR OWN RISK! + --disable-all Disable all checkers of all analyzers. It is equivalent + to using "--disable default" as the first argument. ``` Both `--enable` and `--disable` take individual checkers, checker groups or @@ -1501,6 +1508,17 @@ special checker groups: `alpha.`, `debug.`, `osx.`, `abseil-`, `android-`, can be used to "further" enable `alpha.` checkers, and disable `misc` ones. +##### `--disable-all` + +Some checkers are always enabled by default, because they are categorized in +`default` profile. This flag is equivalent to using `--disable default` which +technically disables all checkers. The motivation behind `--disable-all` is to +enable one specific checker and disable everything else: + +```sh +CodeChecker check -l compile_commands.json --disable-all --enable core.DivideZero +``` + #### Cross Translation Unit (CTU) analysis mode If the `clang` static analyzer binary in your installation supports