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/ExpectedTypes.h =================================================================== --- clangd/ExpectedTypes.h +++ clangd/ExpectedTypes.h @@ -39,6 +39,7 @@ /// Construct an instance from a clang::QualType. This is usually a /// PreferredType from a clang's completion context. static llvm::Optional fromType(ASTContext &Ctx, QualType Type); + static OpaqueType fromRaw(llvm::StringRef Data) { return OpaqueType(Data); } /// Get the raw byte representation of the type. You can only rely on the /// types being equal iff their raw representation is the same. The particular 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. These are raw representation of `OpaqueType`. + 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.h =================================================================== --- clangd/index/dex/Dex.h +++ clangd/index/dex/Dex.h @@ -77,6 +77,10 @@ private: void buildIndex(); std::unique_ptr iterator(const Token &Tok) const; + std::unique_ptr + createFileProximityIterator(llvm::ArrayRef ProximityPaths) const; + std::unique_ptr + createTypeBoostingIterator(llvm::ArrayRef Types) const; /// Stores symbols sorted in the descending order of symbol quality.. std::vector Symbols; 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,49 +53,11 @@ 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; } -// Constructs BOOST iterators for Path Proximities. -std::unique_ptr createFileProximityIterator( - llvm::ArrayRef ProximityPaths, - const llvm::DenseMap &InvertedIndex, - const Corpus &Corpus) { - std::vector> BoostingIterators; - // Deduplicate parent URIs extracted from the ProximityPaths. - llvm::StringSet<> ParentURIs; - llvm::StringMap Sources; - for (const auto &Path : ProximityPaths) { - Sources[Path] = SourceParams(); - auto PathURI = URI::create(Path); - const auto PathProximityURIs = generateProximityURIs(PathURI.toString()); - for (const auto &ProximityURI : PathProximityURIs) - ParentURIs.insert(ProximityURI); - } - // Use SymbolRelevanceSignals for symbol relevance evaluation: use defaults - // for all parameters except for Proximity Path distance signal. - SymbolRelevanceSignals PathProximitySignals; - // DistanceCalculator will find the shortest distance from ProximityPaths to - // any URI extracted from the ProximityPaths. - URIDistance DistanceCalculator(Sources); - PathProximitySignals.FileProximityMatch = &DistanceCalculator; - // Try to build BOOST iterator for each Proximity Path provided by - // ProximityPaths. Boosting factor should depend on the distance to the - // Proximity Path: the closer processed path is, the higher boosting factor. - for (const auto &ParentURI : ParentURIs.keys()) { - Token Tok(Token::Kind::ProximityURI, ParentURI); - const auto It = InvertedIndex.find(Tok); - if (It != InvertedIndex.end()) { - // FIXME(kbobyrev): Append LIMIT on top of every BOOST iterator. - PathProximitySignals.SymbolURI = ParentURI; - BoostingIterators.push_back(Corpus.boost( - It->second.iterator(&It->first), PathProximitySignals.evaluate())); - } - } - BoostingIterators.push_back(Corpus.all()); - return Corpus.unionOf(std::move(BoostingIterators)); -} - } // namespace void Dex::buildIndex() { @@ -141,6 +102,57 @@ : It->second.iterator(&It->first); } +// Constructs BOOST iterators for Path Proximities. +std::unique_ptr Dex::createFileProximityIterator( + llvm::ArrayRef ProximityPaths) const { + std::vector> BoostingIterators; + // Deduplicate parent URIs extracted from the ProximityPaths. + llvm::StringSet<> ParentURIs; + llvm::StringMap Sources; + for (const auto &Path : ProximityPaths) { + Sources[Path] = SourceParams(); + auto PathURI = URI::create(Path); + const auto PathProximityURIs = generateProximityURIs(PathURI.toString()); + for (const auto &ProximityURI : PathProximityURIs) + ParentURIs.insert(ProximityURI); + } + // Use SymbolRelevanceSignals for symbol relevance evaluation: use defaults + // for all parameters except for Proximity Path distance signal. + SymbolRelevanceSignals PathProximitySignals; + // DistanceCalculator will find the shortest distance from ProximityPaths to + // any URI extracted from the ProximityPaths. + URIDistance DistanceCalculator(Sources); + PathProximitySignals.FileProximityMatch = &DistanceCalculator; + // Try to build BOOST iterator for each Proximity Path provided by + // ProximityPaths. Boosting factor should depend on the distance to the + // Proximity Path: the closer processed path is, the higher boosting factor. + for (const auto &ParentURI : ParentURIs.keys()) { + // FIXME(kbobyrev): Append LIMIT on top of every BOOST iterator. + auto It = iterator(Token(Token::Kind::ProximityURI, ParentURI)); + if (It->kind() != Iterator::Kind::False) { + PathProximitySignals.SymbolURI = ParentURI; + BoostingIterators.push_back( + Corpus.boost(std::move(It), PathProximitySignals.evaluate())); + } + } + BoostingIterators.push_back(Corpus.all()); + return Corpus.unionOf(std::move(BoostingIterators)); +} + +// Constructs BOOST iterators for preferred types. +std::unique_ptr +Dex::createTypeBoostingIterator(llvm::ArrayRef Types) const { + std::vector> BoostingIterators; + SymbolRelevanceSignals PreferredTypeSignals; + PreferredTypeSignals.TypeMatchesPreferred = true; + auto Boost = PreferredTypeSignals.evaluate(); + for (const auto &T : Types) + BoostingIterators.push_back( + Corpus.boost(iterator(Token(Token::Kind::Type, T)), Boost)); + BoostingIterators.push_back(Corpus.all()); + return Corpus.unionOf(std::move(BoostingIterators)); +} + /// Constructs iterators over tokens extracted from the query and exhausts it /// while applying Callback to each symbol in the order of decreasing quality /// of the matched symbols. @@ -174,8 +186,9 @@ Criteria.push_back(Corpus.unionOf(move(ScopeIterators))); // Add proximity paths boosting (all symbols, some boosted). - Criteria.push_back( - createFileProximityIterator(Req.ProximityPaths, InvertedIndex, Corpus)); + Criteria.push_back(createFileProximityIterator(Req.ProximityPaths)); + // Add boosting for preferred types. + Criteria.push_back(createTypeBoostingIterator(Req.PreferredTypes)); 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 preferred type. + 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