From 647da3e8a5ada3d51b9ca09052c1876f08f4eb0a Mon Sep 17 00:00:00 2001 From: Ilya Biryukov Date: Mon, 26 Nov 2018 15:38:01 +0000 Subject: [PATCH] [clangd] Add type boosting in code completion Reviewers: sammccall, ioeric Reviewed By: sammccall Subscribers: MaskRay, jkorous, arphaman, kadircet, cfe-commits Differential Revision: https://reviews.llvm.org/D52276 llvm-svn: 347562 --- clang-tools-extra/clangd/CodeComplete.cpp | 28 ++++++++++++++++++++++++++-- clang-tools-extra/clangd/Quality.cpp | 7 +++++++ clang-tools-extra/clangd/Quality.h | 8 ++++++++ clang-tools-extra/clangd/index/Index.h | 2 ++ 4 files changed, 43 insertions(+), 2 deletions(-) diff --git a/clang-tools-extra/clangd/CodeComplete.cpp b/clang-tools-extra/clangd/CodeComplete.cpp index c79f017..28cc583 100644 --- a/clang-tools-extra/clangd/CodeComplete.cpp +++ b/clang-tools-extra/clangd/CodeComplete.cpp @@ -24,6 +24,7 @@ #include "CodeCompletionStrings.h" #include "Compiler.h" #include "Diagnostics.h" +#include "ExpectedTypes.h" #include "FileDistance.h" #include "FuzzyMatch.h" #include "Headers.h" @@ -1225,6 +1226,7 @@ class CodeCompleteFlow { std::vector QueryScopes; // Initialized once Sema runs. // Initialized once QueryScopes is initialized, if there are scopes. Optional ScopeProximity; + llvm::Optional PreferredType; // Initialized once Sema runs. // Whether to query symbols from any scope. Initialized once Sema runs. bool AllScopes = false; // Include-insertion and proximity scoring rely on the include structure. @@ -1302,9 +1304,12 @@ public: Inserter.reset(); // Make sure this doesn't out-live Clang. SPAN_ATTACH(Tracer, "sema_completion_kind", getCompletionKindString(Recorder->CCContext.getKind())); - log("Code complete: sema context {0}, query scopes [{1}] (AnyScope={2})", + log("Code complete: sema context {0}, query scopes [{1}] (AnyScope={2}), " + "expected type {3}", getCompletionKindString(Recorder->CCContext.getKind()), - join(QueryScopes.begin(), QueryScopes.end(), ","), AllScopes); + join(QueryScopes.begin(), QueryScopes.end(), ","), AllScopes, + PreferredType ? Recorder->CCContext.getPreferredType().getAsString() + : ""); }); Recorder = RecorderOwner.get(); @@ -1354,6 +1359,9 @@ private: getQueryScopes(Recorder->CCContext, *Recorder->CCSema, Opts); if (!QueryScopes.empty()) ScopeProximity.emplace(QueryScopes); + PreferredType = + OpaqueType::fromType(Recorder->CCSema->getASTContext(), + Recorder->CCContext.getPreferredType()); // Sema provides the needed context to query the index. // FIXME: in addition to querying for extra/overlapping symbols, we should // explicitly request symbols corresponding to Sema results. @@ -1492,6 +1500,8 @@ private: Relevance.FileProximityMatch = FileProximity.getPointer(); if (ScopeProximity) Relevance.ScopeProximityMatch = ScopeProximity.getPointer(); + if (PreferredType) + Relevance.HadContextType = true; auto &First = Bundle.front(); if (auto FuzzyScore = fuzzyScore(First)) @@ -1506,10 +1516,24 @@ private: Relevance.merge(*Candidate.IndexResult); Origin |= Candidate.IndexResult->Origin; FromIndex = true; + if (!Candidate.IndexResult->Type.empty()) + Relevance.HadSymbolType |= true; + if (PreferredType && + PreferredType->raw() == Candidate.IndexResult->Type) { + Relevance.TypeMatchesPreferred = true; + } } if (Candidate.SemaResult) { Quality.merge(*Candidate.SemaResult); Relevance.merge(*Candidate.SemaResult); + if (PreferredType) { + if (auto CompletionType = OpaqueType::fromCompletionResult( + Recorder->CCSema->getASTContext(), *Candidate.SemaResult)) { + Relevance.HadSymbolType |= true; + if (PreferredType == CompletionType) + Relevance.TypeMatchesPreferred = true; + } + } Origin |= SymbolOrigin::AST; } } diff --git a/clang-tools-extra/clangd/Quality.cpp b/clang-tools-extra/clangd/Quality.cpp index 640f543..cb1f64a 100644 --- a/clang-tools-extra/clangd/Quality.cpp +++ b/clang-tools-extra/clangd/Quality.cpp @@ -369,6 +369,9 @@ float SymbolRelevanceSignals::evaluate() const { } } + if (TypeMatchesPreferred) + Score *= 5.0; + // Penalize non-instance members when they are accessed via a class instance. if (!IsInstanceMember && (Context == CodeCompletionContext::CCC_DotMemberAccess || @@ -412,6 +415,10 @@ raw_ostream &operator<<(raw_ostream &OS, const SymbolRelevanceSignals &S) { OS << formatv("\tIndex scope boost: {0}\n", scopeBoost(*S.ScopeProximityMatch, S.SymbolScope)); + OS << formatv( + "\tType matched preferred: {0} (Context type: {1}, Symbol type: {2}\n", + S.TypeMatchesPreferred, S.HadContextType, S.HadSymbolType); + return OS; } diff --git a/clang-tools-extra/clangd/Quality.h b/clang-tools-extra/clangd/Quality.h index d718556..f85e427 100644 --- a/clang-tools-extra/clangd/Quality.h +++ b/clang-tools-extra/clangd/Quality.h @@ -28,6 +28,7 @@ #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_QUALITY_H #define LLVM_CLANG_TOOLS_EXTRA_CLANGD_QUALITY_H +#include "ExpectedTypes.h" #include "FileDistance.h" #include "clang/Sema/CodeCompleteConsumer.h" #include "llvm/ADT/ArrayRef.h" @@ -122,6 +123,13 @@ struct SymbolRelevanceSignals { // Whether symbol is an instance member of a class. bool IsInstanceMember = false; + // Whether clang provided a preferred type in the completion context. + bool HadContextType = false; + // Whether a source completion item or a symbol had a type information. + bool HadSymbolType = false; + // Whether the item matches the type expected in the completion context. + bool TypeMatchesPreferred = false; + void merge(const CodeCompletionResult &SemaResult); void merge(const Symbol &IndexResult); diff --git a/clang-tools-extra/clangd/index/Index.h b/clang-tools-extra/clangd/index/Index.h index 0c1d586..11c1176 100644 --- a/clang-tools-extra/clangd/index/Index.h +++ b/clang-tools-extra/clangd/index/Index.h @@ -494,6 +494,8 @@ struct FuzzyFindRequest { /// Paths should be absolute. std::vector ProximityPaths; + // FIXME(ibiryukov): add expected type to the request. + bool operator==(const FuzzyFindRequest &Req) const { return std::tie(Query, Scopes, Limit, RestrictForCodeCompletion, ProximityPaths) == -- 2.7.4