diff --git a/clang-tools-extra/clangd/Selection.cpp b/clang-tools-extra/clangd/Selection.cpp index 14c05d1c0b496..d7630f4481f2d 100644 --- a/clang-tools-extra/clangd/Selection.cpp +++ b/clang-tools-extra/clangd/Selection.cpp @@ -10,6 +10,7 @@ #include "Logger.h" #include "SourceCode.h" #include "clang/AST/ASTTypeTraits.h" +#include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" @@ -594,13 +595,23 @@ class SelectionVisitor : public RecursiveASTVisitor { // Usually empty, but sometimes children cover tokens but shouldn't own them. SourceRange earlySourceRange(const DynTypedNode &N) { if (const Decl *D = N.get()) { + // We want constructor name to be claimed by TypeLoc not the constructor + // itself. Similar for deduction guides, we rather want to select the + // underlying TypeLoc. + // FIXME: Unfortunately this doesn't work, even though RecursiveASTVisitor + // traverses the underlying TypeLoc inside DeclarationName, it is null for + // constructors. + if (isa(D) || isa(D)) + return SourceRange(); + // This will capture Field, Function, MSProperty, NonTypeTemplateParm and + // VarDecls. We want the name in the declarator to be claimed by the decl + // and not by any children. For example: // void [[foo]](); - if (auto *FD = llvm::dyn_cast(D)) - return FD->getNameInfo().getSourceRange(); // int (*[[s]])(); - else if (auto *VD = llvm::dyn_cast(D)) - return VD->getLocation(); - } else if (const auto* CCI = N.get()) { + // struct X { int [[hash]] [32]; [[operator]] int();} + if (const auto *DD = llvm::dyn_cast(D)) + return DD->getLocation(); + } else if (const auto *CCI = N.get()) { // : [[b_]](42) return CCI->getMemberLocation(); } diff --git a/clang-tools-extra/clangd/unittests/HoverTests.cpp b/clang-tools-extra/clangd/unittests/HoverTests.cpp index 89b529d9b4199..eb47b5a541a6d 100644 --- a/clang-tools-extra/clangd/unittests/HoverTests.cpp +++ b/clang-tools-extra/clangd/unittests/HoverTests.cpp @@ -339,7 +339,7 @@ class Foo {})cpp"; HI.Definition = "~X()"; HI.Parameters.emplace(); }}, - {"class X { operator [[in^t]](); };", + {"class X { [[op^erator]] int(); };", [](HoverInfo &HI) { HI.NamespaceScope = ""; HI.Name = "operator int"; @@ -348,6 +348,13 @@ class Foo {})cpp"; HI.Definition = "operator int()"; HI.Parameters.emplace(); }}, + {"class X { operator [[^X]]*(); };", + [](HoverInfo &HI) { + HI.NamespaceScope = ""; + HI.Name = "X"; + HI.Kind = index::SymbolKind::Class; + HI.Definition = "class X {}"; + }}, // auto on lambda {R"cpp( diff --git a/clang-tools-extra/clangd/unittests/SelectionTests.cpp b/clang-tools-extra/clangd/unittests/SelectionTests.cpp index 581309b1dccc4..0cd9ca09401e1 100644 --- a/clang-tools-extra/clangd/unittests/SelectionTests.cpp +++ b/clang-tools-extra/clangd/unittests/SelectionTests.cpp @@ -329,6 +329,12 @@ TEST(SelectionTest, CommonAncestor) { decltype([[^a]] + a) b; )cpp", "DeclRefExpr"}, + + {"struct foo { [[int has^h<:32:>]]; };", "FieldDecl"}, + {"struct foo { [[op^erator int()]]; };", "CXXConversionDecl"}, + {"struct foo { [[^~foo()]]; };", "CXXDestructorDecl"}, + // FIXME: The following to should be class itself instead. + {"struct foo { [[fo^o(){}]] };", "CXXConstructorDecl"}, }; for (const Case &C : Cases) { Annotations Test(C.Code);