Index: clangd/CodeComplete.cpp =================================================================== --- clangd/CodeComplete.cpp +++ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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; } } Index: clangd/Quality.h =================================================================== --- clangd/Quality.h +++ 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 @@ // 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); Index: clangd/Quality.cpp =================================================================== --- clangd/Quality.cpp +++ clangd/Quality.cpp @@ -369,6 +369,9 @@ } } + 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 @@ 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; } Index: clangd/index/Index.h =================================================================== --- clangd/index/Index.h +++ clangd/index/Index.h @@ -494,6 +494,8 @@ /// 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) ==