Files
clice/scripts/run_clang_tidy.py
ykiko 342d82a7aa chore: add CLAUDE.md, clang-tidy, and agent workflow tooling (#419)
## Summary
- Add `.claude/CLAUDE.md` with project guide, C++ coding style,
correction patterns from past AI interactions, and pre-commit/pre-PR
workflows
- Add `.claude/commands/` with `/build`, `/test`, `/format` slash
commands for Claude Code
- Add `.clang-tidy` configuration
- Add `scripts/run_clang_tidy.py` for parallel clang-tidy with progress
reporting (reads CDB, filters to `src/` and `tests/` only)
- Add pixi tasks: `clang-tidy`, `lint-cpp`, `lint-python`, `lint`
- Add `clang-tools` dependency for clang-tidy
- Update `.gitignore` to track `.claude/CLAUDE.md` and
`.claude/commands/`

## Test plan
- [x] `pixi run format` passes
- [x] `pixi run lint-python` passes (ruff check)
- [x] `scripts/run_clang_tidy.py` correctly filters to project files
only

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 19:09:39 +08:00

67 lines
1.9 KiB
Python

#!/usr/bin/env python3
"""Run clang-tidy in parallel on all files in compile_commands.json."""
import json
import subprocess
import sys
import threading
from concurrent.futures import ThreadPoolExecutor, as_completed
from pathlib import Path
def main():
build_dir = sys.argv[1] if len(sys.argv) > 1 else "build/RelWithDebInfo"
cdb_path = Path(build_dir) / "compile_commands.json"
if not cdb_path.exists():
print(f"Error: {cdb_path} not found. Run cmake-config first.", file=sys.stderr)
sys.exit(1)
project_root = Path(__file__).resolve().parent.parent
src_dirs = (project_root / "src", project_root / "tests")
cdb = json.loads(cdb_path.read_text())
files = [
entry["file"]
for entry in cdb
if any(Path(entry["file"]).resolve().is_relative_to(d) for d in src_dirs)
]
total = len(files)
lock = threading.Lock()
done = 0
failed = []
def run(file: str) -> tuple[str, int, str]:
result = subprocess.run(
["clang-tidy", "-p", build_dir, "--quiet", file],
capture_output=True,
text=True,
)
return file, result.returncode, result.stdout + result.stderr
with ThreadPoolExecutor() as pool:
futures = {pool.submit(run, f): f for f in files}
for future in as_completed(futures):
file, code, output = future.result()
with lock:
done += 1
name = Path(file).name
if code != 0:
failed.append(file)
print(f"[{done}/{total}] FAIL {name}")
if output.strip():
print(output, end="")
else:
print(f"[{done}/{total}] OK {name}")
if failed:
print(f"\nclang-tidy failed on {len(failed)}/{total} files.", file=sys.stderr)
sys.exit(1)
print(f"\nclang-tidy passed on {total} files.")
if __name__ == "__main__":
main()