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

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to