This is an archive of the discontinued LLVM Phabricator instance.

[clangd] Add callbacks on parsed AST in addition to parsed preambles
ClosedPublic

Authored by ilya-biryukov on Aug 16 2018, 9:06 AM.

Details

Summary

Will be used for updating the dynamic index on updates to the open files.
Currently we collect only information coming from the preamble
AST. This has a bunch of limitations:

  • Dynamic index misses important information from the body of the file, e.g. locations of definitions.
  • XRefs cannot be collected at all, since we can only obtain full information for the current file (preamble is parsed with skipped function bodies, therefore not reliable).

This patch only adds the new callback, actually updating the index
will be added in a follow-up patch.

Diff Detail

Repository
rL LLVM

Event Timeline

ilya-biryukov created this revision.Aug 16 2018, 9:06 AM

Dynamic index misses important information from the body of the file, e.g. locations of definitions
XRefs cannot be collected at all, since we can only obtain full information for the current file (preamble is parsed with skipped function bodies, therefore not reliable).

These seem to be known limitations of the dynamic index. The dynamic index, in general, only handles things that are in headers; information in the main file can usually be obtained from Sema/AST (outside of the index). For example, definition/xrefs locations can be merged from index and the AST.

This patch only adds the new callback, actually updating the index will be added in a follow-up patch.

How do we plan to merge symbols from the preamble callback and the main file callback? The current FileIndex only allows swapping all symbols.

Dynamic index misses important information from the body of the file, e.g. locations of definitions
XRefs cannot be collected at all, since we can only obtain full information for the current file (preamble is parsed with skipped function bodies, therefore not reliable).

These seem to be known limitations of the dynamic index. The dynamic index, in general, only handles things that are in headers; information in the main file can usually be obtained from Sema/AST (outside of the index). For example, definition/xrefs locations can be merged from index and the AST.

We still want this information in the index. One can obtain this information for the current file. However, we still need to keep this info in the index for definitions in the other open files.

This patch only adds the new callback, actually updating the index will be added in a follow-up patch.

How do we plan to merge symbols from the preamble callback and the main file callback? The current FileIndex only allows swapping all symbols.

There are multiple ways to do that, lowest overhead is having two separate slabs: one for preamble symbols, another for symbols in the main file. They will be merged on-the-go when requested.

@ioeric, specifically, see D50889 for an updated FileIndex

Thanks for adding it.

clangd/TUScheduler.cpp
406 ↗(On Diff #161038)

The AST might not get built if WantDiags::No, and will be built in runWithAST.

clangd/TUScheduler.h
66 ↗(On Diff #161038)

Does the callback get called every time we built an AST? clangd only has 3 idle ASTs, if the AST is not there, we rebuild it when needed (even the source code is not changed), and we will update the dynamic index, which seems unnecessary.

It may rarely happen, 3 idle ASTs might cover most cases, I think?

ilya-biryukov added inline comments.Aug 17 2018, 8:35 AM
clangd/TUScheduler.cpp
406 ↗(On Diff #161038)

I suggest we keep it a known limitation and not rebuild the index in that case.
The original intent of WantDiags::No was to update the contents of the file, so that upcoming request can see the new contents (e.g. this is a hack to avoid passing overriden contents of the file in the request itself).
WantDiags::No is always followed by an actual request that wants the diagnostics (and will, therefore, build the AST and emit the callback).

Alternatively, we could unify the code paths building the AST. Would be a bit more intrusive change, but I guess it's worth it.

clangd/TUScheduler.h
66 ↗(On Diff #161038)

Currently we only call this when AST is built for diagnostics, so we will have only a single callback, even if the AST will be rebuilt multiple times because it was flushed out of the cash (as long as the file contents didn't change, of course).

So we do behave optimally in that case and I suggest we keep it this way

ioeric added inline comments.Aug 20 2018, 1:47 AM
clangd/TUScheduler.h
66 ↗(On Diff #161038)

is there any overlap between preamble AST and main AST? If so, could you elaborate in the documentation?

The interfaces look mostly good to me.

clangd/ClangdServer.cpp
73 ↗(On Diff #161038)

I think Ctx should be a pointer which gives us a way (passing a nullptr) to clean up the FileIndex, the same as ParsedAST below.

And I discover that we don't cleanup dynamic index when a file is being closed, is it expected or a bug?

clangd/TUScheduler.cpp
406 ↗(On Diff #161038)

I see, SG, thanks!

clangd/TUScheduler.h
66 ↗(On Diff #161038)

Currently we only call this when AST is built for diagnostics, so we will have only a single callback, even if the AST will be rebuilt multiple times because it was flushed out of the cash (as long as the file contents didn't change, of course).

It sounds reasonable, thanks for the explanation. Could you clarify it in the comment?

is there any overlap between preamble AST and main AST? If so, could you elaborate in the documentation?

AFAIK, both of them contain different TopLevelDecls, but it is still possible to get the Decl* (declared in header) when visiting the main AST (e.g. when visiting the void foo() {} definition in MainAST, we can still get the void foo(); declaration in PreambleAST).

  • Provide noop callbacks implementation by default.
  • Update docs.
ilya-biryukov added inline comments.Aug 21 2018, 7:36 AM
clangd/ClangdServer.cpp
73 ↗(On Diff #161038)

I suggest we add an extra method to DynamicIndex that we call when the file is closed. I don't think it's intentional that we don't clean up the index for the closed files.
Not sure what's the best way to handle invalid ASTs, but we're never calling the current callback with nullptr anyway, so I suggest we keep it a reference to better reflect that callbacks don't actually handle any errors for us.

hokein accepted this revision.Aug 22 2018, 1:14 AM

Thanks! Looks good.

clangd/ClangdServer.cpp
73 ↗(On Diff #161038)

SG, and it is out of scope of this patch. Let's figure it out in the clean-up-index patch.

This revision is now accepted and ready to land.Aug 22 2018, 1:14 AM
ilya-biryukov added inline comments.Aug 22 2018, 2:34 AM
clangd/ClangdServer.cpp
73 ↗(On Diff #161038)

LG, I'll come up with a follow-up cleanup patch when done with these patches

This revision was automatically updated to reflect the committed changes.