Index: clangd/CodeComplete.cpp =================================================================== --- clangd/CodeComplete.cpp +++ clangd/CodeComplete.cpp @@ -195,55 +195,6 @@ return HeaderFile{std::move(*Resolved), /*Verbatim=*/false}; } -// First traverses all method definitions inside current class/struct/union -// definition. Than traverses base classes to find virtual methods that haven't -// been overriden within current context. -// FIXME(kadircet): Currently we cannot see declarations below completion point. -// It is because Sema gets run only upto completion point. Need to find a -// solution to run it for the whole class/struct/union definition. -static std::vector -getNonOverridenMethodCompletionResults(const DeclContext *DC, Sema *S) { - const auto *CR = llvm::dyn_cast(DC); - // If not inside a class/struct/union return empty. - if (!CR) - return {}; - // First store overrides within current class. - // These are stored by name to make querying fast in the later step. - llvm::StringMap> Overrides; - for (auto *Method : CR->methods()) { - if (!Method->isVirtual() || !Method->getIdentifier()) - continue; - Overrides[Method->getName()].push_back(Method); - } - - std::vector Results; - for (const auto &Base : CR->bases()) { - const auto *BR = Base.getType().getTypePtr()->getAsCXXRecordDecl(); - if (!BR) - continue; - for (auto *Method : BR->methods()) { - if (!Method->isVirtual() || !Method->getIdentifier()) - continue; - const auto it = Overrides.find(Method->getName()); - bool IsOverriden = false; - if (it != Overrides.end()) { - for (auto *MD : it->second) { - // If the method in current body is not an overload of this virtual - // function, then it overrides this one. - if (!S->IsOverload(MD, Method, false)) { - IsOverriden = true; - break; - } - } - } - if (!IsOverriden) - Results.emplace_back(Method, 0); - } - } - - return Results; -} - /// A code completion result, in clang-native form. /// It may be promoted to a CompletionItem if it's among the top-ranked results. struct CompletionCandidate { @@ -253,9 +204,6 @@ const Symbol *IndexResult = nullptr; llvm::SmallVector RankedIncludeHeaders; - // States whether this item is an override suggestion. - bool IsOverride = false; - // Returns a token identifying the overload set this is part of. // 0 indicates it's not part of any overload set. size_t overloadSet() const { @@ -424,8 +372,6 @@ Completion.Documentation = getDocComment(ASTCtx, *C.SemaResult, /*CommentsFromHeader=*/false); } - if (C.IsOverride) - S.OverrideSuffix = true; } CodeCompletion build() { @@ -433,12 +379,6 @@ Completion.Signature = summarizeSignature(); Completion.SnippetSuffix = summarizeSnippet(); Completion.BundleSize = Bundled.size(); - if (summarizeOverride()) { - Completion.Name = Completion.ReturnType + ' ' + - std::move(Completion.Name) + - std::move(Completion.Signature) + " override"; - Completion.Signature.clear(); - } return std::move(Completion); } @@ -447,7 +387,6 @@ std::string SnippetSuffix; std::string Signature; std::string ReturnType; - bool OverrideSuffix; }; // If all BundledEntrys have the same value for a property, return it. @@ -495,12 +434,6 @@ return "(…)"; } - bool summarizeOverride() const { - if (auto *OverrideSuffix = onlyValue<&BundledEntry::OverrideSuffix>()) - return *OverrideSuffix; - return false; - } - ASTContext &ASTCtx; CodeCompletion Completion; SmallVector Bundled; @@ -1358,11 +1291,8 @@ ? queryIndex() : SymbolSlab(); trace::Span Tracer("Populate CodeCompleteResult"); - // Merge Sema, Index and Override results, score them, and pick the - // winners. - const auto Overrides = getNonOverridenMethodCompletionResults( - Recorder->CCSema->CurContext, Recorder->CCSema); - auto Top = mergeResults(Recorder->Results, IndexResults, Overrides); + // Merge Sema and Index results, score them, and pick the winners. + auto Top = mergeResults(Recorder->Results, IndexResults); CodeCompleteResult Output; // Convert the results to final form, assembling the expensive strings. @@ -1413,26 +1343,22 @@ return std::move(ResultsBuilder).build(); } - // Merges Sema, Index and Override results where possible, to form - // CompletionCandidates. Groups overloads if desired, to form - // CompletionCandidate::Bundles. The bundles are scored and top results are - // returned, best to worst. + // Merges Sema and Index results where possible, to form CompletionCandidates. + // Groups overloads if desired, to form CompletionCandidate::Bundles. The + // bundles are scored and top results are returned, best to worst. std::vector mergeResults(const std::vector &SemaResults, - const SymbolSlab &IndexResults, - const std::vector &OverrideResults) { + const SymbolSlab &IndexResults) { trace::Span Tracer("Merge and score results"); std::vector Bundles; llvm::DenseMap BundleLookup; auto AddToBundles = [&](const CodeCompletionResult *SemaResult, - const Symbol *IndexResult, - bool IsOverride) { + const Symbol *IndexResult) { CompletionCandidate C; C.SemaResult = SemaResult; C.IndexResult = IndexResult; if (C.IndexResult) C.RankedIncludeHeaders = getRankedIncludes(*C.IndexResult); - C.IsOverride = IsOverride; C.Name = IndexResult ? IndexResult->Name : Recorder->getName(*SemaResult); if (auto OverloadSet = Opts.BundleOverloads ? C.overloadSet() : 0) { auto Ret = BundleLookup.try_emplace(OverloadSet, Bundles.size()); @@ -1459,19 +1385,12 @@ }; // Emit all Sema results, merging them with Index results if possible. for (auto &SemaResult : Recorder->Results) - AddToBundles(&SemaResult, CorrespondingIndexResult(SemaResult), false); - // Handle OverrideResults the same way we deal with SemaResults. Since these - // results use the same structs as a SemaResult it is safe to do that, but - // we need to make sure we dont' duplicate things in future if Sema starts - // to provide them as well. - for (auto &OverrideResult : OverrideResults) - AddToBundles(&OverrideResult, CorrespondingIndexResult(OverrideResult), - true); + AddToBundles(&SemaResult, CorrespondingIndexResult(SemaResult)); // Now emit any Index-only results. for (const auto &IndexResult : IndexResults) { if (UsedIndexResults.count(&IndexResult)) continue; - AddToBundles(/*SemaResult=*/nullptr, &IndexResult, false); + AddToBundles(/*SemaResult=*/nullptr, &IndexResult); } // We only keep the best N results at any time, in "native" format. TopN Top( Index: unittests/clangd/CodeCompleteTests.cpp =================================================================== --- unittests/clangd/CodeCompleteTests.cpp +++ unittests/clangd/CodeCompleteTests.cpp @@ -1806,6 +1806,58 @@ )cpp"); } +TEST(CompletionTest, SuggestOverridesWithPartialMatches) { + MockFSProvider FS; + MockCompilationDatabase CDB; + IgnoreDiagnostics DiagConsumer; + ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest()); + + auto File = testPath("foo.cpp"); + const Annotations Test(R"cpp( + class A { + public: + virtual void vfunc(bool param); + virtual void vfunc(bool param, int p); + void func(bool param); + }; + class B : public A { + virtual int ttt(bool param) const; + void vfunc(bool param, int p) override; + }; + class C : public B { + public: + void vfunc(bool param) override; + $1^vo$2^id $3^ + }; + )cpp"); + runAddDocument(Server, File, Test.code()); + { + const auto Results = completions(Server, Test.code(), Test.point("1")); + EXPECT_THAT( + Results.Completions, + AllOf(Contains(Labeled("void vfunc(bool param, int p) override")), + Not(Contains(Labeled("void vfunc(bool param) override"))), + Contains(Labeled("int ttt(bool param) const override")))); + } + { + const auto Results = completions(Server, Test.code(), Test.point("2")); + EXPECT_THAT( + Results.Completions, + AllOf(Contains(Labeled("void vfunc(bool param, int p) override")), + Not(Contains(Labeled("void vfunc(bool param) override"))), + Not(Contains(Labeled("int ttt(bool param) const override"))))); + } + { + const auto Results = completions(Server, Test.code(), Test.point("3")); + EXPECT_THAT( + Results.Completions, + AllOf(Not(Contains(Labeled("void vfunc(bool param, int p) override"))), + Not(Contains(Labeled("void vfunc(bool param) override"))), + Not(Contains(Labeled("int ttt(bool param) const override"))))); + } +} + + TEST(SpeculateCompletionFilter, Filters) { Annotations F(R"cpp($bof^ $bol^