mirror of
https://github.com/MaskRay/ccls.git
synced 2024-11-22 07:35:08 +00:00
Remove $ccls/random; remove DB::symbols; decrease DB::entities grow rate
This commit is contained in:
parent
42bcf2b58f
commit
bb08fdfa02
@ -230,7 +230,6 @@ target_sources(ccls PRIVATE
|
|||||||
src/messages/ccls_freshen_index.cc
|
src/messages/ccls_freshen_index.cc
|
||||||
src/messages/ccls_inheritance_hierarchy.cc
|
src/messages/ccls_inheritance_hierarchy.cc
|
||||||
src/messages/ccls_member_hierarchy.cc
|
src/messages/ccls_member_hierarchy.cc
|
||||||
src/messages/ccls_random.cc
|
|
||||||
src/messages/ccls_vars.cc
|
src/messages/ccls_vars.cc
|
||||||
src/messages/exit.cc
|
src/messages/exit.cc
|
||||||
src/messages/initialize.cc
|
src/messages/initialize.cc
|
||||||
|
@ -64,7 +64,7 @@ struct SymbolRef : Reference {
|
|||||||
: Reference{range, usr, kind, role} {}
|
: Reference{range, usr, kind, role} {}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Represents an occurrence of a variable/type, |id,kind| refer to the lexical
|
// Represents an occurrence of a variable/type, |usr,kind| refer to the lexical
|
||||||
// parent.
|
// parent.
|
||||||
struct Use : Reference {
|
struct Use : Reference {
|
||||||
// |file| is used in Query* but not in Index*
|
// |file| is used in Query* but not in Index*
|
||||||
@ -239,7 +239,10 @@ struct VarDef : NameMixin<VarDef> {
|
|||||||
// (declaration).
|
// (declaration).
|
||||||
StorageClass storage = StorageClass::Invalid;
|
StorageClass storage = StorageClass::Invalid;
|
||||||
|
|
||||||
bool is_local() const { return kind == lsSymbolKind::Variable; }
|
bool is_local() const {
|
||||||
|
return spell && spell->kind != SymbolKind::File &&
|
||||||
|
storage == StorageClass::None;
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<Usr> GetBases() const { return {}; }
|
std::vector<Usr> GetBases() const { return {}; }
|
||||||
bool operator==(const VarDef& o) const {
|
bool operator==(const VarDef& o) const {
|
||||||
|
@ -125,7 +125,7 @@ MessageHandler::MessageHandler() {
|
|||||||
// static
|
// static
|
||||||
std::vector<MessageHandler*>* MessageHandler::message_handlers = nullptr;
|
std::vector<MessageHandler*>* MessageHandler::message_handlers = nullptr;
|
||||||
|
|
||||||
bool FindFileOrFail(QueryDatabase* db,
|
bool FindFileOrFail(DB* db,
|
||||||
Project* project,
|
Project* project,
|
||||||
std::optional<lsRequestId> id,
|
std::optional<lsRequestId> id,
|
||||||
const std::string& absolute_path,
|
const std::string& absolute_path,
|
||||||
@ -186,7 +186,7 @@ void EmitInactiveLines(WorkingFile* working_file,
|
|||||||
pipeline::WriteStdout(kMethodType_CclsPublishInactiveRegions, out);
|
pipeline::WriteStdout(kMethodType_CclsPublishInactiveRegions, out);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSemanticHighlighting(QueryDatabase* db,
|
void EmitSemanticHighlighting(DB* db,
|
||||||
SemanticHighlightSymbolCache* semantic_cache,
|
SemanticHighlightSymbolCache* semantic_cache,
|
||||||
WorkingFile* working_file,
|
WorkingFile* working_file,
|
||||||
QueryFile* file) {
|
QueryFile* file) {
|
||||||
|
@ -20,7 +20,7 @@ struct ImportManager;
|
|||||||
struct IncludeComplete;
|
struct IncludeComplete;
|
||||||
struct MultiQueueWaiter;
|
struct MultiQueueWaiter;
|
||||||
struct Project;
|
struct Project;
|
||||||
struct QueryDatabase;
|
struct DB;
|
||||||
struct WorkingFile;
|
struct WorkingFile;
|
||||||
struct WorkingFiles;
|
struct WorkingFiles;
|
||||||
|
|
||||||
@ -101,7 +101,7 @@ MAKE_REFLECT_STRUCT(Out_CclsPublishSemanticHighlighting,
|
|||||||
static type type##message_handler_instance_;
|
static type type##message_handler_instance_;
|
||||||
|
|
||||||
struct MessageHandler {
|
struct MessageHandler {
|
||||||
QueryDatabase* db = nullptr;
|
DB* db = nullptr;
|
||||||
MultiQueueWaiter* waiter = nullptr;
|
MultiQueueWaiter* waiter = nullptr;
|
||||||
Project* project = nullptr;
|
Project* project = nullptr;
|
||||||
DiagnosticsEngine* diag_engine = nullptr;
|
DiagnosticsEngine* diag_engine = nullptr;
|
||||||
@ -134,7 +134,7 @@ struct BaseMessageHandler : MessageHandler {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
bool FindFileOrFail(QueryDatabase* db,
|
bool FindFileOrFail(DB* db,
|
||||||
Project* project,
|
Project* project,
|
||||||
std::optional<lsRequestId> id,
|
std::optional<lsRequestId> id,
|
||||||
const std::string& absolute_path,
|
const std::string& absolute_path,
|
||||||
@ -144,7 +144,7 @@ bool FindFileOrFail(QueryDatabase* db,
|
|||||||
void EmitInactiveLines(WorkingFile* working_file,
|
void EmitInactiveLines(WorkingFile* working_file,
|
||||||
const std::vector<Range>& inactive_regions);
|
const std::vector<Range>& inactive_regions);
|
||||||
|
|
||||||
void EmitSemanticHighlighting(QueryDatabase* db,
|
void EmitSemanticHighlighting(DB* db,
|
||||||
SemanticHighlightSymbolCache* semantic_cache,
|
SemanticHighlightSymbolCache* semantic_cache,
|
||||||
WorkingFile* working_file,
|
WorkingFile* working_file,
|
||||||
QueryFile* file);
|
QueryFile* file);
|
||||||
|
@ -34,13 +34,13 @@ struct Handler_CclsBase : BaseMessageHandler<In_CclsBase> {
|
|||||||
FindSymbolsAtLocation(working_file, file, request->params.position)) {
|
FindSymbolsAtLocation(working_file, file, request->params.position)) {
|
||||||
if (sym.kind == SymbolKind::Type) {
|
if (sym.kind == SymbolKind::Type) {
|
||||||
if (const auto* def = db->GetType(sym).AnyDef())
|
if (const auto* def = db->GetType(sym).AnyDef())
|
||||||
out.result = GetLsLocationExs(
|
out.result = GetLsLocationExs(db, working_files,
|
||||||
db, working_files, GetDeclarations(db->usr2type, def->bases));
|
GetTypeDeclarations(db, def->bases));
|
||||||
break;
|
break;
|
||||||
} else if (sym.kind == SymbolKind::Func) {
|
} else if (sym.kind == SymbolKind::Func) {
|
||||||
if (const auto* def = db->GetFunc(sym).AnyDef())
|
if (const auto* def = db->GetFunc(sym).AnyDef())
|
||||||
out.result = GetLsLocationExs(
|
out.result = GetLsLocationExs(db, working_files,
|
||||||
db, working_files, GetDeclarations(db->usr2func, def->bases));
|
GetFuncDeclarations(db, def->bases));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -136,7 +136,7 @@ bool Expand(MessageHandler* m,
|
|||||||
const QueryFunc& func1 = *stack.back();
|
const QueryFunc& func1 = *stack.back();
|
||||||
stack.pop_back();
|
stack.pop_back();
|
||||||
if (auto* def1 = func1.AnyDef()) {
|
if (auto* def1 = func1.AnyDef()) {
|
||||||
EachDefinedEntity(m->db->usr2func, def1->bases, [&](QueryFunc& func2) {
|
EachDefinedFunc(m->db, def1->bases, [&](QueryFunc& func2) {
|
||||||
if (!seen.count(func2.usr)) {
|
if (!seen.count(func2.usr)) {
|
||||||
seen.insert(func2.usr);
|
seen.insert(func2.usr);
|
||||||
stack.push_back(&func2);
|
stack.push_back(&func2);
|
||||||
@ -153,7 +153,7 @@ bool Expand(MessageHandler* m,
|
|||||||
while (stack.size()) {
|
while (stack.size()) {
|
||||||
const QueryFunc& func1 = *stack.back();
|
const QueryFunc& func1 = *stack.back();
|
||||||
stack.pop_back();
|
stack.pop_back();
|
||||||
EachDefinedEntity(m->db->usr2func, func1.derived, [&](QueryFunc& func2) {
|
EachDefinedFunc(m->db, func1.derived, [&](QueryFunc& func2) {
|
||||||
if (!seen.count(func2.usr)) {
|
if (!seen.count(func2.usr)) {
|
||||||
seen.insert(func2.usr);
|
seen.insert(func2.usr);
|
||||||
stack.push_back(&func2);
|
stack.push_back(&func2);
|
||||||
@ -206,7 +206,7 @@ struct Handler_CclsCallHierarchy
|
|||||||
entry.id = std::to_string(params.usr);
|
entry.id = std::to_string(params.usr);
|
||||||
entry.usr = params.usr;
|
entry.usr = params.usr;
|
||||||
entry.callType = CallType::Direct;
|
entry.callType = CallType::Direct;
|
||||||
if (db->usr2func.count(params.usr))
|
if (db->HasFunc(params.usr))
|
||||||
Expand(this, &entry, params.callee, params.callType, params.qualified,
|
Expand(this, &entry, params.callee, params.callType, params.qualified,
|
||||||
params.levels);
|
params.levels);
|
||||||
out.result = std::move(entry);
|
out.result = std::move(entry);
|
||||||
|
@ -169,8 +169,8 @@ struct Handler_CclsInheritanceHierarchy
|
|||||||
entry.id = std::to_string(params.usr);
|
entry.id = std::to_string(params.usr);
|
||||||
entry.usr = params.usr;
|
entry.usr = params.usr;
|
||||||
entry.kind = params.kind;
|
entry.kind = params.kind;
|
||||||
if (((entry.kind == SymbolKind::Func && db->usr2func.count(entry.usr)) ||
|
if (((entry.kind == SymbolKind::Func && db->HasFunc(entry.usr)) ||
|
||||||
(entry.kind == SymbolKind::Type && db->usr2type.count(entry.usr))) &&
|
(entry.kind == SymbolKind::Type && db->HasType(entry.usr))) &&
|
||||||
Expand(this, &entry, params.derived, params.qualified, params.levels))
|
Expand(this, &entry, params.derived, params.qualified, params.levels))
|
||||||
out.result = std::move(entry);
|
out.result = std::move(entry);
|
||||||
} else {
|
} else {
|
||||||
|
@ -138,7 +138,7 @@ bool Expand(MessageHandler* m,
|
|||||||
const auto* def = stack.back()->AnyDef();
|
const auto* def = stack.back()->AnyDef();
|
||||||
stack.pop_back();
|
stack.pop_back();
|
||||||
if (def) {
|
if (def) {
|
||||||
EachDefinedEntity(m->db->usr2type, def->bases, [&](QueryType& type1) {
|
EachDefinedType(m->db, def->bases, [&](QueryType& type1) {
|
||||||
if (!seen.count(type1.usr)) {
|
if (!seen.count(type1.usr)) {
|
||||||
seen.insert(type1.usr);
|
seen.insert(type1.usr);
|
||||||
stack.push_back(&type1);
|
stack.push_back(&type1);
|
||||||
@ -171,7 +171,7 @@ bool Expand(MessageHandler* m,
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (auto it : def->vars) {
|
for (auto it : def->vars) {
|
||||||
QueryVar& var = m->db->usr2var[it.first];
|
QueryVar& var = m->db->Var(it.first);
|
||||||
if (!var.def.empty())
|
if (!var.def.empty())
|
||||||
DoField(m, entry, var, it.second, qualified, levels - 1);
|
DoField(m, entry, var, it.second, qualified, levels - 1);
|
||||||
}
|
}
|
||||||
@ -208,7 +208,7 @@ struct Handler_CclsMemberHierarchy
|
|||||||
GetLsLocation(db, working_files, *def->spell))
|
GetLsLocation(db, working_files, *def->spell))
|
||||||
entry.location = *loc;
|
entry.location = *loc;
|
||||||
}
|
}
|
||||||
EachDefinedEntity(db->usr2var, def->vars, [&](QueryVar& var) {
|
EachDefinedVar(db, def->vars, [&](QueryVar& var) {
|
||||||
DoField(this, &entry, var, -1, qualified, levels - 1);
|
DoField(this, &entry, var, -1, qualified, levels - 1);
|
||||||
});
|
});
|
||||||
return entry;
|
return entry;
|
||||||
@ -247,7 +247,7 @@ struct Handler_CclsMemberHierarchy
|
|||||||
entry.id = std::to_string(params.usr);
|
entry.id = std::to_string(params.usr);
|
||||||
entry.usr = params.usr;
|
entry.usr = params.usr;
|
||||||
// entry.name is empty as it is known by the client.
|
// entry.name is empty as it is known by the client.
|
||||||
if (db->usr2type.count(entry.usr) &&
|
if (db->HasType(entry.usr) &&
|
||||||
Expand(this, &entry, params.qualified, params.levels))
|
Expand(this, &entry, params.qualified, params.levels))
|
||||||
out.result = std::move(entry);
|
out.result = std::move(entry);
|
||||||
} else {
|
} else {
|
||||||
|
@ -1,134 +0,0 @@
|
|||||||
#include "message_handler.h"
|
|
||||||
#include "query_utils.h"
|
|
||||||
#include "pipeline.hh"
|
|
||||||
using namespace ccls;
|
|
||||||
|
|
||||||
#include <math.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <numeric>
|
|
||||||
|
|
||||||
MAKE_HASHABLE(SymbolIdx, t.usr, t.kind);
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
MethodType kMethodType = "$ccls/random";
|
|
||||||
|
|
||||||
struct In_CclsRandom : public RequestInMessage {
|
|
||||||
MethodType GetMethodType() const override { return kMethodType; }
|
|
||||||
};
|
|
||||||
MAKE_REFLECT_STRUCT(In_CclsRandom, id);
|
|
||||||
REGISTER_IN_MESSAGE(In_CclsRandom);
|
|
||||||
|
|
||||||
const double kDeclWeight = 3;
|
|
||||||
const double kDamping = 0.1;
|
|
||||||
|
|
||||||
template <auto Q>
|
|
||||||
void Add(const std::unordered_map<SymbolIdx, int>& sym2id,
|
|
||||||
std::vector<std::unordered_map<int, double>>& adj,
|
|
||||||
const std::vector<Usr>& collection,
|
|
||||||
int n,
|
|
||||||
double w = 1) {
|
|
||||||
for (Usr usr : collection) {
|
|
||||||
auto it = sym2id.find(SymbolIdx{usr, Q});
|
|
||||||
if (it != sym2id.end())
|
|
||||||
adj[it->second][n] += w;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Handler_CclsRandom : BaseMessageHandler<In_CclsRandom> {
|
|
||||||
MethodType GetMethodType() const override { return kMethodType; }
|
|
||||||
|
|
||||||
void Run(In_CclsRandom* request) override {
|
|
||||||
std::unordered_map<SymbolIdx, int> sym2id;
|
|
||||||
std::vector<SymbolIdx> syms;
|
|
||||||
int n = 0;
|
|
||||||
|
|
||||||
for (auto& it : db->usr2func)
|
|
||||||
if (it.second.AnyDef()) {
|
|
||||||
syms.push_back(SymbolIdx{it.first, SymbolKind::Func});
|
|
||||||
sym2id[syms.back()] = n++;
|
|
||||||
}
|
|
||||||
for (auto& it : db->usr2type)
|
|
||||||
if (it.second.AnyDef()) {
|
|
||||||
syms.push_back(SymbolIdx{it.first, SymbolKind::Type});
|
|
||||||
sym2id[syms.back()] = n++;
|
|
||||||
}
|
|
||||||
for (auto& it : db->usr2var)
|
|
||||||
if (it.second.AnyDef()) {
|
|
||||||
syms.push_back(SymbolIdx{it.first, SymbolKind::Var});
|
|
||||||
sym2id[syms.back()] = n++;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<std::unordered_map<int, double>> adj(n);
|
|
||||||
auto add = [&](const std::vector<Use>& uses, double w) {
|
|
||||||
for (Use use : uses) {
|
|
||||||
auto it = sym2id.find(use);
|
|
||||||
if (it != sym2id.end())
|
|
||||||
adj[it->second][n] += w;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
n = 0;
|
|
||||||
for (auto& it : db->usr2func)
|
|
||||||
if (it.second.AnyDef()) {
|
|
||||||
add(it.second.declarations, kDeclWeight);
|
|
||||||
add(it.second.uses, 1);
|
|
||||||
Add<SymbolKind::Func>(sym2id, adj, it.second.derived, n);
|
|
||||||
n++;
|
|
||||||
}
|
|
||||||
for (auto& it : db->usr2type)
|
|
||||||
if (const auto* def = it.second.AnyDef()) {
|
|
||||||
add(it.second.uses, 1);
|
|
||||||
Add<SymbolKind::Var>(sym2id, adj, it.second.instances, n);
|
|
||||||
Add<SymbolKind::Func>(sym2id, adj, def->funcs, n);
|
|
||||||
Add<SymbolKind::Type>(sym2id, adj, def->types, n);
|
|
||||||
//Add<SymbolKind::Var>(sym2id, adj, def->vars, n);
|
|
||||||
n++;
|
|
||||||
}
|
|
||||||
for (auto& it : db->usr2var)
|
|
||||||
if (it.second.AnyDef()) {
|
|
||||||
add(it.second.declarations, kDeclWeight);
|
|
||||||
add(it.second.uses, 1);
|
|
||||||
n++;
|
|
||||||
}
|
|
||||||
for (int i = 0; i < n; i++) {
|
|
||||||
double sum = 0;
|
|
||||||
adj[i][i] += 1;
|
|
||||||
for (auto& it : adj[i])
|
|
||||||
sum += it.second;
|
|
||||||
for (auto& it : adj[i])
|
|
||||||
it.second = it.second / sum * (1 - kDamping);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<double> x(n, 1), y;
|
|
||||||
for (int j = 0; j < 8; j++) {
|
|
||||||
y.assign(n, kDamping);
|
|
||||||
for (int i = 0; i < n; i++)
|
|
||||||
for (auto& it : adj[i])
|
|
||||||
y[it.first] += x[i] * it.second;
|
|
||||||
double d = 0;
|
|
||||||
for (int i = 0; i < n; i++)
|
|
||||||
d = std::max(d, fabs(x[i] - y[i]));
|
|
||||||
if (d < 1e-5)
|
|
||||||
break;
|
|
||||||
x.swap(y);
|
|
||||||
}
|
|
||||||
|
|
||||||
double sum = std::accumulate(x.begin(), x.end(), 0.);
|
|
||||||
Out_LocationList out;
|
|
||||||
out.id = request->id;
|
|
||||||
double roulette = rand() / (RAND_MAX + 1.0) * sum;
|
|
||||||
sum = 0;
|
|
||||||
for (int i = 0; i < n; i++) {
|
|
||||||
sum += x[i];
|
|
||||||
if (sum >= roulette) {
|
|
||||||
if (Maybe<Use> use = GetDefinitionExtent(db, syms[i]))
|
|
||||||
if (auto ls_loc = GetLsLocationEx(db, working_files, *use,
|
|
||||||
g_config->xref.container))
|
|
||||||
out.result.push_back(*ls_loc);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pipeline::WriteStdout(kMethodType, out);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
REGISTER_MESSAGE_HANDLER(Handler_CclsRandom);
|
|
||||||
} // namespace
|
|
@ -43,9 +43,9 @@ struct Handler_CclsVars : BaseMessageHandler<In_CclsVars> {
|
|||||||
[[fallthrough]];
|
[[fallthrough]];
|
||||||
}
|
}
|
||||||
case SymbolKind::Type:
|
case SymbolKind::Type:
|
||||||
out.result = GetLsLocationExs(
|
out.result =
|
||||||
db, working_files,
|
GetLsLocationExs(db, working_files,
|
||||||
GetDeclarations(db->usr2var, db->Type(usr).instances));
|
GetVarDeclarations(db, db->Type(usr).instances));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,7 @@ MAKE_REFLECT_STRUCT(Out_TextDocumentCodeLens, jsonrpc, id, result);
|
|||||||
|
|
||||||
struct CommonCodeLensParams {
|
struct CommonCodeLensParams {
|
||||||
std::vector<TCodeLens>* result;
|
std::vector<TCodeLens>* result;
|
||||||
QueryDatabase* db;
|
DB* db;
|
||||||
WorkingFiles* working_files;
|
WorkingFiles* working_files;
|
||||||
WorkingFile* working_file;
|
WorkingFile* working_file;
|
||||||
};
|
};
|
||||||
@ -118,10 +118,10 @@ struct Handler_TextDocumentCodeLens
|
|||||||
AddCodeLens("ref", "refs", &common, OffsetStartColumn(use, 0),
|
AddCodeLens("ref", "refs", &common, OffsetStartColumn(use, 0),
|
||||||
type.uses, true /*force_display*/);
|
type.uses, true /*force_display*/);
|
||||||
AddCodeLens("derived", "derived", &common, OffsetStartColumn(use, 1),
|
AddCodeLens("derived", "derived", &common, OffsetStartColumn(use, 1),
|
||||||
GetDeclarations(db->usr2type, type.derived),
|
GetTypeDeclarations(db, type.derived),
|
||||||
false /*force_display*/);
|
false /*force_display*/);
|
||||||
AddCodeLens("var", "vars", &common, OffsetStartColumn(use, 2),
|
AddCodeLens("var", "vars", &common, OffsetStartColumn(use, 2),
|
||||||
GetDeclarations(db->usr2var, type.instances),
|
GetVarDeclarations(db, type.instances),
|
||||||
false /*force_display*/);
|
false /*force_display*/);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -168,7 +168,7 @@ struct Handler_TextDocumentCodeLens
|
|||||||
|
|
||||||
AddCodeLens("derived", "derived", &common,
|
AddCodeLens("derived", "derived", &common,
|
||||||
OffsetStartColumn(use, offset++),
|
OffsetStartColumn(use, offset++),
|
||||||
GetDeclarations(db->usr2func, func.derived),
|
GetFuncDeclarations(db, func.derived),
|
||||||
false /*force_display*/);
|
false /*force_display*/);
|
||||||
|
|
||||||
// "Base"
|
// "Base"
|
||||||
@ -196,7 +196,7 @@ struct Handler_TextDocumentCodeLens
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
AddCodeLens("base", "base", &common, OffsetStartColumn(use, 1),
|
AddCodeLens("base", "base", &common, OffsetStartColumn(use, 1),
|
||||||
GetDeclarations(db->usr2type, def->bases),
|
GetTypeDeclarations(db, def->bases),
|
||||||
false /*force_display*/);
|
false /*force_display*/);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ struct Out_TextDocumentDefinition
|
|||||||
};
|
};
|
||||||
MAKE_REFLECT_STRUCT(Out_TextDocumentDefinition, jsonrpc, id, result);
|
MAKE_REFLECT_STRUCT(Out_TextDocumentDefinition, jsonrpc, id, result);
|
||||||
|
|
||||||
std::vector<Use> GetNonDefDeclarationTargets(QueryDatabase* db, SymbolRef sym) {
|
std::vector<Use> GetNonDefDeclarationTargets(DB* db, SymbolRef sym) {
|
||||||
switch (sym.kind) {
|
switch (sym.kind) {
|
||||||
case SymbolKind::Var: {
|
case SymbolKind::Var: {
|
||||||
std::vector<Use> ret = GetNonDefDeclarations(db, sym);
|
std::vector<Use> ret = GetNonDefDeclarations(db, sym);
|
||||||
@ -135,18 +135,16 @@ struct Handler_TextDocumentDefinition
|
|||||||
// substring, we use the tuple <length difference, negative position,
|
// substring, we use the tuple <length difference, negative position,
|
||||||
// not in the same file, line distance> to find the best match.
|
// not in the same file, line distance> to find the best match.
|
||||||
std::tuple<int, int, bool, int> best_score{INT_MAX, 0, true, 0};
|
std::tuple<int, int, bool, int> best_score{INT_MAX, 0, true, 0};
|
||||||
int best_i = -1;
|
SymbolIdx best_sym;
|
||||||
for (int i = 0; i < (int)db->symbols.size(); ++i) {
|
best_sym.kind = SymbolKind::Invalid;
|
||||||
if (db->symbols[i].kind == SymbolKind::Invalid)
|
auto fn = [&](SymbolIdx sym) {
|
||||||
continue;
|
std::string_view short_name = db->GetSymbolName(sym, false),
|
||||||
|
|
||||||
std::string_view short_name = db->GetSymbolName(i, false),
|
|
||||||
name = short_query.size() < query.size()
|
name = short_query.size() < query.size()
|
||||||
? db->GetSymbolName(i, true)
|
? db->GetSymbolName(sym, true)
|
||||||
: short_name;
|
: short_name;
|
||||||
if (short_name != short_query)
|
if (short_name != short_query)
|
||||||
continue;
|
return;
|
||||||
if (Maybe<Use> use = GetDefinitionSpell(db, db->symbols[i])) {
|
if (Maybe<Use> use = GetDefinitionSpell(db, sym)) {
|
||||||
std::tuple<int, int, bool, int> score{
|
std::tuple<int, int, bool, int> score{
|
||||||
int(name.size() - short_query.size()), 0,
|
int(name.size() - short_query.size()), 0,
|
||||||
use->file_id != file_id,
|
use->file_id != file_id,
|
||||||
@ -160,12 +158,20 @@ struct Handler_TextDocumentDefinition
|
|||||||
}
|
}
|
||||||
if (score < best_score) {
|
if (score < best_score) {
|
||||||
best_score = score;
|
best_score = score;
|
||||||
best_i = i;
|
best_sym = sym;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
if (best_i != -1) {
|
for (auto& func : db->funcs)
|
||||||
Maybe<Use> use = GetDefinitionSpell(db, db->symbols[best_i]);
|
fn({func.usr, SymbolKind::Func});
|
||||||
|
for (auto& type : db->types)
|
||||||
|
fn({type.usr, SymbolKind::Type});
|
||||||
|
for (auto& var : db->vars)
|
||||||
|
if (var.def.size() && !var.def[0].is_local())
|
||||||
|
fn({var.usr, SymbolKind::Var});
|
||||||
|
|
||||||
|
if (best_sym.kind != SymbolKind::Invalid) {
|
||||||
|
Maybe<Use> use = GetDefinitionSpell(db, best_sym);
|
||||||
assert(use);
|
assert(use);
|
||||||
if (auto ls_loc = GetLsLocationEx(db, working_files, *use,
|
if (auto ls_loc = GetLsLocationEx(db, working_files, *use,
|
||||||
g_config->xref.container))
|
g_config->xref.container))
|
||||||
|
@ -7,7 +7,7 @@ namespace {
|
|||||||
MethodType kMethodType = "textDocument/hover";
|
MethodType kMethodType = "textDocument/hover";
|
||||||
|
|
||||||
// Find the comments for |sym|, if any.
|
// Find the comments for |sym|, if any.
|
||||||
std::optional<lsMarkedString> GetComments(QueryDatabase* db, SymbolRef sym) {
|
std::optional<lsMarkedString> GetComments(DB* db, SymbolRef sym) {
|
||||||
std::optional<lsMarkedString> ret;
|
std::optional<lsMarkedString> ret;
|
||||||
WithEntity(db, sym, [&](const auto& entity) {
|
WithEntity(db, sym, [&](const auto& entity) {
|
||||||
if (const auto* def = entity.AnyDef())
|
if (const auto* def = entity.AnyDef())
|
||||||
@ -21,7 +21,7 @@ std::optional<lsMarkedString> GetComments(QueryDatabase* db, SymbolRef sym) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Returns the hover or detailed name for `sym`, if any.
|
// Returns the hover or detailed name for `sym`, if any.
|
||||||
std::optional<lsMarkedString> GetHoverOrName(QueryDatabase* db,
|
std::optional<lsMarkedString> GetHoverOrName(DB* db,
|
||||||
LanguageId lang,
|
LanguageId lang,
|
||||||
SymbolRef sym) {
|
SymbolRef sym) {
|
||||||
std::optional<lsMarkedString> ret;
|
std::optional<lsMarkedString> ret;
|
||||||
|
@ -32,13 +32,13 @@ struct Handler_TextDocumentImplementation
|
|||||||
FindSymbolsAtLocation(working_file, file, request->params.position)) {
|
FindSymbolsAtLocation(working_file, file, request->params.position)) {
|
||||||
if (sym.kind == SymbolKind::Type) {
|
if (sym.kind == SymbolKind::Type) {
|
||||||
QueryType& type = db->GetType(sym);
|
QueryType& type = db->GetType(sym);
|
||||||
out.result = GetLsLocationExs(
|
out.result = GetLsLocationExs(db, working_files,
|
||||||
db, working_files, GetDeclarations(db->usr2type, type.derived));
|
GetTypeDeclarations(db, type.derived));
|
||||||
break;
|
break;
|
||||||
} else if (sym.kind == SymbolKind::Func) {
|
} else if (sym.kind == SymbolKind::Func) {
|
||||||
QueryFunc& func = db->GetFunc(sym);
|
QueryFunc& func = db->GetFunc(sym);
|
||||||
out.result = GetLsLocationExs(
|
out.result = GetLsLocationExs(db, working_files,
|
||||||
db, working_files, GetDeclarations(db->usr2func, func.derived));
|
GetFuncDeclarations(db, func.derived));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ using namespace ccls;
|
|||||||
namespace {
|
namespace {
|
||||||
MethodType kMethodType = "textDocument/rename";
|
MethodType kMethodType = "textDocument/rename";
|
||||||
|
|
||||||
lsWorkspaceEdit BuildWorkspaceEdit(QueryDatabase* db,
|
lsWorkspaceEdit BuildWorkspaceEdit(DB* db,
|
||||||
WorkingFiles* working_files,
|
WorkingFiles* working_files,
|
||||||
SymbolRef sym,
|
SymbolRef sym,
|
||||||
const std::string& new_text) {
|
const std::string& new_text) {
|
||||||
|
@ -15,22 +15,21 @@ MethodType kMethodType = "workspace/symbol";
|
|||||||
|
|
||||||
// Lookup |symbol| in |db| and insert the value into |result|.
|
// Lookup |symbol| in |db| and insert the value into |result|.
|
||||||
bool AddSymbol(
|
bool AddSymbol(
|
||||||
QueryDatabase* db,
|
DB* db,
|
||||||
WorkingFiles* working_files,
|
WorkingFiles* working_files,
|
||||||
int i,
|
SymbolIdx sym,
|
||||||
bool use_detailed,
|
bool use_detailed,
|
||||||
std::vector<std::tuple<lsSymbolInformation, bool, int>>* result) {
|
std::vector<std::tuple<lsSymbolInformation, int, SymbolIdx>>* result) {
|
||||||
SymbolIdx symbol = db->symbols[i];
|
|
||||||
std::optional<lsSymbolInformation> info =
|
std::optional<lsSymbolInformation> info =
|
||||||
GetSymbolInfo(db, working_files, symbol, true);
|
GetSymbolInfo(db, working_files, sym, true);
|
||||||
if (!info)
|
if (!info)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
Use loc;
|
Use loc;
|
||||||
if (Maybe<Use> location = GetDefinitionExtent(db, symbol))
|
if (Maybe<Use> location = GetDefinitionExtent(db, sym))
|
||||||
loc = *location;
|
loc = *location;
|
||||||
else {
|
else {
|
||||||
auto decls = GetNonDefDeclarations(db, symbol);
|
auto decls = GetNonDefDeclarations(db, sym);
|
||||||
if (decls.empty())
|
if (decls.empty())
|
||||||
return false;
|
return false;
|
||||||
loc = decls[0];
|
loc = decls[0];
|
||||||
@ -40,7 +39,7 @@ bool AddSymbol(
|
|||||||
if (!ls_location)
|
if (!ls_location)
|
||||||
return false;
|
return false;
|
||||||
info->location = *ls_location;
|
info->location = *ls_location;
|
||||||
result->emplace_back(*info, use_detailed, i);
|
result->emplace_back(*info, int(use_detailed), sym);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,7 +71,7 @@ struct Handler_WorkspaceSymbol : BaseMessageHandler<In_WorkspaceSymbol> {
|
|||||||
std::string query = request->params.query;
|
std::string query = request->params.query;
|
||||||
|
|
||||||
// {symbol info, matching detailed_name or short_name, index}
|
// {symbol info, matching detailed_name or short_name, index}
|
||||||
std::vector<std::tuple<lsSymbolInformation, bool, int>> unsorted;
|
std::vector<std::tuple<lsSymbolInformation, int, SymbolIdx>> cands;
|
||||||
bool sensitive = g_config->workspaceSymbol.caseSensitivity;
|
bool sensitive = g_config->workspaceSymbol.caseSensitivity;
|
||||||
|
|
||||||
// Find subsequence matches.
|
// Find subsequence matches.
|
||||||
@ -82,47 +81,52 @@ struct Handler_WorkspaceSymbol : BaseMessageHandler<In_WorkspaceSymbol> {
|
|||||||
if (!isspace(c))
|
if (!isspace(c))
|
||||||
query_without_space += c;
|
query_without_space += c;
|
||||||
|
|
||||||
for (int i = 0; i < (int)db->symbols.size(); ++i) {
|
auto Add = [&](SymbolIdx sym) {
|
||||||
std::string_view detailed_name = db->GetSymbolName(i, true);
|
std::string_view detailed_name = db->GetSymbolName(sym, true);
|
||||||
int pos =
|
int pos =
|
||||||
ReverseSubseqMatch(query_without_space, detailed_name, sensitive);
|
ReverseSubseqMatch(query_without_space, detailed_name, sensitive);
|
||||||
if (pos >= 0 &&
|
return pos >= 0 &&
|
||||||
AddSymbol(db, working_files, i,
|
AddSymbol(db, working_files, sym,
|
||||||
detailed_name.find(':', pos) != std::string::npos,
|
detailed_name.find(':', pos) != std::string::npos,
|
||||||
&unsorted) &&
|
&cands) &&
|
||||||
unsorted.size() >= g_config->workspaceSymbol.maxNum)
|
cands.size() >= g_config->workspaceSymbol.maxNum;
|
||||||
break;
|
};
|
||||||
}
|
for (auto& func : db->funcs)
|
||||||
|
if (Add({func.usr, SymbolKind::Func}))
|
||||||
|
goto done_add;
|
||||||
|
for (auto& type : db->types)
|
||||||
|
if (Add({type.usr, SymbolKind::Type}))
|
||||||
|
goto done_add;
|
||||||
|
for (auto& var : db->vars)
|
||||||
|
if (var.def.size() && !var.def[0].is_local() &&
|
||||||
|
Add({var.usr, SymbolKind::Var}))
|
||||||
|
goto done_add;
|
||||||
|
done_add:
|
||||||
|
|
||||||
if (g_config->workspaceSymbol.sort && query.size() <= FuzzyMatcher::kMaxPat) {
|
if (g_config->workspaceSymbol.sort && query.size() <= FuzzyMatcher::kMaxPat) {
|
||||||
// Sort results with a fuzzy matching algorithm.
|
// Sort results with a fuzzy matching algorithm.
|
||||||
int longest = 0;
|
int longest = 0;
|
||||||
for (int i = 0; i < int(unsorted.size()); i++) {
|
for (auto& cand : cands)
|
||||||
longest = std::max(
|
longest = std::max(
|
||||||
longest,
|
longest, int(db->GetSymbolName(std::get<2>(cand), true).size()));
|
||||||
int(db->GetSymbolName(std::get<2>(unsorted[i]), true).size()));
|
|
||||||
}
|
|
||||||
FuzzyMatcher fuzzy(query, g_config->workspaceSymbol.caseSensitivity);
|
FuzzyMatcher fuzzy(query, g_config->workspaceSymbol.caseSensitivity);
|
||||||
std::vector<std::pair<int, int>> permutation(unsorted.size());
|
for (auto& cand : cands)
|
||||||
for (int i = 0; i < int(unsorted.size()); i++) {
|
std::get<1>(cand) = fuzzy.Match(
|
||||||
permutation[i] = {
|
db->GetSymbolName(std::get<2>(cand), std::get<1>(cand)));
|
||||||
fuzzy.Match(db->GetSymbolName(std::get<2>(unsorted[i]),
|
std::sort(cands.begin(), cands.end(), [](const auto& l, const auto& r) {
|
||||||
std::get<1>(unsorted[i]))),
|
return std::get<1>(l) > std::get<1>(r);
|
||||||
i};
|
});
|
||||||
|
out.result.reserve(cands.size());
|
||||||
|
for (auto& cand: cands) {
|
||||||
|
// Discard awful candidates.
|
||||||
|
if (std::get<1>(cand) <= FuzzyMatcher::kMinScore)
|
||||||
|
break;
|
||||||
|
out.result.push_back(std::get<0>(cand));
|
||||||
}
|
}
|
||||||
std::sort(permutation.begin(), permutation.end(),
|
|
||||||
std::greater<std::pair<int, int>>());
|
|
||||||
out.result.reserve(unsorted.size());
|
|
||||||
// Discard awful candidates.
|
|
||||||
for (int i = 0; i < int(unsorted.size()) &&
|
|
||||||
permutation[i].first > FuzzyMatcher::kMinScore;
|
|
||||||
i++)
|
|
||||||
out.result.push_back(
|
|
||||||
std::move(std::get<0>(unsorted[permutation[i].second])));
|
|
||||||
} else {
|
} else {
|
||||||
out.result.reserve(unsorted.size());
|
out.result.reserve(cands.size());
|
||||||
for (auto& entry : unsorted)
|
for (auto& cand : cands)
|
||||||
out.result.push_back(std::get<0>(entry));
|
out.result.push_back(std::get<0>(cand));
|
||||||
}
|
}
|
||||||
|
|
||||||
pipeline::WriteStdout(kMethodType, out);
|
pipeline::WriteStdout(kMethodType, out);
|
||||||
|
@ -299,7 +299,7 @@ void Indexer_Main(DiagnosticsEngine* diag_engine,
|
|||||||
indexer_waiter->Wait(index_request);
|
indexer_waiter->Wait(index_request);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Main_OnIndexed(QueryDatabase* db,
|
void Main_OnIndexed(DB* db,
|
||||||
SemanticHighlightSymbolCache* semantic_cache,
|
SemanticHighlightSymbolCache* semantic_cache,
|
||||||
WorkingFiles* working_files,
|
WorkingFiles* working_files,
|
||||||
Index_OnIndexed* response) {
|
Index_OnIndexed* response) {
|
||||||
@ -431,7 +431,7 @@ void MainLoop() {
|
|||||||
auto global_code_complete_cache = std::make_unique<CodeCompleteCache>();
|
auto global_code_complete_cache = std::make_unique<CodeCompleteCache>();
|
||||||
auto non_global_code_complete_cache = std::make_unique<CodeCompleteCache>();
|
auto non_global_code_complete_cache = std::make_unique<CodeCompleteCache>();
|
||||||
auto signature_cache = std::make_unique<CodeCompleteCache>();
|
auto signature_cache = std::make_unique<CodeCompleteCache>();
|
||||||
QueryDatabase db;
|
DB db;
|
||||||
|
|
||||||
// Setup shared references.
|
// Setup shared references.
|
||||||
for (MessageHandler* handler : *MessageHandler::message_handlers) {
|
for (MessageHandler* handler : *MessageHandler::message_handlers) {
|
||||||
|
178
src/query.cc
178
src/query.cc
@ -14,7 +14,7 @@
|
|||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
|
|
||||||
// Used by |HANDLE_MERGEABLE| so only |range| is needed.
|
// Used by |REMOVE_ADD| so only |range| is needed.
|
||||||
MAKE_HASHABLE(Use, t.range, t.file_id);
|
MAKE_HASHABLE(Use, t.range, t.file_id);
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
@ -178,6 +178,7 @@ IndexUpdate IndexUpdate::CreateDelta(IndexFile* previous,
|
|||||||
|
|
||||||
r.files_def_update = BuildFileDefUpdate(std::move(*current));
|
r.files_def_update = BuildFileDefUpdate(std::move(*current));
|
||||||
|
|
||||||
|
r.funcs_hint = int(current->usr2func.size() - previous->usr2func.size());
|
||||||
for (auto& it : previous->usr2func) {
|
for (auto& it : previous->usr2func) {
|
||||||
auto& func = it.second;
|
auto& func = it.second;
|
||||||
if (func.def.spell)
|
if (func.def.spell)
|
||||||
@ -195,6 +196,7 @@ IndexUpdate IndexUpdate::CreateDelta(IndexFile* previous,
|
|||||||
r.funcs_derived[func.usr].second = std::move(func.derived);
|
r.funcs_derived[func.usr].second = std::move(func.derived);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
r.types_hint = int(current->usr2type.size() - previous->usr2type.size());
|
||||||
for (auto& it : previous->usr2type) {
|
for (auto& it : previous->usr2type) {
|
||||||
auto& type = it.second;
|
auto& type = it.second;
|
||||||
if (type.def.spell)
|
if (type.def.spell)
|
||||||
@ -214,6 +216,7 @@ IndexUpdate IndexUpdate::CreateDelta(IndexFile* previous,
|
|||||||
r.types_instances[type.usr].second = std::move(type.instances);
|
r.types_instances[type.usr].second = std::move(type.instances);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
r.vars_hint = int(current->usr2var.size() - previous->usr2var.size());
|
||||||
for (auto& it : previous->usr2var) {
|
for (auto& it : previous->usr2var) {
|
||||||
auto& var = it.second;
|
auto& var = it.second;
|
||||||
if (var.def.spell)
|
if (var.def.spell)
|
||||||
@ -232,34 +235,14 @@ IndexUpdate IndexUpdate::CreateDelta(IndexFile* previous,
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------
|
void DB::RemoveUsrs(SymbolKind kind,
|
||||||
// QUERYDB THREAD FUNCTIONS
|
int file_id,
|
||||||
// ------------------------
|
const std::vector<Usr>& to_remove) {
|
||||||
|
|
||||||
void QueryDatabase::RemoveUsrs(SymbolKind usr_kind,
|
|
||||||
const std::vector<Usr>& to_remove) {
|
|
||||||
switch (usr_kind) {
|
|
||||||
case SymbolKind::Type: {
|
|
||||||
for (Usr usr : to_remove) {
|
|
||||||
QueryType& type = usr2type[usr];
|
|
||||||
if (type.symbol_idx >= 0)
|
|
||||||
symbols[type.symbol_idx].kind = SymbolKind::Invalid;
|
|
||||||
type.def.clear();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void QueryDatabase::RemoveUsrs(
|
|
||||||
SymbolKind kind,
|
|
||||||
int file_id,
|
|
||||||
const std::vector<Usr>& to_remove) {
|
|
||||||
switch (kind) {
|
switch (kind) {
|
||||||
case SymbolKind::Func: {
|
case SymbolKind::Func: {
|
||||||
for (auto usr : to_remove) {
|
for (Usr usr : to_remove) {
|
||||||
|
// FIXME
|
||||||
|
if (!HasFunc(usr)) continue;
|
||||||
QueryFunc& func = Func(usr);
|
QueryFunc& func = Func(usr);
|
||||||
auto it = llvm::find_if(func.def, [=](const QueryFunc::Def& def) {
|
auto it = llvm::find_if(func.def, [=](const QueryFunc::Def& def) {
|
||||||
return def.spell->file_id == file_id;
|
return def.spell->file_id == file_id;
|
||||||
@ -269,8 +252,23 @@ void QueryDatabase::RemoveUsrs(
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case SymbolKind::Type: {
|
||||||
|
for (Usr usr : to_remove) {
|
||||||
|
// FIXME
|
||||||
|
if (!HasType(usr)) continue;
|
||||||
|
QueryType& type = Type(usr);
|
||||||
|
auto it = llvm::find_if(type.def, [=](const QueryType::Def& def) {
|
||||||
|
return def.spell->file_id == file_id;
|
||||||
|
});
|
||||||
|
if (it != type.def.end())
|
||||||
|
type.def.erase(it);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
case SymbolKind::Var: {
|
case SymbolKind::Var: {
|
||||||
for (auto usr : to_remove) {
|
for (Usr usr : to_remove) {
|
||||||
|
// FIXME
|
||||||
|
if (!HasVar(usr)) continue;
|
||||||
QueryVar& var = Var(usr);
|
QueryVar& var = Var(usr);
|
||||||
auto it = llvm::find_if(var.def, [=](const QueryVar::Def& def) {
|
auto it = llvm::find_if(var.def, [=](const QueryVar::Def& def) {
|
||||||
return def.spell->file_id == file_id;
|
return def.spell->file_id == file_id;
|
||||||
@ -281,26 +279,21 @@ void QueryDatabase::RemoveUsrs(
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
assert(false);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void QueryDatabase::ApplyIndexUpdate(IndexUpdate* u) {
|
void DB::ApplyIndexUpdate(IndexUpdate* u) {
|
||||||
// This function runs on the querydb thread.
|
#define REMOVE_ADD(C, F) \
|
||||||
|
for (auto& it : u->C##s_##F) { \
|
||||||
// Example types:
|
auto R = C##_usr.try_emplace({it.first}, C##_usr.size()); \
|
||||||
// storage_name => std::vector<std::optional<QueryType>>
|
if (R.second) \
|
||||||
// merge_update => QueryType::DerivedUpdate =>
|
C##s.emplace_back().usr = it.first; \
|
||||||
// MergeableUpdate<QueryTypeId, QueryTypeId> def => QueryType
|
auto& entity = C##s[R.first->second]; \
|
||||||
// def->def_var_name => std::vector<QueryTypeId>
|
AssignFileId(u->file_id, it.second.first); \
|
||||||
#define HANDLE_MERGEABLE(update_var_name, def_var_name, storage_name) \
|
RemoveRange(entity.F, it.second.first); \
|
||||||
for (auto& it : u->update_var_name) { \
|
AssignFileId(u->file_id, it.second.second); \
|
||||||
auto& entity = storage_name[it.first]; \
|
AddRange(u->file_id, entity.F, it.second.second); \
|
||||||
AssignFileId(u->file_id, it.second.first); \
|
|
||||||
RemoveRange(entity.def_var_name, it.second.first); \
|
|
||||||
AssignFileId(u->file_id, it.second.second); \
|
|
||||||
AddRange(u->file_id, entity.def_var_name, it.second.second); \
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (u->files_removed)
|
if (u->files_removed)
|
||||||
@ -308,101 +301,108 @@ void QueryDatabase::ApplyIndexUpdate(IndexUpdate* u) {
|
|||||||
std::nullopt;
|
std::nullopt;
|
||||||
u->file_id = u->files_def_update ? Update(std::move(*u->files_def_update)) : -1;
|
u->file_id = u->files_def_update ? Update(std::move(*u->files_def_update)) : -1;
|
||||||
|
|
||||||
|
const double grow = 1.3;
|
||||||
|
size_t t;
|
||||||
|
|
||||||
|
if ((t = funcs.size() + u->funcs_hint) > funcs.capacity()) {
|
||||||
|
t = size_t(t * grow);
|
||||||
|
funcs.reserve(t);
|
||||||
|
func_usr.reserve(t);
|
||||||
|
}
|
||||||
RemoveUsrs(SymbolKind::Func, u->file_id, u->funcs_removed);
|
RemoveUsrs(SymbolKind::Func, u->file_id, u->funcs_removed);
|
||||||
Update(u->file_id, std::move(u->funcs_def_update));
|
Update(u->file_id, std::move(u->funcs_def_update));
|
||||||
HANDLE_MERGEABLE(funcs_declarations, declarations, usr2func);
|
REMOVE_ADD(func, declarations);
|
||||||
HANDLE_MERGEABLE(funcs_derived, derived, usr2func);
|
REMOVE_ADD(func, derived);
|
||||||
HANDLE_MERGEABLE(funcs_uses, uses, usr2func);
|
REMOVE_ADD(func, uses);
|
||||||
|
|
||||||
RemoveUsrs(SymbolKind::Type, u->types_removed);
|
if ((t = types.size() + u->types_hint) > types.capacity()) {
|
||||||
|
t = size_t(t * grow);
|
||||||
|
types.reserve(t);
|
||||||
|
type_usr.reserve(t);
|
||||||
|
}
|
||||||
|
RemoveUsrs(SymbolKind::Type, u->file_id, u->types_removed);
|
||||||
Update(u->file_id, std::move(u->types_def_update));
|
Update(u->file_id, std::move(u->types_def_update));
|
||||||
HANDLE_MERGEABLE(types_declarations, declarations, usr2type);
|
REMOVE_ADD(type, declarations);
|
||||||
HANDLE_MERGEABLE(types_derived, derived, usr2type);
|
REMOVE_ADD(type, derived);
|
||||||
HANDLE_MERGEABLE(types_instances, instances, usr2type);
|
REMOVE_ADD(type, instances);
|
||||||
HANDLE_MERGEABLE(types_uses, uses, usr2type);
|
REMOVE_ADD(type, uses);
|
||||||
|
|
||||||
|
if ((t = vars.size() + u->vars_hint) > vars.capacity()) {
|
||||||
|
t = size_t(t * grow);
|
||||||
|
vars.reserve(t);
|
||||||
|
var_usr.reserve(t);
|
||||||
|
}
|
||||||
RemoveUsrs(SymbolKind::Var, u->file_id, u->vars_removed);
|
RemoveUsrs(SymbolKind::Var, u->file_id, u->vars_removed);
|
||||||
Update(u->file_id, std::move(u->vars_def_update));
|
Update(u->file_id, std::move(u->vars_def_update));
|
||||||
HANDLE_MERGEABLE(vars_declarations, declarations, usr2var);
|
REMOVE_ADD(var, declarations);
|
||||||
HANDLE_MERGEABLE(vars_uses, uses, usr2var);
|
REMOVE_ADD(var, uses);
|
||||||
|
|
||||||
#undef HANDLE_MERGEABLE
|
#undef REMOVE_ADD
|
||||||
}
|
}
|
||||||
|
|
||||||
int QueryDatabase::Update(QueryFile::DefUpdate&& u) {
|
int DB::Update(QueryFile::DefUpdate&& u) {
|
||||||
int id = files.size();
|
int id = files.size();
|
||||||
auto it = name2file_id.try_emplace(LowerPathIfInsensitive(u.value.path), id);
|
auto it = name2file_id.try_emplace(LowerPathIfInsensitive(u.value.path), id);
|
||||||
if (it.second)
|
if (it.second)
|
||||||
files.emplace_back().id = id;
|
files.emplace_back().id = id;
|
||||||
QueryFile& existing = files[it.first->second];
|
QueryFile& existing = files[it.first->second];
|
||||||
existing.def = u.value;
|
existing.def = u.value;
|
||||||
UpdateSymbols(&existing.symbol_idx, SymbolKind::File, it.first->second);
|
|
||||||
return existing.id;
|
return existing.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
void QueryDatabase::Update(int file_id,
|
void DB::Update(int file_id, std::vector<std::pair<Usr, QueryFunc::Def>>&& us) {
|
||||||
std::vector<std::pair<Usr, QueryFunc::Def>>&& us) {
|
|
||||||
for (auto& u : us) {
|
for (auto& u : us) {
|
||||||
auto& def = u.second;
|
auto& def = u.second;
|
||||||
assert(!def.detailed_name.empty());
|
assert(!def.detailed_name.empty());
|
||||||
AssignFileId(file_id, def.spell);
|
AssignFileId(file_id, def.spell);
|
||||||
AssignFileId(file_id, def.extent);
|
AssignFileId(file_id, def.extent);
|
||||||
AssignFileId(file_id, def.callees);
|
AssignFileId(file_id, def.callees);
|
||||||
QueryFunc& existing = Func(u.first);
|
auto R = func_usr.try_emplace({u.first}, func_usr.size());
|
||||||
|
if (R.second)
|
||||||
|
funcs.emplace_back();
|
||||||
|
QueryFunc& existing = funcs[R.first->second];
|
||||||
existing.usr = u.first;
|
existing.usr = u.first;
|
||||||
if (!TryReplaceDef(existing.def, std::move(def))) {
|
if (!TryReplaceDef(existing.def, std::move(def)))
|
||||||
existing.def.push_back(std::move(def));
|
existing.def.push_back(std::move(def));
|
||||||
UpdateSymbols(&existing.symbol_idx, SymbolKind::Func, u.first);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void QueryDatabase::Update(int file_id,
|
void DB::Update(int file_id, std::vector<std::pair<Usr, QueryType::Def>>&& us) {
|
||||||
std::vector<std::pair<Usr, QueryType::Def>>&& us) {
|
|
||||||
for (auto& u : us) {
|
for (auto& u : us) {
|
||||||
auto& def = u.second;
|
auto& def = u.second;
|
||||||
assert(!def.detailed_name.empty());
|
assert(!def.detailed_name.empty());
|
||||||
AssignFileId(file_id, def.spell);
|
AssignFileId(file_id, def.spell);
|
||||||
AssignFileId(file_id, def.extent);
|
AssignFileId(file_id, def.extent);
|
||||||
QueryType& existing = Type(u.first);
|
auto R = type_usr.try_emplace({u.first}, type_usr.size());
|
||||||
|
if (R.second)
|
||||||
|
types.emplace_back();
|
||||||
|
QueryType& existing = types[R.first->second];
|
||||||
existing.usr = u.first;
|
existing.usr = u.first;
|
||||||
if (!TryReplaceDef(existing.def, std::move(def))) {
|
if (!TryReplaceDef(existing.def, std::move(def)))
|
||||||
existing.def.push_back(std::move(def));
|
existing.def.push_back(std::move(def));
|
||||||
UpdateSymbols(&existing.symbol_idx, SymbolKind::Type, u.first);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void QueryDatabase::Update(int file_id,
|
void DB::Update(int file_id, std::vector<std::pair<Usr, QueryVar::Def>>&& us) {
|
||||||
std::vector<std::pair<Usr, QueryVar::Def>>&& us) {
|
|
||||||
for (auto& u : us) {
|
for (auto& u : us) {
|
||||||
auto& def = u.second;
|
auto& def = u.second;
|
||||||
assert(!def.detailed_name.empty());
|
assert(!def.detailed_name.empty());
|
||||||
AssignFileId(file_id, def.spell);
|
AssignFileId(file_id, def.spell);
|
||||||
AssignFileId(file_id, def.extent);
|
AssignFileId(file_id, def.extent);
|
||||||
QueryVar& existing = Var(u.first);
|
auto R = var_usr.try_emplace({u.first}, var_usr.size());
|
||||||
|
if (R.second)
|
||||||
|
vars.emplace_back();
|
||||||
|
QueryVar& existing = vars[R.first->second];
|
||||||
existing.usr = u.first;
|
existing.usr = u.first;
|
||||||
if (!TryReplaceDef(existing.def, std::move(def))) {
|
if (!TryReplaceDef(existing.def, std::move(def)))
|
||||||
existing.def.push_back(std::move(def));
|
existing.def.push_back(std::move(def));
|
||||||
if (!existing.def.front().is_local())
|
|
||||||
UpdateSymbols(&existing.symbol_idx, SymbolKind::Var, u.first);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void QueryDatabase::UpdateSymbols(int* symbol_idx,
|
std::string_view DB::GetSymbolName(SymbolIdx sym, bool qualified) {
|
||||||
SymbolKind kind,
|
Usr usr = sym.usr;
|
||||||
Usr usr) {
|
switch (sym.kind) {
|
||||||
if (*symbol_idx < 0) {
|
|
||||||
*symbol_idx = symbols.size();
|
|
||||||
symbols.push_back(SymbolIdx{usr, kind});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string_view QueryDatabase::GetSymbolName(int symbol_idx,
|
|
||||||
bool qualified) {
|
|
||||||
Usr usr = symbols[symbol_idx].usr;
|
|
||||||
switch (symbols[symbol_idx].kind) {
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
case SymbolKind::File:
|
case SymbolKind::File:
|
||||||
|
63
src/query.h
63
src/query.h
@ -3,6 +3,7 @@
|
|||||||
#include "indexer.h"
|
#include "indexer.h"
|
||||||
#include "serializer.h"
|
#include "serializer.h"
|
||||||
|
|
||||||
|
#include <llvm/ADT/DenseMap.h>
|
||||||
#include <llvm/ADT/SmallVector.h>
|
#include <llvm/ADT/SmallVector.h>
|
||||||
#include <llvm/ADT/StringMap.h>
|
#include <llvm/ADT/StringMap.h>
|
||||||
|
|
||||||
@ -10,7 +11,7 @@ struct QueryFile;
|
|||||||
struct QueryType;
|
struct QueryType;
|
||||||
struct QueryFunc;
|
struct QueryFunc;
|
||||||
struct QueryVar;
|
struct QueryVar;
|
||||||
struct QueryDatabase;
|
struct DB;
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct WithFileContent {
|
struct WithFileContent {
|
||||||
@ -42,7 +43,6 @@ struct QueryFile {
|
|||||||
|
|
||||||
int id = -1;
|
int id = -1;
|
||||||
std::optional<Def> def;
|
std::optional<Def> def;
|
||||||
int symbol_idx = -1;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Q, typename QDef>
|
template <typename Q, typename QDef>
|
||||||
@ -67,7 +67,6 @@ using UsrUpdate =
|
|||||||
|
|
||||||
struct QueryFunc : QueryEntity<QueryFunc, FuncDef> {
|
struct QueryFunc : QueryEntity<QueryFunc, FuncDef> {
|
||||||
Usr usr;
|
Usr usr;
|
||||||
int symbol_idx = -1;
|
|
||||||
llvm::SmallVector<Def, 1> def;
|
llvm::SmallVector<Def, 1> def;
|
||||||
std::vector<Use> declarations;
|
std::vector<Use> declarations;
|
||||||
std::vector<Use> uses;
|
std::vector<Use> uses;
|
||||||
@ -76,7 +75,6 @@ struct QueryFunc : QueryEntity<QueryFunc, FuncDef> {
|
|||||||
|
|
||||||
struct QueryType : QueryEntity<QueryType, TypeDef> {
|
struct QueryType : QueryEntity<QueryType, TypeDef> {
|
||||||
Usr usr;
|
Usr usr;
|
||||||
int symbol_idx = -1;
|
|
||||||
llvm::SmallVector<Def, 1> def;
|
llvm::SmallVector<Def, 1> def;
|
||||||
std::vector<Use> declarations;
|
std::vector<Use> declarations;
|
||||||
std::vector<Use> uses;
|
std::vector<Use> uses;
|
||||||
@ -86,7 +84,6 @@ struct QueryType : QueryEntity<QueryType, TypeDef> {
|
|||||||
|
|
||||||
struct QueryVar : QueryEntity<QueryVar, VarDef> {
|
struct QueryVar : QueryEntity<QueryVar, VarDef> {
|
||||||
Usr usr;
|
Usr usr;
|
||||||
int symbol_idx = -1;
|
|
||||||
llvm::SmallVector<Def, 1> def;
|
llvm::SmallVector<Def, 1> def;
|
||||||
std::vector<Use> declarations;
|
std::vector<Use> declarations;
|
||||||
std::vector<Use> uses;
|
std::vector<Use> uses;
|
||||||
@ -108,6 +105,7 @@ struct IndexUpdate {
|
|||||||
std::optional<QueryFile::DefUpdate> files_def_update;
|
std::optional<QueryFile::DefUpdate> files_def_update;
|
||||||
|
|
||||||
// Function updates.
|
// Function updates.
|
||||||
|
int funcs_hint;
|
||||||
std::vector<Usr> funcs_removed;
|
std::vector<Usr> funcs_removed;
|
||||||
std::vector<std::pair<Usr, QueryFunc::Def>> funcs_def_update;
|
std::vector<std::pair<Usr, QueryFunc::Def>> funcs_def_update;
|
||||||
UseUpdate funcs_declarations;
|
UseUpdate funcs_declarations;
|
||||||
@ -115,6 +113,7 @@ struct IndexUpdate {
|
|||||||
UsrUpdate funcs_derived;
|
UsrUpdate funcs_derived;
|
||||||
|
|
||||||
// Type updates.
|
// Type updates.
|
||||||
|
int types_hint;
|
||||||
std::vector<Usr> types_removed;
|
std::vector<Usr> types_removed;
|
||||||
std::vector<std::pair<Usr, QueryType::Def>> types_def_update;
|
std::vector<std::pair<Usr, QueryType::Def>> types_def_update;
|
||||||
UseUpdate types_declarations;
|
UseUpdate types_declarations;
|
||||||
@ -123,23 +122,42 @@ struct IndexUpdate {
|
|||||||
UsrUpdate types_instances;
|
UsrUpdate types_instances;
|
||||||
|
|
||||||
// Variable updates.
|
// Variable updates.
|
||||||
|
int vars_hint;
|
||||||
std::vector<Usr> vars_removed;
|
std::vector<Usr> vars_removed;
|
||||||
std::vector<std::pair<Usr, QueryVar::Def>> vars_def_update;
|
std::vector<std::pair<Usr, QueryVar::Def>> vars_def_update;
|
||||||
UseUpdate vars_declarations;
|
UseUpdate vars_declarations;
|
||||||
UseUpdate vars_uses;
|
UseUpdate vars_uses;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename Q>
|
||||||
|
struct EntityToIndex {
|
||||||
|
using argument_type = const Q&;
|
||||||
|
llvm::DenseMap<Usr, unsigned> m;
|
||||||
|
unsigned operator()(const Q& entity) const {
|
||||||
|
return m[entity.usr];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct WrappedUsr {
|
||||||
|
Usr usr;
|
||||||
|
};
|
||||||
|
template <>
|
||||||
|
struct llvm::DenseMapInfo<WrappedUsr> {
|
||||||
|
static inline WrappedUsr getEmptyKey() { return {0}; }
|
||||||
|
static inline WrappedUsr getTombstoneKey() { return {~0ULL}; }
|
||||||
|
static unsigned getHashValue(WrappedUsr w) { return w.usr; }
|
||||||
|
static bool isEqual(WrappedUsr l, WrappedUsr r) { return l.usr == r.usr; }
|
||||||
|
};
|
||||||
|
|
||||||
// The query database is heavily optimized for fast queries. It is stored
|
// The query database is heavily optimized for fast queries. It is stored
|
||||||
// in-memory.
|
// in-memory.
|
||||||
struct QueryDatabase {
|
struct DB {
|
||||||
// All File/Func/Type/Var symbols.
|
|
||||||
std::vector<SymbolIdx> symbols;
|
|
||||||
|
|
||||||
std::vector<QueryFile> files;
|
std::vector<QueryFile> files;
|
||||||
llvm::StringMap<int> name2file_id;
|
llvm::StringMap<int> name2file_id;
|
||||||
std::unordered_map<Usr, QueryFunc> usr2func;
|
llvm::DenseMap<WrappedUsr, int> func_usr, type_usr, var_usr;
|
||||||
std::unordered_map<Usr, QueryType> usr2type;
|
std::vector<QueryFunc> funcs;
|
||||||
std::unordered_map<Usr, QueryVar> usr2var;
|
std::vector<QueryType> types;
|
||||||
|
std::vector<QueryVar> vars;
|
||||||
|
|
||||||
// Marks the given Usrs as invalid.
|
// Marks the given Usrs as invalid.
|
||||||
void RemoveUsrs(SymbolKind usr_kind, const std::vector<Usr>& to_remove);
|
void RemoveUsrs(SymbolKind usr_kind, const std::vector<Usr>& to_remove);
|
||||||
@ -150,15 +168,18 @@ struct QueryDatabase {
|
|||||||
void Update(int file_id, std::vector<std::pair<Usr, QueryType::Def>>&& us);
|
void Update(int file_id, std::vector<std::pair<Usr, QueryType::Def>>&& us);
|
||||||
void Update(int file_id, std::vector<std::pair<Usr, QueryFunc::Def>>&& us);
|
void Update(int file_id, std::vector<std::pair<Usr, QueryFunc::Def>>&& us);
|
||||||
void Update(int file_id, std::vector<std::pair<Usr, QueryVar::Def>>&& us);
|
void Update(int file_id, std::vector<std::pair<Usr, QueryVar::Def>>&& us);
|
||||||
void UpdateSymbols(int* symbol_idx, SymbolKind kind, Usr usr);
|
std::string_view GetSymbolName(SymbolIdx sym, bool qualified);
|
||||||
std::string_view GetSymbolName(int symbol_idx, bool qualified);
|
|
||||||
|
bool HasFunc(Usr usr) const { return func_usr.count({usr}); }
|
||||||
|
bool HasType(Usr usr) const { return type_usr.count({usr}); }
|
||||||
|
bool HasVar(Usr usr) const { return var_usr.count({usr}); }
|
||||||
|
|
||||||
|
QueryFunc& Func(Usr usr) { return funcs[func_usr[{usr}]]; }
|
||||||
|
QueryType& Type(Usr usr) { return types[type_usr[{usr}]]; }
|
||||||
|
QueryVar& Var(Usr usr) { return vars[var_usr[{usr}]]; }
|
||||||
|
|
||||||
QueryFile& GetFile(SymbolIdx ref) { return files[ref.usr]; }
|
QueryFile& GetFile(SymbolIdx ref) { return files[ref.usr]; }
|
||||||
QueryFunc& GetFunc(SymbolIdx ref) { return usr2func[ref.usr]; }
|
QueryFunc& GetFunc(SymbolIdx ref) { return Func(ref.usr); }
|
||||||
QueryType& GetType(SymbolIdx ref) { return usr2type[ref.usr]; }
|
QueryType& GetType(SymbolIdx ref) { return Type(ref.usr); }
|
||||||
QueryVar& GetVar(SymbolIdx ref) { return usr2var[ref.usr]; }
|
QueryVar& GetVar(SymbolIdx ref) { return Var(ref.usr); }
|
||||||
|
|
||||||
QueryFunc& Func(Usr usr) { return usr2func[usr]; }
|
|
||||||
QueryType& Type(Usr usr) { return usr2type[usr]; }
|
|
||||||
QueryVar& Var(Usr usr) { return usr2var[usr]; }
|
|
||||||
};
|
};
|
||||||
|
@ -14,15 +14,36 @@ int ComputeRangeSize(const Range& range) {
|
|||||||
return range.end.column - range.start.column;
|
return range.end.column - range.start.column;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename Q>
|
||||||
|
std::vector<Use> GetDeclarations(llvm::DenseMap<WrappedUsr, int>& entity_usr,
|
||||||
|
std::vector<Q>& entities,
|
||||||
|
const std::vector<Usr>& usrs) {
|
||||||
|
std::vector<Use> ret;
|
||||||
|
ret.reserve(usrs.size());
|
||||||
|
for (Usr usr : usrs) {
|
||||||
|
Q& entity = entities[entity_usr[{usr}]];
|
||||||
|
bool has_def = false;
|
||||||
|
for (auto& def : entity.def)
|
||||||
|
if (def.spell) {
|
||||||
|
ret.push_back(*def.spell);
|
||||||
|
has_def = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!has_def && entity.declarations.size())
|
||||||
|
ret.push_back(entity.declarations[0]);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
Maybe<Use> GetDefinitionSpell(QueryDatabase* db, SymbolIdx sym) {
|
Maybe<Use> GetDefinitionSpell(DB* db, SymbolIdx sym) {
|
||||||
Maybe<Use> ret;
|
Maybe<Use> ret;
|
||||||
EachEntityDef(db, sym, [&](const auto& def) { return !(ret = def.spell); });
|
EachEntityDef(db, sym, [&](const auto& def) { return !(ret = def.spell); });
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
Maybe<Use> GetDefinitionExtent(QueryDatabase* db, SymbolIdx sym) {
|
Maybe<Use> GetDefinitionExtent(DB* db, SymbolIdx sym) {
|
||||||
// Used to jump to file.
|
// Used to jump to file.
|
||||||
if (sym.kind == SymbolKind::File)
|
if (sym.kind == SymbolKind::File)
|
||||||
return Use{{Range{{0, 0}, {0, 0}}, sym.usr, sym.kind, Role::None},
|
return Use{{Range{{0, 0}, {0, 0}}, sym.usr, sym.kind, Role::None},
|
||||||
@ -32,7 +53,17 @@ Maybe<Use> GetDefinitionExtent(QueryDatabase* db, SymbolIdx sym) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<Use> GetNonDefDeclarations(QueryDatabase* db, SymbolIdx sym) {
|
std::vector<Use> GetFuncDeclarations(DB* db, const std::vector<Usr>& usrs) {
|
||||||
|
return GetDeclarations(db->func_usr, db->funcs, usrs);
|
||||||
|
}
|
||||||
|
std::vector<Use> GetTypeDeclarations(DB* db, const std::vector<Usr>& usrs) {
|
||||||
|
return GetDeclarations(db->type_usr, db->types, usrs);
|
||||||
|
}
|
||||||
|
std::vector<Use> GetVarDeclarations(DB* db, const std::vector<Usr>& usrs) {
|
||||||
|
return GetDeclarations(db->var_usr, db->vars, usrs);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Use> GetNonDefDeclarations(DB* db, SymbolIdx sym) {
|
||||||
switch (sym.kind) {
|
switch (sym.kind) {
|
||||||
case SymbolKind::Func:
|
case SymbolKind::Func:
|
||||||
return db->GetFunc(sym).declarations;
|
return db->GetFunc(sym).declarations;
|
||||||
@ -45,7 +76,7 @@ std::vector<Use> GetNonDefDeclarations(QueryDatabase* db, SymbolIdx sym) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<Use> GetUsesForAllBases(QueryDatabase* db, QueryFunc& root) {
|
std::vector<Use> GetUsesForAllBases(DB* db, QueryFunc& root) {
|
||||||
std::vector<Use> ret;
|
std::vector<Use> ret;
|
||||||
std::vector<QueryFunc*> stack{&root};
|
std::vector<QueryFunc*> stack{&root};
|
||||||
std::unordered_set<Usr> seen;
|
std::unordered_set<Usr> seen;
|
||||||
@ -54,7 +85,7 @@ std::vector<Use> GetUsesForAllBases(QueryDatabase* db, QueryFunc& root) {
|
|||||||
QueryFunc& func = *stack.back();
|
QueryFunc& func = *stack.back();
|
||||||
stack.pop_back();
|
stack.pop_back();
|
||||||
if (auto* def = func.AnyDef()) {
|
if (auto* def = func.AnyDef()) {
|
||||||
EachDefinedEntity(db->usr2func, def->bases, [&](QueryFunc& func1) {
|
EachDefinedFunc(db, def->bases, [&](QueryFunc& func1) {
|
||||||
if (!seen.count(func1.usr)) {
|
if (!seen.count(func1.usr)) {
|
||||||
seen.insert(func1.usr);
|
seen.insert(func1.usr);
|
||||||
stack.push_back(&func1);
|
stack.push_back(&func1);
|
||||||
@ -67,7 +98,7 @@ std::vector<Use> GetUsesForAllBases(QueryDatabase* db, QueryFunc& root) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<Use> GetUsesForAllDerived(QueryDatabase* db, QueryFunc& root) {
|
std::vector<Use> GetUsesForAllDerived(DB* db, QueryFunc& root) {
|
||||||
std::vector<Use> ret;
|
std::vector<Use> ret;
|
||||||
std::vector<QueryFunc*> stack{&root};
|
std::vector<QueryFunc*> stack{&root};
|
||||||
std::unordered_set<Usr> seen;
|
std::unordered_set<Usr> seen;
|
||||||
@ -75,7 +106,7 @@ std::vector<Use> GetUsesForAllDerived(QueryDatabase* db, QueryFunc& root) {
|
|||||||
while (!stack.empty()) {
|
while (!stack.empty()) {
|
||||||
QueryFunc& func = *stack.back();
|
QueryFunc& func = *stack.back();
|
||||||
stack.pop_back();
|
stack.pop_back();
|
||||||
EachDefinedEntity(db->usr2func, func.derived, [&](QueryFunc& func1) {
|
EachDefinedFunc(db, func.derived, [&](QueryFunc& func1) {
|
||||||
if (!seen.count(func1.usr)) {
|
if (!seen.count(func1.usr)) {
|
||||||
seen.insert(func1.usr);
|
seen.insert(func1.usr);
|
||||||
stack.push_back(&func1);
|
stack.push_back(&func1);
|
||||||
@ -88,7 +119,7 @@ std::vector<Use> GetUsesForAllDerived(QueryDatabase* db, QueryFunc& root) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::optional<lsPosition> GetLsPosition(WorkingFile* working_file,
|
std::optional<lsPosition> GetLsPosition(WorkingFile* working_file,
|
||||||
const Position& position) {
|
const Position& position) {
|
||||||
if (!working_file)
|
if (!working_file)
|
||||||
return lsPosition{position.line, position.column};
|
return lsPosition{position.line, position.column};
|
||||||
|
|
||||||
@ -99,7 +130,8 @@ std::optional<lsPosition> GetLsPosition(WorkingFile* working_file,
|
|||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<lsRange> GetLsRange(WorkingFile* working_file, const Range& location) {
|
std::optional<lsRange> GetLsRange(WorkingFile* working_file,
|
||||||
|
const Range& location) {
|
||||||
if (!working_file) {
|
if (!working_file) {
|
||||||
return lsRange{lsPosition{location.start.line, location.start.column},
|
return lsRange{lsPosition{location.start.line, location.start.column},
|
||||||
lsPosition{location.end.line, location.end.column}};
|
lsPosition{location.end.line, location.end.column}};
|
||||||
@ -108,8 +140,8 @@ std::optional<lsRange> GetLsRange(WorkingFile* working_file, const Range& locati
|
|||||||
int start_column = location.start.column, end_column = location.end.column;
|
int start_column = location.start.column, end_column = location.end.column;
|
||||||
std::optional<int> start = working_file->GetBufferPosFromIndexPos(
|
std::optional<int> start = working_file->GetBufferPosFromIndexPos(
|
||||||
location.start.line, &start_column, false);
|
location.start.line, &start_column, false);
|
||||||
std::optional<int> end = working_file->GetBufferPosFromIndexPos(location.end.line,
|
std::optional<int> end = working_file->GetBufferPosFromIndexPos(
|
||||||
&end_column, true);
|
location.end.line, &end_column, true);
|
||||||
if (!start || !end)
|
if (!start || !end)
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
|
|
||||||
@ -128,9 +160,7 @@ std::optional<lsRange> GetLsRange(WorkingFile* working_file, const Range& locati
|
|||||||
lsPosition{*end, end_column}};
|
lsPosition{*end, end_column}};
|
||||||
}
|
}
|
||||||
|
|
||||||
lsDocumentUri GetLsDocumentUri(QueryDatabase* db,
|
lsDocumentUri GetLsDocumentUri(DB* db, int file_id, std::string* path) {
|
||||||
int file_id,
|
|
||||||
std::string* path) {
|
|
||||||
QueryFile& file = db->files[file_id];
|
QueryFile& file = db->files[file_id];
|
||||||
if (file.def) {
|
if (file.def) {
|
||||||
*path = file.def->path;
|
*path = file.def->path;
|
||||||
@ -141,7 +171,7 @@ lsDocumentUri GetLsDocumentUri(QueryDatabase* db,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lsDocumentUri GetLsDocumentUri(QueryDatabase* db, int file_id) {
|
lsDocumentUri GetLsDocumentUri(DB* db, int file_id) {
|
||||||
QueryFile& file = db->files[file_id];
|
QueryFile& file = db->files[file_id];
|
||||||
if (file.def) {
|
if (file.def) {
|
||||||
return lsDocumentUri::FromPath(file.def->path);
|
return lsDocumentUri::FromPath(file.def->path);
|
||||||
@ -150,9 +180,9 @@ lsDocumentUri GetLsDocumentUri(QueryDatabase* db, int file_id) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<lsLocation> GetLsLocation(QueryDatabase* db,
|
std::optional<lsLocation> GetLsLocation(DB* db,
|
||||||
WorkingFiles* working_files,
|
WorkingFiles* working_files,
|
||||||
Use use) {
|
Use use) {
|
||||||
std::string path;
|
std::string path;
|
||||||
lsDocumentUri uri = GetLsDocumentUri(db, use.file_id, &path);
|
lsDocumentUri uri = GetLsDocumentUri(db, use.file_id, &path);
|
||||||
std::optional<lsRange> range =
|
std::optional<lsRange> range =
|
||||||
@ -162,10 +192,10 @@ std::optional<lsLocation> GetLsLocation(QueryDatabase* db,
|
|||||||
return lsLocation{uri, *range};
|
return lsLocation{uri, *range};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<lsLocationEx> GetLsLocationEx(QueryDatabase* db,
|
std::optional<lsLocationEx> GetLsLocationEx(DB* db,
|
||||||
WorkingFiles* working_files,
|
WorkingFiles* working_files,
|
||||||
Use use,
|
Use use,
|
||||||
bool container) {
|
bool container) {
|
||||||
std::optional<lsLocation> ls_loc = GetLsLocation(db, working_files, use);
|
std::optional<lsLocation> ls_loc = GetLsLocation(db, working_files, use);
|
||||||
if (!ls_loc)
|
if (!ls_loc)
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
@ -181,7 +211,7 @@ std::optional<lsLocationEx> GetLsLocationEx(QueryDatabase* db,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<lsLocationEx> GetLsLocationExs(QueryDatabase* db,
|
std::vector<lsLocationEx> GetLsLocationExs(DB* db,
|
||||||
WorkingFiles* working_files,
|
WorkingFiles* working_files,
|
||||||
const std::vector<Use>& uses) {
|
const std::vector<Use>& uses) {
|
||||||
std::vector<lsLocationEx> ret;
|
std::vector<lsLocationEx> ret;
|
||||||
@ -196,7 +226,7 @@ std::vector<lsLocationEx> GetLsLocationExs(QueryDatabase* db,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
lsSymbolKind GetSymbolKind(QueryDatabase* db, SymbolIdx sym) {
|
lsSymbolKind GetSymbolKind(DB* db, SymbolIdx sym) {
|
||||||
lsSymbolKind ret;
|
lsSymbolKind ret;
|
||||||
if (sym.kind == SymbolKind::File)
|
if (sym.kind == SymbolKind::File)
|
||||||
ret = lsSymbolKind::File;
|
ret = lsSymbolKind::File;
|
||||||
@ -213,10 +243,10 @@ lsSymbolKind GetSymbolKind(QueryDatabase* db, SymbolIdx sym) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Returns a symbol. The symbol will have *NOT* have a location assigned.
|
// Returns a symbol. The symbol will have *NOT* have a location assigned.
|
||||||
std::optional<lsSymbolInformation> GetSymbolInfo(QueryDatabase* db,
|
std::optional<lsSymbolInformation> GetSymbolInfo(DB* db,
|
||||||
WorkingFiles* working_files,
|
WorkingFiles* working_files,
|
||||||
SymbolIdx sym,
|
SymbolIdx sym,
|
||||||
bool detailed_name) {
|
bool detailed_name) {
|
||||||
switch (sym.kind) {
|
switch (sym.kind) {
|
||||||
case SymbolKind::Invalid:
|
case SymbolKind::Invalid:
|
||||||
break;
|
break;
|
||||||
@ -254,7 +284,7 @@ std::vector<SymbolRef> FindSymbolsAtLocation(WorkingFile* working_file,
|
|||||||
std::vector<SymbolRef> symbols;
|
std::vector<SymbolRef> symbols;
|
||||||
if (working_file) {
|
if (working_file) {
|
||||||
if (auto line = working_file->GetIndexPosFromBufferPos(
|
if (auto line = working_file->GetIndexPosFromBufferPos(
|
||||||
ls_pos.line, &ls_pos.character, false)) {
|
ls_pos.line, &ls_pos.character, false)) {
|
||||||
ls_pos.line = *line;
|
ls_pos.line = *line;
|
||||||
} else {
|
} else {
|
||||||
ls_pos.line = -1;
|
ls_pos.line = -1;
|
||||||
|
@ -5,66 +5,49 @@
|
|||||||
|
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
|
||||||
Maybe<Use> GetDefinitionSpell(QueryDatabase* db, SymbolIdx sym);
|
Maybe<Use> GetDefinitionSpell(DB* db, SymbolIdx sym);
|
||||||
Maybe<Use> GetDefinitionExtent(QueryDatabase* db, SymbolIdx sym);
|
Maybe<Use> GetDefinitionExtent(DB* db, SymbolIdx sym);
|
||||||
|
|
||||||
// Get defining declaration (if exists) or an arbitrary declaration (otherwise)
|
// Get defining declaration (if exists) or an arbitrary declaration (otherwise)
|
||||||
// for each id.
|
// for each id.
|
||||||
template <typename Q>
|
std::vector<Use> GetFuncDeclarations(DB*, const std::vector<Usr>&);
|
||||||
std::vector<Use> GetDeclarations(std::unordered_map<Usr, Q>& usr2entity,
|
std::vector<Use> GetTypeDeclarations(DB*, const std::vector<Usr>&);
|
||||||
const std::vector<Usr>& usrs) {
|
std::vector<Use> GetVarDeclarations(DB*, const std::vector<Usr>&);
|
||||||
std::vector<Use> ret;
|
|
||||||
ret.reserve(usrs.size());
|
|
||||||
for (Usr usr : usrs) {
|
|
||||||
Q& entity = usr2entity[usr];
|
|
||||||
bool has_def = false;
|
|
||||||
for (auto& def : entity.def)
|
|
||||||
if (def.spell) {
|
|
||||||
ret.push_back(*def.spell);
|
|
||||||
has_def = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (!has_def && entity.declarations.size())
|
|
||||||
ret.push_back(entity.declarations[0]);
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get non-defining declarations.
|
// Get non-defining declarations.
|
||||||
std::vector<Use> GetNonDefDeclarations(QueryDatabase* db, SymbolIdx sym);
|
std::vector<Use> GetNonDefDeclarations(DB* db, SymbolIdx sym);
|
||||||
|
|
||||||
std::vector<Use> GetUsesForAllBases(QueryDatabase* db, QueryFunc& root);
|
std::vector<Use> GetUsesForAllBases(DB* db, QueryFunc& root);
|
||||||
std::vector<Use> GetUsesForAllDerived(QueryDatabase* db, QueryFunc& root);
|
std::vector<Use> GetUsesForAllDerived(DB* db, QueryFunc& root);
|
||||||
std::optional<lsPosition> GetLsPosition(WorkingFile* working_file,
|
std::optional<lsPosition> GetLsPosition(WorkingFile* working_file,
|
||||||
const Position& position);
|
const Position& position);
|
||||||
std::optional<lsRange> GetLsRange(WorkingFile* working_file, const Range& location);
|
std::optional<lsRange> GetLsRange(WorkingFile* working_file,
|
||||||
lsDocumentUri GetLsDocumentUri(QueryDatabase* db,
|
const Range& location);
|
||||||
int file_id,
|
lsDocumentUri GetLsDocumentUri(DB* db, int file_id, std::string* path);
|
||||||
std::string* path);
|
lsDocumentUri GetLsDocumentUri(DB* db, int file_id);
|
||||||
lsDocumentUri GetLsDocumentUri(QueryDatabase* db, int file_id);
|
|
||||||
|
|
||||||
std::optional<lsLocation> GetLsLocation(QueryDatabase* db,
|
std::optional<lsLocation> GetLsLocation(DB* db,
|
||||||
WorkingFiles* working_files,
|
WorkingFiles* working_files,
|
||||||
Use use);
|
Use use);
|
||||||
std::optional<lsLocationEx> GetLsLocationEx(QueryDatabase* db,
|
std::optional<lsLocationEx> GetLsLocationEx(DB* db,
|
||||||
WorkingFiles* working_files,
|
WorkingFiles* working_files,
|
||||||
Use use,
|
Use use,
|
||||||
bool container);
|
bool container);
|
||||||
std::vector<lsLocationEx> GetLsLocationExs(QueryDatabase* db,
|
std::vector<lsLocationEx> GetLsLocationExs(DB* db,
|
||||||
WorkingFiles* working_files,
|
WorkingFiles* working_files,
|
||||||
const std::vector<Use>& refs);
|
const std::vector<Use>& refs);
|
||||||
// Returns a symbol. The symbol will have *NOT* have a location assigned.
|
// Returns a symbol. The symbol will have *NOT* have a location assigned.
|
||||||
std::optional<lsSymbolInformation> GetSymbolInfo(QueryDatabase* db,
|
std::optional<lsSymbolInformation> GetSymbolInfo(DB* db,
|
||||||
WorkingFiles* working_files,
|
WorkingFiles* working_files,
|
||||||
SymbolIdx sym,
|
SymbolIdx sym,
|
||||||
bool detailed_name);
|
bool detailed_name);
|
||||||
|
|
||||||
std::vector<SymbolRef> FindSymbolsAtLocation(WorkingFile* working_file,
|
std::vector<SymbolRef> FindSymbolsAtLocation(WorkingFile* working_file,
|
||||||
QueryFile* file,
|
QueryFile* file,
|
||||||
lsPosition& ls_pos);
|
lsPosition& ls_pos);
|
||||||
|
|
||||||
template <typename Fn>
|
template <typename Fn>
|
||||||
void WithEntity(QueryDatabase* db, SymbolIdx sym, Fn&& fn) {
|
void WithEntity(DB* db, SymbolIdx sym, Fn&& fn) {
|
||||||
switch (sym.kind) {
|
switch (sym.kind) {
|
||||||
case SymbolKind::Invalid:
|
case SymbolKind::Invalid:
|
||||||
case SymbolKind::File:
|
case SymbolKind::File:
|
||||||
@ -82,7 +65,7 @@ void WithEntity(QueryDatabase* db, SymbolIdx sym, Fn&& fn) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename Fn>
|
template <typename Fn>
|
||||||
void EachEntityDef(QueryDatabase* db, SymbolIdx sym, Fn&& fn) {
|
void EachEntityDef(DB* db, SymbolIdx sym, Fn&& fn) {
|
||||||
WithEntity(db, sym, [&](const auto& entity) {
|
WithEntity(db, sym, [&](const auto& entity) {
|
||||||
for (auto& def : entity.def)
|
for (auto& def : entity.def)
|
||||||
if (!fn(def))
|
if (!fn(def))
|
||||||
@ -91,10 +74,7 @@ void EachEntityDef(QueryDatabase* db, SymbolIdx sym, Fn&& fn) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename Fn>
|
template <typename Fn>
|
||||||
void EachOccurrence(QueryDatabase* db,
|
void EachOccurrence(DB* db, SymbolIdx sym, bool include_decl, Fn&& fn) {
|
||||||
SymbolIdx sym,
|
|
||||||
bool include_decl,
|
|
||||||
Fn&& fn) {
|
|
||||||
WithEntity(db, sym, [&](const auto& entity) {
|
WithEntity(db, sym, [&](const auto& entity) {
|
||||||
for (Use use : entity.uses)
|
for (Use use : entity.uses)
|
||||||
fn(use);
|
fn(use);
|
||||||
@ -108,14 +88,31 @@ void EachOccurrence(QueryDatabase* db,
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
lsSymbolKind GetSymbolKind(QueryDatabase* db, SymbolIdx sym);
|
lsSymbolKind GetSymbolKind(DB* db, SymbolIdx sym);
|
||||||
|
|
||||||
template <typename Q, typename Fn>
|
template <typename Fn>
|
||||||
void EachDefinedEntity(std::unordered_map<Usr, Q>& collection,
|
void EachDefinedFunc(DB* db, const std::vector<Usr>& usrs, Fn&& fn) {
|
||||||
const std::vector<Usr>& usrs,
|
|
||||||
Fn&& fn) {
|
|
||||||
for (Usr usr : usrs) {
|
for (Usr usr : usrs) {
|
||||||
Q& obj = collection[usr];
|
auto& obj = db->Func(usr);
|
||||||
|
if (!obj.def.empty())
|
||||||
|
fn(obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <typename Fn>
|
||||||
|
void EachDefinedType(DB* db, const std::vector<Usr>& usrs, Fn&& fn) {
|
||||||
|
for (Usr usr : usrs) {
|
||||||
|
auto& obj = db->Type(usr);
|
||||||
|
if (!obj.def.empty())
|
||||||
|
fn(obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Fn>
|
||||||
|
void EachDefinedVar(DB* db, const std::vector<Usr>& usrs, Fn&& fn) {
|
||||||
|
for (Usr usr : usrs) {
|
||||||
|
auto& obj = db->Var(usr);
|
||||||
if (!obj.def.empty())
|
if (!obj.def.empty())
|
||||||
fn(obj);
|
fn(obj);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user