Skip to content

Commit

Permalink
Merge pull request #3934 from tinloaf/adapt_clangtidy_15
Browse files Browse the repository at this point in the history
[analyzer][cmd] Adapt to new clang-tidy checker options format.
  • Loading branch information
bruntib authored Jun 19, 2023
2 parents 9649ec7 + ec38448 commit 4b91cb8
Show file tree
Hide file tree
Showing 2 changed files with 128 additions and 2 deletions.
40 changes: 38 additions & 2 deletions analyzer/codechecker_analyzer/analyzers/clangtidy/analyzer.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
import subprocess
from typing import List, Tuple

import yaml

from codechecker_common.logger import get_logger

from codechecker_analyzer import analyzer_context, env
Expand Down Expand Up @@ -55,14 +57,48 @@ def parse_checkers(tidy_output):
return checkers


def parse_checker_config_old(config_dump):
"""
Return the parsed clang-tidy config options as a list of
(flag, default_value) tuples. This variant works
for clang-tidy up to version 14.
config_dump -- clang-tidy config options YAML dump in pre-LLVM15 format.
"""
reg = re.compile(r'key:\s+(\S+)\s+value:\s+([^\n]+)')
return re.findall(reg, config_dump)


def parse_checker_config_new(config_dump):
"""
Return the parsed clang-tidy config options as a list of
(flag, default_value) tuples. This variant works
for clang-tidy starting with version 15
config_dump -- clang-tidy config options YAML dump in post-LLVM15 format.
"""
try:
data = yaml.safe_load(config_dump)
if 'CheckOptions' not in data:
return None

return [[key, value]
for (key, value) in data['CheckOptions'].items()]
except ImportError:
return None


def parse_checker_config(config_dump):
"""
Return the parsed clang-tidy config options as a list of
(flag, default_value) tuples.
config_dump -- clang-tidy config options YAML dump.
"""
reg = re.compile(r'key:\s+(\S+)\s+value:\s+([^\n]+)')
return re.findall(reg, config_dump)
result = parse_checker_config_old(config_dump)
if not result:
result = parse_checker_config_new(config_dump)

return result


def parse_analyzer_config(config_dump):
Expand Down
90 changes: 90 additions & 0 deletions analyzer/tests/unit/test_checker_option_parsing.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
# -------------------------------------------------------------------------
#
# Part of the CodeChecker project, under the Apache License v2.0 with
# LLVM Exceptions. See LICENSE for license information.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#
# -------------------------------------------------------------------------

"""
Test the parsing of checker options reported by the analyzers
"""

import unittest
from codechecker_analyzer.analyzers.clangtidy.analyzer \
import parse_checker_config as clangtidy_parse_checker_config


class ClangTidyParseCheckerConfigTest(unittest.TestCase):
"""
Test that the checker config options for clang-tidy are parsed correctly.
"""

def test_old_format(self):
"""
Test parsing of the output of 'clang-tidy -dump-config -checks=*' for
clang-tidy up to LLVM 14.
"""
OLD_FORMAT_EXAMPLE = """
---
Checks: 'clang-diagnostic-*,clang-analyzer-*,clang-diagnostic-*,\
clang-analyzer-*,bugprone-*,-bugprone-easily-swappable-parameters,\
concurrency-*,boost-*,concurrency-*,cppcoreguidelines-init-variables,\
cppcoreguidelines-special-member-functions,misc-*,\
-misc-definitions-in-headers,-misc-non-private-member-variables-in-classes,\
performance-*,-misc-const-correctness,*'
WarningsAsErrors: ''
HeaderFilterRegex: ''
AnalyzeTemporaryDtors: false
FormatStyle: none
CheckOptions:
- key: readability-suspicious-call-argument.PrefixSimilarAbove
value: '30'
- key: cppcoreguidelines-no-malloc.Reallocations
value: '::realloc'
- key: llvmlibc-restrict-system-libc-headers.Includes
value: '-*'
- key: cppcoreguidelines-owning-memory.LegacyResourceConsumers
value: '::free;::realloc;::freopen;::fclose'
- key: modernize-use-auto.MinTypeNameLength
value: '5'
- key: bugprone-reserved-identifier.Invert
value: 'false'
"""
result = clangtidy_parse_checker_config(OLD_FORMAT_EXAMPLE)
# The result can be an arbitrary iterable of pair-likes. To make
# assertions about it easer, we first convert it to a list-of-lists.
result = [[k, v] for (k, v) in result]
self.assertEqual(len(result), 6)
self.assertIn(
["readability-suspicious-call-argument.PrefixSimilarAbove",
"'30'"], result)

def test_new_format(self):
"""
Test parsing of the output of 'clang-tidy -dump-config -checks=*' for
clang-tidy starting with LLVM 15.
"""
NEW_FORMAT_EXAMPLE = """
---
Checks: 'clang-diagnostic-*,clang-analyzer-*,*'
WarningsAsErrors: ''
HeaderFilterRegex: ''
AnalyzeTemporaryDtors: false
FormatStyle: none
CheckOptions:
performance-unnecessary-value-param.IncludeStyle: llvm
readability-suspicious-call-argument.PrefixSimilarAbove: '30'
cppcoreguidelines-no-malloc.Reallocations: '::realloc'
llvmlibc-restrict-system-libc-headers.Includes: '-*'
bugprone-reserved-identifier.Invert: 'false'
cert-dcl16-c.IgnoreMacros: 'true'
"""
result = clangtidy_parse_checker_config(NEW_FORMAT_EXAMPLE)
# The result can be an arbitrary iterable of pair-likes. To make
# assertions about it easer, we first convert it to a list-of-lists.
result = [[k, v] for (k, v) in result]
self.assertEqual(len(result), 6)
self.assertIn(
["readability-suspicious-call-argument.PrefixSimilarAbove", "30"],
result)

0 comments on commit 4b91cb8

Please sign in to comment.