-
Notifications
You must be signed in to change notification settings - Fork 54
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
32
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
32 commits
Select commit
Hold shift + click to select a range
2646e4b
Create clang-tidy report in CI
filipe-cuim 6d28326
Fix llvm-namespace-comment
filipe-cuim 244baea
Fix bugprone-too-small-loop-variable
filipe-cuim 88abe96
Fix clang-analyzer-deadcode.DeadStores
filipe-cuim ec30f62
Fix clang-analyzer-core.NonNullParamChecker
filipe-cuim 1488f1d
Fix bugprone-implicit-widening-of-multiplication-result
filipe-cuim 902f706
Fix bugprone-reserved-identifier
filipe-cuim 67238c5
Fix bugprone-branch-clone
filipe-cuim 2b3363f
Fix bugprone-narrowing-conversions
filipe-cuim aa69f42
Fix llvm-qualified-auto
filipe-cuim 6707211
Fix google-readability-casting
filipe-cuim 260cd52
Fix llvm-else-after-return
filipe-cuim 6ce894b
Update clang-tidy script with arguments
filipe-cuim 904ba21
Update requirements.txt
filipe-cuim 80f463e
Address comments
filipe-cuim 0d0171f
Fix clang-analyzer-core.NullDereference
filipe-cuim d436606
Fix clang-analyzer-security.insecureAPI.strcpy
filipe-cuim c993114
Fix clang-analyzer-core.CallAndMessage
filipe-cuim eb5f9d0
Fix clang-diagnostic-error related to bspIo
filipe-cuim 5098ac8
Suppress bugprone-unhandled-self-assignment
filipe-cuim 7bd88c2
Suppress bugprone-exception-escape
filipe-cuim 561923b
Suppress bugprone-unhandled-self-assignment
filipe-cuim 58a2ae3
Fix cert-err58-cpp
filipe-cuim 425bb38
Suppress cert-dcl50-cpp
filipe-cuim 43f5f1a
Suppress cert-dcl37-c
filipe-cuim 05b7394
Suppress cert-dcl51-cpp
filipe-cuim d43d313
Fix cert-err33-c
filipe-cuim ce1bb67
Fix cert-dcl51-cpp
filipe-cuim e0f4a00
Suppress cert-msc30-c and others related
filipe-cuim 5ed683f
Fix .clang-tidy config error
filipe-cuim b52ac0d
Suppress clang-analyzer-core.DivideZero
filipe-cuim 19193f1
Ignore clang-diagnostic-error for now at script level
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,228 @@ | ||||||||
| """ | ||||||||
| 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", | ||||||||
| ) | ||||||||
|
|
||||||||
| parser.add_argument( | ||||||||
| "--output_file", | ||||||||
| type=str, | ||||||||
| help="Path to the output YAML file where clang-tidy findings will be stored", | ||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit:
Suggested change
|
||||||||
| ) | ||||||||
|
|
||||||||
| 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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: