Skip to content

Commit

Permalink
[WIP-feat] Extend Cppcheck functionality
Browse files Browse the repository at this point in the history
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 <cppcheck_check>` now properly translates to `--suppress
<cppcheck_check> in the cppcheck invocation.
The current run configuration of cppcheck is `--enable=all`.
  • Loading branch information
vodorok committed Jul 11, 2022
1 parent 0841c8b commit dc0e817
Show file tree
Hide file tree
Showing 6 changed files with 43 additions and 11 deletions.
11 changes: 8 additions & 3 deletions analyzer/codechecker_analyzer/analysis_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -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).
Expand All @@ -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.

Expand Down Expand Up @@ -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),
Expand Down Expand Up @@ -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):
Expand Down
26 changes: 22 additions & 4 deletions analyzer/codechecker_analyzer/analyzers/cppcheck/analyzer.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -22,6 +25,8 @@
from .config_handler import CppcheckConfigHandler
from .result_handler import CppcheckResultHandler

from ..config_handler import CheckerState

LOG = get_logger('analyzer.cppcheck')


Expand Down Expand Up @@ -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))
Expand All @@ -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
Expand Down Expand Up @@ -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):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 \
Expand All @@ -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')
Expand All @@ -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':
Expand All @@ -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)

5 changes: 3 additions & 2 deletions codechecker_common/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down

0 comments on commit dc0e817

Please sign in to comment.