Kelsidavis-WoWee/test.sh
2026-03-28 11:45:09 +03:00

133 lines
4.6 KiB
Bash
Executable file

#!/usr/bin/env bash
# test.sh — Run the C++ linter (clang-tidy) against all first-party sources.
#
# Usage:
# ./test.sh # lint src/ and include/ using build/compile_commands.json
# FIX=1 ./test.sh # apply suggested fixes automatically (use with care)
#
# Exit code is non-zero if any clang-tidy diagnostic is emitted.
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$SCRIPT_DIR"
# ---------------------------------------------------------------------------
# Dependency check
# ---------------------------------------------------------------------------
CLANG_TIDY=""
for candidate in clang-tidy clang-tidy-18 clang-tidy-17 clang-tidy-16 clang-tidy-15 clang-tidy-14; do
if command -v "$candidate" >/dev/null 2>&1; then
CLANG_TIDY="$candidate"
break
fi
done
if [[ -z "$CLANG_TIDY" ]]; then
echo "clang-tidy not found. Install it with:"
echo " sudo apt-get install clang-tidy"
exit 1
fi
echo "Using: $($CLANG_TIDY --version | head -1)"
# run-clang-tidy runs checks in parallel; fall back to sequential if absent.
RUN_CLANG_TIDY=""
for candidate in run-clang-tidy run-clang-tidy-18 run-clang-tidy-17 run-clang-tidy-16 run-clang-tidy-15 run-clang-tidy-14; do
if command -v "$candidate" >/dev/null 2>&1; then
RUN_CLANG_TIDY="$candidate"
break
fi
done
# ---------------------------------------------------------------------------
# Build database check
# ---------------------------------------------------------------------------
COMPILE_COMMANDS="$SCRIPT_DIR/build/compile_commands.json"
if [[ ! -f "$COMPILE_COMMANDS" ]]; then
echo "compile_commands.json not found at $COMPILE_COMMANDS"
echo "Run cmake first: cmake -B build -DCMAKE_EXPORT_COMPILE_COMMANDS=ON"
exit 1
fi
# ---------------------------------------------------------------------------
# Source files to check (first-party only)
# ---------------------------------------------------------------------------
mapfile -t SOURCE_FILES < <(
find "$SCRIPT_DIR/src" -type f \( -name '*.cpp' -o -name '*.cxx' -o -name '*.cc' \) | sort
)
if [[ ${#SOURCE_FILES[@]} -eq 0 ]]; then
echo "No source files found in src/"
exit 0
fi
echo "Linting ${#SOURCE_FILES[@]} source files..."
# ---------------------------------------------------------------------------
# Resolve GCC C++ stdlib include paths for clang-tidy
#
# compile_commands.json is generated by GCC. When clang-tidy processes those
# commands with its own clang driver it cannot locate GCC's libstdc++ headers.
# We query GCC for its include search list and forward each path as an
# -isystem extra argument so clang-tidy can find <vector>, <string>, etc.
# ---------------------------------------------------------------------------
EXTRA_TIDY_ARGS=() # for direct clang-tidy: --extra-arg=...
EXTRA_RUN_ARGS=() # for run-clang-tidy: -extra-arg=...
if command -v gcc >/dev/null 2>&1; then
while IFS= read -r inc_path; do
[[ -d "$inc_path" ]] || continue
EXTRA_TIDY_ARGS+=("--extra-arg=-isystem${inc_path}")
EXTRA_RUN_ARGS+=("-extra-arg=-isystem${inc_path}")
done < <(
gcc -E -x c++ - -v < /dev/null 2>&1 \
| sed -n '/#include <\.\.\.> search starts here:/,/End of search list\./p' \
| grep '^ ' \
| sed 's/^ //'
)
fi
# ---------------------------------------------------------------------------
# Run
# ---------------------------------------------------------------------------
FIX="${FIX:-0}"
FIX_FLAG=""
if [[ "$FIX" == "1" ]]; then
FIX_FLAG="-fix"
echo "Fix mode enabled — applying suggested fixes."
fi
FAILED=0
if [[ -n "$RUN_CLANG_TIDY" ]]; then
echo "Running via $RUN_CLANG_TIDY (parallel)..."
# run-clang-tidy takes a source-file regex; match our src/ tree
SRC_REGEX="$(echo "$SCRIPT_DIR/src" | sed 's|/|\\/|g')"
"$RUN_CLANG_TIDY" \
-clang-tidy-binary "$CLANG_TIDY" \
-p "$SCRIPT_DIR/build" \
$FIX_FLAG \
"${EXTRA_RUN_ARGS[@]}" \
"$SRC_REGEX" || FAILED=$?
else
echo "run-clang-tidy not found; running sequentially..."
for f in "${SOURCE_FILES[@]}"; do
"$CLANG_TIDY" \
-p "$SCRIPT_DIR/build" \
$FIX_FLAG \
"${EXTRA_TIDY_ARGS[@]}" \
"$f" || FAILED=$?
done
fi
# ---------------------------------------------------------------------------
# Result
# ---------------------------------------------------------------------------
if [[ $FAILED -ne 0 ]]; then
echo ""
echo "clang-tidy reported issues. Fix them or add suppressions in .clang-tidy."
exit 1
fi
echo ""
echo "Lint passed."