diff --git a/clang-tools-extra/clangd/CodeComplete.cpp b/clang-tools-extra/clangd/CodeComplete.cpp --- a/clang-tools-extra/clangd/CodeComplete.cpp +++ b/clang-tools-extra/clangd/CodeComplete.cpp @@ -1612,14 +1612,16 @@ SymbolQualitySignals Quality; SymbolRelevanceSignals Relevance; Relevance.Context = CCContextKind; - Relevance.Name = Bundle.front().Name; Relevance.Query = SymbolRelevanceSignals::CodeComplete; Relevance.FileProximityMatch = FileProximity.getPointer(); if (ScopeProximity) Relevance.ScopeProximityMatch = ScopeProximity.getPointer(); if (PreferredType) Relevance.HadContextType = true; - Relevance.ContextWords = &ContextWords; + + Relevance.Util.Name = Bundle.front().Name; + Relevance.Util.ContextWords = &ContextWords; + Relevance.calcNameMatchesContext(); auto &First = Bundle.front(); if (auto FuzzyScore = fuzzyScore(First)) diff --git a/clang-tools-extra/clangd/FindSymbols.cpp b/clang-tools-extra/clangd/FindSymbols.cpp --- a/clang-tools-extra/clangd/FindSymbols.cpp +++ b/clang-tools-extra/clangd/FindSymbols.cpp @@ -109,7 +109,6 @@ SymbolQualitySignals Quality; Quality.merge(Sym); SymbolRelevanceSignals Relevance; - Relevance.Name = Sym.Name; Relevance.Query = SymbolRelevanceSignals::Generic; if (auto NameMatch = Filter.match(Sym.Name)) Relevance.NameMatch = *NameMatch; diff --git a/clang-tools-extra/clangd/Quality.h b/clang-tools-extra/clangd/Quality.h --- a/clang-tools-extra/clangd/Quality.h +++ b/clang-tools-extra/clangd/Quality.h @@ -85,17 +85,18 @@ /// Attributes of a symbol-query pair that affect how much we like it. struct SymbolRelevanceSignals { - /// The name of the symbol (for ContextWords). Must be explicitly assigned. - llvm::StringRef Name; + /// Whether name contains some word in context. Must not be set explicitly. + /// Computed by calcNameMatchesContext(). + bool NameMatchesContext = false; /// 0-1+ fuzzy-match score for unqualified name. Must be explicitly assigned. float NameMatch = 1; - /// Lowercase words relevant to the context (e.g. near the completion point). - llvm::StringSet<>* ContextWords = nullptr; + bool Forbidden = false; // Unavailable (e.g const) or inaccessible (private). /// Whether fixits needs to be applied for that completion or not. bool NeedsFixIts = false; bool InBaseClass = false; // A member from base class of the accessed class. + // FIXME: Move this property to utilites. URIDistance *FileProximityMatch = nullptr; /// These are used to calculate proximity between the index symbol and the /// query. @@ -105,6 +106,7 @@ /// Proximity between best declaration and the query. [0-1], 1 is closest. float SemaFileProximityScore = 0; + // FIXME: Move this property to utilites. // Scope proximity is only considered (both index and sema) when this is set. ScopeDistance *ScopeProximityMatch = nullptr; llvm::Optional SymbolScope; @@ -136,6 +138,20 @@ // Whether the item matches the type expected in the completion context. bool TypeMatchesPreferred = false; + // Properties and utilites used to compute derived signals e.g. + // IsNameInContext. These are not directly used by the scoring function. + struct Utility { + /// The name of the symbol (for ContextWords). Must be explicitly assigned. + llvm::StringRef Name; + + /// Lowercase words relevant to the context (e.g. near the completion + /// point). + llvm::StringSet<> *ContextWords = nullptr; + } Util; + + // Sets NameMatchesContext to true iff Name contains any of the ContextWords. + void calcNameMatchesContext(); + void merge(const CodeCompletionResult &SemaResult); void merge(const Symbol &IndexResult); diff --git a/clang-tools-extra/clangd/Quality.cpp b/clang-tools-extra/clangd/Quality.cpp --- a/clang-tools-extra/clangd/Quality.cpp +++ b/clang-tools-extra/clangd/Quality.cpp @@ -348,6 +348,10 @@ return llvm::None; } +void SymbolRelevanceSignals::calcNameMatchesContext() { + NameMatchesContext = wordMatching(Util.Name, Util.ContextWords).hasValue(); +} + float SymbolRelevanceSignals::evaluate() const { float Score = 1; @@ -369,7 +373,7 @@ Score *= SemaSaysInScope ? 2.0 : scopeBoost(*ScopeProximityMatch, SymbolScope); - if (wordMatching(Name, ContextWords)) + if (NameMatchesContext) Score *= 1.5; // Symbols like local variables may only be referenced within their scope. @@ -428,12 +432,12 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const SymbolRelevanceSignals &S) { OS << llvm::formatv("=== Symbol relevance: {0}\n", S.evaluate()); - OS << llvm::formatv("\tName: {0}\n", S.Name); + OS << llvm::formatv("\tName: {0}\n", S.Util.Name); OS << llvm::formatv("\tName match: {0}\n", S.NameMatch); - if (S.ContextWords) + if (S.Util.ContextWords) OS << llvm::formatv( "\tMatching context word: {0}\n", - wordMatching(S.Name, S.ContextWords).getValueOr("")); + wordMatching(S.Util.Name, S.Util.ContextWords).getValueOr("")); OS << llvm::formatv("\tForbidden: {0}\n", S.Forbidden); OS << llvm::formatv("\tNeedsFixIts: {0}\n", S.NeedsFixIts); OS << llvm::formatv("\tIsInstanceMember: {0}\n", S.IsInstanceMember); diff --git a/clang-tools-extra/clangd/XRefs.cpp b/clang-tools-extra/clangd/XRefs.cpp --- a/clang-tools-extra/clangd/XRefs.cpp +++ b/clang-tools-extra/clangd/XRefs.cpp @@ -427,7 +427,6 @@ SymbolQualitySignals Quality; Quality.merge(Sym); SymbolRelevanceSignals Relevance; - Relevance.Name = Sym.Name; Relevance.Query = SymbolRelevanceSignals::Generic; Relevance.merge(Sym); auto Score = diff --git a/clang-tools-extra/clangd/unittests/QualityTests.cpp b/clang-tools-extra/clangd/unittests/QualityTests.cpp --- a/clang-tools-extra/clangd/unittests/QualityTests.cpp +++ b/clang-tools-extra/clangd/unittests/QualityTests.cpp @@ -294,13 +294,17 @@ EXPECT_LT(InBaseClass.evaluate(), Default.evaluate()); llvm::StringSet<> Words = {"one", "two", "three"}; + SymbolRelevanceSignals WithoutMatchingWord; - WithoutMatchingWord.ContextWords = &Words; - WithoutMatchingWord.Name = "four"; + WithoutMatchingWord.Util.ContextWords = &Words; + WithoutMatchingWord.Util.Name = "four"; + WithoutMatchingWord.calcNameMatchesContext(); EXPECT_EQ(WithoutMatchingWord.evaluate(), Default.evaluate()); + SymbolRelevanceSignals WithMatchingWord; - WithMatchingWord.ContextWords = &Words; - WithMatchingWord.Name = "TheTwoTowers"; + WithMatchingWord.Util.ContextWords = &Words; + WithMatchingWord.Util.Name = "TheTwoTowers"; + WithMatchingWord.calcNameMatchesContext(); EXPECT_GT(WithMatchingWord.evaluate(), Default.evaluate()); }