Index: clangd/CodeComplete.cpp =================================================================== --- clangd/CodeComplete.cpp +++ clangd/CodeComplete.cpp @@ -1333,6 +1333,8 @@ Req.AnyScope = AllScopes; // FIXME: we should send multiple weighted paths here. Req.ProximityPaths.push_back(FileName); + if (PreferredType) + Req.PreferredTypes.push_back(PreferredType->raw()); vlog("Code complete: fuzzyFind({0:2})", toJSON(Req)); if (SpecFuzzyFind) Index: clangd/index/Index.h =================================================================== --- clangd/index/Index.h +++ clangd/index/Index.h @@ -454,14 +454,15 @@ /// Contextually relevant files (e.g. the file we're code-completing in). /// Paths should be absolute. std::vector ProximityPaths; - - // FIXME(ibiryukov): add expected type to the request. + /// Preferred types of symbols. + std::vector PreferredTypes; bool operator==(const FuzzyFindRequest &Req) const { return std::tie(Query, Scopes, Limit, RestrictForCodeCompletion, - ProximityPaths) == + ProximityPaths, PreferredTypes) == std::tie(Req.Query, Req.Scopes, Req.Limit, - Req.RestrictForCodeCompletion, Req.ProximityPaths); + Req.RestrictForCodeCompletion, Req.ProximityPaths, + Req.PreferredTypes); } bool operator!=(const FuzzyFindRequest &Req) const { return !(*this == Req); } }; Index: clangd/index/Index.cpp =================================================================== --- clangd/index/Index.cpp +++ clangd/index/Index.cpp @@ -179,7 +179,8 @@ O && O.map("Query", Request.Query) && O.map("Scopes", Request.Scopes) && O.map("AnyScope", Request.AnyScope) && O.map("Limit", Limit) && O.map("RestrictForCodeCompletion", Request.RestrictForCodeCompletion) && - O.map("ProximityPaths", Request.ProximityPaths); + O.map("ProximityPaths", Request.ProximityPaths) && + O.map("PreferredTypes", Request.PreferredTypes); if (OK && Limit <= std::numeric_limits::max()) Request.Limit = Limit; return OK; @@ -193,6 +194,7 @@ {"Limit", Request.Limit}, {"RestrictForCodeCompletion", Request.RestrictForCodeCompletion}, {"ProximityPaths", llvm::json::Array{Request.ProximityPaths}}, + {"PreferredTypes", llvm::json::Array{Request.PreferredTypes}}, }; } Index: clangd/index/dex/Dex.cpp =================================================================== --- clangd/index/dex/Dex.cpp +++ clangd/index/dex/Dex.cpp @@ -42,7 +42,6 @@ // Returns the tokens which are given symbols's characteristics. For example, // trigrams and scopes. // FIXME(kbobyrev): Support more token types: -// * Types // * Namespace proximity std::vector generateSearchTokens(const Symbol &Sym) { std::vector Result = generateIdentifierTrigrams(Sym.Name); @@ -54,6 +53,8 @@ Result.emplace_back(Token::Kind::ProximityURI, ProximityURI); if (Sym.Flags & Symbol::IndexedForCodeCompletion) Result.emplace_back(RestrictedForCodeCompletion); + if (!Sym.Type.empty()) + Result.emplace_back(Token::Kind::Type, Sym.Type); return Result; } @@ -97,6 +98,27 @@ return Corpus.unionOf(std::move(BoostingIterators)); } +// Constructs BOOST iterators for preferred types. +std::unique_ptr createTypeBoostingIterator( + llvm::ArrayRef Types, + const llvm::DenseMap &InvertedIndex, + const Corpus &Corpus) { + std::vector> BoostingIterators; + SymbolRelevanceSignals PreferredTypeSignals; + PreferredTypeSignals.TypeMatchesPreferred = true; + auto Boost = PreferredTypeSignals.evaluate(); + for (const auto &T : Types) { + Token Tok(Token::Kind::Type, T); + const auto It = InvertedIndex.find(Tok); + if (It != InvertedIndex.end()) { + BoostingIterators.push_back( + Corpus.boost(It->second.iterator(&It->first), Boost)); + } + } + BoostingIterators.push_back(Corpus.all()); + return Corpus.unionOf(std::move(BoostingIterators)); +} + } // namespace void Dex::buildIndex() { @@ -176,6 +198,9 @@ // Add proximity paths boosting (all symbols, some boosted). Criteria.push_back( createFileProximityIterator(Req.ProximityPaths, InvertedIndex, Corpus)); + // Add boosting for preferred types. + Criteria.push_back( + createTypeBoostingIterator(Req.PreferredTypes, InvertedIndex, Corpus)); if (Req.RestrictForCodeCompletion) Criteria.push_back(iterator(RestrictedForCodeCompletion)); Index: clangd/index/dex/Token.h =================================================================== --- clangd/index/dex/Token.h +++ clangd/index/dex/Token.h @@ -62,11 +62,11 @@ /// Example: "file:///path/to/clang-tools-extra/clangd/index/SymbolIndex.h" /// and some amount of its parents. ProximityURI, + /// Type of symbol (see `Symbol::Type`). + Type, /// Internal Token type for invalid/special tokens, e.g. empty tokens for /// llvm::DenseMap. Sentinel, - /// FIXME(kbobyrev): Add other Token Kinds - /// * Type with qualified type name or its USR }; Token(Kind TokenKind, llvm::StringRef Data) @@ -91,6 +91,9 @@ case Kind::ProximityURI: OS << "U="; break; + case Kind::Type: + OS << "Ty="; + break; case Kind::Sentinel: OS << "?="; break; Index: unittests/clangd/DexTests.cpp =================================================================== --- unittests/clangd/DexTests.cpp +++ unittests/clangd/DexTests.cpp @@ -688,6 +688,28 @@ EXPECT_THAT(Files, ElementsAre(AnyOf("foo.h", "foo.cc"))); } +TEST(DexTest, PreferredTypesBoosting) { + auto Sym1 = symbol("t1"); + Sym1.Type = "T1"; + auto Sym2 = symbol("t2"); + Sym2.Type = "T2"; + + std::vector Symbols{Sym1, Sym2}; + Dex I(Symbols, RefSlab()); + + FuzzyFindRequest Req; + Req.AnyScope = true; + Req.Query = "t"; + // The best candidate can change depending on the proximity paths. + Req.Limit = 1; + + Req.PreferredTypes = {Sym1.Type}; + EXPECT_THAT(match(I, Req), ElementsAre("t1")); + + Req.PreferredTypes = {Sym2.Type}; + EXPECT_THAT(match(I, Req), ElementsAre("t2")); +} + } // namespace } // namespace dex } // namespace clangd