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..ba2d4c1c2f 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)