[clangd] Trivial setter support when moving items to fields

Extend the Trivial setter documentation to support cases where the value is moved into a field using `std::move`.

Reviewed By: sammccall, kadircet

Differential Revision: https://reviews.llvm.org/D88297
This commit is contained in:
Nathan James 2020-09-29 21:51:14 +01:00
parent 155d2d5300
commit 01a30fa678
No known key found for this signature in database
GPG Key ID: CC007AFCDA90AA5F
2 changed files with 36 additions and 2 deletions

View File

@ -413,6 +413,8 @@ llvm::Optional<StringRef> getterVariableName(const CXXMethodDecl *CMD) {
// If CMD is one of the forms:
// void foo(T arg) { FieldName = arg; }
// R foo(T arg) { FieldName = arg; return *this; }
// void foo(T arg) { FieldName = std::move(arg); }
// R foo(T arg) { FieldName = std::move(arg); return *this; }
// then returns "FieldName"
llvm::Optional<StringRef> setterVariableName(const CXXMethodDecl *CMD) {
assert(CMD->hasBody());
@ -455,6 +457,18 @@ llvm::Optional<StringRef> setterVariableName(const CXXMethodDecl *CMD) {
} else {
return llvm::None;
}
// Detect the case when the item is moved into the field.
if (auto *CE = llvm::dyn_cast<CallExpr>(RHS->IgnoreCasts())) {
if (CE->getNumArgs() != 1)
return llvm::None;
auto *ND = llvm::dyn_cast<NamedDecl>(CE->getCalleeDecl());
if (!ND || !ND->getIdentifier() || ND->getName() != "move" ||
!ND->isInStdNamespace())
return llvm::None;
RHS = CE->getArg(0);
}
auto *DRE = llvm::dyn_cast<DeclRefExpr>(RHS->IgnoreCasts());
if (!DRE || DRE->getDecl() != Arg)
return llvm::None;

View File

@ -698,6 +698,26 @@ class Foo {})cpp";
HI.Parameters->back().Name = "v";
HI.AccessSpecifier = "public";
}},
{// Setter (move)
R"cpp(
namespace std { template<typename T> T&& move(T&& t); }
struct X { int Y; void [[^setY]](float v) { Y = std::move(v); } };
)cpp",
[](HoverInfo &HI) {
HI.Name = "setY";
HI.Kind = index::SymbolKind::InstanceMethod;
HI.NamespaceScope = "";
HI.Definition = "void setY(float v)";
HI.LocalScope = "X::";
HI.Documentation = "Trivial setter for `Y`.";
HI.Type = "void (float)";
HI.ReturnType = "void";
HI.Parameters.emplace();
HI.Parameters->emplace_back();
HI.Parameters->back().Type = "float";
HI.Parameters->back().Name = "v";
HI.AccessSpecifier = "public";
}},
{// Field type initializer.
R"cpp(
struct X { int x = 2; };
@ -802,8 +822,8 @@ class Foo {})cpp";
HI.Type = "int";
HI.AccessSpecifier = "public";
}},
{// No crash on InitListExpr.
R"cpp(
{// No crash on InitListExpr.
R"cpp(
struct Foo {
int a[10];
};