Make clangd check your asserts even with -DNDEBUG

When you configure a CMake project with -DCMAKE_BUILD_TYPE=Release, CMake adds -DNDEBUG to every compile command, and that flag lands in your compile_commands.json. assert is a no-op when NDEBUG is defined, so clangd treats the body of every assert(...) as dead code: no autocomplete, no type checking, no diagnostics. But when you're editing code, you want asserts typechecked no matter what build type you have configured.

The fix is a .clangd file at the root of your project that strips -DNDEBUG for clangd only, without touching your actual build:

CompileFlags:
  Remove: [-DNDEBUG]

🔗 Toy example

CMakeLists.txt:

cmake_minimum_required(VERSION 3.20)
project(toy CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
add_executable(toy main.cpp)

main.cpp contains a deliberate type error inside an assert:

#include <cassert>
#include <vector>

int main() {
    std::vector<int> v;
    assert(v.size() == "oops");
}

Configure a Release build so the compile database carries -DNDEBUG:

cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release

🔗 Before

With no .clangd file, clangd picks up -DNDEBUG from the compile database, skips the assert body, and reports zero errors:

$ clangd --check=main.cpp
I Compile command from CDB is: ... -O3 -DNDEBUG -std=gnu++17 ... -c main.cpp
I All checks completed, 0 errors

🔗 After

Add the .clangd file above. clangd now drops -DNDEBUG from the compile command, the assert becomes live, and the type error surfaces:

$ clangd --check=main.cpp
I Loading config file at .../.clangd
I Compile command from CDB is: ... -O3 -std=gnu++17 ... -c main.cpp
E [typecheck_comparison_of_pointer_integer] Line 6: comparison between pointer and integer ('size_type' (aka 'unsigned long') and 'const char *')
I All checks completed, 1 errors

The Release build is unchanged; only the editor now sees the code you actually wrote inside asserts.