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:
Fangrui Song 2018-09-02 19:11:10 -07:00
parent a8bb605d4a
commit 4f67bd03d5
9 changed files with 181 additions and 173 deletions

View File

@ -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);
}
};

View File

@ -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;

View File

@ -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";

View File

@ -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};

View File

@ -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;

View File

@ -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 &&
sym.range.start.line <= params.endLine)
out.result.push_back(location->range);
}
for (auto [sym, refcnt] : file->symbol2refcnt)
if (refcnt > 0 && params.startLine <= sym.range.start.line &&
sym.range.start.line <= params.endLine)
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);
}
}

View File

@ -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();

View File

@ -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);

View File

@ -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);