mirror of
https://github.com/MaskRay/ccls.git
synced 2024-11-22 07:35:08 +00:00
index.multiVersion: int
Before, QueryFile::Def::{all_symbols,outline} were built by indexers. Now, {symbol,outline}2refcnt are used instead, built by main thread. *_removed are augmented with Query*:Def to allow removal of old {symbol,outline}2refcnt entries.
This commit is contained in:
parent
a8bb605d4a
commit
4f67bd03d5
@ -65,9 +65,9 @@ struct IndexParam {
|
||||
}
|
||||
}
|
||||
|
||||
IndexFile *ConsumeFile(const FileEntry &File) {
|
||||
SeenFile(File);
|
||||
return file_consumer->TryConsumeFile(File, &file_contents);
|
||||
IndexFile *ConsumeFile(const FileEntry &FE) {
|
||||
SeenFile(FE);
|
||||
return file_consumer->TryConsumeFile(FE, &file_contents);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -197,7 +197,9 @@ void EmitSemanticHighlighting(DB *db,
|
||||
// Group symbols together.
|
||||
std::unordered_map<SymbolIdx, Out_CclsPublishSemanticHighlighting::Symbol>
|
||||
grouped_symbols;
|
||||
for (SymbolRef sym : file->def->all_symbols) {
|
||||
for (auto &sym_refcnt : file->symbol2refcnt) {
|
||||
if (sym_refcnt.second <= 0) continue;
|
||||
SymbolRef sym = sym_refcnt.first;
|
||||
std::string_view detailed_name;
|
||||
lsSymbolKind parent_kind = lsSymbolKind::Unknown;
|
||||
lsSymbolKind kind = lsSymbolKind::Unknown;
|
||||
|
@ -6,8 +6,8 @@
|
||||
#include "query_utils.h"
|
||||
using namespace ccls;
|
||||
|
||||
MAKE_REFLECT_STRUCT(QueryFile::Def, path, args, language, outline, all_symbols,
|
||||
skipped_ranges, dependencies);
|
||||
MAKE_REFLECT_STRUCT(QueryFile::Def, path, args, language, skipped_ranges,
|
||||
dependencies);
|
||||
|
||||
namespace {
|
||||
MethodType kMethodType = "$ccls/fileInfo";
|
||||
|
@ -104,7 +104,8 @@ struct Handler_TextDocumentCodeLens
|
||||
common.working_files = working_files;
|
||||
common.working_file = working_files->GetFileByFilename(file->def->path);
|
||||
|
||||
for (SymbolRef sym : file->def->outline) {
|
||||
for (auto [sym, refcnt] : file->outline2refcnt) {
|
||||
if (refcnt <= 0) continue;
|
||||
// NOTE: We OffsetColumn so that the code lens always show up in a
|
||||
// predictable order. Otherwise, the client may randomize it.
|
||||
Use use{{sym.range, sym.usr, sym.kind, sym.role}, file->id};
|
||||
|
@ -105,12 +105,14 @@ struct Handler_TextDocumentDefinition
|
||||
}
|
||||
auto locs = GetLsLocationExs(db, working_files, uses);
|
||||
out.result.insert(out.result.end(), locs.begin(), locs.end());
|
||||
if (!out.result.empty())
|
||||
break;
|
||||
}
|
||||
|
||||
// No symbols - check for includes.
|
||||
if (out.result.empty()) {
|
||||
if (out.result.size()) {
|
||||
std::sort(out.result.begin(), out.result.end());
|
||||
out.result.erase(std::unique(out.result.begin(), out.result.end()),
|
||||
out.result.end());
|
||||
} else {
|
||||
// Check #include
|
||||
for (const IndexInclude &include : file->def->includes) {
|
||||
if (include.line == ls_pos.line) {
|
||||
lsLocationEx result;
|
||||
|
@ -53,20 +53,20 @@ struct Handler_TextDocumentDocumentSymbol
|
||||
if (params.startLine >= 0) {
|
||||
Out_SimpleDocumentSymbol out;
|
||||
out.id = request->id;
|
||||
for (SymbolRef sym : file->def->all_symbols)
|
||||
if (std::optional<lsLocation> location = GetLsLocation(
|
||||
db, working_files,
|
||||
Use{{sym.range, sym.usr, sym.kind, sym.role}, file_id})) {
|
||||
if (params.startLine <= sym.range.start.line &&
|
||||
for (auto [sym, refcnt] : file->symbol2refcnt)
|
||||
if (refcnt > 0 && params.startLine <= sym.range.start.line &&
|
||||
sym.range.start.line <= params.endLine)
|
||||
out.result.push_back(location->range);
|
||||
}
|
||||
if (auto ls_loc = GetLsLocation(
|
||||
db, working_files,
|
||||
Use{{sym.range, sym.usr, sym.kind, sym.role}, file_id}))
|
||||
out.result.push_back(ls_loc->range);
|
||||
std::sort(out.result.begin(), out.result.end());
|
||||
pipeline::WriteStdout(kMethodType, out);
|
||||
} else {
|
||||
Out_TextDocumentDocumentSymbol out;
|
||||
out.id = request->id;
|
||||
for (SymbolRef sym : file->def->outline)
|
||||
for (auto [sym, refcnt] : file->outline2refcnt) {
|
||||
if (refcnt <= 0) continue;
|
||||
if (std::optional<lsSymbolInformation> info =
|
||||
GetSymbolInfo(db, working_files, sym, false)) {
|
||||
if (sym.kind == SymbolKind::Var) {
|
||||
@ -82,6 +82,7 @@ struct Handler_TextDocumentDocumentSymbol
|
||||
out.result.push_back(*info);
|
||||
}
|
||||
}
|
||||
}
|
||||
pipeline::WriteStdout(kMethodType, out);
|
||||
}
|
||||
}
|
||||
|
252
src/query.cc
252
src/query.cc
@ -17,34 +17,13 @@
|
||||
|
||||
namespace {
|
||||
|
||||
void AssignFileId(const Lid2file_id &lid2file_id, int file_id, SymbolRef &ref) {
|
||||
if (ref.kind == SymbolKind::File)
|
||||
ref.usr = file_id;
|
||||
}
|
||||
|
||||
void AssignFileId(const Lid2file_id &lid2file_id, int file_id, Use &use) {
|
||||
if (use.kind == SymbolKind::File)
|
||||
use.usr = file_id;
|
||||
if (use.file_id == -1)
|
||||
use.file_id = file_id;
|
||||
else
|
||||
use.file_id = lid2file_id.find(use.file_id)->second;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void AssignFileId(const Lid2file_id &, int file_id, T &) {}
|
||||
|
||||
template <typename T>
|
||||
void AssignFileId(const Lid2file_id &lid2file_id, int file_id, Maybe<T> &x) {
|
||||
if (x)
|
||||
AssignFileId(lid2file_id, file_id, *x);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void AssignFileId(const Lid2file_id &lid2file_id, int file_id,
|
||||
std::vector<T> &xs) {
|
||||
for (T &x : xs)
|
||||
AssignFileId(lid2file_id, file_id, x);
|
||||
if (use.kind == SymbolKind::File)
|
||||
use.usr = use.file_id;
|
||||
}
|
||||
|
||||
void AddRange(std::vector<Use> &into, const std::vector<Use> &from) {
|
||||
@ -78,79 +57,6 @@ QueryFile::DefUpdate BuildFileDefUpdate(const IndexFile &indexed) {
|
||||
for (auto &dep : indexed.dependencies)
|
||||
def.dependencies.push_back(dep.first());
|
||||
def.language = indexed.language;
|
||||
|
||||
auto add_all_symbols = [&](Use use, Usr usr, SymbolKind kind) {
|
||||
def.all_symbols.push_back(SymbolRef{{use.range, usr, kind, use.role}});
|
||||
};
|
||||
auto add_outline = [&](Use use, Usr usr, SymbolKind kind) {
|
||||
def.outline.push_back(SymbolRef{{use.range, usr, kind, use.role}});
|
||||
};
|
||||
|
||||
for (auto &it : indexed.usr2type) {
|
||||
const IndexType &type = it.second;
|
||||
if (type.def.spell)
|
||||
add_all_symbols(*type.def.spell, type.usr, SymbolKind::Type);
|
||||
if (type.def.extent)
|
||||
add_outline(*type.def.extent, type.usr, SymbolKind::Type);
|
||||
for (Use decl : type.declarations) {
|
||||
add_all_symbols(decl, type.usr, SymbolKind::Type);
|
||||
// Constructor positions have references to the class,
|
||||
// which we do not want to show in textDocument/documentSymbol
|
||||
if (!(decl.role & Role::Reference))
|
||||
add_outline(decl, type.usr, SymbolKind::Type);
|
||||
}
|
||||
for (Use use : type.uses)
|
||||
if (use.file_id == -1)
|
||||
add_all_symbols(use, type.usr, SymbolKind::Type);
|
||||
}
|
||||
for (auto &it : indexed.usr2func) {
|
||||
const IndexFunc &func = it.second;
|
||||
if (func.def.spell)
|
||||
add_all_symbols(*func.def.spell, func.usr, SymbolKind::Func);
|
||||
if (func.def.extent)
|
||||
add_outline(*func.def.extent, func.usr, SymbolKind::Func);
|
||||
for (Use use : func.declarations) {
|
||||
add_all_symbols(use, func.usr, SymbolKind::Func);
|
||||
add_outline(use, func.usr, SymbolKind::Func);
|
||||
}
|
||||
for (Use use : func.uses)
|
||||
if (use.file_id == -1) {
|
||||
// Make ranges of implicit function calls larger (spanning one more
|
||||
// column to the left/right). This is hacky but useful. e.g.
|
||||
// textDocument/definition on the space/semicolon in `A a;` or `return
|
||||
// 42;` will take you to the constructor.
|
||||
if (use.role & Role::Implicit) {
|
||||
if (use.range.start.column > 0)
|
||||
use.range.start.column--;
|
||||
use.range.end.column++;
|
||||
}
|
||||
add_all_symbols(use, func.usr, SymbolKind::Func);
|
||||
}
|
||||
}
|
||||
for (auto &it : indexed.usr2var) {
|
||||
const IndexVar &var = it.second;
|
||||
if (var.def.spell)
|
||||
add_all_symbols(*var.def.spell, var.usr, SymbolKind::Var);
|
||||
if (var.def.extent)
|
||||
add_outline(*var.def.extent, var.usr, SymbolKind::Var);
|
||||
for (Use decl : var.declarations) {
|
||||
add_all_symbols(decl, var.usr, SymbolKind::Var);
|
||||
add_outline(decl, var.usr, SymbolKind::Var);
|
||||
}
|
||||
for (Use use : var.uses)
|
||||
if (use.file_id == -1)
|
||||
add_all_symbols(use, var.usr, SymbolKind::Var);
|
||||
}
|
||||
|
||||
std::sort(def.outline.begin(), def.outline.end(),
|
||||
[](const SymbolRef &a, const SymbolRef &b) {
|
||||
return a.range.start < b.range.start;
|
||||
});
|
||||
std::sort(def.all_symbols.begin(), def.all_symbols.end(),
|
||||
[](const SymbolRef &a, const SymbolRef &b) {
|
||||
return a.range.start < b.range.start;
|
||||
});
|
||||
|
||||
return {std::move(def), std::move(indexed.file_contents)};
|
||||
}
|
||||
|
||||
@ -182,7 +88,7 @@ IndexUpdate IndexUpdate::CreateDelta(IndexFile *previous, IndexFile *current) {
|
||||
for (auto &it : previous->usr2func) {
|
||||
auto &func = it.second;
|
||||
if (func.def.detailed_name[0])
|
||||
r.funcs_removed.push_back(func.usr);
|
||||
r.funcs_removed.emplace_back(func.usr, func.def);
|
||||
r.funcs_declarations[func.usr].first = std::move(func.declarations);
|
||||
r.funcs_uses[func.usr].first = std::move(func.uses);
|
||||
r.funcs_derived[func.usr].first = std::move(func.derived);
|
||||
@ -200,7 +106,7 @@ IndexUpdate IndexUpdate::CreateDelta(IndexFile *previous, IndexFile *current) {
|
||||
for (auto &it : previous->usr2type) {
|
||||
auto &type = it.second;
|
||||
if (type.def.detailed_name[0])
|
||||
r.types_removed.push_back(type.usr);
|
||||
r.types_removed.emplace_back(type.usr, type.def);
|
||||
r.types_declarations[type.usr].first = std::move(type.declarations);
|
||||
r.types_uses[type.usr].first = std::move(type.uses);
|
||||
r.types_derived[type.usr].first = std::move(type.derived);
|
||||
@ -220,7 +126,7 @@ IndexUpdate IndexUpdate::CreateDelta(IndexFile *previous, IndexFile *current) {
|
||||
for (auto &it : previous->usr2var) {
|
||||
auto &var = it.second;
|
||||
if (var.def.detailed_name[0])
|
||||
r.vars_removed.push_back(var.usr);
|
||||
r.vars_removed.emplace_back(var.usr, var.def);
|
||||
r.vars_declarations[var.usr].first = std::move(var.declarations);
|
||||
r.vars_uses[var.usr].first = std::move(var.uses);
|
||||
}
|
||||
@ -235,11 +141,12 @@ IndexUpdate IndexUpdate::CreateDelta(IndexFile *previous, IndexFile *current) {
|
||||
return r;
|
||||
}
|
||||
|
||||
template <typename Def>
|
||||
void DB::RemoveUsrs(SymbolKind kind, int file_id,
|
||||
const std::vector<Usr> &to_remove) {
|
||||
const std::vector<std::pair<Usr, Def>> &to_remove) {
|
||||
switch (kind) {
|
||||
case SymbolKind::Func: {
|
||||
for (Usr usr : to_remove) {
|
||||
for (auto &[usr, _] : to_remove) {
|
||||
// FIXME
|
||||
if (!HasFunc(usr))
|
||||
continue;
|
||||
@ -253,7 +160,7 @@ void DB::RemoveUsrs(SymbolKind kind, int file_id,
|
||||
break;
|
||||
}
|
||||
case SymbolKind::Type: {
|
||||
for (Usr usr : to_remove) {
|
||||
for (auto &[usr, _] : to_remove) {
|
||||
// FIXME
|
||||
if (!HasType(usr))
|
||||
continue;
|
||||
@ -267,7 +174,7 @@ void DB::RemoveUsrs(SymbolKind kind, int file_id,
|
||||
break;
|
||||
}
|
||||
case SymbolKind::Var: {
|
||||
for (Usr usr : to_remove) {
|
||||
for (auto &[usr, _] : to_remove) {
|
||||
// FIXME
|
||||
if (!HasVar(usr))
|
||||
continue;
|
||||
@ -292,43 +199,68 @@ void DB::ApplyIndexUpdate(IndexUpdate *u) {
|
||||
if (R.second) \
|
||||
C##s.emplace_back().usr = it.first; \
|
||||
auto &entity = C##s[R.first->second]; \
|
||||
AssignFileId(prev_lid2file_id, u->file_id, it.second.first); \
|
||||
RemoveRange(entity.F, it.second.first); \
|
||||
AssignFileId(lid2file_id, u->file_id, it.second.second); \
|
||||
AddRange(entity.F, it.second.second); \
|
||||
}
|
||||
|
||||
std::unordered_map<int, int> prev_lid2file_id, lid2file_id;
|
||||
for (auto &[lid, path] : u->prev_lid2path)
|
||||
prev_lid2file_id[lid] = GetFileId(path);
|
||||
for (auto &[lid, path] : u->lid2path)
|
||||
lid2file_id[lid] = GetFileId(path);
|
||||
for (auto &[lid, path] : u->lid2path) {
|
||||
int file_id = GetFileId(path);
|
||||
lid2file_id[lid] = file_id;
|
||||
if (!files[file_id].def) {
|
||||
files[file_id].def = QueryFile::Def();
|
||||
files[file_id].def->path = path;
|
||||
}
|
||||
}
|
||||
|
||||
// References (Use &use) in this function are important to update file_id.
|
||||
auto Ref = [&](std::unordered_map<int, int> &lid2fid, Usr usr,
|
||||
SymbolKind kind, Use &use, int delta) {
|
||||
use.file_id =
|
||||
use.file_id == -1 ? u->file_id : lid2fid.find(use.file_id)->second;
|
||||
int &v =
|
||||
files[use.file_id]
|
||||
.symbol2refcnt[SymbolRef{{use.range, usr, kind, use.role}}];
|
||||
v += delta;
|
||||
assert(v >= 0);
|
||||
};
|
||||
auto RefO = [&](std::unordered_map<int, int> &lid2fid, Usr usr,
|
||||
SymbolKind kind, Use &use, int delta) {
|
||||
use.file_id =
|
||||
use.file_id == -1 ? u->file_id : lid2fid.find(use.file_id)->second;
|
||||
files[use.file_id]
|
||||
.outline2refcnt[SymbolRef{{use.range, usr, kind, use.role}}] += delta;
|
||||
};
|
||||
|
||||
auto UpdateUses = [&](Usr usr, SymbolKind kind,
|
||||
llvm::DenseMap<WrappedUsr, int> &entity_usr,
|
||||
auto &entities, auto &p) {
|
||||
auto &entities, auto &p, bool hint_implicit) {
|
||||
auto R = entity_usr.try_emplace({usr}, entity_usr.size());
|
||||
if (R.second)
|
||||
vars.emplace_back().usr = usr;
|
||||
auto &entity = entities[R.first->second];
|
||||
for (Use &use : p.first) {
|
||||
if (use.file_id == -1)
|
||||
use.file_id = u->file_id;
|
||||
else {
|
||||
use.file_id = prev_lid2file_id.find(use.file_id)->second;
|
||||
files[use.file_id]
|
||||
.symbol2refcnt[SymbolRef{{use.range, usr, kind, use.role}}]--;
|
||||
if (hint_implicit && use.role & Role::Implicit) {
|
||||
// Make ranges of implicit function calls larger (spanning one more
|
||||
// column to the left/right). This is hacky but useful. e.g.
|
||||
// textDocument/definition on the space/semicolon in `A a;` or ` 42;`
|
||||
// will take you to the constructor.
|
||||
if (use.range.start.column > 0)
|
||||
use.range.start.column--;
|
||||
use.range.end.column++;
|
||||
}
|
||||
Ref(prev_lid2file_id, usr, kind, use, -1);
|
||||
}
|
||||
RemoveRange(entity.uses, p.first);
|
||||
for (Use &use : p.second) {
|
||||
if (use.file_id == -1)
|
||||
use.file_id = u->file_id;
|
||||
else {
|
||||
use.file_id = lid2file_id.find(use.file_id)->second;
|
||||
files[use.file_id]
|
||||
.symbol2refcnt[SymbolRef{{use.range, usr, kind, use.role}}]++;
|
||||
if (hint_implicit && use.role & Role::Implicit) {
|
||||
if (use.range.start.column > 0)
|
||||
use.range.start.column--;
|
||||
use.range.end.column++;
|
||||
}
|
||||
Ref(lid2file_id, usr, kind, use, 1);
|
||||
}
|
||||
AddRange(entity.uses, p.second);
|
||||
};
|
||||
@ -347,36 +279,72 @@ void DB::ApplyIndexUpdate(IndexUpdate *u) {
|
||||
funcs.reserve(t);
|
||||
func_usr.reserve(t);
|
||||
}
|
||||
for (auto &[usr, def] : u->funcs_removed) {
|
||||
if (def.spell)
|
||||
Ref(prev_lid2file_id, usr, SymbolKind::Func, *def.spell, -1);
|
||||
if (def.extent)
|
||||
RefO(prev_lid2file_id, usr, SymbolKind::Func, *def.extent, -1);
|
||||
}
|
||||
RemoveUsrs(SymbolKind::Func, u->file_id, u->funcs_removed);
|
||||
Update(lid2file_id, u->file_id, std::move(u->funcs_def_update));
|
||||
for (auto &[usr, del_add]: u->funcs_declarations) {
|
||||
for (Use &use : del_add.first)
|
||||
Ref(prev_lid2file_id, usr, SymbolKind::Func, use, -1);
|
||||
for (Use &use : del_add.second)
|
||||
Ref(lid2file_id, usr, SymbolKind::Func, use, 1);
|
||||
}
|
||||
REMOVE_ADD(func, declarations);
|
||||
REMOVE_ADD(func, derived);
|
||||
for (auto &[usr, p] : u->funcs_uses)
|
||||
UpdateUses(usr, SymbolKind::Func, func_usr, funcs, p);
|
||||
UpdateUses(usr, SymbolKind::Func, func_usr, funcs, p, true);
|
||||
|
||||
if ((t = types.size() + u->types_hint) > types.capacity()) {
|
||||
t = size_t(t * grow);
|
||||
types.reserve(t);
|
||||
type_usr.reserve(t);
|
||||
}
|
||||
for (auto &[usr, def] : u->types_removed) {
|
||||
if (def.spell)
|
||||
Ref(prev_lid2file_id, usr, SymbolKind::Type, *def.spell, -1);
|
||||
if (def.extent)
|
||||
RefO(prev_lid2file_id, usr, SymbolKind::Type, *def.extent, -1);
|
||||
}
|
||||
RemoveUsrs(SymbolKind::Type, u->file_id, u->types_removed);
|
||||
Update(lid2file_id, u->file_id, std::move(u->types_def_update));
|
||||
for (auto &[usr, del_add]: u->types_declarations) {
|
||||
for (Use &use : del_add.first)
|
||||
Ref(prev_lid2file_id, usr, SymbolKind::Type, use, -1);
|
||||
for (Use &use : del_add.second)
|
||||
Ref(lid2file_id, usr, SymbolKind::Type, use, 1);
|
||||
}
|
||||
REMOVE_ADD(type, declarations);
|
||||
REMOVE_ADD(type, derived);
|
||||
REMOVE_ADD(type, instances);
|
||||
for (auto &[usr, p] : u->types_uses)
|
||||
UpdateUses(usr, SymbolKind::Type, type_usr, types, p);
|
||||
UpdateUses(usr, SymbolKind::Type, type_usr, types, p, false);
|
||||
|
||||
if ((t = vars.size() + u->vars_hint) > vars.capacity()) {
|
||||
t = size_t(t * grow);
|
||||
vars.reserve(t);
|
||||
var_usr.reserve(t);
|
||||
}
|
||||
for (auto &[usr, def] : u->vars_removed) {
|
||||
if (def.spell)
|
||||
Ref(prev_lid2file_id, usr, SymbolKind::Var, *def.spell, -1);
|
||||
if (def.extent)
|
||||
RefO(prev_lid2file_id, usr, SymbolKind::Var, *def.extent, -1);
|
||||
}
|
||||
RemoveUsrs(SymbolKind::Var, u->file_id, u->vars_removed);
|
||||
Update(lid2file_id, u->file_id, std::move(u->vars_def_update));
|
||||
for (auto &[usr, del_add]: u->vars_declarations) {
|
||||
for (Use &use : del_add.first)
|
||||
Ref(prev_lid2file_id, usr, SymbolKind::Var, use, -1);
|
||||
for (Use &use : del_add.second)
|
||||
Ref(lid2file_id, usr, SymbolKind::Var, use, 1);
|
||||
}
|
||||
REMOVE_ADD(var, declarations);
|
||||
for (auto &[usr, p] : u->vars_uses)
|
||||
UpdateUses(usr, SymbolKind::Var, var_usr, vars, p);
|
||||
UpdateUses(usr, SymbolKind::Var, var_usr, vars, p, false);
|
||||
|
||||
#undef REMOVE_ADD
|
||||
}
|
||||
@ -402,9 +370,17 @@ void DB::Update(const Lid2file_id &lid2file_id, int file_id,
|
||||
auto &def = u.second;
|
||||
assert(def.detailed_name[0]);
|
||||
u.second.file_id = file_id;
|
||||
AssignFileId(lid2file_id, file_id, def.spell);
|
||||
AssignFileId(lid2file_id, file_id, def.extent);
|
||||
AssignFileId(lid2file_id, file_id, def.callees);
|
||||
if (def.spell) {
|
||||
AssignFileId(lid2file_id, file_id, *def.spell);
|
||||
files[def.spell->file_id].symbol2refcnt[{
|
||||
{def.spell->range, u.first, SymbolKind::Func, def.spell->role}}]++;
|
||||
}
|
||||
if (def.extent) {
|
||||
AssignFileId(lid2file_id, file_id, *def.extent);
|
||||
files[def.extent->file_id].outline2refcnt[{
|
||||
{def.extent->range, u.first, SymbolKind::Func, def.extent->role}}]++;
|
||||
}
|
||||
|
||||
auto R = func_usr.try_emplace({u.first}, func_usr.size());
|
||||
if (R.second)
|
||||
funcs.emplace_back();
|
||||
@ -421,8 +397,16 @@ void DB::Update(const Lid2file_id &lid2file_id, int file_id,
|
||||
auto &def = u.second;
|
||||
assert(def.detailed_name[0]);
|
||||
u.second.file_id = file_id;
|
||||
AssignFileId(lid2file_id, file_id, def.spell);
|
||||
AssignFileId(lid2file_id, file_id, def.extent);
|
||||
if (def.spell) {
|
||||
AssignFileId(lid2file_id, file_id, *def.spell);
|
||||
files[def.spell->file_id].symbol2refcnt[{
|
||||
{def.spell->range, u.first, SymbolKind::Type, def.spell->role}}]++;
|
||||
}
|
||||
if (def.extent) {
|
||||
AssignFileId(lid2file_id, file_id, *def.extent);
|
||||
files[def.extent->file_id].outline2refcnt[{
|
||||
{def.extent->range, u.first, SymbolKind::Type, def.extent->role}}]++;
|
||||
}
|
||||
auto R = type_usr.try_emplace({u.first}, type_usr.size());
|
||||
if (R.second)
|
||||
types.emplace_back();
|
||||
@ -439,8 +423,16 @@ void DB::Update(const Lid2file_id &lid2file_id, int file_id,
|
||||
auto &def = u.second;
|
||||
assert(def.detailed_name[0]);
|
||||
u.second.file_id = file_id;
|
||||
AssignFileId(lid2file_id, file_id, def.spell);
|
||||
AssignFileId(lid2file_id, file_id, def.extent);
|
||||
if (def.spell) {
|
||||
AssignFileId(lid2file_id, file_id, *def.spell);
|
||||
files[def.spell->file_id].symbol2refcnt[{
|
||||
{def.spell->range, u.first, SymbolKind::Var, def.spell->role}}]++;
|
||||
}
|
||||
if (def.extent) {
|
||||
AssignFileId(lid2file_id, file_id, *def.extent);
|
||||
files[def.extent->file_id].outline2refcnt[{
|
||||
{def.extent->range, u.first, SymbolKind::Var, def.extent->role}}]++;
|
||||
}
|
||||
auto R = var_usr.try_emplace({u.first}, var_usr.size());
|
||||
if (R.second)
|
||||
vars.emplace_back();
|
||||
|
31
src/query.h
31
src/query.h
@ -10,6 +10,21 @@
|
||||
#include <llvm/ADT/SmallVector.h>
|
||||
#include <llvm/ADT/StringMap.h>
|
||||
|
||||
namespace llvm {
|
||||
template <> struct DenseMapInfo<SymbolRef> {
|
||||
static inline SymbolRef getEmptyKey() { return {}; }
|
||||
static inline SymbolRef getTombstoneKey() {
|
||||
SymbolRef ret{};
|
||||
ret.usr = -1;
|
||||
return ret;
|
||||
}
|
||||
static unsigned getHashValue(SymbolRef sym) {
|
||||
return std::hash<SymbolRef>()(sym);
|
||||
}
|
||||
static bool isEqual(SymbolRef l, SymbolRef r) { return l == r; }
|
||||
};
|
||||
}
|
||||
|
||||
struct QueryFile {
|
||||
struct Def {
|
||||
std::string path;
|
||||
@ -17,10 +32,6 @@ struct QueryFile {
|
||||
LanguageId language;
|
||||
// Includes in the file.
|
||||
std::vector<IndexInclude> includes;
|
||||
// Outline of the file (ie, for code lens).
|
||||
std::vector<SymbolRef> outline;
|
||||
// Every symbol found in the file (ie, for goto definition)
|
||||
std::vector<SymbolRef> all_symbols;
|
||||
// Parts of the file which are disabled.
|
||||
std::vector<Range> skipped_ranges;
|
||||
// Used by |$ccls/freshenIndex|.
|
||||
@ -31,7 +42,8 @@ struct QueryFile {
|
||||
|
||||
int id = -1;
|
||||
std::optional<Def> def;
|
||||
std::unordered_map<SymbolRef, int> symbol2refcnt;
|
||||
llvm::DenseMap<SymbolRef, int> symbol2refcnt;
|
||||
llvm::DenseMap<SymbolRef, int> outline2refcnt;
|
||||
};
|
||||
|
||||
template <typename Q, typename QDef> struct QueryEntity {
|
||||
@ -98,7 +110,7 @@ struct IndexUpdate {
|
||||
|
||||
// Function updates.
|
||||
int funcs_hint;
|
||||
std::vector<Usr> funcs_removed;
|
||||
std::vector<std::pair<Usr, QueryFunc::Def>> funcs_removed;
|
||||
std::vector<std::pair<Usr, QueryFunc::Def>> funcs_def_update;
|
||||
UseUpdate funcs_declarations;
|
||||
UseUpdate funcs_uses;
|
||||
@ -106,7 +118,7 @@ struct IndexUpdate {
|
||||
|
||||
// Type updates.
|
||||
int types_hint;
|
||||
std::vector<Usr> types_removed;
|
||||
std::vector<std::pair<Usr, QueryType::Def>> types_removed;
|
||||
std::vector<std::pair<Usr, QueryType::Def>> types_def_update;
|
||||
UseUpdate types_declarations;
|
||||
UseUpdate types_uses;
|
||||
@ -115,7 +127,7 @@ struct IndexUpdate {
|
||||
|
||||
// Variable updates.
|
||||
int vars_hint;
|
||||
std::vector<Usr> vars_removed;
|
||||
std::vector<std::pair<Usr, QueryVar::Def>> vars_removed;
|
||||
std::vector<std::pair<Usr, QueryVar::Def>> vars_def_update;
|
||||
UseUpdate vars_declarations;
|
||||
UseUpdate vars_uses;
|
||||
@ -143,8 +155,9 @@ struct DB {
|
||||
std::vector<QueryType> types;
|
||||
std::vector<QueryVar> vars;
|
||||
|
||||
template <typename Def>
|
||||
void RemoveUsrs(SymbolKind kind, int file_id,
|
||||
const std::vector<Usr> &to_remove);
|
||||
const std::vector<std::pair<Usr, Def>> &to_remove);
|
||||
// Insert the contents of |update| into |db|.
|
||||
void ApplyIndexUpdate(IndexUpdate *update);
|
||||
int GetFileId(const std::string &path);
|
||||
|
@ -147,29 +147,28 @@ std::vector<Use> GetUsesForAllDerived(DB *db, QueryFunc &root) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::optional<lsPosition> GetLsPosition(WorkingFile *working_file,
|
||||
std::optional<lsPosition> GetLsPosition(WorkingFile *wfile,
|
||||
const Position &position) {
|
||||
if (!working_file)
|
||||
if (!wfile || wfile->index_lines.empty())
|
||||
return lsPosition{position.line, position.column};
|
||||
|
||||
int column = position.column;
|
||||
if (std::optional<int> start =
|
||||
working_file->GetBufferPosFromIndexPos(position.line, &column, false))
|
||||
wfile->GetBufferPosFromIndexPos(position.line, &column, false))
|
||||
return lsPosition{*start, column};
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<lsRange> GetLsRange(WorkingFile *working_file,
|
||||
std::optional<lsRange> GetLsRange(WorkingFile *wfile,
|
||||
const Range &location) {
|
||||
if (!working_file) {
|
||||
if (!wfile || wfile->index_lines.empty())
|
||||
return lsRange{lsPosition{location.start.line, location.start.column},
|
||||
lsPosition{location.end.line, 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 = wfile->GetBufferPosFromIndexPos(
|
||||
location.start.line, &start_column, false);
|
||||
std::optional<int> end = working_file->GetBufferPosFromIndexPos(
|
||||
std::optional<int> end = wfile->GetBufferPosFromIndexPos(
|
||||
location.end.line, &end_column, true);
|
||||
if (!start || !end)
|
||||
return std::nullopt;
|
||||
@ -303,12 +302,13 @@ std::optional<lsSymbolInformation> GetSymbolInfo(DB *db,
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::vector<SymbolRef> FindSymbolsAtLocation(WorkingFile *working_file,
|
||||
std::vector<SymbolRef> FindSymbolsAtLocation(WorkingFile *wfile,
|
||||
QueryFile *file,
|
||||
lsPosition &ls_pos) {
|
||||
std::vector<SymbolRef> symbols;
|
||||
if (working_file) {
|
||||
if (auto line = working_file->GetIndexPosFromBufferPos(
|
||||
// If multiVersion > 0, index may not exist and thus index_lines is empty.
|
||||
if (wfile && wfile->index_lines.size()) {
|
||||
if (auto line = wfile->GetIndexPosFromBufferPos(
|
||||
ls_pos.line, &ls_pos.character, false)) {
|
||||
ls_pos.line = *line;
|
||||
} else {
|
||||
@ -317,9 +317,6 @@ std::vector<SymbolRef> FindSymbolsAtLocation(WorkingFile *working_file,
|
||||
}
|
||||
}
|
||||
|
||||
for (SymbolRef sym : file->def->all_symbols)
|
||||
if (sym.range.Contains(ls_pos.line, ls_pos.character))
|
||||
symbols.push_back(sym);
|
||||
for (auto [sym, refcnt] : file->symbol2refcnt)
|
||||
if (refcnt > 0 && sym.range.Contains(ls_pos.line, ls_pos.character))
|
||||
symbols.push_back(sym);
|
||||
|
Loading…
Reference in New Issue
Block a user