When erasing a USR only erase def data.

This should hopefully fix some bad indexes. It is possible that a def is temporarily deleted. In that case, we don't want to nuke all of the callers/etc so that if the def is restored we still have that information.

If the def is actually erased it the normal IndexUpdate remove logic will eventually purge the extra state outside of just the def (ie, callers).
This commit is contained in:
Jacob Dufault 2017-10-16 22:44:58 -07:00
parent 272e23901c
commit 809a55a351
4 changed files with 318 additions and 352 deletions

View File

@ -104,9 +104,9 @@ bool FindFileOrFail(QueryDatabase* db,
QueryFileId* out_file_id = nullptr) { QueryFileId* out_file_id = nullptr) {
auto it = db->usr_to_file.find(LowerPathIfCaseInsensitive(absolute_path)); auto it = db->usr_to_file.find(LowerPathIfCaseInsensitive(absolute_path));
if (it != db->usr_to_file.end()) { if (it != db->usr_to_file.end()) {
optional<QueryFile>& file = db->files[it->second.id]; QueryFile& file = db->files[it->second.id];
if (file) { if (file.def) {
*out_query_file = &file.value(); *out_query_file = &file;
if (out_file_id) if (out_file_id)
*out_file_id = QueryFileId(it->second.id); *out_file_id = QueryFileId(it->second.id);
return true; return true;
@ -194,25 +194,25 @@ optional<int> FindIncludeLine(const std::vector<std::string>& lines,
optional<QueryFileId> GetImplementationFile(QueryDatabase* db, optional<QueryFileId> GetImplementationFile(QueryDatabase* db,
QueryFileId file_id, QueryFileId file_id,
QueryFile* file) { QueryFile* file) {
for (SymbolRef sym : file->def.outline) { for (SymbolRef sym : file->def->outline) {
switch (sym.idx.kind) { switch (sym.idx.kind) {
case SymbolKind::Func: { case SymbolKind::Func: {
optional<QueryFunc>& func = db->funcs[sym.idx.idx]; QueryFunc& func = db->funcs[sym.idx.idx];
// Note: we ignore the definition if it is in the same file (ie, // Note: we ignore the definition if it is in the same file (ie,
// possibly a header). // possibly a header).
if (func && func->def.definition_extent && if (func.def && func.def->definition_extent &&
func->def.definition_extent->path != file_id) { func.def->definition_extent->path != file_id) {
return func->def.definition_extent->path; return func.def->definition_extent->path;
} }
break; break;
} }
case SymbolKind::Var: { case SymbolKind::Var: {
optional<QueryVar>& var = db->vars[sym.idx.idx]; QueryVar& var = db->vars[sym.idx.idx];
// Note: we ignore the definition if it is in the same file (ie, // Note: we ignore the definition if it is in the same file (ie,
// possibly a header). // possibly a header).
if (var && var->def.definition_extent && if (var.def && var.def->definition_extent &&
var->def.definition_extent->path != file_id) { var.def->definition_extent->path != file_id) {
return db->vars[sym.idx.idx]->def.definition_extent->path; return db->vars[sym.idx.idx].def->definition_extent->path;
} }
break; break;
} }
@ -223,7 +223,7 @@ optional<QueryFileId> GetImplementationFile(QueryDatabase* db,
// No associated definition, scan the project for a file in the same // No associated definition, scan the project for a file in the same
// directory with the same base-name. // directory with the same base-name.
std::string original_path = LowerPathIfCaseInsensitive(file->def.path); std::string original_path = LowerPathIfCaseInsensitive(file->def->path);
std::string target_path = original_path; std::string target_path = original_path;
size_t last = target_path.find_last_of('.'); size_t last = target_path.find_last_of('.');
if (last != std::string::npos) { if (last != std::string::npos) {
@ -253,18 +253,18 @@ void EnsureImplFile(QueryDatabase* db,
optional<lsDocumentUri>& impl_uri, optional<lsDocumentUri>& impl_uri,
optional<QueryFileId>& impl_file_id) { optional<QueryFileId>& impl_file_id) {
if (!impl_uri.has_value()) { if (!impl_uri.has_value()) {
optional<QueryFile>& file = db->files[file_id.id]; QueryFile& file = db->files[file_id.id];
assert(file); assert(file.def);
impl_file_id = GetImplementationFile(db, file_id, &file.value()); impl_file_id = GetImplementationFile(db, file_id, &file);
if (!impl_file_id.has_value()) if (!impl_file_id.has_value())
impl_file_id = file_id; impl_file_id = file_id;
optional<QueryFile>& impl_file = db->files[impl_file_id->id]; QueryFile& impl_file = db->files[impl_file_id->id];
if (impl_file) if (impl_file.def)
impl_uri = lsDocumentUri::FromPath(impl_file->def.path); impl_uri = lsDocumentUri::FromPath(impl_file.def->path);
else else
impl_uri = lsDocumentUri::FromPath(file->def.path); impl_uri = lsDocumentUri::FromPath(file.def->path);
} }
} }
@ -275,6 +275,7 @@ optional<lsTextEdit> BuildAutoImplementForFunction(QueryDatabase* db,
QueryFileId decl_file_id, QueryFileId decl_file_id,
QueryFileId impl_file_id, QueryFileId impl_file_id,
QueryFunc& func) { QueryFunc& func) {
assert(func.def);
for (const QueryLocation& decl : func.declarations) { for (const QueryLocation& decl : func.declarations) {
if (decl.path != decl_file_id) if (decl.path != decl_file_id)
continue; continue;
@ -285,13 +286,12 @@ optional<lsTextEdit> BuildAutoImplementForFunction(QueryDatabase* db,
optional<std::string> type_name; optional<std::string> type_name;
optional<lsPosition> same_file_insert_end; optional<lsPosition> same_file_insert_end;
if (func.def.declaring_type) { if (func.def->declaring_type) {
optional<QueryType>& declaring_type = QueryType& declaring_type = db->types[func.def->declaring_type->id];
db->types[func.def.declaring_type->id]; if (declaring_type.def) {
if (declaring_type) { type_name = declaring_type.def->short_name;
type_name = declaring_type->def.short_name;
optional<lsRange> ls_type_def_extent = GetLsRange( optional<lsRange> ls_type_def_extent = GetLsRange(
working_file, declaring_type->def.definition_extent->range); working_file, declaring_type.def->definition_extent->range);
if (ls_type_def_extent) { if (ls_type_def_extent) {
same_file_insert_end = ls_type_def_extent->end; same_file_insert_end = ls_type_def_extent->end;
same_file_insert_end->character += 1; // move past semicolon. same_file_insert_end->character += 1; // move past semicolon.
@ -321,21 +321,21 @@ optional<lsTextEdit> BuildAutoImplementForFunction(QueryDatabase* db,
best_pos.line = default_line; best_pos.line = default_line;
int best_dist = INT_MAX; int best_dist = INT_MAX;
optional<QueryFile>& file = db->files[impl_file_id.id]; QueryFile& file = db->files[impl_file_id.id];
assert(file); assert(file.def);
for (SymbolRef sym : file->def.outline) { for (SymbolRef sym : file.def->outline) {
switch (sym.idx.kind) { switch (sym.idx.kind) {
case SymbolKind::Func: { case SymbolKind::Func: {
optional<QueryFunc>& sym_func = db->funcs[sym.idx.idx]; QueryFunc& sym_func = db->funcs[sym.idx.idx];
if (!sym_func || !sym_func->def.definition_extent) if (!sym_func.def || !sym_func.def->definition_extent)
break; break;
for (QueryLocation& func_decl : sym_func->declarations) { for (QueryLocation& func_decl : sym_func.declarations) {
if (func_decl.path == decl_file_id) { if (func_decl.path == decl_file_id) {
int dist = func_decl.range.start.line - decl.range.start.line; int dist = func_decl.range.start.line - decl.range.start.line;
if (abs(dist) < abs(best_dist)) { if (abs(dist) < abs(best_dist)) {
optional<lsLocation> def_loc = GetLsLocation( optional<lsLocation> def_loc = GetLsLocation(
db, working_files, *sym_func->def.definition_extent); db, working_files, *sym_func.def->definition_extent);
if (!def_loc) if (!def_loc)
continue; continue;
@ -1486,19 +1486,19 @@ bool QueryDbMainLoop(Config* config,
// Unmark all files whose timestamp has changed. // Unmark all files whose timestamp has changed.
CacheLoader cache_loader(config); CacheLoader cache_loader(config);
for (const auto& file : db->files) { for (const auto& file : db->files) {
if (!file) if (!file.def)
continue; continue;
optional<int64_t> modification_timestamp = optional<int64_t> modification_timestamp =
GetLastModificationTime(file->def.path); GetLastModificationTime(file.def->path);
if (!modification_timestamp) if (!modification_timestamp)
continue; continue;
optional<int64_t> cached_modification = optional<int64_t> cached_modification =
timestamp_manager->GetLastCachedModificationTime(&cache_loader, timestamp_manager->GetLastCachedModificationTime(&cache_loader,
file->def.path); file.def->path);
if (modification_timestamp != cached_modification) if (modification_timestamp != cached_modification)
file_consumer_shared->Reset(file->def.path); file_consumer_shared->Reset(file.def->path);
} }
// Send index requests for every file. // Send index requests for every file.
@ -1524,7 +1524,7 @@ bool QueryDbMainLoop(Config* config,
break; break;
WorkingFile* working_file = WorkingFile* working_file =
working_files->GetFileByFilename(file->def.path); working_files->GetFileByFilename(file->def->path);
Out_CqueryTypeHierarchyTree response; Out_CqueryTypeHierarchyTree response;
response.id = msg->id; response.id = msg->id;
@ -1556,7 +1556,7 @@ bool QueryDbMainLoop(Config* config,
break; break;
WorkingFile* working_file = WorkingFile* working_file =
working_files->GetFileByFilename(file->def.path); working_files->GetFileByFilename(file->def->path);
Out_CqueryCallTree response; Out_CqueryCallTree response;
response.id = msg->id; response.id = msg->id;
@ -1598,18 +1598,16 @@ bool QueryDbMainLoop(Config* config,
break; break;
WorkingFile* working_file = WorkingFile* working_file =
working_files->GetFileByFilename(file->def.path); working_files->GetFileByFilename(file->def->path);
Out_LocationList response; Out_LocationList response;
response.id = msg->id; response.id = msg->id;
for (const SymbolRef& ref : for (const SymbolRef& ref :
FindSymbolsAtLocation(working_file, file, msg->params.position)) { FindSymbolsAtLocation(working_file, file, msg->params.position)) {
if (ref.idx.kind == SymbolKind::Type) { if (ref.idx.kind == SymbolKind::Type) {
optional<QueryType>& type = db->types[ref.idx.idx]; QueryType& type = db->types[ref.idx.idx];
if (!type)
continue;
std::vector<QueryLocation> locations = std::vector<QueryLocation> locations =
ToQueryLocation(db, type->instances); ToQueryLocation(db, type.instances);
response.result = GetLsLocations(db, working_files, locations); response.result = GetLsLocations(db, working_files, locations);
} }
} }
@ -1626,23 +1624,21 @@ bool QueryDbMainLoop(Config* config,
break; break;
WorkingFile* working_file = WorkingFile* working_file =
working_files->GetFileByFilename(file->def.path); working_files->GetFileByFilename(file->def->path);
Out_LocationList response; Out_LocationList response;
response.id = msg->id; response.id = msg->id;
for (const SymbolRef& ref : for (const SymbolRef& ref :
FindSymbolsAtLocation(working_file, file, msg->params.position)) { FindSymbolsAtLocation(working_file, file, msg->params.position)) {
if (ref.idx.kind == SymbolKind::Func) { if (ref.idx.kind == SymbolKind::Func) {
optional<QueryFunc>& func = db->funcs[ref.idx.idx]; QueryFunc& func = db->funcs[ref.idx.idx];
if (!func)
continue;
std::vector<QueryLocation> locations = std::vector<QueryLocation> locations =
ToQueryLocation(db, func->callers); ToQueryLocation(db, func.callers);
for (QueryFuncRef func_ref : for (QueryFuncRef func_ref :
GetCallersForAllBaseFunctions(db, *func)) GetCallersForAllBaseFunctions(db, func))
locations.push_back(func_ref.loc); locations.push_back(func_ref.loc);
for (QueryFuncRef func_ref : for (QueryFuncRef func_ref :
GetCallersForAllDerivedFunctions(db, *func)) GetCallersForAllDerivedFunctions(db, func))
locations.push_back(func_ref.loc); locations.push_back(func_ref.loc);
response.result = GetLsLocations(db, working_files, locations); response.result = GetLsLocations(db, working_files, locations);
@ -1661,25 +1657,23 @@ bool QueryDbMainLoop(Config* config,
break; break;
WorkingFile* working_file = WorkingFile* working_file =
working_files->GetFileByFilename(file->def.path); working_files->GetFileByFilename(file->def->path);
Out_LocationList response; Out_LocationList response;
response.id = msg->id; response.id = msg->id;
for (const SymbolRef& ref : for (const SymbolRef& ref :
FindSymbolsAtLocation(working_file, file, msg->params.position)) { FindSymbolsAtLocation(working_file, file, msg->params.position)) {
if (ref.idx.kind == SymbolKind::Type) { if (ref.idx.kind == SymbolKind::Type) {
optional<QueryType>& type = db->types[ref.idx.idx]; QueryType& type = db->types[ref.idx.idx];
if (!type) if (!type.def)
continue; continue;
std::vector<QueryLocation> locations = std::vector<QueryLocation> locations =
ToQueryLocation(db, type->def.parents); ToQueryLocation(db, type.def->parents);
response.result = GetLsLocations(db, working_files, locations); response.result = GetLsLocations(db, working_files, locations);
} else if (ref.idx.kind == SymbolKind::Func) { } else if (ref.idx.kind == SymbolKind::Func) {
optional<QueryFunc>& func = db->funcs[ref.idx.idx]; QueryFunc& func = db->funcs[ref.idx.idx];
if (!func)
continue;
optional<QueryLocation> location = optional<QueryLocation> location =
GetBaseDefinitionOrDeclarationSpelling(db, *func); GetBaseDefinitionOrDeclarationSpelling(db, func);
if (!location) if (!location)
continue; continue;
optional<lsLocation> ls_loc = optional<lsLocation> ls_loc =
@ -1702,25 +1696,21 @@ bool QueryDbMainLoop(Config* config,
break; break;
WorkingFile* working_file = WorkingFile* working_file =
working_files->GetFileByFilename(file->def.path); working_files->GetFileByFilename(file->def->path);
Out_LocationList response; Out_LocationList response;
response.id = msg->id; response.id = msg->id;
for (const SymbolRef& ref : for (const SymbolRef& ref :
FindSymbolsAtLocation(working_file, file, msg->params.position)) { FindSymbolsAtLocation(working_file, file, msg->params.position)) {
if (ref.idx.kind == SymbolKind::Type) { if (ref.idx.kind == SymbolKind::Type) {
optional<QueryType>& type = db->types[ref.idx.idx]; QueryType& type = db->types[ref.idx.idx];
if (!type)
continue;
std::vector<QueryLocation> locations = std::vector<QueryLocation> locations =
ToQueryLocation(db, type->derived); ToQueryLocation(db, type.derived);
response.result = GetLsLocations(db, working_files, locations); response.result = GetLsLocations(db, working_files, locations);
} else if (ref.idx.kind == SymbolKind::Func) { } else if (ref.idx.kind == SymbolKind::Func) {
optional<QueryFunc>& func = db->funcs[ref.idx.idx]; QueryFunc& func = db->funcs[ref.idx.idx];
if (!func)
continue;
std::vector<QueryLocation> locations = std::vector<QueryLocation> locations =
ToQueryLocation(db, func->derived); ToQueryLocation(db, func.derived);
response.result = GetLsLocations(db, working_files, locations); response.result = GetLsLocations(db, working_files, locations);
} }
} }
@ -1824,7 +1814,7 @@ bool QueryDbMainLoop(Config* config,
break; break;
WorkingFile* working_file = WorkingFile* working_file =
working_files->GetFileByFilename(file->def.path); working_files->GetFileByFilename(file->def->path);
Out_TextDocumentRename response; Out_TextDocumentRename response;
response.id = msg->id; response.id = msg->id;
@ -2064,7 +2054,7 @@ bool QueryDbMainLoop(Config* config,
break; break;
WorkingFile* working_file = WorkingFile* working_file =
working_files->GetFileByFilename(file->def.path); working_files->GetFileByFilename(file->def->path);
Out_TextDocumentDefinition response; Out_TextDocumentDefinition response;
response.id = msg->id; response.id = msg->id;
@ -2126,7 +2116,7 @@ bool QueryDbMainLoop(Config* config,
// No symbols - check for includes. // No symbols - check for includes.
if (response.result.empty()) { if (response.result.empty()) {
for (const IndexInclude& include : file->def.includes) { for (const IndexInclude& include : file->def->includes) {
if (include.line == target_line) { if (include.line == target_line) {
lsLocation result; lsLocation result;
result.uri = lsDocumentUri::FromPath(include.resolved_path); result.uri = lsDocumentUri::FromPath(include.resolved_path);
@ -2150,7 +2140,7 @@ bool QueryDbMainLoop(Config* config,
break; break;
WorkingFile* working_file = WorkingFile* working_file =
working_files->GetFileByFilename(file->def.path); working_files->GetFileByFilename(file->def->path);
Out_TextDocumentDocumentHighlight response; Out_TextDocumentDocumentHighlight response;
response.id = msg->id; response.id = msg->id;
@ -2191,7 +2181,7 @@ bool QueryDbMainLoop(Config* config,
break; break;
WorkingFile* working_file = WorkingFile* working_file =
working_files->GetFileByFilename(file->def.path); working_files->GetFileByFilename(file->def->path);
Out_TextDocumentHover response; Out_TextDocumentHover response;
response.id = msg->id; response.id = msg->id;
@ -2200,7 +2190,7 @@ bool QueryDbMainLoop(Config* config,
FindSymbolsAtLocation(working_file, file, msg->params.position)) { FindSymbolsAtLocation(working_file, file, msg->params.position)) {
// Found symbol. Return hover. // Found symbol. Return hover.
optional<lsRange> ls_range = GetLsRange( optional<lsRange> ls_range = GetLsRange(
working_files->GetFileByFilename(file->def.path), ref.loc.range); working_files->GetFileByFilename(file->def->path), ref.loc.range);
if (!ls_range) if (!ls_range)
continue; continue;
@ -2222,7 +2212,7 @@ bool QueryDbMainLoop(Config* config,
break; break;
WorkingFile* working_file = WorkingFile* working_file =
working_files->GetFileByFilename(file->def.path); working_files->GetFileByFilename(file->def->path);
Out_TextDocumentReferences response; Out_TextDocumentReferences response;
response.id = msg->id; response.id = msg->id;
@ -2266,7 +2256,7 @@ bool QueryDbMainLoop(Config* config,
&file)) &file))
break; break;
for (SymbolRef ref : file->def.outline) { for (SymbolRef ref : file->def->outline) {
optional<lsSymbolInformation> info = optional<lsSymbolInformation> info =
GetSymbolInfo(db, working_files, ref.idx); GetSymbolInfo(db, working_files, ref.idx);
if (!info) if (!info)
@ -2304,7 +2294,7 @@ bool QueryDbMainLoop(Config* config,
<< msg->params.textDocument.uri.GetPath(); << msg->params.textDocument.uri.GetPath();
break; break;
} }
for (const IndexInclude& include : file->def.includes) { for (const IndexInclude& include : file->def->includes) {
optional<int> buffer_line; optional<int> buffer_line;
optional<std::string> buffer_line_content = optional<std::string> buffer_line_content =
working_file->GetBufferLineContentFromIndexLine(include.line, working_file->GetBufferLineContentFromIndexLine(include.line,
@ -2376,8 +2366,8 @@ bool QueryDbMainLoop(Config* config,
for (SymbolRef sym : syms) { for (SymbolRef sym : syms) {
switch (sym.idx.kind) { switch (sym.idx.kind) {
case SymbolKind::Type: { case SymbolKind::Type: {
optional<QueryType>& type = db->types[sym.idx.idx]; QueryType& type = db->types[sym.idx.idx];
if (!type) if (!type.def)
break; break;
int num_edits = 0; int num_edits = 0;
@ -2385,16 +2375,16 @@ bool QueryDbMainLoop(Config* config,
// Get implementation file. // Get implementation file.
Out_TextDocumentCodeAction::Command command; Out_TextDocumentCodeAction::Command command;
for (QueryFuncId func_id : type->def.funcs) { for (QueryFuncId func_id : type.def->funcs) {
optional<QueryFunc>& func_def = db->funcs[func_id.id]; QueryFunc& func_def = db->funcs[func_id.id];
if (!func_def || func_def->def.definition_extent) if (!func_def.def || func_def.def->definition_extent)
continue; continue;
EnsureImplFile(db, file_id, impl_uri /*out*/, EnsureImplFile(db, file_id, impl_uri /*out*/,
impl_file_id /*out*/); impl_file_id /*out*/);
optional<lsTextEdit> edit = BuildAutoImplementForFunction( optional<lsTextEdit> edit = BuildAutoImplementForFunction(
db, working_files, working_file, default_line, file_id, db, working_files, working_file, default_line, file_id,
*impl_file_id, *func_def); *impl_file_id, func_def);
if (!edit) if (!edit)
continue; continue;
@ -2423,15 +2413,15 @@ bool QueryDbMainLoop(Config* config,
command.arguments.textDocumentUri = *impl_uri; command.arguments.textDocumentUri = *impl_uri;
command.title = "Auto-Implement " + std::to_string(num_edits) + command.title = "Auto-Implement " + std::to_string(num_edits) +
" methods on " + type->def.short_name; " methods on " + type.def->short_name;
command.command = "cquery._autoImplement"; command.command = "cquery._autoImplement";
response.result.push_back(command); response.result.push_back(command);
break; break;
} }
case SymbolKind::Func: { case SymbolKind::Func: {
optional<QueryFunc>& func = db->funcs[sym.idx.idx]; QueryFunc& func = db->funcs[sym.idx.idx];
if (!func || func->def.definition_extent) if (!func.def || func.def->definition_extent)
break; break;
EnsureImplFile(db, file_id, impl_uri /*out*/, EnsureImplFile(db, file_id, impl_uri /*out*/,
@ -2439,12 +2429,12 @@ bool QueryDbMainLoop(Config* config,
// Get implementation file. // Get implementation file.
Out_TextDocumentCodeAction::Command command; Out_TextDocumentCodeAction::Command command;
command.title = "Auto-Implement " + func->def.short_name; command.title = "Auto-Implement " + func.def->short_name;
command.command = "cquery._autoImplement"; command.command = "cquery._autoImplement";
command.arguments.textDocumentUri = *impl_uri; command.arguments.textDocumentUri = *impl_uri;
optional<lsTextEdit> edit = BuildAutoImplementForFunction( optional<lsTextEdit> edit = BuildAutoImplementForFunction(
db, working_files, working_file, default_line, file_id, db, working_files, working_file, default_line, file_id,
*impl_file_id, *func); *impl_file_id, func);
if (!edit) if (!edit)
break; break;
@ -2496,11 +2486,11 @@ bool QueryDbMainLoop(Config* config,
if (!decl_file_id) if (!decl_file_id)
continue; continue;
optional<QueryFile>& decl_file = db->files[decl_file_id->id]; QueryFile& decl_file = db->files[decl_file_id->id];
if (!decl_file) if (!decl_file.def)
continue; continue;
include_absolute_paths.insert(decl_file->def.path); include_absolute_paths.insert(decl_file.def->path);
} }
// Build include strings. // Build include strings.
@ -2591,50 +2581,50 @@ bool QueryDbMainLoop(Config* config,
common.result = &response.result; common.result = &response.result;
common.db = db; common.db = db;
common.working_files = working_files; common.working_files = working_files;
common.working_file = working_files->GetFileByFilename(file->def.path); common.working_file = working_files->GetFileByFilename(file->def->path);
for (SymbolRef ref : file->def.outline) { for (SymbolRef ref : file->def->outline) {
// NOTE: We OffsetColumn so that the code lens always show up in a // NOTE: We OffsetColumn so that the code lens always show up in a
// predictable order. Otherwise, the client may randomize it. // predictable order. Otherwise, the client may randomize it.
SymbolIdx symbol = ref.idx; SymbolIdx symbol = ref.idx;
switch (symbol.kind) { switch (symbol.kind) {
case SymbolKind::Type: { case SymbolKind::Type: {
optional<QueryType>& type = db->types[symbol.idx]; QueryType& type = db->types[symbol.idx];
if (!type) if (!type.def)
continue; continue;
AddCodeLens("ref", "refs", &common, ref.loc.OffsetStartColumn(0), AddCodeLens("ref", "refs", &common, ref.loc.OffsetStartColumn(0),
type->uses, type->def.definition_spelling, type.uses, type.def->definition_spelling,
true /*force_display*/); true /*force_display*/);
AddCodeLens("derived", "derived", &common, AddCodeLens("derived", "derived", &common,
ref.loc.OffsetStartColumn(1), ref.loc.OffsetStartColumn(1),
ToQueryLocation(db, type->derived), nullopt, ToQueryLocation(db, type.derived), nullopt,
false /*force_display*/); false /*force_display*/);
AddCodeLens("var", "vars", &common, ref.loc.OffsetStartColumn(2), AddCodeLens("var", "vars", &common, ref.loc.OffsetStartColumn(2),
ToQueryLocation(db, type->instances), nullopt, ToQueryLocation(db, type.instances), nullopt,
false /*force_display*/); false /*force_display*/);
break; break;
} }
case SymbolKind::Func: { case SymbolKind::Func: {
optional<QueryFunc>& func = db->funcs[symbol.idx]; QueryFunc& func = db->funcs[symbol.idx];
if (!func) if (!func.def)
continue; continue;
int16_t offset = 0; int16_t offset = 0;
std::vector<QueryFuncRef> base_callers = std::vector<QueryFuncRef> base_callers =
GetCallersForAllBaseFunctions(db, *func); GetCallersForAllBaseFunctions(db, func);
std::vector<QueryFuncRef> derived_callers = std::vector<QueryFuncRef> derived_callers =
GetCallersForAllDerivedFunctions(db, *func); GetCallersForAllDerivedFunctions(db, func);
if (base_callers.empty() && derived_callers.empty()) { if (base_callers.empty() && derived_callers.empty()) {
AddCodeLens("call", "calls", &common, AddCodeLens("call", "calls", &common,
ref.loc.OffsetStartColumn(offset++), ref.loc.OffsetStartColumn(offset++),
ToQueryLocation(db, func->callers), nullopt, ToQueryLocation(db, func.callers), nullopt,
true /*force_display*/); true /*force_display*/);
} else { } else {
AddCodeLens("direct call", "direct calls", &common, AddCodeLens("direct call", "direct calls", &common,
ref.loc.OffsetStartColumn(offset++), ref.loc.OffsetStartColumn(offset++),
ToQueryLocation(db, func->callers), nullopt, ToQueryLocation(db, func.callers), nullopt,
false /*force_display*/); false /*force_display*/);
if (!base_callers.empty()) if (!base_callers.empty())
AddCodeLens("base call", "base calls", &common, AddCodeLens("base call", "base calls", &common,
@ -2650,12 +2640,12 @@ bool QueryDbMainLoop(Config* config,
AddCodeLens("derived", "derived", &common, AddCodeLens("derived", "derived", &common,
ref.loc.OffsetStartColumn(offset++), ref.loc.OffsetStartColumn(offset++),
ToQueryLocation(db, func->derived), nullopt, ToQueryLocation(db, func.derived), nullopt,
false /*force_display*/); false /*force_display*/);
// "Base" // "Base"
optional<QueryLocation> base_loc = optional<QueryLocation> base_loc =
GetBaseDefinitionOrDeclarationSpelling(db, *func); GetBaseDefinitionOrDeclarationSpelling(db, func);
if (base_loc) { if (base_loc) {
optional<lsLocation> ls_base = optional<lsLocation> ls_base =
GetLsLocation(db, working_files, *base_loc); GetLsLocation(db, working_files, *base_loc);
@ -2680,21 +2670,21 @@ bool QueryDbMainLoop(Config* config,
break; break;
} }
case SymbolKind::Var: { case SymbolKind::Var: {
optional<QueryVar>& var = db->vars[symbol.idx]; QueryVar& var = db->vars[symbol.idx];
if (!var) if (!var.def)
continue; continue;
if (var->def.is_local && !config->codeLensOnLocalVariables) if (var.def->is_local && !config->codeLensOnLocalVariables)
continue; continue;
bool force_display = true; bool force_display = true;
// Do not show 0 refs on macro with no uses, as it is most likely // Do not show 0 refs on macro with no uses, as it is most likely
// a header guard. // a header guard.
if (var->def.is_macro) if (var.def->is_macro)
force_display = false; force_display = false;
AddCodeLens("ref", "refs", &common, ref.loc.OffsetStartColumn(0), AddCodeLens("ref", "refs", &common, ref.loc.OffsetStartColumn(0),
var->uses, var->def.definition_spelling, var.uses, var.def->definition_spelling,
force_display); force_display);
break; break;
} }

View File

@ -6,7 +6,6 @@
#include <optional.h> #include <optional.h>
#include <loguru.hpp> #include <loguru.hpp>
#include <cassert> #include <cassert>
#include <cstdint> #include <cstdint>
#include <functional> #include <functional>
@ -15,7 +14,6 @@
#include <unordered_map> #include <unordered_map>
#include <unordered_set> #include <unordered_set>
// TODO: Make all copy constructors explicit. // TODO: Make all copy constructors explicit.
namespace { namespace {
@ -665,22 +663,22 @@ void QueryDatabase::RemoveUsrs(SymbolKind usr_kind,
switch (usr_kind) { switch (usr_kind) {
case SymbolKind::File: { case SymbolKind::File: {
for (const Usr& usr : to_remove) for (const Usr& usr : to_remove)
files[usr_to_file[LowerPathIfCaseInsensitive(usr)].id] = nullopt; files[usr_to_file[LowerPathIfCaseInsensitive(usr)].id].def = nullopt;
break; break;
} }
case SymbolKind::Type: { case SymbolKind::Type: {
for (const Usr& usr : to_remove) for (const Usr& usr : to_remove)
types[usr_to_type[usr].id] = nullopt; types[usr_to_type[usr].id].def = nullopt;
break; break;
} }
case SymbolKind::Func: { case SymbolKind::Func: {
for (const Usr& usr : to_remove) for (const Usr& usr : to_remove)
funcs[usr_to_func[usr].id] = nullopt; funcs[usr_to_func[usr].id].def = nullopt;
break; break;
} }
case SymbolKind::Var: { case SymbolKind::Var: {
for (const Usr& usr : to_remove) for (const Usr& usr : to_remove)
vars[usr_to_var[usr].id] = nullopt; vars[usr_to_var[usr].id].def = nullopt;
break; break;
} }
case SymbolKind::Invalid: case SymbolKind::Invalid:
@ -699,10 +697,8 @@ void QueryDatabase::ApplyIndexUpdate(IndexUpdate* update) {
#define HANDLE_MERGEABLE(update_var_name, def_var_name, storage_name) \ #define HANDLE_MERGEABLE(update_var_name, def_var_name, storage_name) \
for (auto merge_update : update->update_var_name) { \ for (auto merge_update : update->update_var_name) { \
auto& def = storage_name[merge_update.id.id]; \ auto& def = storage_name[merge_update.id.id]; \
if (!def) \ AddRange(&def.def_var_name, merge_update.to_add); \
continue; /* TODO: Should we continue or create an empty def? */ \ RemoveRange(&def.def_var_name, merge_update.to_remove); \
AddRange(&def->def_var_name, merge_update.to_add); \
RemoveRange(&def->def_var_name, merge_update.to_remove); \
} }
RemoveUsrs(SymbolKind::File, update->files_removed); RemoveUsrs(SymbolKind::File, update->files_removed);
@ -735,12 +731,10 @@ void QueryDatabase::ImportOrUpdate(
auto it = usr_to_file.find(LowerPathIfCaseInsensitive(def.path)); auto it = usr_to_file.find(LowerPathIfCaseInsensitive(def.path));
assert(it != usr_to_file.end()); assert(it != usr_to_file.end());
optional<QueryFile>& existing = files[it->second.id]; QueryFile& existing = files[it->second.id];
if (!existing)
existing = QueryFile(def.path);
existing->def = def; existing.def = def;
UpdateDetailedNames(&existing->detailed_name_idx, SymbolKind::File, UpdateDetailedNames(&existing.detailed_name_idx, SymbolKind::File,
it->second.id, def.path); it->second.id, def.path);
} }
} }
@ -756,16 +750,15 @@ void QueryDatabase::ImportOrUpdate(
assert(it != usr_to_type.end()); assert(it != usr_to_type.end());
assert(it->second.id >= 0 && it->second.id < types.size()); assert(it->second.id >= 0 && it->second.id < types.size());
optional<QueryType>& existing = types[it->second.id]; QueryType& existing = types[it->second.id];
if (!existing)
existing = QueryType(def.usr);
// Keep the existing definition if it is higher quality. // Keep the existing definition if it is higher quality.
if (existing->def.definition_spelling && !def.definition_spelling) if (existing.def && existing.def->definition_spelling &&
!def.definition_spelling)
continue; continue;
existing->def = def; existing.def = def;
UpdateDetailedNames(&existing->detailed_name_idx, SymbolKind::Type, UpdateDetailedNames(&existing.detailed_name_idx, SymbolKind::Type,
it->second.id, def.detailed_name); it->second.id, def.detailed_name);
} }
} }
@ -781,16 +774,15 @@ void QueryDatabase::ImportOrUpdate(
assert(it != usr_to_func.end()); assert(it != usr_to_func.end());
assert(it->second.id >= 0 && it->second.id < funcs.size()); assert(it->second.id >= 0 && it->second.id < funcs.size());
optional<QueryFunc>& existing = funcs[it->second.id]; QueryFunc& existing = funcs[it->second.id];
if (!existing)
existing = QueryFunc(def.usr);
// Keep the existing definition if it is higher quality. // Keep the existing definition if it is higher quality.
if (existing->def.definition_spelling && !def.definition_spelling) if (existing.def && existing.def->definition_spelling &&
!def.definition_spelling)
continue; continue;
existing->def = def; existing.def = def;
UpdateDetailedNames(&existing->detailed_name_idx, SymbolKind::Func, UpdateDetailedNames(&existing.detailed_name_idx, SymbolKind::Func,
it->second.id, def.detailed_name); it->second.id, def.detailed_name);
} }
} }
@ -806,17 +798,16 @@ void QueryDatabase::ImportOrUpdate(
assert(it != usr_to_var.end()); assert(it != usr_to_var.end());
assert(it->second.id >= 0 && it->second.id < vars.size()); assert(it->second.id >= 0 && it->second.id < vars.size());
optional<QueryVar>& existing = vars[it->second.id]; QueryVar& existing = vars[it->second.id];
if (!existing)
existing = QueryVar(def.usr);
// Keep the existing definition if it is higher quality. // Keep the existing definition if it is higher quality.
if (existing->def.definition_spelling && !def.definition_spelling) if (existing.def && existing.def->definition_spelling &&
!def.definition_spelling)
continue; continue;
existing->def = def; existing.def = def;
if (!def.is_local) if (!def.is_local)
UpdateDetailedNames(&existing->detailed_name_idx, SymbolKind::Var, UpdateDetailedNames(&existing.detailed_name_idx, SymbolKind::Var,
it->second.id, def.detailed_name); it->second.id, def.detailed_name);
} }
} }
@ -952,14 +943,14 @@ TEST_CASE("apply delta") {
&previous_map, &current_map, &previous, &current); &previous_map, &current_map, &previous, &current);
db.ApplyIndexUpdate(&import_update); db.ApplyIndexUpdate(&import_update);
REQUIRE(db.funcs[0]->callers.size() == 2); REQUIRE(db.funcs[0].callers.size() == 2);
REQUIRE(db.funcs[0]->callers[0].loc.range == Range(Position(1, 0))); REQUIRE(db.funcs[0].callers[0].loc.range == Range(Position(1, 0)));
REQUIRE(db.funcs[0]->callers[1].loc.range == Range(Position(2, 0))); REQUIRE(db.funcs[0].callers[1].loc.range == Range(Position(2, 0)));
db.ApplyIndexUpdate(&delta_update); db.ApplyIndexUpdate(&delta_update);
REQUIRE(db.funcs[0]->callers.size() == 2); REQUIRE(db.funcs[0].callers.size() == 2);
REQUIRE(db.funcs[0]->callers[0].loc.range == Range(Position(4, 0))); REQUIRE(db.funcs[0].callers[0].loc.range == Range(Position(4, 0)));
REQUIRE(db.funcs[0]->callers[1].loc.range == Range(Position(5, 0))); REQUIRE(db.funcs[0].callers[1].loc.range == Range(Position(5, 0)));
} }
TEST_SUITE_END(); TEST_SUITE_END();

View File

@ -169,10 +169,13 @@ struct QueryFile {
using DefUpdate = Def; using DefUpdate = Def;
DefUpdate def; optional<DefUpdate> def;
size_t detailed_name_idx = (size_t)-1; size_t detailed_name_idx = (size_t)-1;
QueryFile(const std::string& path) { def.path = path; } QueryFile(const std::string& path) {
def = DefUpdate();
def->path = path;
}
}; };
MAKE_REFLECT_STRUCT(QueryFile::Def, path, outline, all_symbols); MAKE_REFLECT_STRUCT(QueryFile::Def, path, outline, all_symbols);
@ -185,7 +188,7 @@ struct QueryType {
using InstancesUpdate = MergeableUpdate<QueryTypeId, QueryVarId>; using InstancesUpdate = MergeableUpdate<QueryTypeId, QueryVarId>;
using UsesUpdate = MergeableUpdate<QueryTypeId, QueryLocation>; using UsesUpdate = MergeableUpdate<QueryTypeId, QueryLocation>;
DefUpdate def; optional<DefUpdate> def;
std::vector<QueryTypeId> derived; std::vector<QueryTypeId> derived;
std::vector<QueryVarId> instances; std::vector<QueryVarId> instances;
std::vector<QueryLocation> uses; std::vector<QueryLocation> uses;
@ -204,7 +207,7 @@ struct QueryFunc {
using DerivedUpdate = MergeableUpdate<QueryFuncId, QueryFuncId>; using DerivedUpdate = MergeableUpdate<QueryFuncId, QueryFuncId>;
using CallersUpdate = MergeableUpdate<QueryFuncId, QueryFuncRef>; using CallersUpdate = MergeableUpdate<QueryFuncId, QueryFuncRef>;
DefUpdate def; optional<DefUpdate> def;
std::vector<QueryLocation> declarations; std::vector<QueryLocation> declarations;
std::vector<QueryFuncId> derived; std::vector<QueryFuncId> derived;
std::vector<QueryFuncRef> callers; std::vector<QueryFuncRef> callers;
@ -218,7 +221,7 @@ struct QueryVar {
VarDefDefinitionData<QueryTypeId, QueryFuncId, QueryVarId, QueryLocation>; VarDefDefinitionData<QueryTypeId, QueryFuncId, QueryVarId, QueryLocation>;
using UsesUpdate = MergeableUpdate<QueryVarId, QueryLocation>; using UsesUpdate = MergeableUpdate<QueryVarId, QueryLocation>;
DefUpdate def; optional<DefUpdate> def;
std::vector<QueryLocation> uses; std::vector<QueryLocation> uses;
size_t detailed_name_idx = (size_t)-1; size_t detailed_name_idx = (size_t)-1;
@ -298,10 +301,10 @@ struct QueryDatabase {
std::vector<SymbolIdx> symbols; std::vector<SymbolIdx> symbols;
// Raw data storage. Accessible via SymbolIdx instances. // Raw data storage. Accessible via SymbolIdx instances.
std::vector<optional<QueryFile>> files; std::vector<QueryFile> files;
std::vector<optional<QueryType>> types; std::vector<QueryType> types;
std::vector<optional<QueryFunc>> funcs; std::vector<QueryFunc> funcs;
std::vector<optional<QueryVar>> vars; std::vector<QueryVar> vars;
// Lookup symbol based on a usr. // Lookup symbol based on a usr.
// NOTE: For usr_to_file make sure to call LowerPathIfCaseInsensitive on key. // NOTE: For usr_to_file make sure to call LowerPathIfCaseInsensitive on key.

View File

@ -15,25 +15,25 @@ int ComputeRangeSize(const Range& range) {
optional<QueryLocation> GetDefinitionSpellingOfSymbol(QueryDatabase* db, optional<QueryLocation> GetDefinitionSpellingOfSymbol(QueryDatabase* db,
const QueryTypeId& id) { const QueryTypeId& id) {
optional<QueryType>& type = db->types[id.id]; QueryType& type = db->types[id.id];
if (type) if (type.def)
return type->def.definition_spelling; return type.def->definition_spelling;
return nullopt; return nullopt;
} }
optional<QueryLocation> GetDefinitionSpellingOfSymbol(QueryDatabase* db, optional<QueryLocation> GetDefinitionSpellingOfSymbol(QueryDatabase* db,
const QueryFuncId& id) { const QueryFuncId& id) {
optional<QueryFunc>& func = db->funcs[id.id]; QueryFunc& func = db->funcs[id.id];
if (func) if (func.def)
return func->def.definition_spelling; return func.def->definition_spelling;
return nullopt; return nullopt;
} }
optional<QueryLocation> GetDefinitionSpellingOfSymbol(QueryDatabase* db, optional<QueryLocation> GetDefinitionSpellingOfSymbol(QueryDatabase* db,
const QueryVarId& id) { const QueryVarId& id) {
optional<QueryVar>& var = db->vars[id.id]; QueryVar& var = db->vars[id.id];
if (var) if (var.def)
return var->def.definition_spelling; return var.def->definition_spelling;
return nullopt; return nullopt;
} }
@ -41,21 +41,21 @@ optional<QueryLocation> GetDefinitionSpellingOfSymbol(QueryDatabase* db,
const SymbolIdx& symbol) { const SymbolIdx& symbol) {
switch (symbol.kind) { switch (symbol.kind) {
case SymbolKind::Type: { case SymbolKind::Type: {
optional<QueryType>& type = db->types[symbol.idx]; QueryType& type = db->types[symbol.idx];
if (type) if (type.def)
return type->def.definition_spelling; return type.def->definition_spelling;
break; break;
} }
case SymbolKind::Func: { case SymbolKind::Func: {
optional<QueryFunc>& func = db->funcs[symbol.idx]; QueryFunc& func = db->funcs[symbol.idx];
if (func) if (func.def)
return func->def.definition_spelling; return func.def->definition_spelling;
break; break;
} }
case SymbolKind::Var: { case SymbolKind::Var: {
optional<QueryVar>& var = db->vars[symbol.idx]; QueryVar& var = db->vars[symbol.idx];
if (var) if (var.def)
return var->def.definition_spelling; return var.def->definition_spelling;
break; break;
} }
case SymbolKind::File: case SymbolKind::File:
@ -71,21 +71,21 @@ optional<QueryLocation> GetDefinitionExtentOfSymbol(QueryDatabase* db,
const SymbolIdx& symbol) { const SymbolIdx& symbol) {
switch (symbol.kind) { switch (symbol.kind) {
case SymbolKind::Type: { case SymbolKind::Type: {
optional<QueryType>& type = db->types[symbol.idx]; QueryType& type = db->types[symbol.idx];
if (type) if (type.def)
return type->def.definition_extent; return type.def->definition_extent;
break; break;
} }
case SymbolKind::Func: { case SymbolKind::Func: {
optional<QueryFunc>& func = db->funcs[symbol.idx]; QueryFunc& func = db->funcs[symbol.idx];
if (func) if (func.def)
return func->def.definition_extent; return func.def->definition_extent;
break; break;
} }
case SymbolKind::Var: { case SymbolKind::Var: {
optional<QueryVar>& var = db->vars[symbol.idx]; QueryVar& var = db->vars[symbol.idx];
if (var) if (var.def)
return var->def.definition_extent; return var.def->definition_extent;
break; break;
} }
case SymbolKind::File: { case SymbolKind::File: {
@ -103,21 +103,21 @@ optional<QueryLocation> GetDefinitionExtentOfSymbol(QueryDatabase* db,
std::string GetHoverForSymbol(QueryDatabase* db, const SymbolIdx& symbol) { std::string GetHoverForSymbol(QueryDatabase* db, const SymbolIdx& symbol) {
switch (symbol.kind) { switch (symbol.kind) {
case SymbolKind::Type: { case SymbolKind::Type: {
optional<QueryType>& type = db->types[symbol.idx]; QueryType& type = db->types[symbol.idx];
if (type) if (type.def)
return type->def.detailed_name; return type.def->detailed_name;
break; break;
} }
case SymbolKind::Func: { case SymbolKind::Func: {
optional<QueryFunc>& func = db->funcs[symbol.idx]; QueryFunc& func = db->funcs[symbol.idx];
if (func) if (func.def)
return func->def.detailed_name; return func.def->detailed_name;
break; break;
} }
case SymbolKind::Var: { case SymbolKind::Var: {
optional<QueryVar>& var = db->vars[symbol.idx]; QueryVar& var = db->vars[symbol.idx];
if (var) if (var.def)
return var->def.detailed_name; return var.def->detailed_name;
break; break;
} }
case SymbolKind::File: case SymbolKind::File:
@ -133,25 +133,23 @@ optional<QueryFileId> GetDeclarationFileForSymbol(QueryDatabase* db,
const SymbolIdx& symbol) { const SymbolIdx& symbol) {
switch (symbol.kind) { switch (symbol.kind) {
case SymbolKind::Type: { case SymbolKind::Type: {
optional<QueryType>& type = db->types[symbol.idx]; QueryType& type = db->types[symbol.idx];
if (type && type->def.definition_spelling) if (type.def && type.def->definition_spelling)
return type->def.definition_spelling->path; return type.def->definition_spelling->path;
break; break;
} }
case SymbolKind::Func: { case SymbolKind::Func: {
optional<QueryFunc>& func = db->funcs[symbol.idx]; QueryFunc& func = db->funcs[symbol.idx];
if (func) { if (!func.declarations.empty())
if (!func->declarations.empty()) return func.declarations[0].path;
return func->declarations[0].path; if (func.def && func.def->definition_spelling)
if (func->def.definition_spelling) return func.def->definition_spelling->path;
return func->def.definition_spelling->path;
}
break; break;
} }
case SymbolKind::Var: { case SymbolKind::Var: {
optional<QueryVar>& var = db->vars[symbol.idx]; QueryVar& var = db->vars[symbol.idx];
if (var && var->def.definition_spelling) if (var.def && var.def->definition_spelling)
return var->def.definition_spelling->path; return var.def->definition_spelling->path;
break; break;
} }
case SymbolKind::File: { case SymbolKind::File: {
@ -214,28 +212,21 @@ std::vector<QueryLocation> GetUsesOfSymbol(QueryDatabase* db,
const SymbolIdx& symbol) { const SymbolIdx& symbol) {
switch (symbol.kind) { switch (symbol.kind) {
case SymbolKind::Type: { case SymbolKind::Type: {
optional<QueryType>& type = db->types[symbol.idx]; QueryType& type = db->types[symbol.idx];
if (type) return type.uses;
return type->uses;
break;
} }
case SymbolKind::Func: { case SymbolKind::Func: {
// TODO: the vector allocation could be avoided. // TODO: the vector allocation could be avoided.
optional<QueryFunc>& func = db->funcs[symbol.idx]; QueryFunc& func = db->funcs[symbol.idx];
if (func) { std::vector<QueryLocation> result = ToQueryLocation(db, func.callers);
std::vector<QueryLocation> result = ToQueryLocation(db, func->callers); AddRange(&result, func.declarations);
AddRange(&result, func->declarations); if (func.def && func.def->definition_spelling)
if (func->def.definition_spelling) result.push_back(*func.def->definition_spelling);
result.push_back(*func->def.definition_spelling);
return result; return result;
} }
break;
}
case SymbolKind::Var: { case SymbolKind::Var: {
optional<QueryVar>& var = db->vars[symbol.idx]; QueryVar& var = db->vars[symbol.idx];
if (var) return var.uses;
return var->uses;
break;
} }
case SymbolKind::File: case SymbolKind::File:
case SymbolKind::Invalid: { case SymbolKind::Invalid: {
@ -255,24 +246,22 @@ std::vector<QueryLocation> GetDeclarationsOfSymbolForGotoDefinition(
// function has the postfix `ForGotoDefintion`, but it lets the user // function has the postfix `ForGotoDefintion`, but it lets the user
// jump to the start of a type if clicking goto-definition on the same // jump to the start of a type if clicking goto-definition on the same
// type from within the type definition. // type from within the type definition.
optional<QueryType>& type = db->types[symbol.idx]; QueryType& type = db->types[symbol.idx];
if (type) { if (type.def) {
optional<QueryLocation> declaration = type->def.definition_spelling; optional<QueryLocation> declaration = type.def->definition_spelling;
if (declaration) if (declaration)
return {*declaration}; return {*declaration};
} }
break; break;
} }
case SymbolKind::Func: { case SymbolKind::Func: {
optional<QueryFunc>& func = db->funcs[symbol.idx]; QueryFunc& func = db->funcs[symbol.idx];
if (func) return func.declarations;
return func->declarations;
break;
} }
case SymbolKind::Var: { case SymbolKind::Var: {
optional<QueryVar>& var = db->vars[symbol.idx]; QueryVar& var = db->vars[symbol.idx];
if (var) { if (var.def) {
optional<QueryLocation> declaration = var->def.declaration; optional<QueryLocation> declaration = var.def->declaration;
if (declaration) if (declaration)
return {*declaration}; return {*declaration};
} }
@ -288,15 +277,15 @@ std::vector<QueryLocation> GetDeclarationsOfSymbolForGotoDefinition(
optional<QueryLocation> GetBaseDefinitionOrDeclarationSpelling( optional<QueryLocation> GetBaseDefinitionOrDeclarationSpelling(
QueryDatabase* db, QueryDatabase* db,
QueryFunc& func) { QueryFunc& func) {
if (!func.def.base) if (!func.def->base)
return nullopt;
optional<QueryFunc>& base = db->funcs[func.def.base->id];
if (!base)
return nullopt; return nullopt;
QueryFunc& base = db->funcs[func.def->base->id];
auto def = base->def.definition_spelling; optional<QueryLocation> def;
if (!def && !base->declarations.empty()) if (base.def)
def = base->declarations[0]; def = base.def->definition_spelling;
if (!def && !base.declarations.empty())
def = base.declarations[0];
return def; return def;
} }
@ -306,28 +295,25 @@ bool HasCallersOnSelfOrBaseOrDerived(QueryDatabase* db, QueryFunc& root) {
return true; return true;
// Check for base calls. // Check for base calls.
optional<QueryFuncId> func_id = root.def.base; optional<QueryFuncId> func_id = root.def->base;
while (func_id) { while (func_id) {
optional<QueryFunc>& func = db->funcs[func_id->id]; QueryFunc& func = db->funcs[func_id->id];
if (!func) if (!func.callers.empty())
break;
if (!func->callers.empty())
return true; return true;
func_id = func->def.base; if (!func.def)
break;
func_id = func.def->base;
} }
// Check for derived calls. // Check for derived calls.
std::queue<QueryFuncId> queue; std::queue<QueryFuncId> queue;
PushRange(&queue, root.derived); PushRange(&queue, root.derived);
while (!queue.empty()) { while (!queue.empty()) {
optional<QueryFunc>& func = db->funcs[queue.front().id]; QueryFunc& func = db->funcs[queue.front().id];
queue.pop(); queue.pop();
if (!func) if (!func.callers.empty())
continue;
if (!func->derived.empty())
return true; return true;
PushRange(&queue, func->derived); PushRange(&queue, func.derived);
} }
return false; return false;
@ -337,14 +323,14 @@ std::vector<QueryFuncRef> GetCallersForAllBaseFunctions(QueryDatabase* db,
QueryFunc& root) { QueryFunc& root) {
std::vector<QueryFuncRef> callers; std::vector<QueryFuncRef> callers;
optional<QueryFuncId> func_id = root.def.base; optional<QueryFuncId> func_id = root.def->base;
while (func_id) { while (func_id) {
optional<QueryFunc>& func = db->funcs[func_id->id]; QueryFunc& func = db->funcs[func_id->id];
if (!func) AddRange(&callers, func.callers);
break;
AddRange(&callers, func->callers); if (!func.def)
func_id = func->def.base; break;
func_id = func.def->base;
} }
return callers; return callers;
@ -358,13 +344,11 @@ std::vector<QueryFuncRef> GetCallersForAllDerivedFunctions(QueryDatabase* db,
PushRange(&queue, root.derived); PushRange(&queue, root.derived);
while (!queue.empty()) { while (!queue.empty()) {
optional<QueryFunc>& func = db->funcs[queue.front().id]; QueryFunc& func = db->funcs[queue.front().id];
queue.pop(); queue.pop();
if (!func)
continue;
PushRange(&queue, func->derived); PushRange(&queue, func.derived);
AddRange(&callers, func->callers); AddRange(&callers, func.callers);
} }
return callers; return callers;
@ -412,9 +396,9 @@ optional<lsRange> GetLsRange(WorkingFile* working_file, const Range& location) {
lsDocumentUri GetLsDocumentUri(QueryDatabase* db, lsDocumentUri GetLsDocumentUri(QueryDatabase* db,
QueryFileId file_id, QueryFileId file_id,
std::string* path) { std::string* path) {
optional<QueryFile>& file = db->files[file_id.id]; QueryFile& file = db->files[file_id.id];
if (file) { if (file.def) {
*path = file->def.path; *path = file.def->path;
return lsDocumentUri::FromPath(*path); return lsDocumentUri::FromPath(*path);
} else { } else {
*path = ""; *path = "";
@ -423,9 +407,9 @@ lsDocumentUri GetLsDocumentUri(QueryDatabase* db,
} }
lsDocumentUri GetLsDocumentUri(QueryDatabase* db, QueryFileId file_id) { lsDocumentUri GetLsDocumentUri(QueryDatabase* db, QueryFileId file_id) {
optional<QueryFile>& file = db->files[file_id.id]; QueryFile& file = db->files[file_id.id];
if (file) { if (file.def) {
return lsDocumentUri::FromPath(file->def.path); return lsDocumentUri::FromPath(file.def->path);
} else { } else {
return lsDocumentUri::FromPath(""); return lsDocumentUri::FromPath("");
} }
@ -468,54 +452,54 @@ optional<lsSymbolInformation> GetSymbolInfo(QueryDatabase* db,
SymbolIdx symbol) { SymbolIdx symbol) {
switch (symbol.kind) { switch (symbol.kind) {
case SymbolKind::File: { case SymbolKind::File: {
optional<QueryFile>& file = db->files[symbol.idx]; QueryFile& file = db->files[symbol.idx];
if (!file) if (!file.def)
return nullopt; return nullopt;
lsSymbolInformation info; lsSymbolInformation info;
info.name = file->def.path; info.name = file.def->path;
info.kind = lsSymbolKind::File; info.kind = lsSymbolKind::File;
return info; return info;
} }
case SymbolKind::Type: { case SymbolKind::Type: {
optional<QueryType>& type = db->types[symbol.idx]; QueryType& type = db->types[symbol.idx];
if (!type) if (!type.def)
return nullopt; return nullopt;
lsSymbolInformation info; lsSymbolInformation info;
info.name = type->def.short_name; info.name = type.def->short_name;
if (type->def.detailed_name != type->def.short_name) if (type.def->detailed_name != type.def->short_name)
info.containerName = type->def.detailed_name; info.containerName = type.def->detailed_name;
info.kind = lsSymbolKind::Class; info.kind = lsSymbolKind::Class;
return info; return info;
} }
case SymbolKind::Func: { case SymbolKind::Func: {
optional<QueryFunc>& func = db->funcs[symbol.idx]; QueryFunc& func = db->funcs[symbol.idx];
if (!func) if (!func.def)
return nullopt; return nullopt;
lsSymbolInformation info; lsSymbolInformation info;
info.name = func->def.short_name; info.name = func.def->short_name;
info.containerName = func->def.detailed_name; info.containerName = func.def->detailed_name;
info.kind = lsSymbolKind::Function; info.kind = lsSymbolKind::Function;
if (func->def.declaring_type.has_value()) { if (func.def->declaring_type.has_value()) {
optional<QueryType>& container = QueryType& container =
db->types[func->def.declaring_type->id]; db->types[func.def->declaring_type->id];
if (container) if (container.def)
info.kind = lsSymbolKind::Method; info.kind = lsSymbolKind::Method;
} }
return info; return info;
} }
case SymbolKind::Var: { case SymbolKind::Var: {
optional<QueryVar>& var = db->vars[symbol.idx]; QueryVar& var = db->vars[symbol.idx];
if (!var) if (!var.def)
return nullopt; return nullopt;
lsSymbolInformation info; lsSymbolInformation info;
info.name += var->def.short_name; info.name += var.def->short_name;
info.containerName = var->def.detailed_name; info.containerName = var.def->detailed_name;
info.kind = lsSymbolKind::Variable; info.kind = lsSymbolKind::Variable;
return info; return info;
} }
@ -585,11 +569,11 @@ lsWorkspaceEdit BuildWorkspaceEdit(QueryDatabase* db,
if (path_to_edit.find(location.path) == path_to_edit.end()) { if (path_to_edit.find(location.path) == path_to_edit.end()) {
path_to_edit[location.path] = lsTextDocumentEdit(); path_to_edit[location.path] = lsTextDocumentEdit();
optional<QueryFile>& file = db->files[location.path.id]; QueryFile& file = db->files[location.path.id];
if (!file) if (!file.def)
continue; continue;
const std::string& path = file->def.path; const std::string& path = file.def->path;
path_to_edit[location.path].textDocument.uri = path_to_edit[location.path].textDocument.uri =
lsDocumentUri::FromPath(path); lsDocumentUri::FromPath(path);
@ -630,7 +614,7 @@ std::vector<SymbolRef> FindSymbolsAtLocation(WorkingFile* working_file,
target_line = *index_line; target_line = *index_line;
} }
for (const SymbolRef& ref : file->def.all_symbols) { for (const SymbolRef& ref : file->def->all_symbols) {
if (ref.loc.range.Contains(target_line, target_column)) if (ref.loc.range.Contains(target_line, target_column))
symbols.push_back(ref); symbols.push_back(ref);
} }
@ -660,23 +644,23 @@ NonElidedVector<Out_CqueryTypeHierarchyTree::TypeEntry>
BuildParentInheritanceHierarchyForType(QueryDatabase* db, BuildParentInheritanceHierarchyForType(QueryDatabase* db,
WorkingFiles* working_files, WorkingFiles* working_files,
QueryTypeId root) { QueryTypeId root) {
optional<QueryType>& root_type = db->types[root.id]; QueryType& root_type = db->types[root.id];
if (!root_type) if (!root_type.def)
return {}; return {};
NonElidedVector<Out_CqueryTypeHierarchyTree::TypeEntry> parent_entries; NonElidedVector<Out_CqueryTypeHierarchyTree::TypeEntry> parent_entries;
parent_entries.reserve(root_type->def.parents.size()); parent_entries.reserve(root_type.def->parents.size());
for (QueryTypeId parent_id : root_type->def.parents) { for (QueryTypeId parent_id : root_type.def->parents) {
optional<QueryType>& parent_type = db->types[parent_id.id]; QueryType& parent_type = db->types[parent_id.id];
if (!parent_type) if (!parent_type.def)
continue; continue;
Out_CqueryTypeHierarchyTree::TypeEntry parent_entry; Out_CqueryTypeHierarchyTree::TypeEntry parent_entry;
parent_entry.name = parent_type->def.detailed_name; parent_entry.name = parent_type.def->detailed_name;
if (parent_type->def.definition_spelling) if (parent_type.def->definition_spelling)
parent_entry.location = GetLsLocation( parent_entry.location = GetLsLocation(
db, working_files, *parent_type->def.definition_spelling); db, working_files, *parent_type.def->definition_spelling);
parent_entry.children = parent_entry.children =
BuildParentInheritanceHierarchyForType(db, working_files, parent_id); BuildParentInheritanceHierarchyForType(db, working_files, parent_id);
@ -690,19 +674,19 @@ optional<Out_CqueryTypeHierarchyTree::TypeEntry>
BuildInheritanceHierarchyForType(QueryDatabase* db, BuildInheritanceHierarchyForType(QueryDatabase* db,
WorkingFiles* working_files, WorkingFiles* working_files,
QueryTypeId root_id) { QueryTypeId root_id) {
optional<QueryType>& root_type = db->types[root_id.id]; QueryType& root_type = db->types[root_id.id];
if (!root_type) if (!root_type.def)
return nullopt; return nullopt;
Out_CqueryTypeHierarchyTree::TypeEntry entry; Out_CqueryTypeHierarchyTree::TypeEntry entry;
// Name and location. // Name and location.
entry.name = root_type->def.detailed_name; entry.name = root_type.def->detailed_name;
if (root_type->def.definition_spelling) if (root_type.def->definition_spelling)
entry.location = entry.location =
GetLsLocation(db, working_files, *root_type->def.definition_spelling); GetLsLocation(db, working_files, *root_type.def->definition_spelling);
entry.children.reserve(root_type->derived.size()); entry.children.reserve(root_type.derived.size());
// Base types. // Base types.
Out_CqueryTypeHierarchyTree::TypeEntry base; Out_CqueryTypeHierarchyTree::TypeEntry base;
@ -714,7 +698,7 @@ BuildInheritanceHierarchyForType(QueryDatabase* db,
entry.children.push_back(base); entry.children.push_back(base);
// Add derived. // Add derived.
for (QueryTypeId derived : root_type->derived) { for (QueryTypeId derived : root_type.derived) {
auto derived_entry = auto derived_entry =
BuildInheritanceHierarchyForType(db, working_files, derived); BuildInheritanceHierarchyForType(db, working_files, derived);
if (derived_entry) if (derived_entry)
@ -728,21 +712,21 @@ NonElidedVector<Out_CqueryTypeHierarchyTree::TypeEntry>
BuildParentInheritanceHierarchyForFunc(QueryDatabase* db, BuildParentInheritanceHierarchyForFunc(QueryDatabase* db,
WorkingFiles* working_files, WorkingFiles* working_files,
QueryFuncId root) { QueryFuncId root) {
optional<QueryFunc>& root_func = db->funcs[root.id]; QueryFunc& root_func = db->funcs[root.id];
if (!root_func || !root_func->def.base) if (!root_func.def || !root_func.def->base)
return {}; return {};
optional<QueryFunc>& parent_func = db->funcs[root_func->def.base->id]; QueryFunc& parent_func = db->funcs[root_func.def->base->id];
if (!parent_func) if (!parent_func.def)
return {}; return {};
Out_CqueryTypeHierarchyTree::TypeEntry parent_entry; Out_CqueryTypeHierarchyTree::TypeEntry parent_entry;
parent_entry.name = parent_func->def.detailed_name; parent_entry.name = parent_func.def->detailed_name;
if (parent_func->def.definition_spelling) if (parent_func.def->definition_spelling)
parent_entry.location = parent_entry.location =
GetLsLocation(db, working_files, *parent_func->def.definition_spelling); GetLsLocation(db, working_files, *parent_func.def->definition_spelling);
parent_entry.children = BuildParentInheritanceHierarchyForFunc( parent_entry.children = BuildParentInheritanceHierarchyForFunc(
db, working_files, *root_func->def.base); db, working_files, *root_func.def->base);
NonElidedVector<Out_CqueryTypeHierarchyTree::TypeEntry> entries; NonElidedVector<Out_CqueryTypeHierarchyTree::TypeEntry> entries;
entries.push_back(parent_entry); entries.push_back(parent_entry);
@ -753,19 +737,19 @@ optional<Out_CqueryTypeHierarchyTree::TypeEntry>
BuildInheritanceHierarchyForFunc(QueryDatabase* db, BuildInheritanceHierarchyForFunc(QueryDatabase* db,
WorkingFiles* working_files, WorkingFiles* working_files,
QueryFuncId root_id) { QueryFuncId root_id) {
optional<QueryFunc>& root_func = db->funcs[root_id.id]; QueryFunc& root_func = db->funcs[root_id.id];
if (!root_func) if (!root_func.def)
return nullopt; return nullopt;
Out_CqueryTypeHierarchyTree::TypeEntry entry; Out_CqueryTypeHierarchyTree::TypeEntry entry;
// Name and location. // Name and location.
entry.name = root_func->def.detailed_name; entry.name = root_func.def->detailed_name;
if (root_func->def.definition_spelling) if (root_func.def->definition_spelling)
entry.location = entry.location =
GetLsLocation(db, working_files, *root_func->def.definition_spelling); GetLsLocation(db, working_files, *root_func.def->definition_spelling);
entry.children.reserve(root_func->derived.size()); entry.children.reserve(root_func.derived.size());
// Base types. // Base types.
Out_CqueryTypeHierarchyTree::TypeEntry base; Out_CqueryTypeHierarchyTree::TypeEntry base;
@ -777,7 +761,7 @@ BuildInheritanceHierarchyForFunc(QueryDatabase* db,
entry.children.push_back(base); entry.children.push_back(base);
// Add derived. // Add derived.
for (QueryFuncId derived : root_func->derived) { for (QueryFuncId derived : root_func.derived) {
auto derived_entry = auto derived_entry =
BuildInheritanceHierarchyForFunc(db, working_files, derived); BuildInheritanceHierarchyForFunc(db, working_files, derived);
if (derived_entry) if (derived_entry)
@ -791,21 +775,19 @@ NonElidedVector<Out_CqueryCallTree::CallEntry> BuildInitialCallTree(
QueryDatabase* db, QueryDatabase* db,
WorkingFiles* working_files, WorkingFiles* working_files,
QueryFuncId root) { QueryFuncId root) {
optional<QueryFunc>& root_func = db->funcs[root.id]; QueryFunc& root_func = db->funcs[root.id];
if (!root_func) if (!root_func.def || !root_func.def->definition_spelling)
return {};
if (!root_func->def.definition_spelling)
return {}; return {};
optional<lsLocation> def_loc = optional<lsLocation> def_loc =
GetLsLocation(db, working_files, *root_func->def.definition_spelling); GetLsLocation(db, working_files, *root_func.def->definition_spelling);
if (!def_loc) if (!def_loc)
return {}; return {};
Out_CqueryCallTree::CallEntry entry; Out_CqueryCallTree::CallEntry entry;
entry.name = root_func->def.short_name; entry.name = root_func.def->short_name;
entry.usr = root_func->def.usr; entry.usr = root_func.def->usr;
entry.location = *def_loc; entry.location = *def_loc;
entry.hasCallers = HasCallersOnSelfOrBaseOrDerived(db, *root_func); entry.hasCallers = HasCallersOnSelfOrBaseOrDerived(db, root_func);
NonElidedVector<Out_CqueryCallTree::CallEntry> result; NonElidedVector<Out_CqueryCallTree::CallEntry> result;
result.push_back(entry); result.push_back(entry);
return result; return result;
@ -815,8 +797,8 @@ NonElidedVector<Out_CqueryCallTree::CallEntry> BuildExpandCallTree(
QueryDatabase* db, QueryDatabase* db,
WorkingFiles* working_files, WorkingFiles* working_files,
QueryFuncId root) { QueryFuncId root) {
optional<QueryFunc>& root_func = db->funcs[root.id]; QueryFunc& root_func = db->funcs[root.id];
if (!root_func) if (!root_func.def)
return {}; return {};
auto format_location = auto format_location =
@ -825,9 +807,9 @@ NonElidedVector<Out_CqueryCallTree::CallEntry> BuildExpandCallTree(
std::string base; std::string base;
if (declaring_type) { if (declaring_type) {
optional<QueryType> type = db->types[declaring_type->id]; QueryType type = db->types[declaring_type->id];
if (type) if (type.def)
base = type->def.detailed_name; base = type.def->detailed_name;
} }
if (base.empty()) { if (base.empty()) {
@ -869,17 +851,17 @@ NonElidedVector<Out_CqueryCallTree::CallEntry> BuildExpandCallTree(
} }
if (caller.has_id()) { if (caller.has_id()) {
optional<QueryFunc>& call_func = db->funcs[caller.id_.id]; QueryFunc& call_func = db->funcs[caller.id_.id];
if (!call_func) if (!call_func.def)
return; return;
Out_CqueryCallTree::CallEntry call_entry; Out_CqueryCallTree::CallEntry call_entry;
call_entry.name = call_entry.name =
call_func->def.short_name + " (" + call_func.def->short_name + " (" +
format_location(*call_location, call_func->def.declaring_type) + ")"; format_location(*call_location, call_func.def->declaring_type) + ")";
call_entry.usr = call_func->def.usr; call_entry.usr = call_func.def->usr;
call_entry.location = *call_location; call_entry.location = *call_location;
call_entry.hasCallers = HasCallersOnSelfOrBaseOrDerived(db, *call_func); call_entry.hasCallers = HasCallersOnSelfOrBaseOrDerived(db, call_func);
call_entry.callType = call_type; call_entry.callType = call_type;
result.push_back(call_entry); result.push_back(call_entry);
} else { } else {
@ -896,13 +878,13 @@ NonElidedVector<Out_CqueryCallTree::CallEntry> BuildExpandCallTree(
}; };
std::vector<QueryFuncRef> base_callers = std::vector<QueryFuncRef> base_callers =
GetCallersForAllBaseFunctions(db, *root_func); GetCallersForAllBaseFunctions(db, root_func);
std::vector<QueryFuncRef> derived_callers = std::vector<QueryFuncRef> derived_callers =
GetCallersForAllDerivedFunctions(db, *root_func); GetCallersForAllDerivedFunctions(db, root_func);
result.reserve(root_func->callers.size() + base_callers.size() + result.reserve(root_func.callers.size() + base_callers.size() +
derived_callers.size()); derived_callers.size());
for (QueryFuncRef caller : root_func->callers) for (QueryFuncRef caller : root_func.callers)
handle_caller(caller, Out_CqueryCallTree::CallType::Direct); handle_caller(caller, Out_CqueryCallTree::CallType::Direct);
for (QueryFuncRef caller : base_callers) { for (QueryFuncRef caller : base_callers) {
// Do not show calls to the base function coming from this function. // Do not show calls to the base function coming from this function.