Page MenuHomePhabricator

[clangd] Add desugared type to hover
Needs ReviewPublic

Authored by lh123 on Wed, Nov 24, 3:21 AM.

Details

Summary

Add desugared type to hover when the desugared type and the pretty-printed type are different.

c++
template<typename T>
struct TestHover {
  using Type = T;
};

int main() {
  TestHover<int>::Type a;
}

variable a

Type: TestHover<int>::Type (aka 'int')

Diff Detail

Event Timeline

lh123 created this revision.Wed, Nov 24, 3:21 AM
lh123 requested review of this revision.Wed, Nov 24, 3:21 AM
lh123 updated this revision to Diff 389452.Wed, Nov 24, 3:32 AM

add testcase

lh123 edited the summary of this revision. (Show Details)Wed, Nov 24, 3:33 AM
lh123 updated this revision to Diff 389638.Wed, Nov 24, 7:20 PM

format code and add testcase for template.

lh123 added a comment.Wed, Nov 24, 7:27 PM

Related discussions: D72498

lh123 edited the summary of this revision. (Show Details)Wed, Nov 24, 7:28 PM

I agree we often show the wrong amount of sugar, and with the thrust of this patch.

Some pareto-improments are possible with a single type, but we can't solve this problem satisfactorily:

  • the right amount of sugar can vary for the same code pattern (vector<T>::iterator vs cast_retty<x, y>::ret_type)
  • it can depend on what the reader's context is, which we can't know

However I think desugaring all the way to the canonical type, and showing it whenever the strings are not exactly equal, are too blunt as policies.
A similar situation in clang is deciding when to print "aka" in a diagnostic, and what the AKA type should be. The code controlling that is in Desugar() in clang/lib/AST/ASTDiagnostic.cpp. It's handled pretty carefully, and in a place that's likely to be well-maintained.
(It's also wrapped in functions that process a whole diagnostic to take into account multiple types that appear, which we can ignore).

I'd suggest we expose that function from ASTDiagnostic.h and use it for this purpose.

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

This seems like a pretty important case to handle.
A wrinkle is that this gets treated as C++ code (e.g. client-side syntax highlighted).

So we might need something like

int64_t
// aka
long long

or

int64_t
// aka: long long
1090

I'm not sure that quoting the aka type when we don't quote the original is appropriate

1140

I think printing two types here is too disruptive to the reading flow, this is a parenthetical already

clang-tools-extra/clangd/Hover.h
48

instead of these ad-hoc pairs, I'd suggest introducing a common struct like:

Optional<PrintedType> Type;

struct PrintedType {
  std::string Type;
  Optional<std::string> AKA;
};

that way producing function like printType and formatting functions that produce "foo (aka bar)" can more simply be shared between instances of this pattern

lh123 updated this revision to Diff 389909.Thu, Nov 25, 9:51 PM

address comment.

Herald added a project: Restricted Project. · View Herald TranscriptThu, Nov 25, 9:51 PM
lh123 marked 4 inline comments as done.Thu, Nov 25, 9:52 PM
lh123 updated this revision to Diff 389911.Thu, Nov 25, 10:05 PM

fix some bug.

lh123 updated this revision to Diff 389915.Thu, Nov 25, 10:25 PM
lh123 retitled this revision from [clangd] Add canonical type to hover to [clangd] Add desugared type to hover.
lh123 edited the summary of this revision. (Show Details)
  1. rename CanType to DesugaredTy.
  2. fix some bug in compare PrintedType.
lh123 updated this revision to Diff 389921.Thu, Nov 25, 11:24 PM

handle TypeAliasTemplateDecl.

lh123 updated this revision to Diff 389924.EditedThu, Nov 25, 11:29 PM

rename TTD to TAT.

lh123 updated this revision to Diff 389931.Fri, Nov 26, 12:28 AM

Move some desugared type to Definition.

lh123 added inline comments.Fri, Nov 26, 12:31 AM
clang-tools-extra/clangd/Hover.cpp
706

It seems we can't do this, vscode always display

int64_t
// aka: long long

as

int64_t
    // aka: long long

So I change it to int64_t // aka: long long

lh123 added inline comments.Fri, Nov 26, 1:13 AM
clang-tools-extra/clangd/Hover.cpp
174

It seems we lost namespace qualifiers.
It always display std::string as basic_string<char>

lh123 added inline comments.Fri, Nov 26, 1:18 AM
clang-tools-extra/clangd/Hover.cpp
174

Should we set FullyQualifiedName printing policy for DesugaredTy.

lh123 added inline comments.Fri, Nov 26, 1:25 AM
clang-tools-extra/clangd/Hover.cpp
174

Sometimes we need to distinguish certain types with the same name based on the fully qualified name.
eg.

namespace custom {
template <typename T> struct vector {};
} // namespace custom

void code() {
  custom::vector<size_t> a;
  std::vector<size_t> b;
}

Currently, both a and b show vector<unsigned long>.

lh123 updated this revision to Diff 389968.Fri, Nov 26, 2:50 AM
lh123 changed the repository for this revision from rZORG LLVM Github Zorg to rG LLVM Github Monorepo.

This looks pretty good in terms of behavior, some impl comments but we should land this.

My main remaining concern is just that this will trigger too often when there's no confusion over types, and clutter the display.
Some common cases I'm worried about:

  • std::string -> basic_string<char>. Maybe we should special-case this to hide the aka?
  • int64_t vs long long et al. I have no idea what to do about this.

@kadircet hopefully has thoughts on what hover should look like

clang-tools-extra/clangd/Hover.cpp
143–144

nit: ASTCtx or Ctx to distinguish from clangd::Context

149–150

nit: declare a HoverInfo::PrintedType Result and write directly into it instead of these partial variables?

168

prefer printing into the same string rather than copying into a new one

174

I'd lean against setting FullyQualifiedName for the AKA type. Clang doesn't for diagnostics (I see 'std::string' aka 'basic_string<char>').
It is more specific and adds verbosity. It should be very rare that it is the only way to find things out, e.g. in your example the *original* types would be different as they include the namespace as spelled in the code.

174

The e.g. "class " prefix isn't needed in the a.k.a, so no need to copy strings for that.

(and in fact I'm not sure it's possible to hit an AKA when this string is nonempty)

195

How strongly do you feel about handling this case?

This code is much more surprising than the previous version and maybe we can find a simpler way to express it, but all of this only matters if we have a template-template-paramater with a non-type-template-parameter with nontrivial sugar which obscures meaning.

That seems pretty unlikely to ever come up, and if it does I'm not sure repeating the whole TTP is a great experience.

I'd suggest just dropping the possibility of an AKA type here until someone runs into a case where it's a real issue...

690

HI.Definition = std::move(PType.Type)

690

this formatting of the definition appears twice, pull out a function? string typeAsDefinition(PrintedType) or so

1088–1089

appendCode(llvm::to_string(ReturnType))

(from ScopedPrinter.h)

1260

Hmm, this seems to render as:

std::string Foo = "" (aka basic_string<char>)

it's not *completely* clear what the aka refers to.
I don't have a better solution, though.
@kadircet any opinions here?

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

you could reduce the noise here by giving PrintedType a constructor from char* or so...

clang/include/clang/AST/ASTDiagnostic.h
38

when exposing this, we should probably give it a more specific name like desugarForDiagnostic, so it's not confused with the various QT->desugar() or getCanonicalType() type functions.

While renaming, it should start with a lowercase d.

My main remaining concern is just that this will trigger too often when there's no confusion over types, and clutter the display.
Some common cases I'm worried about:

  • std::string -> basic_string<char>. Maybe we should special-case this to hide the aka?
  • int64_t vs long long et al. I have no idea what to do about this.

As discussed offline I share these concerns, and it's not the first time we're facing them. I am afraid that this might be disturbing for a good fraction of users if we don't polish it around common types.
A couple of suggestions I have (they don't necessarily need to land as part of this patch, but I think we should land some damage control mechanism before next release):

  • Make AKA-printing completely optional, to give users a way out (while probably starting with off by default and experimenting for a while to see the most annoying cases and polishing them as needed)
  • Have a list of user-configurable FQNs that AKA printing would be disabled for (and provide a good set of defaults inside clangd for STL)
clang-tools-extra/clangd/Hover.cpp
1260

i think it's attached to the type of the parameter, not it's name nor the initializer-expr. so I think we should move this closer to the type (i.e. std::string (aka basic_sting<char>) Foo = "", basically llvm::toString(P.Type) ?)

lh123 updated this revision to Diff 390149.Sat, Nov 27, 2:58 AM
lh123 marked 13 inline comments as done.

address comment.

lh123 updated this revision to Diff 390153.Sat, Nov 27, 4:08 AM

format code.

lh123 updated this revision to Diff 390154.Sat, Nov 27, 4:09 AM

format again.

nridge added a subscriber: nridge.Mon, Nov 29, 1:25 PM
lh123 updated this revision to Diff 391545.Thu, Dec 2, 10:08 PM

rebase to head.