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/QualityTests.cpp =================================================================== --- unittests/clangd/QualityTests.cpp +++ unittests/clangd/QualityTests.cpp @@ -118,6 +118,45 @@ EXPECT_LT(sortText(0, "a"), sortText(0, "z")); } +TEST(QualityTests, BoostCurrentFileDecls) { + TestTU Test; + Test.HeaderFilename = "foo.h"; + Test.HeaderCode = R"cpp( + int test_func_in_header(); + int test_func_in_header_and_cpp(); + )cpp"; + Test.Code = R"cpp( + #include "foo.h" + int ::test_func_in_header_and_cpp() { + } + int test_func_in_cpp(); + + int test() { + test_func_^ + } + )cpp"; + + ParsedAST AST = Test.build(); + + SymbolQualitySignals FuncInCpp; + FuncInCpp.merge(CodeCompletionResult(&findDecl(AST, "test_func_in_cpp"), + CCP_Declaration)); + EXPECT_TRUE(FuncInCpp.AllDeclsInMainFile); + + SymbolQualitySignals FuncInHeader; + FuncInHeader.merge(CodeCompletionResult(&findDecl(AST, "test_func_in_header"), + CCP_Declaration)); + EXPECT_FALSE(FuncInHeader.AllDeclsInMainFile); + + SymbolQualitySignals FuncInHeaderAndCpp; + FuncInHeaderAndCpp.merge(CodeCompletionResult( + &findDecl(AST, "test_func_in_header_and_cpp"), CCP_Declaration)); + EXPECT_FALSE(FuncInHeaderAndCpp.AllDeclsInMainFile); + + EXPECT_LE(FuncInHeader.evaluate(), FuncInCpp.evaluate()); + EXPECT_FLOAT_EQ(FuncInHeader.evaluate(), FuncInHeaderAndCpp.evaluate()); +} + } // namespace } // namespace clangd } // namespace clang Index: unittests/clangd/TestTU.cpp =================================================================== --- unittests/clangd/TestTU.cpp +++ unittests/clangd/TestTU.cpp @@ -1,5 +1,4 @@ -//===--- TestTU.cpp - Scratch source files for testing ------------*- -//C++-*-===// +//===--- TestTU.cpp - Scratch source files for testing -------------------===// // // The LLVM Compiler Infrastructure // @@ -78,11 +77,11 @@ auto *ND = dyn_cast(D); if (!ND || ND->getNameAsString() != QName) continue; - if (Result) { + if (Result && ND->getCanonicalDecl() != Result) { ADD_FAILURE() << "Multiple Decls named " << QName; assert(false && "QName is not unique"); } - Result = ND; + Result = cast(ND->getCanonicalDecl()); } if (!Result) { ADD_FAILURE() << "No Decl named " << QName << " in AST";