Skip to content

Commit

Permalink
[analyzer] Handle getting options for old analyzer version
Browse files Browse the repository at this point in the history
In case of Clang Static Analyzer we try to get analyzer / checker configuration
options by using the `-analyzer-config-help` / `-analyzer-checker-option-help`
options which were introduced in Clang 8.

With this patch we will handle the use case when someone is using an older version
of clang which doesn't support these options.
  • Loading branch information
csordasmarton committed Apr 30, 2021
1 parent 763b61d commit 1d2e7a1
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 5 deletions.
28 changes: 24 additions & 4 deletions analyzer/codechecker_analyzer/analyzers/clangsa/analyzer.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
import shlex
import subprocess

from typing import Dict, List

from codechecker_common.logger import get_logger

from codechecker_analyzer import env
Expand All @@ -33,19 +35,25 @@
LOG = get_logger('analyzer')


def parse_clang_help_page(command, start_label, environ):
def parse_clang_help_page(
command: List[str],
start_label: str,
environ: Dict[str, str]
) -> List[str]:
"""
Parse the clang help page starting from a specific label.
Returns a list of (flag, description) tuples.
"""
try:
help_page = subprocess.check_output(
command,
stderr=subprocess.STDOUT,
env=environ,
universal_newlines=True,
encoding="utf-8",
errors="ignore")
except (subprocess.CalledProcessError, OSError):
LOG.debug("Failed to run '%s' command!", command)
return []

help_page = help_page[help_page.index(start_label) + len(start_label):]
Expand Down Expand Up @@ -131,23 +139,35 @@ def add_checker_config(self, checker_cfg):
self.__checker_configs.append(checker_cfg)

@classmethod
def get_analyzer_checkers(cls, cfg_handler, environ):
def get_analyzer_checkers(
cls,
cfg_handler: config_handler.ClangSAConfigHandler,
environ: Dict[str, str]
) -> List[str]:
"""Return the list of the supported checkers."""
checker_list_args = clang_options.get_analyzer_checkers_cmd(
cfg_handler,
alpha=True)
return parse_clang_help_page(checker_list_args, 'CHECKERS:', environ)

@classmethod
def get_checker_config(cls, cfg_handler, environ):
def get_checker_config(
cls,
cfg_handler: config_handler.ClangSAConfigHandler,
environ: Dict[str, str]
) -> List[str]:
"""Return the list of checker config options."""
checker_config_args = clang_options.get_checker_config_cmd(
cfg_handler,
alpha=True)
return parse_clang_help_page(checker_config_args, 'OPTIONS:', environ)

@classmethod
def get_analyzer_config(cls, cfg_handler, environ):
def get_analyzer_config(
cls,
cfg_handler: config_handler.ClangSAConfigHandler,
environ: Dict[str, str]
) -> List[str]:
"""Return the list of analyzer config options."""
analyzer_config_args = clang_options.get_analyzer_config_cmd(
cfg_handler)
Expand Down
7 changes: 7 additions & 0 deletions analyzer/codechecker_analyzer/cmd/analyzers.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

import argparse
import subprocess
import sys

from codechecker_analyzer import analyzer_context
from codechecker_analyzer import env
Expand Down Expand Up @@ -173,6 +174,12 @@ def uglify(text):

configs = analyzer_class.get_analyzer_config(config_handler,
analyzer_environment)
if not configs:
LOG.error("Failed to get analyzer configuration options for '%s' "
"analyzer! Please try to upgrade your analyzer version "
"to use this feature.", analyzer)
sys.exit(1)

rows = [(':'.join((analyzer, c[0])), c[1]) if 'details' in args
else (':'.join((analyzer, c[0])),) for c in configs]

Expand Down
16 changes: 15 additions & 1 deletion analyzer/codechecker_analyzer/cmd/checkers.py
Original file line number Diff line number Diff line change
Expand Up @@ -282,16 +282,30 @@ def format_guideline(guideline):
header = list(map(uglify, header))

rows = []
analyzer_failures = []
for analyzer in working_analyzers:
config_handler = analyzer_config_map.get(analyzer)
analyzer_class = analyzer_types.supported_analyzers[analyzer]

configs = analyzer_class.get_checker_config(config_handler,
analyzer_environment)
if not configs:
analyzer_failures.append(analyzer)
continue

rows.extend((':'.join((analyzer, c[0])), c[1]) if 'details' in args
else (':'.join((analyzer, c[0])),) for c in configs)

print(twodim.to_str(args.output_format, header, rows))
if rows:
print(twodim.to_str(args.output_format, header, rows))

if analyzer_failures:
LOG.error("Failed to get checker configuration options for '%s' "
"analyzer(s)! Please try to upgrade your analyzer "
"version to use this feature.",
', '.join(analyzer_failures))
sys.exit(1)

return

if args.guideline is not None and len(args.guideline) == 0:
Expand Down

0 comments on commit 1d2e7a1

Please sign in to comment.