forked from OSchip/llvm-project
[clangd] Type hints for structured bindings
Hints are shown for the individual bindings, not the aggregate. Differential Revision: https://reviews.llvm.org/D104617
This commit is contained in:
parent
a39bb960fc
commit
a15adbcddd
|
@ -32,6 +32,14 @@ public:
|
|||
TypeHintPolicy.SuppressScope = true; // keep type names short
|
||||
TypeHintPolicy.AnonymousTagLocations =
|
||||
false; // do not print lambda locations
|
||||
// Print canonical types. Otherwise, SuppressScope would result in
|
||||
// things like "metafunction<args>::type" being shorted to just "type",
|
||||
// which is useless. This is particularly important for structured
|
||||
// bindings that use the tuple_element protocol, where the non-canonical
|
||||
// types would be "tuple_element<I, A>::type".
|
||||
// Note, for "auto", we would often prefer sugared types, but the AST
|
||||
// doesn't currently retain them in DeducedType anyways.
|
||||
TypeHintPolicy.PrintCanonicalTypes = true;
|
||||
}
|
||||
|
||||
bool VisitCXXConstructExpr(CXXConstructExpr *E) {
|
||||
|
@ -76,9 +84,8 @@ public:
|
|||
if (auto *AT = D->getReturnType()->getContainedAutoType()) {
|
||||
QualType Deduced = AT->getDeducedType();
|
||||
if (!Deduced.isNull()) {
|
||||
addInlayHint(D->getFunctionTypeLoc().getRParenLoc(),
|
||||
InlayHintKind::TypeHint,
|
||||
"-> " + D->getReturnType().getAsString(TypeHintPolicy));
|
||||
addTypeHint(D->getFunctionTypeLoc().getRParenLoc(), D->getReturnType(),
|
||||
"-> ");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -86,10 +93,14 @@ public:
|
|||
}
|
||||
|
||||
bool VisitVarDecl(VarDecl *D) {
|
||||
// Do not show hints for the aggregate in a structured binding.
|
||||
// In the future, we may show hints for the individual bindings.
|
||||
if (isa<DecompositionDecl>(D))
|
||||
// Do not show hints for the aggregate in a structured binding,
|
||||
// but show hints for the individual bindings.
|
||||
if (auto *DD = dyn_cast<DecompositionDecl>(D)) {
|
||||
for (auto *Binding : DD->bindings()) {
|
||||
addTypeHint(Binding->getLocation(), Binding->getType(), ": ");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (D->getType()->getContainedAutoType()) {
|
||||
if (!D->getType()->isDependentType()) {
|
||||
|
@ -98,8 +109,7 @@ public:
|
|||
// (e.g. for `const auto& x = 42`, print `const int&`).
|
||||
// Alternatively, we could place the hint on the `auto`
|
||||
// (and then just print the type deduced for the `auto`).
|
||||
addInlayHint(D->getLocation(), InlayHintKind::TypeHint,
|
||||
": " + D->getType().getAsString(TypeHintPolicy));
|
||||
addTypeHint(D->getLocation(), D->getType(), ": ");
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
@ -311,6 +321,15 @@ private:
|
|||
Kind, Label.str()});
|
||||
}
|
||||
|
||||
void addTypeHint(SourceRange R, QualType T, llvm::StringRef Prefix) {
|
||||
// Do not print useless "NULL TYPE" hint.
|
||||
if (!T.getTypePtrOrNull())
|
||||
return;
|
||||
|
||||
addInlayHint(R, InlayHintKind::TypeHint,
|
||||
std::string(Prefix) + T.getAsString(TypeHintPolicy));
|
||||
}
|
||||
|
||||
std::vector<InlayHint> &Results;
|
||||
ASTContext &AST;
|
||||
FileID MainFileID;
|
||||
|
|
|
@ -461,19 +461,70 @@ TEST(TypeHints, Lambda) {
|
|||
ExpectedHint{": int", "init"});
|
||||
}
|
||||
|
||||
TEST(TypeHints, StructuredBindings) {
|
||||
// FIXME: Not handled yet.
|
||||
// To handle it, we could print:
|
||||
// - the aggregate type next to the 'auto', or
|
||||
// - the individual types inside the brackets
|
||||
// The latter is probably more useful.
|
||||
// Structured bindings tests.
|
||||
// Note, we hint the individual bindings, not the aggregate.
|
||||
|
||||
TEST(TypeHints, StructuredBindings_PublicStruct) {
|
||||
assertTypeHints(R"cpp(
|
||||
// Struct with public fields.
|
||||
struct Point {
|
||||
int x;
|
||||
int y;
|
||||
};
|
||||
Point foo();
|
||||
auto [x, y] = foo();
|
||||
auto [$x[[x]], $y[[y]]] = foo();
|
||||
)cpp",
|
||||
ExpectedHint{": int", "x"}, ExpectedHint{": int", "y"});
|
||||
}
|
||||
|
||||
TEST(TypeHints, StructuredBindings_Array) {
|
||||
assertTypeHints(R"cpp(
|
||||
int arr[2];
|
||||
auto [$x[[x]], $y[[y]]] = arr;
|
||||
)cpp",
|
||||
ExpectedHint{": int", "x"}, ExpectedHint{": int", "y"});
|
||||
}
|
||||
|
||||
TEST(TypeHints, StructuredBindings_TupleLike) {
|
||||
assertTypeHints(R"cpp(
|
||||
// Tuple-like type.
|
||||
struct IntPair {
|
||||
int a;
|
||||
int b;
|
||||
};
|
||||
namespace std {
|
||||
template <typename T>
|
||||
struct tuple_size {};
|
||||
template <>
|
||||
struct tuple_size<IntPair> {
|
||||
constexpr static unsigned value = 2;
|
||||
};
|
||||
template <unsigned I, typename T>
|
||||
struct tuple_element {};
|
||||
template <unsigned I>
|
||||
struct tuple_element<I, IntPair> {
|
||||
using type = int;
|
||||
};
|
||||
}
|
||||
template <unsigned I>
|
||||
int get(const IntPair& p) {
|
||||
if constexpr (I == 0) {
|
||||
return p.a;
|
||||
} else if constexpr (I == 1) {
|
||||
return p.b;
|
||||
}
|
||||
}
|
||||
IntPair bar();
|
||||
auto [$x[[x]], $y[[y]]] = bar();
|
||||
)cpp",
|
||||
ExpectedHint{": int", "x"}, ExpectedHint{": int", "y"});
|
||||
}
|
||||
|
||||
TEST(TypeHints, StructuredBindings_NoInitializer) {
|
||||
assertTypeHints(R"cpp(
|
||||
// No initializer (ill-formed).
|
||||
// Do not show useless "NULL TYPE" hint.
|
||||
auto [x, y]; /*error-ok*/
|
||||
)cpp");
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue