[PATCH] D153114: [clangd] [C++20] [Modules] Support C++20 modules for clangd

Sam McCall via Phabricator via cfe-commits cfe-commits at lists.llvm.org
Thu Aug 31 01:40:25 PDT 2023


sammccall added a comment.

In D153114#4630318 <https://reviews.llvm.org/D153114#4630318>, @ChuanqiXu wrote:

> @sammccall @nridge while I am looking for the initial support for modules in clangd, I failed to find the mechanism to update files after I update a header file.
>
> e.g., when I am opening the following file:
>
>   // a.cc
>   #include "a.h"
>   ...
>
> and there is a concurrent update to `a.h`. How can the ASTWorker of `a.cc` know such changes so that it can update the corresponding Preamble of `a.cc`?

The PrecompiledPreamble structure (defined in clang, not clangd) consists of a handle to the `*.pch` file, and also a list of filenames that it was built from. We can test whether it's out of date by `stat()`ing the input files (`PrecompiledPreamble::CanReuse`).

Once upon a time, clangd used this in a simple way: the ASTWorker always called <https://github.com/llvm/llvm-project/blob/release/10.x/clang-tools-extra/clangd/TUScheduler.cpp#L434-L442> [`clangd::buildPreamble(inputs, old preamble)`](https://github.com/llvm/llvm-project/blob/release/10.x/clang-tools-extra/clangd/Preamble.cpp#L101-L107) which would just return the old one if it was still valid.

For a while now we've had async preambles which are more complicated but use the same underlying mechanism. Each file has an ASTWorker thread and a PreambleThread. When the ASTWorker thread wants to reuse preamble, it notifies the PreambleThread "hey, maybe rebuild the preamble?" but meanwhile it charges on using the old stale preamble. The preamble asynchronously performs the validity check <https://github.com/llvm/llvm-project/blob/release/17.x/clang-tools-extra/clangd/TUScheduler.cpp#L1059-L1071>, rebuilds the preamble if needed, and eventually informs the ASTWorker which ensures the up-to-date preamble is eventually used.

This is a "pull" system: we only check if the preamble is valid when we tried to use it, i.e. when the main-file changed. If you just touch a header on disk but do nothing else, we won't rebuild either the main file or the preamble.

> In the comments of `ClangdServer::reparseOpenFilesIfNeeded()`, I see:
>
>> /// Requests a reparse of currently opened files using their latest source.
>> /// This will typically only rebuild if something other than the source has
>> /// changed (e.g. the CDB yields different flags, or **files included in the
>> /// preamble have been modified**).

Because the above is a pull system, editing a header doesn't update e.g. diagnostics in files that include that header.
So this is a workaround: it requests all files to be rebuilt from current sources, so we pull on all preambles.
Then at every layer we try to ensure this does no work if nothing has changed :-)

In practice we call this in response to didSave (user edited+saved a header in their editor), we could potentially call it in response to changes on disk as Nathan suggested, and I think we have a custom integration somewhere that calls it when we know externally that compile flags have changed.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D153114/new/

https://reviews.llvm.org/D153114



More information about the cfe-commits mailing list