Index: clangd/CodeComplete.cpp =================================================================== --- clangd/CodeComplete.cpp +++ clangd/CodeComplete.cpp @@ -243,6 +243,8 @@ const IncludeInserter &Includes, llvm::StringRef SemaDocComment) const { assert(bool(SemaResult) == bool(SemaCCS)); + assert(bool(SemaResult) || bool(IndexResult)); + CompletionItem I; bool InsertingInclude = false; // Whether a new #include will be added. if (SemaResult) { @@ -252,8 +254,14 @@ I.filterText = getFilterText(*SemaCCS); I.documentation = formatDocumentation(*SemaCCS, SemaDocComment); I.detail = getDetail(*SemaCCS); + if (SemaResult->Kind == CodeCompletionResult::RK_Declaration) + if (const auto *D = SemaResult->getDeclaration()) + if (const auto *ND = llvm::dyn_cast(D)) + I.QualifiedName = ND->getQualifiedNameAsString(); } if (IndexResult) { + if (I.QualifiedName.empty()) + I.QualifiedName = (IndexResult->Scope + IndexResult->Name).str(); if (I.kind == CompletionItemKind::Missing) I.kind = toCompletionItemKind(IndexResult->SymInfo.Kind); // FIXME: reintroduce a way to show the index source for debugging. Index: clangd/Protocol.h =================================================================== --- clangd/Protocol.h +++ clangd/Protocol.h @@ -734,6 +734,13 @@ // // data?: any - A data entry field that is preserved on a completion item // between a completion and a completion resolve request. + + // C++ extension that is only expected to be used by users of ClangdServer's + // C++ API. Not serialized from/to json. + /// Qualified name of the symbol this item corresponds to. Empty if the item + /// has no corresponding symbol (e.g. keyword). + /// FIXME: find a more precise way to identify a completion item. + std::string QualifiedSymbolName; }; json::Expr toJSON(const CompletionItem &); llvm::raw_ostream &operator<<(llvm::raw_ostream &, const CompletionItem &); Index: unittests/clangd/CodeCompleteTests.cpp =================================================================== --- unittests/clangd/CodeCompleteTests.cpp +++ unittests/clangd/CodeCompleteTests.cpp @@ -44,6 +44,7 @@ // GMock helpers for matching completion items. MATCHER_P(Named, Name, "") { return arg.insertText == Name; } +MATCHER_P(QName, Name, "") { return arg.QualifiedName == Name; } MATCHER_P(Labeled, Label, "") { std::string Indented; if (!StringRef(Label).startswith( @@ -1251,6 +1252,18 @@ Failed()); } +TEST(CompletionTest, QualifiedNames) { + auto Results = completions( + R"cpp( + namespace ns { int local; void both(); } + void f() { ::ns::^ } + )cpp", + {func("ns::both"), cls("ns::Index")}); + // We get results from both index and sema, with no duplicates. + EXPECT_THAT(Results.items, + UnorderedElementsAre(QName("ns::local"), QName("ns::Index"), + QName("ns::both"))); +} } // namespace } // namespace clangd