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.