-
Notifications
You must be signed in to change notification settings - Fork 55
Configure ci clang tidy report #338
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
Open
filipe-cuim
wants to merge
34
commits into
eclipse-openbsw:main
Choose a base branch
from
filipe-cuim:ConfigureCIClangTidyReport
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
34 commits
Select commit
Hold shift + click to select a range
73e4ef4
Create clang-tidy report in CI
filipe-cuim 74786b2
Fix llvm-namespace-comment
filipe-cuim 07b3780
Fix bugprone-too-small-loop-variable
filipe-cuim 9933cc3
Fix clang-analyzer-deadcode.DeadStores
filipe-cuim 3321a9a
Fix clang-analyzer-core.NonNullParamChecker
filipe-cuim ae14739
Fix bugprone-implicit-widening-of-multiplication-result
filipe-cuim c2b52bb
Fix bugprone-reserved-identifier
filipe-cuim 8597487
Fix bugprone-branch-clone
filipe-cuim 9a44142
Fix bugprone-narrowing-conversions
filipe-cuim a651908
Fix llvm-qualified-auto
filipe-cuim 4041057
Fix google-readability-casting
filipe-cuim f7717b5
Fix llvm-else-after-return
filipe-cuim ce90d0a
Update clang-tidy script with arguments
filipe-cuim 4dc46b4
Update requirements.txt
filipe-cuim dc85b04
Address comments
filipe-cuim a26b24a
Fix clang-analyzer-core.NullDereference
filipe-cuim bcdb8e1
Fix clang-analyzer-security.insecureAPI.strcpy
filipe-cuim b6d7e14
Fix clang-analyzer-core.CallAndMessage
filipe-cuim 440d113
Fix clang-diagnostic-error related to bspIo
filipe-cuim 69a4f71
Suppress bugprone-unhandled-self-assignment
filipe-cuim b0aa497
Suppress bugprone-exception-escape
filipe-cuim c435fee
Suppress bugprone-unhandled-self-assignment
filipe-cuim d45d7f7
Fix cert-err58-cpp
filipe-cuim 13b23ee
Suppress cert-dcl50-cpp
filipe-cuim 7817bb3
Suppress cert-dcl37-c
filipe-cuim c053b38
Suppress cert-dcl51-cpp
filipe-cuim 8684f64
Fix cert-err33-c
filipe-cuim 8bd882b
Fix cert-dcl51-cpp
filipe-cuim 3cfec67
Suppress cert-msc30-c and others related
filipe-cuim e9a4ea5
Fix .clang-tidy config error
filipe-cuim 0e6c20b
Suppress clang-analyzer-core.DivideZero
filipe-cuim b8f1625
Ignore clang-diagnostic-error for now at script level
filipe-cuim 96927fc
Disable cert-dcl37-c and cert-dcl51-cpp globally
filipe-cuim 32d6b0f
Upload clang-tidy report only if findings are found
filipe-cuim File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,230 @@ | ||
| """ | ||
| Clang-tidy Checker | ||
| ================== | ||
| This script runs the llvm helper tool run-clang-tidy on all compilation units specified by compile_commands.json. | ||
| It filters out files from excluded directories (by default: 3rdparty), exports the findings to a specified YAML file, | ||
| and generates a detailed report with the number of findings per diagnostic which is printed to stdout. | ||
|
|
||
| The script exits with: | ||
| - Exit code 0: No findings detected | ||
| - Exit code 1: Findings were detected or an error occurred | ||
| """ | ||
|
|
||
| import argparse | ||
| import subprocess | ||
| import sys | ||
| import yaml | ||
| from pathlib import Path | ||
| from collections import Counter | ||
|
|
||
|
|
||
| def parse_arguments(): | ||
| """ | ||
| Parse command line arguments. | ||
|
|
||
| Returns: | ||
| argparse.Namespace: Parsed command line arguments | ||
| """ | ||
| parser = argparse.ArgumentParser( | ||
| description="Run clang-tidy on a CMake build directory and analyze findings.", | ||
| formatter_class=argparse.RawDescriptionHelpFormatter, | ||
| epilog=""" | ||
| Examples: | ||
| %(prog)s --build_directory build/tests/posix/Debug --output_file ct-findings.yaml | ||
| %(prog)s --build_directory build/tests/posix/Debug --output_file ct-findings.yaml --exclude "test|mock" | ||
| %(prog)s --build_directory build/tests/posix/Debug --output_file ct-findings.yaml --quiet | ||
| %(prog)s --build_directory build/tests/posix/Debug --output_file ct-findings.yaml --verbose | ||
| """, | ||
| ) | ||
|
|
||
| parser.add_argument( | ||
| "--build_directory", | ||
| type=Path, | ||
| help="Path to the build directory containing compile_commands.json generated by CMake", | ||
| required=True, | ||
| ) | ||
|
|
||
| parser.add_argument( | ||
| "--output_file", | ||
| type=str, | ||
| help="Path to the output YAML file where clang-tidy findings will be stored", | ||
filipe-cuim marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| required=True, | ||
| ) | ||
|
|
||
| parser.add_argument( | ||
| "--exclude", | ||
| type=str, | ||
| default="3rdparty", | ||
| help="Regular expression pattern to match files to exclude (default: '3rdparty')", | ||
| ) | ||
|
|
||
| parser.add_argument( | ||
| "--ignore-checks", | ||
| type=str, | ||
| default="", | ||
| help="Comma-separated list of diagnostic names to ignore (e.g., 'clang-diagnostic-error,clang-diagnostic-warning')", | ||
| ) | ||
|
|
||
| output_group = parser.add_mutually_exclusive_group() | ||
| output_group.add_argument( | ||
| "--quiet", | ||
| action="store_true", | ||
| help="Suppress run-clang-tidy progress output (default)", | ||
| ) | ||
|
|
||
| output_group.add_argument( | ||
| "--verbose", | ||
| action="store_true", | ||
| help="Show run-clang-tidy progress output", | ||
| ) | ||
|
|
||
| args = parser.parse_args() | ||
|
|
||
| # Validate that build directory exists | ||
| if not args.build_directory.exists(): | ||
| parser.error(f"Build directory does not exist: {args.build_directory}") | ||
|
|
||
| # Validate that compile_commands.json exists in build directory | ||
| compile_commands = args.build_directory / "compile_commands.json" | ||
| if not compile_commands.exists(): | ||
| parser.error( | ||
| f"compile_commands.json not found in build directory: {args.build_directory}" | ||
| ) | ||
|
|
||
| return args | ||
|
|
||
|
|
||
| def count_findings(file_name: Path, ignored_checks: list = []) -> int: | ||
| """ | ||
| Reads the YAML file generated by clang-tidy and counts the number of findings per diagnostic name. | ||
|
|
||
| Args: | ||
| file_name: Path to the YAML file containing clang-tidy findings | ||
| ignored_checks: List of diagnostic names to ignore | ||
|
|
||
| Returns: | ||
| Total number of findings (excluding ignored checks) | ||
| """ | ||
|
|
||
| with open(file_name, "r") as f: | ||
| data = yaml.safe_load(f) | ||
|
|
||
| # Count findings per diagnostic name | ||
| counter = Counter() | ||
| ignored_counter = Counter() | ||
|
|
||
| for diagnostic in data.get("Diagnostics", []): | ||
| diagnostic_name = diagnostic.get("DiagnosticName") | ||
| if diagnostic_name: | ||
| if diagnostic_name in ignored_checks: | ||
| ignored_counter[diagnostic_name] += 1 | ||
| else: | ||
| counter[diagnostic_name] += 1 | ||
|
|
||
| # Sort by count (descending) and then by name | ||
| sorted_findings = sorted(counter.items(), key=lambda x: (-x[1], x[0])) | ||
|
|
||
| # Print the report | ||
| total_findings = sum(counter.values()) | ||
| total_ignored = sum(ignored_counter.values()) | ||
| print("Clang-Tidy Findings Report") | ||
| print("=" * 60) | ||
| print(f"\nTotal unique checks: {len(sorted_findings)}") | ||
| print(f"Total findings: {total_findings}") | ||
| if total_ignored > 0: | ||
| print(f"Total ignored findings: {total_ignored}") | ||
|
|
||
| if sorted_findings: | ||
| print("\nFindings per check:") | ||
| print("-" * 60) | ||
|
|
||
| for check_name, count in sorted_findings: | ||
| print(f"{check_name}: {count}") | ||
| else: | ||
| print("\n✓ No findings detected!") | ||
|
|
||
| if total_ignored > 0: | ||
| print("\nIgnored findings:") | ||
| print("-" * 60) | ||
| for check_name, count in sorted( | ||
| ignored_counter.items(), key=lambda x: (-x[1], x[0]) | ||
| ): | ||
| print(f"{check_name}: {count}") | ||
|
|
||
| return total_findings | ||
|
|
||
|
|
||
| def run_clang_tidy( | ||
| build_dir: Path, output_file: Path, exclude_pattern: str, quiet: bool | ||
| ) -> int: | ||
| """ | ||
| Run clang-tidy on the build directory. | ||
|
|
||
| Args: | ||
| build_dir: Path to the build directory | ||
| output_file: Path to the output YAML file | ||
| exclude_pattern: Regular expression pattern to exclude files | ||
| quiet: Whether to suppress run-clang-tidy output | ||
|
|
||
| Returns: | ||
| Return code from run-clang-tidy | ||
| """ | ||
| # Convert the exclusion pattern to a negative lookahead pattern | ||
| # This makes run-clang-tidy check files that DO NOT match the exclude pattern | ||
| negated_pattern = f"^(?!.*({exclude_pattern})).*" | ||
|
|
||
| cmd = [ | ||
| "run-clang-tidy-17.py", | ||
| "-p", | ||
| str(build_dir), | ||
| "-export-fixes", | ||
| str(output_file), | ||
| negated_pattern, | ||
| ] | ||
|
|
||
| if quiet: | ||
| cmd.insert(3, "-quiet") | ||
|
|
||
| try: | ||
| result = subprocess.run(cmd, check=False) | ||
| return result.returncode | ||
| except FileNotFoundError: | ||
| print( | ||
| "Error: run-clang-tidy not found. Please ensure LLVM tools are installed.", | ||
| file=sys.stderr, | ||
| ) | ||
| sys.exit(1) | ||
| except Exception as e: | ||
| print(f"Error running clang-tidy: {e}", file=sys.stderr) | ||
| sys.exit(1) | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| args = parse_arguments() | ||
|
|
||
| print(f"Running clang-tidy on build directory: {args.build_directory}") | ||
| print(f"Output file: {args.output_file}") | ||
| print(f"Exclude pattern: {args.exclude}") | ||
| print("-" * 60) | ||
|
|
||
| # Run clang-tidy | ||
| run_clang_tidy( | ||
| args.build_directory, | ||
| args.output_file, | ||
| args.exclude, | ||
| not args.verbose, # quiet mode is default unless --verbose is specified | ||
| ) | ||
|
|
||
| # Parse ignored checks | ||
| ignored_checks = [ | ||
| check.strip() for check in args.ignore_checks.split(",") if check.strip() | ||
| ] | ||
|
|
||
| # Count and report findings | ||
| number_of_findings = count_findings(args.output_file, ignored_checks) | ||
|
|
||
| # Exit with appropriate code | ||
| if number_of_findings != 0: | ||
| sys.exit(1) | ||
| else: | ||
| sys.exit(0) | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.