Index: clang-tools-extra/trunk/clangd/CodeComplete.cpp =================================================================== --- clang-tools-extra/trunk/clangd/CodeComplete.cpp +++ clang-tools-extra/trunk/clangd/CodeComplete.cpp @@ -294,6 +294,13 @@ std::priority_queue Candidates; for (unsigned I = 0; I < NumResults; ++I) { auto &Result = Results[I]; + // We drop hidden items, as they cannot be found by the lookup after + // inserting the corresponding completion item and only produce noise and + // duplicates in the completion list. However, there is one exception. If + // Result has a Qualifier which is non-informative, we can refer to an + // item by adding that qualifier, so we don't filter out this item. + if (Result.Hidden && (!Result.Qualifier || Result.QualifierIsInformative)) + continue; if (!ClangdOpts.IncludeIneligibleResults && (Result.Availability == CXAvailability_NotAvailable || Result.Availability == CXAvailability_NotAccessible)) Index: clang-tools-extra/trunk/unittests/clangd/CodeCompleteTests.cpp =================================================================== --- clang-tools-extra/trunk/unittests/clangd/CodeCompleteTests.cpp +++ clang-tools-extra/trunk/unittests/clangd/CodeCompleteTests.cpp @@ -592,6 +592,22 @@ Doc("Doooc"), Detail("void")))); } +TEST(CompletionTest, NoDuplicates) { + auto Items = completions(R"cpp( +struct Adapter { + void method(); +}; + +void Adapter::method() { + Adapter^ +} + )cpp") + .items; + + // Make sure there are no duplicate entries of 'Adapter'. + EXPECT_THAT(Items, ElementsAre(Named("Adapter"), Named("~Adapter"))); +} + } // namespace } // namespace clangd } // namespace clang