This is an archive of the discontinued LLVM Phabricator instance.

[clangd] Smarter hover on auto and decltype
ClosedPublic

Authored by qchateau on Dec 14 2020, 8:36 AM.

Details

Reviewers
sammccall
Group Reviewers
Restricted Project
Commits
rGc46c7c9bcf97: [clangd] Smarter hover on auto and decltype
Summary

Only show the keyword as the hover "Name".

Show whether the type is deduced or undeduced as
the hover "Documentation".

Show the deduced type (if any) as the "Definition".

Don't show any hover information for:

  • the "auto" word of "decltype(auto)"
  • "auto" in lambda parameters
  • "auto" in template arguments

This diff is a suggestion based on what @sammccall suggested in https://reviews.llvm.org/D92977 about hover on "auto". It somehow "hacks" onto the "Documentation" and "Definition" fields of HoverInfo. It sure looks good on VSCode, let me know if this seem acceptable to you.

Diff Detail

Event Timeline

qchateau created this revision.Dec 14 2020, 8:36 AM
qchateau requested review of this revision.Dec 14 2020, 8:36 AM
qchateau edited the summary of this revision. (Show Details)Dec 14 2020, 8:41 AM
qchateau added reviewers: sammccall, Restricted Project.
qchateau added a subscriber: sammccall.

Thanks! This seems more consistent with our other hovers, but is going to be better-formatted/more attractive in VSCode.
There are a couple of wrinkles I'd like to discuss :-)

Brevity

This is clear and mostly consistent (documentation excepted), but uses three lines where clearly two would do - the "auto" title provides very little information, and the documentation only a bit more (pun intended!)

Can we combine them? The title has SymbolKind which normally holds the category. We can't easily add new SymbolKinds (it's an enum we don't own, which we should fix, but that's a yak-shave). But TypeAlias almost fits these roles for auto. What do you think about setting Kind/Name/Definition? This would give:

type-alias `auto`
const Foo&

This leaves the question of what to do with undeduced auto, maybe:

type-alias `auto`
/* not deduced */

(There are other cases: function parameter types void foo(auto X) and NTTP types template <auto X> class Y but we can punt on those)

this

D92041 recently added support for showing the type when hovering over this. It followed the existing auto behavior (put everything in Name) because that's the only place we were showing types per se.

So you're going to have a merge conflict, and we need to decide how to render it.

I don't really have a better idea than setting Name = "this", setting Definition, and leaving Kind=Unknown. Maybe we can do better once we can easily extend the SymbolKind enum.

qchateau updated this revision to Diff 312432.Dec 17 2020, 3:44 AM
  • Rebase on master after D92041
  • Remove the usage of the "Documentation" field
  • Use the TypeAlias Kind on auto and decltype
  • Move code related to hover on this in a new function
  • Update hover on this to be consistent with this change

We can't easily add new SymbolKinds (it's an enum we don't own, which we should fix, but that's a yak-shave). But TypeAlias almost fits these roles for auto.

Yes I originally wanted to have "deduced-type auto" but I realized it would not be easy. I did not think of TypeAlias, let's use this until we can do better.

(There are other cases: function parameter types void foo(auto X) and NTTP types template <auto X> class Y but we can punt on those)

For now I disabled them (instead of displaying nonsense as we did before). Anyway as a user, I have zero useful information to get when hovering on these word, I prefer nothing rather than a useless pop-up.

Agree with all the conclusions you've come to here. Main two issues are:

  • the new traversal added to patch up some cases isn't the right approach IMO.
  • some accidental regressions

I'd also like to distinguish decltype(auto) from other decltypes, but it's a problem with our existing helpers so let's not try that in this patch.

clang-tools-extra/clangd/Hover.cpp
618

You've rewritten this logic compared to the old getHoverContents(QualType), and I think there are regressions:

  • We've dropped class documentation (see e.g. ac3f9e48421712168884d59cbfe8b294dd76a19b, this is visible in the tests)
  • we're no longer using printName() to print tag-decls, which I expect changes e.g. the printing of anyonymous structs which is special-cased in that function (we have tests for this but probably not in combination with auto)
  • we're no longer using the printing-policy to print non-tag types, which will lead to some random changes

I don't see a reason for these changes, can we revert them?

631

This functionality (reporting the auto type in structured bindings, and not reporting non-deduced uses of auto) belongs in the getDeducedType() helper rather than as a layer on top.
(Especially because it has to be done via an AST traversal rather than SelectionTree)

I'd suggest leaving it out of this patch to get this the original change landed quickly - this seems like a mostly-unrelated enhancement. But up to you.

880

decltype(auto) and decltype(expr) are fairly different things and ultimately we should be displaying them differently I think ("decltype(auto)" vs "decltype(...)").

Unfortunately it's awkward because our getDeducedType helper handles both at the moment (and so is misnamed, because decltype(expr) isn't deduced at all).

Can you add // FIXME: distinguish decltype(auto) vs decltype(expr) and I'll do some refactoring later?

clang-tools-extra/clangd/unittests/HoverTests.cpp
986

(not convinced this is fundamentally not useful - the fact that it's a template parameter means it's probably worth having a hover card for it at some point. But I agree with suppressing it for now)

1883

can we have a decltype test where the result is dependent?
e.g..

template <typename T>
struct X {
  using Y = ^decltype(T::Z);
};

should yield a definition of "<dependent type>" rather than "/* not deduced */".
(Since regular decltype() is not a deduced type)

qchateau updated this revision to Diff 312545.Dec 17 2020, 10:06 AM
qchateau marked 3 inline comments as done.

I updated this diff according to your review. There are a few things that may still need change but I need your input, see my other comments :)

qchateau added inline comments.Dec 17 2020, 10:08 AM
clang-tools-extra/clangd/Hover.cpp
618
  • I can re-add class documentation, but should it work when auto is a pointer or a ref ? In that case, I'll need something like your unwrapType of https://reviews.llvm.org/D93314
  • printName will print C instead of class C even if I hack around and give it the right PrintingPolicy. The problem is that IDE (at least VSCode) does not know what C is and cannot color it, which looks a nice less nice. Up to you !
  • I can re-add the printing policy for non-tag types, and add it for tag-types if we chose not to use printName.
631

I'll remove this. I'll leave out the case of structured bindings for arrays (which is really weird and specific), but I guess I'll fix`getDeducedType` to return the undeduced QualType instead of None (which it already does but only for return types).

880

Sure, I'll add the comment. I'll leave that refactoring to you, I'm not quite sure how you intent to achieve it.

clang-tools-extra/clangd/unittests/HoverTests.cpp
986

As a user I'd prefer the hover to work over the whole decltype(auto) expression. But that does not seem quite compatible with the way tokens are parsed.

Are you suggesting I remove the test case or should I add a FIXME comment ?

sammccall accepted this revision.Dec 17 2020, 5:45 PM

Thanks! I think this is in pretty good shape, remaining stuff is up to you.

Let me know if/when you want me to land this!

clang-tools-extra/clangd/Hover.cpp
618

should it work when auto is a pointer or a ref?

I think no need for now, I just want to avoid the regression.
(Nice to have, but at least in the codebases I work in, auto is much more common than decltype(auto) so it's rarely a reference, and pointers are idiomatically written auto*)

printName will print C instead of class C even if I hack around and give it the right PrintingPolicy.

Yeah... it's not supposed to, though the extra clarity is valuable here. You could just hack around this and prepend the TagTypeKind yourself :-)

clang-tools-extra/clangd/unittests/HoverTests.cpp
986

Sorry, I think we're talking about different examples.

(I agree decltype(auto) should ideally be a single thing and we should support hover on all of it, no need to address in this patch, FIXME would be nice).

But I was talking about the lambda auto parameter, where your comment says "not useful". Anyway, nothing to do here either except maybe soften the comment to "not supported at the moment".

1719

can you restore the comments to the original position above the struct, so we test that the documentation comment is included?

This revision is now accepted and ready to land.Dec 17 2020, 5:45 PM
qchateau updated this revision to Diff 312747.Dec 18 2020, 3:40 AM
qchateau marked 5 inline comments as done.
  • Verify documentation in hover test on 'auto'
  • Fixed comments
  • Converted raw string to string to avoid trailing whitespace

You can land this if it is still fine after my final update.

email: quentin.chateau@gmail.com

Thanks !

clang-tools-extra/clangd/unittests/HoverTests.cpp
986

Ahah yes my bad, I copy pasted the comment x)
I fixed it

2444–2454

I've also changed this raw string to a normal string (and another one line 2729) because they include whitespace at the end of the line. Git complains about it and my editor automatically trims trailing whitespace. I assume I'm not the only one using this setting and it annoyed me more than it should.

qchateau updated this revision to Diff 312757.Dec 18 2020, 4:40 AM

Fix ExpandAutoType to not expand undeduced auto

sammccall added inline comments.Dec 18 2020, 7:24 AM
clang-tools-extra/clangd/AST.cpp
353

I added a comment to getDeducedType() - I think the intent here is that we return the AutoType itself if it's not deduced, right?

clang-tools-extra/clangd/Hover.cpp
591

I dropped this unused param

618

Hmm, it looks like this wasn't done. It's now printing e.g. class vector<class Foo> which seems more confusing than either class vector<Foo> or vector<Foo> (even if we lose some highlighting). I'll send a followup with proposed changes here.

This revision was automatically updated to reflect the committed changes.
qchateau added inline comments.Dec 18 2020, 7:37 AM
clang-tools-extra/clangd/AST.cpp
353

It is already the case for return types in VisitFunctionDecl, but not for types visited in in VisitDeclaratorDecl. I simply made it consistent. One could argue getDeducedType should return None when the type is not deduced, and I'd not argue against that. Though I have t admit this behavior makes things simpler for the hover feature.

clang-tools-extra/clangd/Hover.cpp
591

Good catch

618

We can probably use printDefinition for tag types and keep getAsString for non tag types. That would also make the definition close to what we get when hovering on an explicit type (as opposed to 'auto'). We'd probably need to set the scopes in HoverInfo as well, printDefinition does not print them.