1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
|
//===--- MemIndex.cpp - Dynamic in-memory symbol index. ----------*- C++-*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===-------------------------------------------------------------------===//
#include "MemIndex.h"
#include "FuzzyMatch.h"
#include "Quality.h"
#include "index/Index.h"
#include "support/Trace.h"
namespace clang {
namespace clangd {
std::unique_ptr<SymbolIndex> MemIndex::build(SymbolSlab Slab, RefSlab Refs,
RelationSlab Relations) {
// Store Slab size before it is moved.
const auto BackingDataSize = Slab.bytes() + Refs.bytes();
auto Data = std::make_pair(std::move(Slab), std::move(Refs));
return std::make_unique<MemIndex>(Data.first, Data.second, Relations,
std::move(Data), BackingDataSize);
}
bool MemIndex::fuzzyFind(
const FuzzyFindRequest &Req,
llvm::function_ref<void(const Symbol &)> Callback) const {
assert(!StringRef(Req.Query).contains("::") &&
"There must be no :: in query.");
trace::Span Tracer("MemIndex fuzzyFind");
TopN<std::pair<float, const Symbol *>> Top(
Req.Limit.value_or(std::numeric_limits<size_t>::max()));
FuzzyMatcher Filter(Req.Query);
bool More = false;
for (const auto &Pair : Index) {
const Symbol *Sym = Pair.second;
// Exact match against all possible scopes.
if (!Req.AnyScope && !llvm::is_contained(Req.Scopes, Sym->Scope))
continue;
if (Req.RestrictForCodeCompletion &&
!(Sym->Flags & Symbol::IndexedForCodeCompletion))
continue;
if (auto Score = Filter.match(Sym->Name))
if (Top.push({*Score * quality(*Sym), Sym}))
More = true; // An element with smallest score was discarded.
}
auto Results = std::move(Top).items();
SPAN_ATTACH(Tracer, "results", static_cast<int>(Results.size()));
for (const auto &Item : Results)
Callback(*Item.second);
return More;
}
void MemIndex::lookup(const LookupRequest &Req,
llvm::function_ref<void(const Symbol &)> Callback) const {
trace::Span Tracer("MemIndex lookup");
for (const auto &ID : Req.IDs) {
auto I = Index.find(ID);
if (I != Index.end())
Callback(*I->second);
}
}
bool MemIndex::refs(const RefsRequest &Req,
llvm::function_ref<void(const Ref &)> Callback) const {
trace::Span Tracer("MemIndex refs");
uint32_t Remaining = Req.Limit.value_or(std::numeric_limits<uint32_t>::max());
for (const auto &ReqID : Req.IDs) {
auto SymRefs = Refs.find(ReqID);
if (SymRefs == Refs.end())
continue;
for (const auto &O : SymRefs->second) {
if (!static_cast<int>(Req.Filter & O.Kind))
continue;
if (Remaining == 0)
return true; // More refs were available.
--Remaining;
Callback(O);
}
}
return false; // We reported all refs.
}
bool MemIndex::containedRefs(
const ContainedRefsRequest &Req,
llvm::function_ref<void(const ContainedRefsResult &)> Callback) const {
trace::Span Tracer("MemIndex refersTo");
uint32_t Remaining = Req.Limit.value_or(std::numeric_limits<uint32_t>::max());
for (const auto &Pair : Refs) {
for (const auto &R : Pair.second) {
if (!static_cast<int>(ContainedRefsRequest::SupportedRefKinds & R.Kind) ||
Req.ID != R.Container)
continue;
if (Remaining == 0)
return true; // More refs were available.
--Remaining;
Callback({R.Location, R.Kind, Pair.first});
}
}
return false; // We reported all refs.
}
void MemIndex::relations(
const RelationsRequest &Req,
llvm::function_ref<void(const SymbolID &, const Symbol &)> Callback) const {
uint32_t Remaining = Req.Limit.value_or(std::numeric_limits<uint32_t>::max());
for (const SymbolID &Subject : Req.Subjects) {
LookupRequest LookupReq;
auto It = Relations.find(
std::make_pair(Subject, static_cast<uint8_t>(Req.Predicate)));
if (It != Relations.end()) {
for (const auto &Obj : It->second) {
if (Remaining > 0) {
--Remaining;
LookupReq.IDs.insert(Obj);
}
}
}
lookup(LookupReq, [&](const Symbol &Object) { Callback(Subject, Object); });
}
}
llvm::unique_function<IndexContents(llvm::StringRef) const>
MemIndex::indexedFiles() const {
return [this](llvm::StringRef FileURI) {
return Files.contains(FileURI) ? IdxContents : IndexContents::None;
};
}
size_t MemIndex::estimateMemoryUsage() const {
return Index.getMemorySize() + Refs.getMemorySize() +
Relations.getMemorySize() + BackingDataSize;
}
} // namespace clangd
} // namespace clang
|