From bcb62bd828c585f6ddef3f9bcd606edb745e6ec1 Mon Sep 17 00:00:00 2001 From: Daniel Krupp Date: Thu, 29 Aug 2024 12:17:52 +0200 Subject: [PATCH] Adding a --drop-reports-from-skipped-files parameter to analyze The report filtering post processing step was removed as part of the --skip SKIPFILE parameter and was separated out to a --drop-reports-from-skipped-files paramer. This way the reports are not skipped as a post processing step by default. With the argument set to true the legacy behaviour is triggered that is all reports from the files which are skipped from the analysis are dropped. --- .../codechecker_analyzer/analysis_manager.py | 12 +++--- analyzer/codechecker_analyzer/analyzer.py | 4 +- analyzer/codechecker_analyzer/cmd/analyze.py | 20 +++++++-- analyzer/codechecker_analyzer/cmd/check.py | 11 ++++- analyzer/tests/functional/skip/test_skip.py | 42 ++++++++++++++++++- 5 files changed, 78 insertions(+), 11 deletions(-) diff --git a/analyzer/codechecker_analyzer/analysis_manager.py b/analyzer/codechecker_analyzer/analysis_manager.py index 6b22ca4231..c087262fa2 100644 --- a/analyzer/codechecker_analyzer/analysis_manager.py +++ b/analyzer/codechecker_analyzer/analysis_manager.py @@ -216,7 +216,7 @@ def prepare_check(action, analyzer_config, output_dir, def handle_success( - rh, result_file, result_base, skip_handlers, + rh, result_file, result_base, filter_handlers, rs_handler: ReviewStatusHandler, capture_analysis_output, success_dir ): @@ -230,7 +230,7 @@ def handle_success( save_output(os.path.join(success_dir, result_base), rh.analyzer_stdout, rh.analyzer_stderr) - rh.postprocess_result(skip_handlers, rs_handler) + rh.postprocess_result(filter_handlers, rs_handler) # Generated reports will be handled separately at store. @@ -487,7 +487,8 @@ def check(check_data): skiplist handler is None if no skip file was configured. """ actions_map, action, analyzer_config, \ - output_dir, skip_handlers, rs_handler, quiet_output_on_stdout, \ + output_dir, skip_handlers, filter_handlers, \ + rs_handler, quiet_output_on_stdout, \ capture_analysis_output, generate_reproducer, analysis_timeout, \ ctu_reanalyze_on_failure, \ output_dirs, statistics_data = check_data @@ -605,7 +606,7 @@ def handle_analysis_result(success, zip_file=zip_file): if success: handle_success(rh, result_file, result_base, - skip_handlers, rs_handler, + filter_handlers, rs_handler, capture_analysis_output, success_dir) elif not generate_reproducer: handle_failure(source_analyzer, rh, @@ -719,7 +720,7 @@ def skip_cpp(compile_actions, skip_handlers): def start_workers(actions_map, actions, analyzer_config_map, - jobs, output_path, skip_handlers, + jobs, output_path, skip_handlers, filter_handlers, rs_handler: ReviewStatusHandler, metadata_tool, quiet_analyze, capture_analysis_output, generate_reproducer, timeout, ctu_reanalyze_on_failure, statistics_data, manager, @@ -785,6 +786,7 @@ def signal_handler(signum, _): analyzer_config_map.get(build_action.analyzer_type), output_path, skip_handlers, + filter_handlers, rs_handler, quiet_analyze, capture_analysis_output, diff --git a/analyzer/codechecker_analyzer/analyzer.py b/analyzer/codechecker_analyzer/analyzer.py index b6135f5aac..13d4fbdb8e 100644 --- a/analyzer/codechecker_analyzer/analyzer.py +++ b/analyzer/codechecker_analyzer/analyzer.py @@ -130,7 +130,8 @@ def __has_enabled_checker(ch: AnalyzerConfigHandler): for _, (state, _) in ch.checks().items()) -def perform_analysis(args, skip_handlers, rs_handler: ReviewStatusHandler, +def perform_analysis(args, skip_handlers, filter_handlers, + rs_handler: ReviewStatusHandler, actions, metadata_tool, compile_cmd_count): """ Perform static analysis via the given (or if not, all) analyzers, @@ -335,6 +336,7 @@ def perform_analysis(args, skip_handlers, rs_handler: ReviewStatusHandler, config_map, args.jobs, args.output_path, skip_handlers, + filter_handlers, rs_handler, metadata_tool, 'quiet' in args, diff --git a/analyzer/codechecker_analyzer/cmd/analyze.py b/analyzer/codechecker_analyzer/cmd/analyze.py index 72faeb4be7..ebf82aef57 100644 --- a/analyzer/codechecker_analyzer/cmd/analyze.py +++ b/analyzer/codechecker_analyzer/cmd/analyze.py @@ -183,6 +183,14 @@ def add_arguments_to_parser(parser): "Please consult the User guide on how a " "Skipfile should be laid out.") + skip_mode.add_argument('--drop-reports-from-skipped-files', + dest="drop_skipped_reports", + required=False, + action='store_true', + default=False, + help="Filter our reports from files that were " + "skipped from the analysis.") + skip_mode.add_argument('--file', nargs='+', dest="files", @@ -1097,8 +1105,13 @@ def main(args): LOG.error(f"Found no compilation commands in '{args.input}'") sys.exit(1) - # Process the skip list if present. + # Process the skip list if present. This will filter out analysis actions. skip_handlers = __get_skip_handlers(args, compile_commands) + # Post processin filters + filter_handlers = None + if ('drop_skipped_reports' in args and args.drop_skipped_reports): + filter_handlers = skip_handlers + rs_handler = review_status_handler.ReviewStatusHandler(args.output_path) try: @@ -1244,8 +1257,9 @@ def main(args): LOG.debug_analyzer("Compile commands forwarded for analysis: %d", compile_cmd_count.analyze) - analyzer.perform_analysis(args, skip_handlers, rs_handler, actions, - metadata_tool, compile_cmd_count) + analyzer.perform_analysis(args, skip_handlers, filter_handlers, + rs_handler, actions, metadata_tool, + compile_cmd_count) __update_skip_file(args) __update_review_status_config(args) diff --git a/analyzer/codechecker_analyzer/cmd/check.py b/analyzer/codechecker_analyzer/cmd/check.py index 3af194a890..c68e1da120 100644 --- a/analyzer/codechecker_analyzer/cmd/check.py +++ b/analyzer/codechecker_analyzer/cmd/check.py @@ -275,7 +275,7 @@ def add_arguments_to_parser(parser): "more information.\n" "USE WISELY AND AT YOUR OWN RISK!") - skip_mode = analyzer_opts.add_mutually_exclusive_group() + skip_mode = parser.add_argument_group("file filter arguments") skip_mode.add_argument('-i', '--ignore', '--skip', dest="skipfile", required=False, @@ -285,6 +285,14 @@ def add_arguments_to_parser(parser): "Please consult the User guide on how a " "Skipfile should be laid out.") + skip_mode.add_argument('--drop-reports-from-skipped-files', + dest="drop_skipped_reports", + required=False, + action='store_true', + default=False, + help="Filter our reports from files that were " + "skipped from the analysis.") + skip_mode.add_argument('--file', nargs='+', dest="files", @@ -881,6 +889,7 @@ def __update_if_key_exists(source, target, key): # after the call. args_to_update = ['quiet', 'skipfile', + 'drop_skipped_reports', 'files', 'analyzers', 'add_compiler_defaults', diff --git a/analyzer/tests/functional/skip/test_skip.py b/analyzer/tests/functional/skip/test_skip.py index 79950be4ad..21a4bc27cc 100644 --- a/analyzer/tests/functional/skip/test_skip.py +++ b/analyzer/tests/functional/skip/test_skip.py @@ -136,7 +136,47 @@ def __run_parse(self, extra_options=None): def test_skip(self): """Analyze a project with a skip file.""" - self.__log_and_analyze_simple(["--ignore", "skipfile"]) + # we should see a report from skip.h + # we should not see a report from file_to_be_skipped.cpp + self.__log_and_analyze_simple(["--ignore", "skipfile_drop"]) + + # Check if file is skipped. + report_dir_files = os.listdir(self.report_dir) + for f in report_dir_files: + self.assertFalse("file_to_be_skipped.cpp" in f) + + # Check if report from the report file is removed. + report_dir_files = os.listdir(self.report_dir) + report_file_to_check = None + for f in report_dir_files: + if "skip_header.cpp" in f: + report_file_to_check = os.path.join(self.report_dir, f) + break + + self.assertIsNotNone(report_file_to_check, + "Report file should be generated.") + report_data = {} + with open(report_file_to_check, 'rb') as plist_file: + report_data = plistlib.load(plist_file) + files = report_data['files'] + + skipped_file_index = None + for i, f in enumerate(files): + if "skip.h" in f: + skipped_file_index = i + break + + self.assertNotEqual( skipped_file_index, None, + "Reports from headers should be kept" + " if the header is not on the skiplist") + + def test_drop_reports(self): + """Analyze a project with a skip file.""" + # we should not see a report from skip.h + # we should not see a report from file_to_be_skipped.cpp + + self.__log_and_analyze_simple(["--ignore", "skipfile", + "--drop-reports-from-skipped-files"]) # Check if file is skipped. report_dir_files = os.listdir(self.report_dir)