diff --git a/clang-tools-extra/clangd/Hover.cpp b/clang-tools-extra/clangd/Hover.cpp --- a/clang-tools-extra/clangd/Hover.cpp +++ b/clang-tools-extra/clangd/Hover.cpp @@ -455,6 +455,21 @@ } else { return llvm::None; } + + // Detect the case when the item is moved into the field. + if (auto *CE = llvm::dyn_cast(RHS->IgnoreCasts())) { + // Make sure we get the version of move with 1 arg, the other is for moving + // ranges. + if (CE->getNumArgs() != 1) + return llvm::None; + auto *ND = llvm::dyn_cast(CE->getCalleeDecl()); + if (!ND) + return llvm::None; + if (ND->getName() != "move" || !ND->isInStdNamespace()) + return llvm::None; + RHS = CE->getArg(0); + } + auto *DRE = llvm::dyn_cast(RHS->IgnoreCasts()); if (!DRE || DRE->getDecl() != Arg) return llvm::None; diff --git a/clang-tools-extra/clangd/unittests/HoverTests.cpp b/clang-tools-extra/clangd/unittests/HoverTests.cpp --- a/clang-tools-extra/clangd/unittests/HoverTests.cpp +++ b/clang-tools-extra/clangd/unittests/HoverTests.cpp @@ -698,6 +698,26 @@ HI.Parameters->back().Name = "v"; HI.AccessSpecifier = "public"; }}, + {// Setter (move) + R"cpp( + namespace std { template 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 @@ HI.Type = "int"; HI.AccessSpecifier = "public"; }}, - {// No crash on InitListExpr. - R"cpp( + {// No crash on InitListExpr. + R"cpp( struct Foo { int a[10]; };