name: Clang

on:
  push:
    branches: ["master"]
    tags: ["4.*"]
  pull_request:
    branches: ["master"]

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

jobs:
  format:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6

      - name: Install dependencies
        uses: ./.github/workflows/actions/ubuntu-build-deps
        with:
          SUDO: true

      - name: Install `clang-format-15`
        run: sudo apt install -y clang-format-15
      - name: Prepare `clang-format`
        run: |
          set -e
          if which clang-format-15 2>&1 >/dev/null
          then
              sudo cp $(which clang-format-15) $(which clang-format)
          fi
          clang-format --version

      - run: ./configure

      - run: make lint

  sanitize:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        sanitizer:
          - address,pointer-compare,pointer-subtract
          - thread
    env:
      CFLAGS:       -fno-omit-frame-pointer -fstack-protector-all -fsanitize=${{ matrix.sanitizer }},bounds,enum -fsanitize-address-use-after-scope -fsanitize-address-use-after-return=always -fsanitize-recover=address -fsanitize-memory-track-origins=2
      CC:           clang
      ASAN_OPTIONS: strict_string_checks=1:detect_stack_use_after_return=1:check_initialization_order=1:detect_leaks=0:detect_invalid_pointer_pairs=1:halt_on_error=0
    steps:
      - uses: actions/checkout@v6

      - name: Install dependencies
        uses: ./.github/workflows/actions/ubuntu-build-deps
        with:
          SUDO: true

      - run: ./configure
      - run: make -j $(nproc)

      - run: make check

      - run: ./run_tests.sh
        working-directory: examples/
      - run: ./run_tests_conf.sh
        working-directory: examples/

  tidy:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        config: ["Release"]
    steps:
      - uses: actions/checkout@v6

      - name: Install dependencies
        uses: ./.github/workflows/actions/ubuntu-build-deps
        with:
          SUDO: true

      - name: Configure
        run: cmake -G Ninja -B build -DCMAKE_BUILD_TYPE=${{ matrix.config }} 
                                     -DCMAKE_EXPORT_COMPILE_COMMANDS=true
      - name: Compile
        run: cmake --build build --parallel --config ${{ matrix.config }}

      # Implicitly requires `build/compile_commands.json` to exist
      - name: Run `clang-tidy`
        run: |
          set -e
          wget https://raw.githubusercontent.com/llvm/llvm-project/llvmorg-14.0.6/clang-tools-extra/clang-tidy/tool/run-clang-tidy.py
          chmod +x run-clang-tidy.py
          ./run-clang-tidy.py -j $(nproc) -p build

      # Implicitly requires `build/compile_commands.json` to exist
      - name: Run IWYU
        run: |
          set -e
          wget https://raw.githubusercontent.com/include-what-you-use/include-what-you-use/clang_14/iwyu_tool.py
          chmod +x iwyu_tool.py
          # iwyu_tool.py returns non-zero if any executions returned nonzero. Which... happens to be useless unless the project is already IWYU clean.
          ./iwyu_tool.py -j $(nproc) -p build -- -Xiwyu --mapping_file=${GITHUB_WORKSPACE}/iwyu-ubuntu.imp | grep -v "has correct" | uniq || exit 0
