diff --git a/.clang-tidy b/.clang-tidy new file mode 100644 index 00000000..da3e4cff --- /dev/null +++ b/.clang-tidy @@ -0,0 +1,44 @@ +# clang-tidy configuration for WoWee +# Targets C++20. Checks are tuned for a Vulkan/game-engine codebase: +# - reinterpret_cast, pointer arithmetic, and magic numbers are frequent +# in low-level graphics/network code, so the most aggressive +# cppcoreguidelines and readability-magic-numbers checks are disabled. +--- +Checks: > + bugprone-*, + clang-analyzer-*, + performance-*, + modernize-use-nullptr, + modernize-use-override, + modernize-use-default-member-init, + modernize-use-emplace, + modernize-loop-convert, + modernize-deprecated-headers, + modernize-make-unique, + modernize-make-shared, + readability-braces-around-statements, + readability-container-size-empty, + readability-delete-null-pointer, + readability-else-after-return, + readability-misplaced-array-index, + readability-non-const-parameter, + readability-redundant-control-flow, + readability-redundant-declaration, + readability-simplify-boolean-expr, + readability-string-compare, + -bugprone-easily-swappable-parameters, + -clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling, + -performance-avoid-endl + +WarningsAsErrors: '' + +# Suppress the noise from GCC-only LTO flags in compile_commands.json. +# clang doesn't support -fno-fat-lto-objects; this silences the harmless warning. +ExtraArgs: + - -Wno-ignored-optimization-argument + +HeaderFilterRegex: '^.*/include/.*\.hpp$' + +CheckOptions: +- key: modernize-use-default-member-init.UseAssignment + value: true diff --git a/test.sh b/test.sh new file mode 100755 index 00000000..ef600a66 --- /dev/null +++ b/test.sh @@ -0,0 +1,133 @@ +#!/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 , , 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."