diff options
author | Eric Liu <ioeric@google.com> | 2018-10-17 11:19:02 +0000 |
---|---|---|
committer | Eric Liu <ioeric@google.com> | 2018-10-17 11:19:02 +0000 |
commit | 3fac4ef1fdb4e6b2b4743f33498612c233da325d (patch) | |
tree | f3dbf1cda024228cff98f9e00d8dbd50188144e6 /clang-tools-extra/clangd/Quality.cpp | |
parent | e2566b5d877c415f128a9f3d75ef2173bf32c347 (diff) | |
download | bcm5719-llvm-3fac4ef1fdb4e6b2b4743f33498612c233da325d.tar.gz bcm5719-llvm-3fac4ef1fdb4e6b2b4743f33498612c233da325d.zip |
[clangd] Support scope proximity in code completion.
Summary:
This should make all-scope completion more usable. Scope proximity for
indexes will be added in followup patch.
Reviewers: sammccall
Reviewed By: sammccall
Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D53131
llvm-svn: 344688
Diffstat (limited to 'clang-tools-extra/clangd/Quality.cpp')
-rw-r--r-- | clang-tools-extra/clangd/Quality.cpp | 60 |
1 files changed, 48 insertions, 12 deletions
diff --git a/clang-tools-extra/clangd/Quality.cpp b/clang-tools-extra/clangd/Quality.cpp index 5060a14d2aa..1fb47d5654e 100644 --- a/clang-tools-extra/clangd/Quality.cpp +++ b/clang-tools-extra/clangd/Quality.cpp @@ -18,10 +18,16 @@ #include "clang/Basic/CharInfo.h" #include "clang/Basic/SourceManager.h" #include "clang/Sema/CodeCompleteConsumer.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringRef.h" #include "llvm/Support/Casting.h" #include "llvm/Support/FormatVariadic.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/raw_ostream.h" +#include <algorithm> #include <cmath> namespace clang { @@ -268,6 +274,7 @@ void SymbolRelevanceSignals::merge(const Symbol &IndexResult) { // relevant to non-completion requests, we should recognize class members etc. SymbolURI = IndexResult.CanonicalDeclaration.FileURI; + SymbolScope = IndexResult.Scope; IsInstanceMember |= isInstanceMember(IndexResult.SymInfo); } @@ -277,6 +284,7 @@ void SymbolRelevanceSignals::merge(const CodeCompletionResult &SemaCCResult) { Forbidden = true; if (SemaCCResult.Declaration) { + SemaSaysInScope = true; // We boost things that have decls in the main file. We give a fixed score // for all other declarations in sema as they are already included in the // translation unit. @@ -284,7 +292,7 @@ void SymbolRelevanceSignals::merge(const CodeCompletionResult &SemaCCResult) { hasUsingDeclInMainFile(SemaCCResult)) ? 1.0 : 0.6; - SemaProximityScore = std::max(DeclProximity, SemaProximityScore); + SemaFileProximityScore = std::max(DeclProximity, SemaFileProximityScore); IsInstanceMember |= isInstanceMember(SemaCCResult.Declaration); } @@ -295,8 +303,8 @@ void SymbolRelevanceSignals::merge(const CodeCompletionResult &SemaCCResult) { NeedsFixIts = !SemaCCResult.FixIts.empty(); } -static std::pair<float, unsigned> proximityScore(llvm::StringRef SymbolURI, - URIDistance *D) { +static std::pair<float, unsigned> uriProximity(llvm::StringRef SymbolURI, + URIDistance *D) { if (!D || SymbolURI.empty()) return {0.f, 0u}; unsigned Distance = D->distance(SymbolURI); @@ -304,6 +312,16 @@ static std::pair<float, unsigned> proximityScore(llvm::StringRef SymbolURI, return {std::exp(Distance * -0.4f / FileDistanceOptions().UpCost), Distance}; } +static float scopeBoost(ScopeDistance &Distance, + llvm::Optional<llvm::StringRef> SymbolScope) { + if (!SymbolScope) + return 1; + auto D = Distance.distance(*SymbolScope); + if (D == FileDistance::Unreachable) + return 0.4; + return std::max(0.5, 2.0 * std::pow(0.6, D / 2.0)); +} + float SymbolRelevanceSignals::evaluate() const { float Score = 1; @@ -312,10 +330,18 @@ float SymbolRelevanceSignals::evaluate() const { Score *= NameMatch; - // Proximity scores are [0,1] and we translate them into a multiplier in the - // range from 1 to 3. - Score *= 1 + 2 * std::max(proximityScore(SymbolURI, FileProximityMatch).first, - SemaProximityScore); + // File proximity scores are [0,1] and we translate them into a multiplier in + // the range from 1 to 3. + Score *= 1 + 2 * std::max(uriProximity(SymbolURI, FileProximityMatch).first, + SemaFileProximityScore); + + if (ScopeProximityMatch) + // Use a constant scope boost for sema results, as scopes of sema results + // can be tricky (e.g. class/function scope). Set to the max boost as we + // don't load top-level symbols from the preamble and sema results are + // always in the accessible scope. + Score *= + SemaSaysInScope ? 2.0 : scopeBoost(*ScopeProximityMatch, SymbolScope); // Symbols like local variables may only be referenced within their scope. // Conversely if we're in that scope, it's likely we'll reference them. @@ -358,15 +384,25 @@ raw_ostream &operator<<(raw_ostream &OS, const SymbolRelevanceSignals &S) { OS << formatv("\tNeedsFixIts: {0}\n", S.NeedsFixIts); OS << formatv("\tIsInstanceMember: {0}\n", S.IsInstanceMember); OS << formatv("\tContext: {0}\n", getCompletionKindString(S.Context)); + OS << formatv("\tQuery type: {0}\n", static_cast<int>(S.Query)); + OS << formatv("\tScope: {0}\n", static_cast<int>(S.Scope)); + OS << formatv("\tSymbol URI: {0}\n", S.SymbolURI); + OS << formatv("\tSymbol scope: {0}\n", + S.SymbolScope ? *S.SymbolScope : "<None>"); + if (S.FileProximityMatch) { - auto Score = proximityScore(S.SymbolURI, S.FileProximityMatch); - OS << formatv("\tIndex proximity: {0} (distance={1})\n", Score.first, + auto Score = uriProximity(S.SymbolURI, S.FileProximityMatch); + OS << formatv("\tIndex URI proximity: {0} (distance={1})\n", Score.first, Score.second); } - OS << formatv("\tSema proximity: {0}\n", S.SemaProximityScore); - OS << formatv("\tQuery type: {0}\n", static_cast<int>(S.Query)); - OS << formatv("\tScope: {0}\n", static_cast<int>(S.Scope)); + OS << formatv("\tSema file proximity: {0}\n", S.SemaFileProximityScore); + + OS << formatv("\tSema says in scope: {0}\n", S.SemaSaysInScope); + if (S.ScopeProximityMatch) + OS << formatv("\tIndex scope boost: {0}\n", + scopeBoost(*S.ScopeProximityMatch, S.SymbolScope)); + return OS; } |