[PATCH] D102148: [clangd] Type hints for variables with 'auto' type
Sam McCall via Phabricator via cfe-commits
cfe-commits at lists.llvm.org
Wed May 26 04:46:07 PDT 2021
sammccall accepted this revision.
sammccall added a comment.
This revision is now accepted and ready to land.
Sorry *again* about the delayed response, will explain off-list.
This looks great. There's a substantive question about `auto &x⟦: int &⟧ = 42` vs `auto⟦int⟧ &x = 42`. But I don't think this should block landing this unless you want to.
================
Comment at: clang-tools-extra/clangd/InlayHints.cpp:33
+ TypeHintPolicy.SuppressScope = true; // keep type names short
+ TypeHintPolicy.AnonymousTagLocations =
+ false; // do not print lambda locations
----------------
For lambda values, the overwhelmingly common case is `auto X = <lambda-expr>`.
A few reasons we may want to not show these at all (and so omit type hints for lambdas as a first approximation):
- the fact that it's a lambda is pretty obvious
- lambdas very often have complex introducers (captures/params) that a hint will displace/add noise to
- we may want to add type hints to captures-with-initializers, which are very much like auto-typed variables, and the fewer hints we have to cram on a line the better
(fine to consider this stuff later, just wanted to mention it)
================
Comment at: clang-tools-extra/clangd/InlayHints.cpp:76
+ bool VisitVarDecl(VarDecl *D) {
+ // Structured binding - not handled yet.
+ if (isa<DecompositionDecl>(D))
----------------
FWIW I think hinting the individual bindings will be more useful and also more consistent with the other hints you have here.
================
Comment at: clang-tools-extra/clangd/InlayHints.cpp:81
+ if (auto *AT = D->getType()->getContainedAutoType()) {
+ if (!D->getType()->isDependentType()) {
+ addInlayHint(D->getLocation(), InlayHintKind::TypeHint,
----------------
why this check vs checking whether AT is deduced?
(thus fixing the dependent `T` testcase)
At first I assumed this was the usual "AutoType in AST doesn't store the deduced type" problem, but shouldn't it work properly if we're starting at the variable type?
================
Comment at: clang-tools-extra/clangd/InlayHints.cpp:82
+ if (!D->getType()->isDependentType()) {
+ addInlayHint(D->getLocation(), InlayHintKind::TypeHint,
+ ": " + D->getType().getAsString(TypeHintPolicy));
----------------
This places the hint on the variable rather than the `auto`. And fittingly (but subtly), it prints type rather than just the placeholder type (e.g. `const auto& x = 42` => `const int&`, not `int`)
This decision is worth a comment, and probably a little discussion :-)
The alternative of annotating `auto` has advantages:
- the deduced `auto` type is the most obvious question when reading the code
- that `auto` deduces to a particular type is the "correct" model, and may lead to better language understanding. Extreme unrealistic example: in `auto x = foo(), *y = bar();` I'd strongly prefer one hint.
- the hint will often be shorter, which is an important consideration since we're reflowing column-limited text
- the annotated code more closely resembles code that does not use `auto`
And annotating the variable has advantages too:
- the type of the variable is the most directly important fact
- generalizes better to cases where `auto` is not present (lambda captures, individual structured bindings)
- i suspect simpler implementation
My intuition is to expect annotating `auto` to be a little nicer, mostly because it will come closer to making code read the same way whether it uses `auto` or not. I'm not certain though. Interested if you have strong feelings about this!
To save a round-trip: a likely conclusion is "maybe annotating auto is better, but it's not clear and/or it's a bunch of work". That's 100% fine, but we should just leave a comment whether this is something decided against vs desirable but deferred vs unsure.
================
Comment at: clang-tools-extra/clangd/unittests/InlayHintTests.cpp:445
+ assertTypeHints(R"cpp(
+ auto $L[[L]] = [](int a, int b) { return a + b; };
+ )cpp",
----------------
consider `= [b(1+1)](int a) { ... }` and we can consider adding type hints to b later
================
Comment at: clang-tools-extra/clangd/unittests/InlayHintTests.cpp:487
+}
+
+// Annoyances:
----------------
It'd be useful to have cases showing how we handle "bulky" typenames, e.g. `ns::OuterClass::Template<int>` which I think we render as `Template<int>`.
================
Comment at: clang-tools-extra/clangd/unittests/InlayHintTests.cpp:489
+// Annoyances:
+// - auto x = dyn_cast<LongTypeName>(y);
+// - stdlib algos return unwieldy __normal_iterator<X*, ...> type
----------------
not sure if you meant dynamic_cast or dyn_cast here, both are important but distinct!
================
Comment at: clang-tools-extra/clangd/unittests/InlayHintTests.cpp:489
+// Annoyances:
+// - auto x = dyn_cast<LongTypeName>(y);
+// - stdlib algos return unwieldy __normal_iterator<X*, ...> type
----------------
sammccall wrote:
> not sure if you meant dynamic_cast or dyn_cast here, both are important but distinct!
maybe mention the other low-hanging fruit cases from the patch description too
================
Comment at: clang-tools-extra/clangd/unittests/InlayHintTests.cpp:490
+// - auto x = dyn_cast<LongTypeName>(y);
+// - stdlib algos return unwieldy __normal_iterator<X*, ...> type
+
----------------
The use of a `__reserved` name might be a good hint this is a structural type whose name is not a meaningful hint. (I guess maybe that's already what you meant!)
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D102148/new/
https://reviews.llvm.org/D102148
More information about the cfe-commits
mailing list