#!/usr/bin/env bash # scripts/quality/clang-tidy.sh # # Run clang-tidy over every public header under code/include/. We use # `--use-color` and tee output to build-tidy/clang-tidy.log for later # diffing. # # Local-only. The check is exploratory until we agree on which warning # classes are reasonable to enforce — CGAL header-only code triggers a # lot of `modernize-*` / `readability-*` warnings that are upstream's # choice, not ours. See `.clang-tidy` for the curated subset. # # Usage: # bash scripts/quality/clang-tidy.sh # all headers # bash scripts/quality/clang-tidy.sh code/include/CGAL # subset # # Prerequisite: a compile_commands.json with the right include paths # (cmake generates this automatically with CMAKE_EXPORT_COMPILE_COMMANDS=ON). # # Exit codes: # 0 clang-tidy ran (output captured) # 1 clang-tidy reported at least one error (post-policy filter) # 2 prerequisite missing set -euo pipefail ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" cd "$ROOT" BUILD_DIR="build-tidy" LOG="$BUILD_DIR/clang-tidy.log" command -v clang-tidy >/dev/null 2>&1 || { echo "FAIL: clang-tidy not in PATH." >&2 echo " macOS: brew install llvm && export PATH=\"\$(brew --prefix llvm)/bin:\$PATH\"" >&2 echo " Linux: sudo apt install clang-tidy" >&2 exit 2 } TARGET_DIR="${1:-code/include}" [ -d "$TARGET_DIR" ] || { echo "FAIL: $TARGET_DIR is not a directory" >&2; exit 2; } # Generate compile_commands.json (clang-tidy needs it for include paths). cmake -S code -B "$BUILD_DIR" \ -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \ -DCMAKE_BUILD_TYPE=Release \ -Wno-dev >/dev/null mkdir -p "$BUILD_DIR" : > "$LOG" # Find every .h / .hpp under TARGET_DIR (skip deps + macOS dup files). HEADERS=$(find "$TARGET_DIR" \ \( -name "*.h" -o -name "*.hpp" \) \ -type f \ | grep -v "code/deps/" \ | grep -v " 2\." \ | sort) echo "========================================" echo " clang-tidy run" echo " target: $TARGET_DIR" echo " config: .clang-tidy" echo " log: $LOG" echo "========================================" echo n=0 for h in $HEADERS; do n=$((n + 1)) echo "── [$n] $h ─────────────────────────────────" # Use --quiet so we only see actual diagnostics, not "n warnings # generated" boilerplate. Pipe through tee for the log file. clang-tidy --quiet \ -p "$BUILD_DIR" \ "$h" 2>&1 | tee -a "$LOG" || true done echo echo "── Summary ──────────────────────────────────" warn=$(grep -c "warning:" "$LOG" || true) err=$(grep -c "error:" "$LOG" || true) echo " files inspected: $n" echo " warnings: $warn" echo " errors: $err" echo " full log: $LOG" if [ "${err:-0}" -gt 0 ]; then exit 1 fi exit 0