This is an archive of the discontinued LLVM Phabricator instance.

[clangd] Allow AST request without range
ClosedPublic

Authored by ckandeler on Apr 22 2021, 5:38 AM.

Details

Summary

If no range is given, return the translation unit AST.
This is useful for tooling operations that require e.g. the full path to
a node.

Diff Detail

Event Timeline

ckandeler created this revision.Apr 22 2021, 5:38 AM
ckandeler requested review of this revision.Apr 22 2021, 5:38 AM
Herald added a project: Restricted Project. · View Herald TranscriptApr 22 2021, 5:38 AM

Thanks! I'm not sure why range was required to start with, probably just lacking a use case.

Only real issue is I think we should update the signature on ClangdServer.

This is useful for tooling operations that require e.g. the full path to

a node.

This could be a fairly bulky/inefficient way of getting that though, for large files!

clang-tools-extra/clangd/ClangdServer.cpp
906

I don't think it makes sense to give an empty range this special meaning.
Can we change ClangdServer::getAST() to take an Optional<Range> instead?

clang-tools-extra/clangd/test/ast-no-range.test
1

We try to cover the features we can in gtests (here unittests/DumpASTTests.cpp) - could you add one?

(Having a lit test too is reasonable as it tests the serialization of requests etc, but not essential)

Only real issue is I think we should update the signature on ClangdServer.

Is that an action point for me?

This is useful for tooling operations that require e.g. the full path to

a node.

This could be a fairly bulky/inefficient way of getting that though, for large files!

Right, though there are probably other good reasons to have access to the full AST.
For this particular example, it might make more sense to (optionally) provide the node's parent
or indeed the AST path, but I think both of these would be more intrusive code-wise.

ckandeler updated this revision to Diff 339633.Apr 22 2021, 7:54 AM

Addressed reviewer comments.

ckandeler marked 2 inline comments as done.Apr 22 2021, 7:55 AM
ckandeler updated this revision to Diff 339948.Apr 23 2021, 2:00 AM

Addressed clang-tidy and clang-format comments

sammccall added inline comments.Apr 23 2021, 2:34 AM
clang-tools-extra/clangd/ClangdServer.cpp
895

Ooh, there's a problem here...

TraverseDecl(TranslationUnitDecl) is going to deserialize the whole preamble and try to return the AST for every decl in every included header.
Apart from a huge amount of data, it's going to be extremely slow, we try to avoid ever doing this.

I think this should be observable in a unit test: if you set TestTU.Code and TestTU.HeaderCode, we want decls from the latter not to be visible in the dumped tree.


Instead, dumpAST should call DumpVisitor.TraverseAST(), which runs over the TraversalScope forest (i.e. all the top-level decls of the current file). But we still need the TranslationUnitDecl in order to have a single root.

Therefore I think we need this logic for "full tree" dumping:

DumpVisitor.traverseNode("declaration", TUDecl, [&] { DumpVisitor.TraverseAST() });

I think it's OK to keep the dumpAST signature as-is (i.e. pass a DynTypedNode with TUDecl in it as you're doing now) and just override TraverseTranslationUnitDecl with this special case. However both dumpAST() and the callsite should have a comment saying that TranslationUnitDecl is safe/has these special semantics, as that's not typical in clangd.


(The previous version of this patch had this problem too, it was just less obvious. Sorry for not catching it in the first round!)

clang-tools-extra/clangd/ClangdServer.h
347 ↗(On Diff #339948)

Nit: we tend to pass Range etc by value rather than const ref.
I actually have no idea why! But probably best to be consistent and if we clean this up we can do it everywhere at once.

clang-tools-extra/clangd/Protocol.h
1728–1729

nit: top-level->root
(We usually use "top-level" to mean children of TUDecl)

clang-tools-extra/clangd/unittests/DumpASTTests.cpp
160 ↗(On Diff #339948)

as mentioned, this test should have decls in the header file too (HeaderCode, which is implicitly included) to make sure that we're not returning those

ckandeler updated this revision to Diff 339994.Apr 23 2021, 5:44 AM

Fixed TU traversal

ckandeler updated this revision to Diff 339995.Apr 23 2021, 5:45 AM
ckandeler marked 2 inline comments as done.

"top-level" -> "root"

ckandeler marked 2 inline comments as done.Apr 23 2021, 5:45 AM
sammccall accepted this revision.Apr 23 2021, 6:11 AM

Fantastic, thank you! Just a couple of nits.

Want me to land this for you?

clang-tools-extra/clangd/DumpAST.cpp
339 ↗(On Diff #339995)

The naming causes a bit of confusion over whether this is a (CRTP) override of a RecursiveASTVisitor method. (It's not, as that method is called TraverseTranslationUnitDecl).

I'd suggest either:

  • (trivial) rename to traverseTUDecl, and move this away from the comment above that says this is overriding traversal
  • (maybe more elegant) instead of this function change the lambda inside TraverseDecl to be if (is TUDecl) TraverseAST() else Base::TraverseDecl(D). Then I don't think the special case in dumpAST() is needed at all.
405 ↗(On Diff #339995)

this comment should rather go in the .h file

This revision is now accepted and ready to land.Apr 23 2021, 6:11 AM
ckandeler updated this revision to Diff 340014.Apr 23 2021, 7:08 AM

Fixed remaining issues

ckandeler marked 2 inline comments as done.Apr 23 2021, 7:09 AM

Want me to land this for you?

Yes, please. I don't have push privileges. Thanks for the prompt and helpful review.

This revision was landed with ongoing or failed builds.Apr 23 2021, 12:35 PM
This revision was automatically updated to reflect the committed changes.