Design of clangd

A language server’s main responsibilities are:

Most of the design documentation focuses on the concepts, if you’re interested in the implementation we try to keep the code well-documented.

code walkthrough

Compile commands

Clangd needs to make choices about how to parse each open file, such as:

clangd determines a virtual compiler command for each file (e.g. clang foo.cc -Iheaders/) and uses this to configure its parser. Ideally this command comes from the build system.

Compile flags can control many subtle pieces of the clang parser, so compile commands are an important configuration point.

Compile commands

Request handling

clangd is based on the clang compiler, and at its core runs the clang parser in a loop. The parser produces diagnostics as it encounters problems, and the end result is a clang AST. The AST is saved to answer queries like “what kind of symbol is under the cursor”.

There is one such loop for each open file. The TUScheduler class manages a collection of ASTWorkers, each running on its own thread. Most operations run on these threads, though code completion is a notable exception.

threads and request handling

Index

C/C++/Objective-C are designed so that you can parse one source file at a time, without needing to see the whole program. This means that the resulting AST lacks certain information:

To solve this, clangd maintains a database of symbols found anywhere in the program, called the index. This is extracted from each open file as it is parsed, and also by parsing the whole project in the background.

the clangd index

Remote index

The remote index system allows a codebase index to be built offline and shared across many clangd instances with an RPC server.

remote index

Include Cleaner

Issues diagnostics for unused includes and provides tools for keeping a minimal set of required includes.

include cleaner

✏️