How CLion’s Switch to clangd Changes C++ Code Completion and Refactoring
Learn why CLion 2023.1+ uses clangd for C++ intelligence, how to keep compile_commands.json in sync, and what trade‑offs to watch for.
13 Oct 2026, 14:59 UTC

The problem: missing completions after a CLion update
\nAfter upgrading to CLion 2023.1 or later, you may notice that code completion feels slower, some diagnostics disappear, or refactorings behave differently. The IDE no longer relies on its proprietary C++ engine; instead, it delegates most language intelligence to clangd, the LLVM‑based Language Server Protocol implementation. This shift brings IDE‑agnostic features but also introduces a new dependency: a correct compile_commands.json file that tells clangd exactly how each source file is compiled.
Understanding clangd in CLion
\nCLion now starts a clangd process for each opened project. clangd reads the compile commands to build an abstract syntax tree (AST) index, which powers:
\n- \n
- Semantic code completion (with a fuzzy fallback) \n
- On‑the‑fly diagnostics (errors, warnings, clang‑tidy checks) \n
- Navigation and refactoring (Rename, Change Signature, Extract Method/Variable) \n
The engine is exposed in the IDE UI: hovering over a warning shows a badge that reads “clangd”, and the Problems tool window lists the source of each diagnostic.
\nEnsuring compile_commands.json is correct
\nCLion can generate this file automatically from CMake, Meson, or custom build scripts. To enable generation:
\n- \n
- Open Settings → Build, Execution, Deployment → CMake. \n
- Check Generate compile_commands.json. \n
- Reload the CMake project (click the reload icon in the CMake tool window). \n
- Verify that a file named
compile_commands.jsonappears at the project root. \n
The file is an array of objects, each containing:
\n{\n \"directory\": \"/path/to/project\",\n \"command\": \"/usr/bin/clang++ -std=c++20 -Iinclude -Wall -c src/foo.cpp -o src/foo.o\",\n \"file\": \"src/foo.cpp\"\n}\n\nIf you switch build configurations (e.g., Debug ↔ Release), CLion regenerates the file for the active profile, triggering a re‑index.
\nWorked example: enabling diagnostics and a cross‑file rename
\nSuppose you have a header utils.h declaring a function process_data used in main.cpp and worker.cpp. You want to rename the function to handle_data and see the change reflected everywhere.
- \n
- Make sure
compile_commands.jsonlists the correct include path forutils.h(look for-Iincludeor similar in the command strings). \n - Place the cursor on
process_datain any source file. \n - Choose Refactor → Rename… (or press
Shift+F6). \n - In the preview dialog, CLion shows a diff powered by clangd: each file that contains the symbol is highlighted, and the change list includes the exact line numbers. \n
- Click Do Refactor. CLion applies the changes and records them in the local history for undo. \n
To confirm that the diagnostic engine is indeed clangd, introduce an unused variable in main.cpp:
int main() {\n int unused = 42; // clangd will flag this\n return 0;\n}\n\nAfter saving, the gutter displays a yellow squiggle. Hovering over it shows a tooltip that includes the text “clangd”. If you disable the Generate compile_commands.json option and reload CMake, the same unused variable may no longer be highlighted, demonstrating the dependence on accurate compile commands.
\nTrade‑offs and limitations
\nWhile clangd brings many IDE‑agnostic benefits, there are practical considerations:
\n- \n
- Stale compile commands: If the build system changes but
compile_commands.jsonis not regenerated, clangd may report false‑positive diagnostics or miss completions. The fix is to enable automatic generation or manually run the build system’s equivalent of--trace-compile. \n - Memory usage: Indexing large monorepos can consume several gigabytes of RAM. You can limit the indexed directories via Settings → Languages & Frameworks → C++ → Clangd → Indexing scope or adjust clangd’s background priority with extra arguments like
-j 4. \n - C++20/23 support: Certain recent language features (e.g., modules, concepts‑heavy templates) have incomplete support in clangd compared to the legacy engine. Complex template‑dependent refactorings may be more conservative. \n
- Toolchain differences: On Windows, clangd uses clang‑cl compatibility mode; MSVC‑specific flags such as
/Zc:preprocessormay have limited effect. \n
Actionable closing: verify and tune your setup
\nFollow these steps to ensure clangd works reliably in your CLion project:
\n- \n
- Check the version: Help → About should show “clangd” in the language engine line and a version ≥ 2023.1. \n
- Enable compile command generation as described above and confirm the file exists. \n
- Run a quick diagnostic test (e.g., add an unused variable) and verify the clangd badge appears. \n
- If you notice high memory usage, open Settings → Languages & Frameworks → C++ → Clangd and set a custom indexing scope or add
--background-index-priority=lowto the clangd arguments. \n - For remote development (Docker, WSL, SSH), ensure the remote toolchain’s clangd binary matches the IDE’s expectations: Settings → Build, Execution, Deployment → Toolchains → select the remote toolchain → verify
clangd --versionmatches the IDE’s reported version. \n - When troubleshooting, consult the clangd log via Help → Diagnostic Tools → Clangd Log to see LSP traffic and indexing status. \n
By keeping compile_commands.json in sync and adjusting indexing limits, you can reap the benefits of clangd’s consistent diagnostics and refactorings while avoiding the most common pitfalls.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.