Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[analyzers] Deprecate --all and --details for analyzers #4056

Merged
merged 2 commits into from
Oct 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion analyzer/codechecker_analyzer/analyzer.py
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ def perform_analysis(args, skip_handlers, actions, metadata_tool,

# TODO: cppcheck may require a different environment than clang.
version = analyzer_types.supported_analyzers[analyzer] \
.get_version(context.analyzer_env)
.get_binary_version(context.analyzer_env)
metadata_info['analyzer_statistics']['version'] = version

metadata_tool['analyzers'][analyzer] = metadata_info
Expand Down
13 changes: 11 additions & 2 deletions analyzer/codechecker_analyzer/analyzers/analyzer_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,18 @@ def resolve_missing_binary(cls, configured_binary, environ):
"""
raise NotImplementedError("Subclasses should implement this!")

@abstractmethod
def get_binary_version(self, environ, details=False) -> str:
"""
Return the version number of the binary that CodeChecker found, even
if its incompatible. If details is true, additional version information
is provided. If details is false, the return value should be
convertible to a distutils.version.StrictVersion type.
"""
raise NotImplementedError("Subclasses should implement this!")

@classmethod
def is_binary_version_incompatible(cls, configured_binary, environ) \
-> Optional[str]:
def is_binary_version_incompatible(cls, environ) -> Optional[str]:
"""
CodeChecker can only execute certain versions of analyzers.
Returns a error object (an optional string). If the return value is
Expand Down
6 changes: 2 additions & 4 deletions analyzer/codechecker_analyzer/analyzers/analyzer_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,8 +186,7 @@ def check_supported_analyzers(analyzers):
# Check version compatibility of the analyzer binary.
if analyzer_bin:
analyzer = supported_analyzers[analyzer_name]
error = analyzer.is_binary_version_incompatible(analyzer_bin,
check_env)
error = analyzer.is_binary_version_incompatible(check_env)
if error:
failed_analyzers.add((analyzer_name,
f"Incompatible version: {error}"))
Expand Down Expand Up @@ -221,8 +220,7 @@ def construct_analyzer(buildaction,
LOG.error('Unsupported analyzer type: %s', analyzer_type)
return analyzer

except Exception as ex:
LOG.debug_analyzer(ex)
except Exception:
# We should've detected well before this point that something is off
# with the analyzer. We can't recover here.
raise
Expand Down
14 changes: 8 additions & 6 deletions analyzer/codechecker_analyzer/analyzers/clangsa/analyzer.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,16 +171,18 @@ def __add_plugin_load_flags(cls, analyzer_cmd: List[str]):
analyzer_cmd.extend(["-load", plugin])

@classmethod
def get_version(cls, env=None):
""" Get analyzer version information. """
version = [cls.analyzer_binary(), '--version']
def get_binary_version(self, environ, details=False) -> str:
if details:
version = [self.analyzer_binary(), '--version']
else:
version = [self.analyzer_binary(), '-dumpversion']
try:
output = subprocess.check_output(version,
env=env,
env=environ,
universal_newlines=True,
encoding="utf-8",
errors="ignore")
return output
return output.strip()
except (subprocess.CalledProcessError, OSError) as oerr:
LOG.warning("Failed to get analyzer version: %s",
' '.join(version))
Expand Down Expand Up @@ -578,7 +580,7 @@ def resolve_missing_binary(cls, configured_binary, environ):
return clang

@classmethod
def is_binary_version_incompatible(cls, configured_binary, environ):
def is_binary_version_incompatible(cls, environ):
"""
We support pretty much every ClangSA version.
"""
Expand Down
23 changes: 17 additions & 6 deletions analyzer/codechecker_analyzer/analyzers/clangtidy/analyzer.py
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,16 @@ def need_asterisk(checker: str) -> bool:
return result


def parse_version(tidy_output):
"""
Parse clang-tidy version output and return the version number.
"""
version_re = re.compile(r'.*version (?P<version>[\d\.]+)', re.S)
match = version_re.match(tidy_output)
if match:
return match.group('version')


class ClangTidy(analyzer_base.SourceAnalyzer):
"""
Constructs the clang tidy analyzer commands.
Expand All @@ -220,16 +230,17 @@ def analyzer_binary(cls):
.analyzer_binaries[cls.ANALYZER_NAME]

@classmethod
def get_version(cls, env=None):
""" Get analyzer version information. """
version = [cls.analyzer_binary(), '--version']
def get_binary_version(self, environ, details=False) -> str:
version = [self.analyzer_binary(), '--version']
try:
output = subprocess.check_output(version,
env=env,
env=environ,
universal_newlines=True,
encoding="utf-8",
errors="ignore")
return output
if details:
return output.strip()
return parse_version(output)
except (subprocess.CalledProcessError, OSError) as oerr:
LOG.warning("Failed to get analyzer version: %s",
' '.join(version))
Expand Down Expand Up @@ -533,7 +544,7 @@ def resolve_missing_binary(cls, configured_binary, environ):
return clangtidy

@classmethod
def is_binary_version_incompatible(cls, configured_binary, environ):
def is_binary_version_incompatible(cls, environ):
"""
We support pretty much every Clang-Tidy version.
"""
Expand Down
36 changes: 10 additions & 26 deletions analyzer/codechecker_analyzer/analyzers/cppcheck/analyzer.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ def parse_version(cppcheck_output):
version_re = re.compile(r'^Cppcheck (?P<version>[\d\.]+)')
match = version_re.match(cppcheck_output)
if match:
return StrictVersion(match.group('version'))
return match.group('version')


class Cppcheck(analyzer_base.SourceAnalyzer):
Expand All @@ -83,16 +83,18 @@ def analyzer_binary(cls):
.analyzer_binaries[cls.ANALYZER_NAME]

@classmethod
def get_version(cls, env=None):
def get_binary_version(self, environ, details=False) -> str:
""" Get analyzer version information. """
version = [cls.analyzer_binary(), '--version']
version = [self.analyzer_binary(), '--version']
try:
output = subprocess.check_output(version,
env=env,
env=environ,
universal_newlines=True,
encoding="utf-8",
errors="ignore")
return output
if details:
return output.strip()
return parse_version(output)
except (subprocess.CalledProcessError, OSError) as oerr:
LOG.warning("Failed to get analyzer version: %s",
' '.join(version))
Expand Down Expand Up @@ -334,33 +336,15 @@ def resolve_missing_binary(cls, configured_binary, env):
return cppcheck

@classmethod
def __get_analyzer_version(cls, analyzer_binary, env):
"""
Return the analyzer version.
"""
command = [analyzer_binary, "--version"]

try:
result = subprocess.check_output(
command,
env=env,
encoding="utf-8",
errors="ignore")
return parse_version(result)
except (subprocess.CalledProcessError, OSError):
return []

@classmethod
def is_binary_version_incompatible(cls, configured_binary, environ):
def is_binary_version_incompatible(cls, environ):
"""
Check the version compatibility of the given analyzer binary.
"""
analyzer_version = \
cls.__get_analyzer_version(configured_binary, environ)
analyzer_version = cls.get_binary_version(environ)

# The analyzer version should be above 1.80 because '--plist-output'
# argument was introduced in this release.
if analyzer_version >= StrictVersion("1.80"):
if StrictVersion(analyzer_version) >= StrictVersion("1.80"):
return None

return "CppCheck binary found is too old at " \
Expand Down
23 changes: 9 additions & 14 deletions analyzer/codechecker_analyzer/analyzers/gcc/analyzer.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,6 @@ def analyzer_binary(cls):
return analyzer_context.get_context() \
.analyzer_binaries[cls.ANALYZER_NAME]

@classmethod
def get_version(cls, env=None):
""" Get analyzer version information. """
return cls.__get_analyzer_version(cls.analyzer_binary(), env)

def add_checker_config(self, checker_cfg):
# TODO
pass
Expand Down Expand Up @@ -174,19 +169,20 @@ def resolve_missing_binary(cls, configured_binary, env):
pass

@classmethod
def __get_analyzer_version(cls, analyzer_binary, env):
def get_binary_version(self, environ, details=False) -> str:
"""
Return the analyzer version.
"""
# --version outputs a lot of garbage as well (like copyright info),
# this only contains the version info.
version = [analyzer_binary, '-dumpfullversion']
if details:
version = [self.analyzer_binary(), '--version']
else:
version = [self.analyzer_binary(), '-dumpfullversion']
try:
output = subprocess.check_output(version,
env=env,
env=environ,
encoding="utf-8",
errors="ignore")
return output
return output.strip()
except (subprocess.CalledProcessError, OSError) as oerr:
LOG.warning("Failed to get analyzer version: %s",
' '.join(version))
Expand All @@ -195,12 +191,11 @@ def __get_analyzer_version(cls, analyzer_binary, env):
return None

@classmethod
def is_binary_version_incompatible(cls, configured_binary, environ):
def is_binary_version_incompatible(cls, environ):
"""
Check the version compatibility of the given analyzer binary.
"""
analyzer_version = \
cls.__get_analyzer_version(configured_binary, environ)
analyzer_version = cls.get_binary_version(environ)

# The analyzer version should be above 13.0.0 because the
# '-fdiagnostics-format=sarif-file' argument was introduced in this
Expand Down
Loading
Loading