From dc0e817bba393b05e6f3241e8a48f4e420b853e0 Mon Sep 17 00:00:00 2001 From: vodorok Date: Fri, 1 Jul 2022 13:32:32 +0200 Subject: [PATCH] [WIP-feat] Extend Cppcheck functionality This patch is a work in progress, there are debug prints all over the place inside Codechecker, treat it accordingly. Will be amended, and split up, when I am back from vacation. Cppcheck now works in a raw directory instead of directly into the workspace folder. Exponential explosion of reports in plist files are now fixed. Checker disable now works on native levels. The `--disable ` now properly translates to `--suppress in the cppcheck invocation. The current run configuration of cppcheck is `--enable=all`. --- .../codechecker_analyzer/analysis_manager.py | 11 +++++--- .../analyzers/cppcheck/analyzer.py | 26 ++++++++++++++++--- .../analyzers/cppcheck/result_handler.py | 9 +++++-- codechecker_common/cli.py | 5 ++-- .../analyzers/cppcheck/analyzer_result.py | 2 ++ .../report/parser/plist.py | 1 + 6 files changed, 43 insertions(+), 11 deletions(-) diff --git a/analyzer/codechecker_analyzer/analysis_manager.py b/analyzer/codechecker_analyzer/analysis_manager.py index a56fb82b1b..9d16104237 100644 --- a/analyzer/codechecker_analyzer/analysis_manager.py +++ b/analyzer/codechecker_analyzer/analysis_manager.py @@ -221,7 +221,7 @@ def prepare_check(action, analyzer_config, output_dir, checker_labels, def handle_success(rh, result_file, result_base, skip_handlers, - capture_analysis_output, success_dir): + capture_analysis_output, success_dir, config_handler): """ Result postprocessing is required if the analysis was successful (mainly clang tidy output conversion is done). @@ -232,7 +232,7 @@ def handle_success(rh, result_file, result_base, skip_handlers, save_output(os.path.join(success_dir, result_base), rh.analyzer_stdout, rh.analyzer_stderr) - rh.postprocess_result(skip_handlers) + rh.postprocess_result(skip_handlers, config_handler) # Generated reports will be handled separately at store. @@ -608,7 +608,7 @@ def handle_analysis_result(success, zip_file=zip_file): if success: handle_success(rh, result_file, result_base, skip_handlers, capture_analysis_output, - success_dir) + success_dir, analyzer_config) elif not generate_reproducer: handle_failure(source_analyzer, rh, os.path.join(failed_dir, zip_file), @@ -764,6 +764,11 @@ def signal_handler(signum, frame): if not os.path.exists(reproducer_dir) and generate_reproducer: os.makedirs(reproducer_dir) + # Cppcheck raw output directory + cppcheck_dir = os.path.join(output_path, "cppcheck") + if not os.path.exists(cppcheck_dir): + os.makedirs(cppcheck_dir) + # Collect what other TUs were involved during CTU analysis. ctu_connections_dir = os.path.join(output_path, "ctu_connections") if not os.path.exists(ctu_connections_dir): diff --git a/analyzer/codechecker_analyzer/analyzers/cppcheck/analyzer.py b/analyzer/codechecker_analyzer/analyzers/cppcheck/analyzer.py index 55aa4ae19e..a3ba9317b9 100644 --- a/analyzer/codechecker_analyzer/analyzers/cppcheck/analyzer.py +++ b/analyzer/codechecker_analyzer/analyzers/cppcheck/analyzer.py @@ -6,9 +6,12 @@ """ """ from distutils.version import StrictVersion +from pathlib import Path +from pprint import pprint import os import re import shlex +import shutil import subprocess import xml.etree.ElementTree as ET @@ -22,6 +25,8 @@ from .config_handler import CppcheckConfigHandler from .result_handler import CppcheckResultHandler +from ..config_handler import CheckerState + LOG = get_logger('analyzer.cppcheck') @@ -88,13 +93,22 @@ def construct_analyzer_cmd(self, result_handler): # Enable or disable checkers. enabled_severity_levels = set() suppressed_checkers = set() + + for checker_name, value in config.checks().items(): - if not value[0]: + #print(checker_name) + #pprint(value) + if value[0] == CheckerState.disabled: + print( checker_name, value) suppressed_checkers.add(checker_name) # TODO: Check severity handling in cppcheck # elif value.severity and value.severity != 'error': # enabled_severity_levels.add(value.severity) + # TODO remove this: + # Codechecker enable params should handle + analyzer_cmd.append('--enable=all') + if enabled_severity_levels: analyzer_cmd.append('--enable=' + ','.join(enabled_severity_levels)) @@ -116,7 +130,9 @@ def construct_analyzer_cmd(self, result_handler): # print(include) # analyzer_cmd.extend(['-I', include]) - analyzer_cmd.append('--plist-output=' + result_handler.workspace) + analyzer_cmd.append('--plist-output=' +\ + str(Path(result_handler.workspace, "cppcheck"))) + analyzer_cmd.append(self.source_file) return analyzer_cmd @@ -161,13 +177,15 @@ def post_analyze(self, result_handler): Renames the generated plist file with a unique name. """ file_name = os.path.splitext(os.path.basename(self.source_file))[0] - output_file = os.path.join(result_handler.workspace, + output_file = os.path.join(result_handler.workspace, "cppcheck", file_name + '.plist') if os.path.exists(output_file): output = os.path.join(result_handler.workspace, result_handler.analyzer_result_file) - os.rename(output_file, output) + shutil.copy2(output_file, output) + print("post_analyze", self.config_handler) + # os.rename(output_file, output) @classmethod def resolve_missing_binary(cls, configured_binary, env): diff --git a/analyzer/codechecker_analyzer/analyzers/cppcheck/result_handler.py b/analyzer/codechecker_analyzer/analyzers/cppcheck/result_handler.py index d6ea2e0a67..196808649d 100644 --- a/analyzer/codechecker_analyzer/analyzers/cppcheck/result_handler.py +++ b/analyzer/codechecker_analyzer/analyzers/cppcheck/result_handler.py @@ -7,6 +7,7 @@ Result handler for Cppcheck. """ from typing import Optional +from pprint import pprint from codechecker_report_converter.report.parser.base import AnalyzerInfo from codechecker_report_converter.analyzers.cppcheck.analyzer_result import \ @@ -17,6 +18,8 @@ from codechecker_common.logger import get_logger from codechecker_common.skiplist_handler import SkipListHandlers +from .config_handler import CppcheckConfigHandler + from ..result_handler_base import ResultHandler LOG = get_logger('analyzer.cppcheck') @@ -32,15 +35,16 @@ def __init__(self, *args, **kwargs): super(CppcheckResultHandler, self).__init__(*args, **kwargs) - def postprocess_result(self, skip_handlers: Optional[SkipListHandlers]): + def postprocess_result(self, skip_handlers: Optional[SkipListHandlers], config_handler: CppcheckConfigHandler): """ Generate analyzer result output file which can be parsed and stored into the database. """ LOG.debug_analyzer(self.analyzer_stdout) - reports = AnalyzerResult().get_reports(self.workspace) + reports = AnalyzerResult().get_reports(self.analyzer_result_file) reports = [r for r in reports if not r.skip(skip_handlers)] + # pprint(reports) hash_type = HashType.PATH_SENSITIVE if self.report_hash_type == 'context-free-v2': @@ -54,3 +58,4 @@ def postprocess_result(self, skip_handlers: Optional[SkipListHandlers]): report_file.create( self.analyzer_result_file, reports, self.checker_labels, self.analyzer_info) + diff --git a/codechecker_common/cli.py b/codechecker_common/cli.py index b4f2699f6c..4e3113ee50 100755 --- a/codechecker_common/cli.py +++ b/codechecker_common/cli.py @@ -93,8 +93,9 @@ def main(): """ CodeChecker main command line. """ - os.environ['CC_LIB_DIR'] = os.path.dirname(os.path.dirname( - os.path.realpath(__file__))) + if not os.environ.get('CC_LIB_DIR'): + os.environ['CC_LIB_DIR'] = \ + os.path.dirname(os.path.dirname(os.path.realpath(__file__))) data_files_dir_path = get_data_files_dir_path() os.environ['CC_DATA_FILES_DIR'] = data_files_dir_path diff --git a/tools/report-converter/codechecker_report_converter/analyzers/cppcheck/analyzer_result.py b/tools/report-converter/codechecker_report_converter/analyzers/cppcheck/analyzer_result.py index 59b7e0da56..a3da940d13 100644 --- a/tools/report-converter/codechecker_report_converter/analyzers/cppcheck/analyzer_result.py +++ b/tools/report-converter/codechecker_report_converter/analyzers/cppcheck/analyzer_result.py @@ -50,4 +50,6 @@ def get_reports(self, analyzer_result_path: str) -> List[Report]: plist_file, None, file_cache) reports.extend(plist_reports) + print(len(reports)) + print(analyzer_result_path) return reports diff --git a/tools/report-converter/codechecker_report_converter/report/parser/plist.py b/tools/report-converter/codechecker_report_converter/report/parser/plist.py index 2725559b97..1e5de29be7 100644 --- a/tools/report-converter/codechecker_report_converter/report/parser/plist.py +++ b/tools/report-converter/codechecker_report_converter/report/parser/plist.py @@ -214,6 +214,7 @@ def get_reports( reports.append(report) except KeyError as ex: + pdb.post_mortem() LOG.warning("Failed to get file path id! Found files: %s. " "KeyError: %s", files, ex) except IndexError as iex: