Index: clangd/AST.h =================================================================== --- clangd/AST.h +++ clangd/AST.h @@ -26,7 +26,10 @@ /// /// The returned location is usually the spelling location where the name of the /// decl occurs in the code. -SourceLocation findNameLoc(const clang::Decl* D); +SourceLocation findNameLoc(const Decl *D); + +/// Returns true iff all redecls of \p D are in the main file. +bool allDeclsInMainFile(const Decl *D); } // namespace clangd } // namespace clang Index: clangd/AST.cpp =================================================================== --- clangd/AST.cpp +++ clangd/AST.cpp @@ -17,8 +17,8 @@ namespace clangd { using namespace llvm; -SourceLocation findNameLoc(const clang::Decl* D) { - const auto& SM = D->getASTContext().getSourceManager(); +SourceLocation findNameLoc(const Decl *D) { + const auto &SM = D->getASTContext().getSourceManager(); // FIXME: Revisit the strategy, the heuristic is limitted when handling // macros, we should use the location where the whole definition occurs. SourceLocation SpellingLoc = SM.getSpellingLoc(D->getLocation()); @@ -38,5 +38,15 @@ return SpellingLoc; } +bool allDeclsInMainFile(const Decl *D) { + const SourceManager &SM = D->getASTContext().getSourceManager(); + for (auto *Redecl : D->redecls()) { + auto Loc = Redecl->getLocation(); + if (!SM.isWrittenInMainFile(Loc)) + return false; + } + return true; +} + } // namespace clangd } // namespace clang Index: clangd/Quality.h =================================================================== --- clangd/Quality.h +++ clangd/Quality.h @@ -47,6 +47,7 @@ unsigned SemaCCPriority = 0; // 1-80, 1 is best. 0 means absent. // FIXME: this is actually a mix of symbol // quality and relevance. Untangle this. + bool AllDeclsInMainFile = false; bool Deprecated = false; unsigned References = 0; Index: clangd/Quality.cpp =================================================================== --- clangd/Quality.cpp +++ clangd/Quality.cpp @@ -7,6 +7,7 @@ // //===---------------------------------------------------------------------===// #include "Quality.h" +#include "AST.h" #include "index/Index.h" #include "clang/Sema/CodeCompleteConsumer.h" #include "llvm/Support/FormatVariadic.h" @@ -19,7 +20,8 @@ void SymbolQualitySignals::merge(const CodeCompletionResult &SemaCCResult) { SemaCCPriority = SemaCCResult.Priority; - + if (SemaCCResult.Declaration) + AllDeclsInMainFile = allDeclsInMainFile(SemaCCResult.Declaration); if (SemaCCResult.Availability == CXAvailability_Deprecated) Deprecated = true; } @@ -41,6 +43,10 @@ // Priority 80 is a really bad score. Score *= 2 - std::min(80, SemaCCPriority) / 40; + // Things declared in the main file get a large boost. + if (AllDeclsInMainFile) + Score *= 2; + if (Deprecated) Score *= 0.1; Index: unittests/clangd/CodeCompleteTests.cpp =================================================================== --- unittests/clangd/CodeCompleteTests.cpp +++ unittests/clangd/CodeCompleteTests.cpp @@ -962,6 +962,48 @@ } } +TEST(CompletionTest, BoostCurrentFileDecls) { + MockFSProvider FS; + FS.Files[testPath("foo.h")] = R"cpp( + int test_func_in_header(); + int test_func_in_header_and_cpp(); + )cpp"; + + MockCompilationDatabase CDB; + IgnoreDiagnostics DiagConsumer; + ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest()); + llvm::StringLiteral Text = R"cpp( + #include "foo.h" + int ::test_func_in_header_and_cpp() { + } + int test_func_in_cpp(); + + int test() { + test_func_^ + } + )cpp"; + + auto Results = + completions(Server, Text, {}, clangd::CodeCompleteOptions()).items; + std::sort(Results.begin(), Results.end(), + [](const CompletionItem &L, const CompletionItem &R) { + return L.sortText < R.sortText; + }); + ASSERT_THAT(Results, + UnorderedElementsAre(Named("test_func_in_cpp"), + Named("test_func_in_header"), + Named("test_func_in_header_and_cpp"))); + + auto &FuncInCpp = Results[0]; + auto &FuncInHeader = Results[1]; + auto &FuncInHeaderAndCpp = Results[2]; + + EXPECT_LE(FuncInHeader.scoreInfo->finalScore, + FuncInCpp.scoreInfo->finalScore); + EXPECT_FLOAT_EQ(FuncInHeader.scoreInfo->finalScore, + FuncInHeaderAndCpp.scoreInfo->finalScore); +} + } // namespace } // namespace clangd } // namespace clang