This is an archive of the discontinued LLVM Phabricator instance.

[clangd] Publish diagnostics with stale preambles
ClosedPublic

Authored by kadircet on Feb 21 2023, 1:06 AM.

Details

Summary

This patch achieves this by building an AST and invoking main file
callbacks on each update, in addition to preamble updates.

It means we might have some extra AST builds now (e.g. if an update was
with a stale preamble and there were no reads on it, we would only build
an AST once we had the fresh preamble. Now we'll build 2, once with the
stale preamble and another with the fresh one, but we'll have one more
diagnostics cycle in between.).

This patch preserves forward progress of diagnostics by always using the
latest main file contents when emitting diagnostics after preamble
builds. It also guarantees eventual consistency:

  • if an update doesn't invalidate preamble, we'll emit diagnostics with fresh preamble already.
  • if an update invalidates preamble, we'll first emit diagnostics with stale contents, and then once the preamble build finishes it'll emit diagnostics (as preamble has changed) with newest version.

This has implications on parsing callbacks, as previously onMainAST
callback was called at most once, now it can be called up to 2 times.
All of the existing clients can already deal with callback firing
multiple times.

Diff Detail

Event Timeline

kadircet created this revision.Feb 21 2023, 1:06 AM
Herald added a project: Restricted Project. · View Herald TranscriptFeb 21 2023, 1:06 AM
kadircet requested review of this revision.Feb 21 2023, 1:06 AM

Looks pretty good. I think we can build the main file & preamble in parallel. Otherwise nits.

clang-tools-extra/clangd/TUScheduler.cpp
946

We should probably kick off the preamble rebuild before doing this synchronous AST rebuild, so the two can run in parallel.

1134

This explanation focuses on the potential problems (why the other behavior is wrong) and on the AllowStalePreamble mode only. I think it would be more enlightening to talk both about problems and correctness, and about the old mode and the new mode.

Maybe:

The file may have been edited since we started building this preamble.

If diagnostics need a fresh preamble, we must use the old version that matches the preamble. We make forward progress as updatePreamble() receives increasing versions, and this is the only place we emit diagnostics.

If diagnostics can use a stale preamble, we use the current contents of the file instead.
This provides more up-to-date diagnostics, and avoids diagnostics going backwards (we may have already emitted staler-preamble diagnostics for the new version). We still have eventual consistency: at some point updatePreamble() will catch up to the current file.
clang-tools-extra/clangd/unittests/TUSchedulerTests.cpp
1203

class comment?

// Callbacks that blocks the preamble thread after the first preamble is built.

1226

having a method on the PreambleCallbacks which calls update() on the scheduler seems pretty confusing - outside its responsibilities.

I'd suggest just moving this method and its associated state out of the class, and have onMainAST just invoke a callback. (I see the appeal of wrapping this in a class, I just don't think it should be *this* class)

1237

this nullopt stuff isn't used in the test, ADD_FAILURE and return something random instead?

1261

this should rather be *Unblock*Preamble, I think, as that's what triggering it does?

I'd suggest using this name rather than N inside the class too, would make it a bit less mysterious

1273

nit: Pair("1", "1") - tests should be explicit rather than DRY
maybe even Pair(/*Preamble=*/"1", /*Main=*/"1")

(and in the next two - the "eventual consistency" assert is probably fine as-is I think)

kadircet updated this revision to Diff 499224.Feb 21 2023, 10:20 AM
kadircet marked 7 inline comments as done.
  • Notify preamble peer before building an AST, to concurrently build fresh preamble & AST.
  • Refactoring for tests
sammccall accepted this revision.Feb 22 2023, 5:43 AM
This revision is now accepted and ready to land.Feb 22 2023, 5:43 AM
This revision was landed with ongoing or failed builds.Feb 22 2023, 6:55 AM
This revision was automatically updated to reflect the committed changes.