mirror of
https://github.com/MaskRay/ccls.git
synced 2025-02-20 15:40:57 +00:00
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:
parent
272e23901c
commit
809a55a351
@ -104,9 +104,9 @@ bool FindFileOrFail(QueryDatabase* db,
|
||||
QueryFileId* out_file_id = nullptr) {
|
||||
auto it = db->usr_to_file.find(LowerPathIfCaseInsensitive(absolute_path));
|
||||
if (it != db->usr_to_file.end()) {
|
||||
optional<QueryFile>& file = db->files[it->second.id];
|
||||
if (file) {
|
||||
*out_query_file = &file.value();
|
||||
QueryFile& file = db->files[it->second.id];
|
||||
if (file.def) {
|
||||
*out_query_file = &file;
|
||||
if (out_file_id)
|
||||
*out_file_id = QueryFileId(it->second.id);
|
||||
return true;
|
||||
@ -194,25 +194,25 @@ optional<int> FindIncludeLine(const std::vector<std::string>& lines,
|
||||
optional<QueryFileId> GetImplementationFile(QueryDatabase* db,
|
||||
QueryFileId file_id,
|
||||
QueryFile* file) {
|
||||
for (SymbolRef sym : file->def.outline) {
|
||||
for (SymbolRef sym : file->def->outline) {
|
||||
switch (sym.idx.kind) {
|
||||
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,
|
||||
// possibly a header).
|
||||
if (func && func->def.definition_extent &&
|
||||
func->def.definition_extent->path != file_id) {
|
||||
return func->def.definition_extent->path;
|
||||
if (func.def && func.def->definition_extent &&
|
||||
func.def->definition_extent->path != file_id) {
|
||||
return func.def->definition_extent->path;
|
||||
}
|
||||
break;
|
||||
}
|
||||
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,
|
||||
// possibly a header).
|
||||
if (var && var->def.definition_extent &&
|
||||
var->def.definition_extent->path != file_id) {
|
||||
return db->vars[sym.idx.idx]->def.definition_extent->path;
|
||||
if (var.def && var.def->definition_extent &&
|
||||
var.def->definition_extent->path != file_id) {
|
||||
return db->vars[sym.idx.idx].def->definition_extent->path;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -223,7 +223,7 @@ optional<QueryFileId> GetImplementationFile(QueryDatabase* db,
|
||||
|
||||
// No associated definition, scan the project for a file in the same
|
||||
// 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;
|
||||
size_t last = target_path.find_last_of('.');
|
||||
if (last != std::string::npos) {
|
||||
@ -253,18 +253,18 @@ void EnsureImplFile(QueryDatabase* db,
|
||||
optional<lsDocumentUri>& impl_uri,
|
||||
optional<QueryFileId>& impl_file_id) {
|
||||
if (!impl_uri.has_value()) {
|
||||
optional<QueryFile>& file = db->files[file_id.id];
|
||||
assert(file);
|
||||
QueryFile& file = db->files[file_id.id];
|
||||
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())
|
||||
impl_file_id = file_id;
|
||||
|
||||
optional<QueryFile>& impl_file = db->files[impl_file_id->id];
|
||||
if (impl_file)
|
||||
impl_uri = lsDocumentUri::FromPath(impl_file->def.path);
|
||||
QueryFile& impl_file = db->files[impl_file_id->id];
|
||||
if (impl_file.def)
|
||||
impl_uri = lsDocumentUri::FromPath(impl_file.def->path);
|
||||
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 impl_file_id,
|
||||
QueryFunc& func) {
|
||||
assert(func.def);
|
||||
for (const QueryLocation& decl : func.declarations) {
|
||||
if (decl.path != decl_file_id)
|
||||
continue;
|
||||
@ -285,13 +286,12 @@ optional<lsTextEdit> BuildAutoImplementForFunction(QueryDatabase* db,
|
||||
|
||||
optional<std::string> type_name;
|
||||
optional<lsPosition> same_file_insert_end;
|
||||
if (func.def.declaring_type) {
|
||||
optional<QueryType>& declaring_type =
|
||||
db->types[func.def.declaring_type->id];
|
||||
if (declaring_type) {
|
||||
type_name = declaring_type->def.short_name;
|
||||
if (func.def->declaring_type) {
|
||||
QueryType& declaring_type = db->types[func.def->declaring_type->id];
|
||||
if (declaring_type.def) {
|
||||
type_name = declaring_type.def->short_name;
|
||||
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) {
|
||||
same_file_insert_end = ls_type_def_extent->end;
|
||||
same_file_insert_end->character += 1; // move past semicolon.
|
||||
@ -321,21 +321,21 @@ optional<lsTextEdit> BuildAutoImplementForFunction(QueryDatabase* db,
|
||||
best_pos.line = default_line;
|
||||
int best_dist = INT_MAX;
|
||||
|
||||
optional<QueryFile>& file = db->files[impl_file_id.id];
|
||||
assert(file);
|
||||
for (SymbolRef sym : file->def.outline) {
|
||||
QueryFile& file = db->files[impl_file_id.id];
|
||||
assert(file.def);
|
||||
for (SymbolRef sym : file.def->outline) {
|
||||
switch (sym.idx.kind) {
|
||||
case SymbolKind::Func: {
|
||||
optional<QueryFunc>& sym_func = db->funcs[sym.idx.idx];
|
||||
if (!sym_func || !sym_func->def.definition_extent)
|
||||
QueryFunc& sym_func = db->funcs[sym.idx.idx];
|
||||
if (!sym_func.def || !sym_func.def->definition_extent)
|
||||
break;
|
||||
|
||||
for (QueryLocation& func_decl : sym_func->declarations) {
|
||||
for (QueryLocation& func_decl : sym_func.declarations) {
|
||||
if (func_decl.path == decl_file_id) {
|
||||
int dist = func_decl.range.start.line - decl.range.start.line;
|
||||
if (abs(dist) < abs(best_dist)) {
|
||||
optional<lsLocation> def_loc = GetLsLocation(
|
||||
db, working_files, *sym_func->def.definition_extent);
|
||||
db, working_files, *sym_func.def->definition_extent);
|
||||
if (!def_loc)
|
||||
continue;
|
||||
|
||||
@ -1486,19 +1486,19 @@ bool QueryDbMainLoop(Config* config,
|
||||
// Unmark all files whose timestamp has changed.
|
||||
CacheLoader cache_loader(config);
|
||||
for (const auto& file : db->files) {
|
||||
if (!file)
|
||||
if (!file.def)
|
||||
continue;
|
||||
|
||||
optional<int64_t> modification_timestamp =
|
||||
GetLastModificationTime(file->def.path);
|
||||
GetLastModificationTime(file.def->path);
|
||||
if (!modification_timestamp)
|
||||
continue;
|
||||
|
||||
optional<int64_t> cached_modification =
|
||||
timestamp_manager->GetLastCachedModificationTime(&cache_loader,
|
||||
file->def.path);
|
||||
file.def->path);
|
||||
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.
|
||||
@ -1524,7 +1524,7 @@ bool QueryDbMainLoop(Config* config,
|
||||
break;
|
||||
|
||||
WorkingFile* working_file =
|
||||
working_files->GetFileByFilename(file->def.path);
|
||||
working_files->GetFileByFilename(file->def->path);
|
||||
|
||||
Out_CqueryTypeHierarchyTree response;
|
||||
response.id = msg->id;
|
||||
@ -1556,7 +1556,7 @@ bool QueryDbMainLoop(Config* config,
|
||||
break;
|
||||
|
||||
WorkingFile* working_file =
|
||||
working_files->GetFileByFilename(file->def.path);
|
||||
working_files->GetFileByFilename(file->def->path);
|
||||
|
||||
Out_CqueryCallTree response;
|
||||
response.id = msg->id;
|
||||
@ -1598,18 +1598,16 @@ bool QueryDbMainLoop(Config* config,
|
||||
break;
|
||||
|
||||
WorkingFile* working_file =
|
||||
working_files->GetFileByFilename(file->def.path);
|
||||
working_files->GetFileByFilename(file->def->path);
|
||||
|
||||
Out_LocationList response;
|
||||
response.id = msg->id;
|
||||
for (const SymbolRef& ref :
|
||||
FindSymbolsAtLocation(working_file, file, msg->params.position)) {
|
||||
if (ref.idx.kind == SymbolKind::Type) {
|
||||
optional<QueryType>& type = db->types[ref.idx.idx];
|
||||
if (!type)
|
||||
continue;
|
||||
QueryType& type = db->types[ref.idx.idx];
|
||||
std::vector<QueryLocation> locations =
|
||||
ToQueryLocation(db, type->instances);
|
||||
ToQueryLocation(db, type.instances);
|
||||
response.result = GetLsLocations(db, working_files, locations);
|
||||
}
|
||||
}
|
||||
@ -1626,23 +1624,21 @@ bool QueryDbMainLoop(Config* config,
|
||||
break;
|
||||
|
||||
WorkingFile* working_file =
|
||||
working_files->GetFileByFilename(file->def.path);
|
||||
working_files->GetFileByFilename(file->def->path);
|
||||
|
||||
Out_LocationList response;
|
||||
response.id = msg->id;
|
||||
for (const SymbolRef& ref :
|
||||
FindSymbolsAtLocation(working_file, file, msg->params.position)) {
|
||||
if (ref.idx.kind == SymbolKind::Func) {
|
||||
optional<QueryFunc>& func = db->funcs[ref.idx.idx];
|
||||
if (!func)
|
||||
continue;
|
||||
QueryFunc& func = db->funcs[ref.idx.idx];
|
||||
std::vector<QueryLocation> locations =
|
||||
ToQueryLocation(db, func->callers);
|
||||
ToQueryLocation(db, func.callers);
|
||||
for (QueryFuncRef func_ref :
|
||||
GetCallersForAllBaseFunctions(db, *func))
|
||||
GetCallersForAllBaseFunctions(db, func))
|
||||
locations.push_back(func_ref.loc);
|
||||
for (QueryFuncRef func_ref :
|
||||
GetCallersForAllDerivedFunctions(db, *func))
|
||||
GetCallersForAllDerivedFunctions(db, func))
|
||||
locations.push_back(func_ref.loc);
|
||||
|
||||
response.result = GetLsLocations(db, working_files, locations);
|
||||
@ -1661,25 +1657,23 @@ bool QueryDbMainLoop(Config* config,
|
||||
break;
|
||||
|
||||
WorkingFile* working_file =
|
||||
working_files->GetFileByFilename(file->def.path);
|
||||
working_files->GetFileByFilename(file->def->path);
|
||||
|
||||
Out_LocationList response;
|
||||
response.id = msg->id;
|
||||
for (const SymbolRef& ref :
|
||||
FindSymbolsAtLocation(working_file, file, msg->params.position)) {
|
||||
if (ref.idx.kind == SymbolKind::Type) {
|
||||
optional<QueryType>& type = db->types[ref.idx.idx];
|
||||
if (!type)
|
||||
QueryType& type = db->types[ref.idx.idx];
|
||||
if (!type.def)
|
||||
continue;
|
||||
std::vector<QueryLocation> locations =
|
||||
ToQueryLocation(db, type->def.parents);
|
||||
ToQueryLocation(db, type.def->parents);
|
||||
response.result = GetLsLocations(db, working_files, locations);
|
||||
} else if (ref.idx.kind == SymbolKind::Func) {
|
||||
optional<QueryFunc>& func = db->funcs[ref.idx.idx];
|
||||
if (!func)
|
||||
continue;
|
||||
QueryFunc& func = db->funcs[ref.idx.idx];
|
||||
optional<QueryLocation> location =
|
||||
GetBaseDefinitionOrDeclarationSpelling(db, *func);
|
||||
GetBaseDefinitionOrDeclarationSpelling(db, func);
|
||||
if (!location)
|
||||
continue;
|
||||
optional<lsLocation> ls_loc =
|
||||
@ -1702,25 +1696,21 @@ bool QueryDbMainLoop(Config* config,
|
||||
break;
|
||||
|
||||
WorkingFile* working_file =
|
||||
working_files->GetFileByFilename(file->def.path);
|
||||
working_files->GetFileByFilename(file->def->path);
|
||||
|
||||
Out_LocationList response;
|
||||
response.id = msg->id;
|
||||
for (const SymbolRef& ref :
|
||||
FindSymbolsAtLocation(working_file, file, msg->params.position)) {
|
||||
if (ref.idx.kind == SymbolKind::Type) {
|
||||
optional<QueryType>& type = db->types[ref.idx.idx];
|
||||
if (!type)
|
||||
continue;
|
||||
QueryType& type = db->types[ref.idx.idx];
|
||||
std::vector<QueryLocation> locations =
|
||||
ToQueryLocation(db, type->derived);
|
||||
ToQueryLocation(db, type.derived);
|
||||
response.result = GetLsLocations(db, working_files, locations);
|
||||
} else if (ref.idx.kind == SymbolKind::Func) {
|
||||
optional<QueryFunc>& func = db->funcs[ref.idx.idx];
|
||||
if (!func)
|
||||
continue;
|
||||
QueryFunc& func = db->funcs[ref.idx.idx];
|
||||
std::vector<QueryLocation> locations =
|
||||
ToQueryLocation(db, func->derived);
|
||||
ToQueryLocation(db, func.derived);
|
||||
response.result = GetLsLocations(db, working_files, locations);
|
||||
}
|
||||
}
|
||||
@ -1824,7 +1814,7 @@ bool QueryDbMainLoop(Config* config,
|
||||
break;
|
||||
|
||||
WorkingFile* working_file =
|
||||
working_files->GetFileByFilename(file->def.path);
|
||||
working_files->GetFileByFilename(file->def->path);
|
||||
|
||||
Out_TextDocumentRename response;
|
||||
response.id = msg->id;
|
||||
@ -2064,7 +2054,7 @@ bool QueryDbMainLoop(Config* config,
|
||||
break;
|
||||
|
||||
WorkingFile* working_file =
|
||||
working_files->GetFileByFilename(file->def.path);
|
||||
working_files->GetFileByFilename(file->def->path);
|
||||
|
||||
Out_TextDocumentDefinition response;
|
||||
response.id = msg->id;
|
||||
@ -2126,7 +2116,7 @@ bool QueryDbMainLoop(Config* config,
|
||||
|
||||
// No symbols - check for includes.
|
||||
if (response.result.empty()) {
|
||||
for (const IndexInclude& include : file->def.includes) {
|
||||
for (const IndexInclude& include : file->def->includes) {
|
||||
if (include.line == target_line) {
|
||||
lsLocation result;
|
||||
result.uri = lsDocumentUri::FromPath(include.resolved_path);
|
||||
@ -2150,7 +2140,7 @@ bool QueryDbMainLoop(Config* config,
|
||||
break;
|
||||
|
||||
WorkingFile* working_file =
|
||||
working_files->GetFileByFilename(file->def.path);
|
||||
working_files->GetFileByFilename(file->def->path);
|
||||
|
||||
Out_TextDocumentDocumentHighlight response;
|
||||
response.id = msg->id;
|
||||
@ -2191,7 +2181,7 @@ bool QueryDbMainLoop(Config* config,
|
||||
break;
|
||||
|
||||
WorkingFile* working_file =
|
||||
working_files->GetFileByFilename(file->def.path);
|
||||
working_files->GetFileByFilename(file->def->path);
|
||||
|
||||
Out_TextDocumentHover response;
|
||||
response.id = msg->id;
|
||||
@ -2200,7 +2190,7 @@ bool QueryDbMainLoop(Config* config,
|
||||
FindSymbolsAtLocation(working_file, file, msg->params.position)) {
|
||||
// Found symbol. Return hover.
|
||||
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)
|
||||
continue;
|
||||
|
||||
@ -2222,7 +2212,7 @@ bool QueryDbMainLoop(Config* config,
|
||||
break;
|
||||
|
||||
WorkingFile* working_file =
|
||||
working_files->GetFileByFilename(file->def.path);
|
||||
working_files->GetFileByFilename(file->def->path);
|
||||
|
||||
Out_TextDocumentReferences response;
|
||||
response.id = msg->id;
|
||||
@ -2266,7 +2256,7 @@ bool QueryDbMainLoop(Config* config,
|
||||
&file))
|
||||
break;
|
||||
|
||||
for (SymbolRef ref : file->def.outline) {
|
||||
for (SymbolRef ref : file->def->outline) {
|
||||
optional<lsSymbolInformation> info =
|
||||
GetSymbolInfo(db, working_files, ref.idx);
|
||||
if (!info)
|
||||
@ -2304,7 +2294,7 @@ bool QueryDbMainLoop(Config* config,
|
||||
<< msg->params.textDocument.uri.GetPath();
|
||||
break;
|
||||
}
|
||||
for (const IndexInclude& include : file->def.includes) {
|
||||
for (const IndexInclude& include : file->def->includes) {
|
||||
optional<int> buffer_line;
|
||||
optional<std::string> buffer_line_content =
|
||||
working_file->GetBufferLineContentFromIndexLine(include.line,
|
||||
@ -2376,8 +2366,8 @@ bool QueryDbMainLoop(Config* config,
|
||||
for (SymbolRef sym : syms) {
|
||||
switch (sym.idx.kind) {
|
||||
case SymbolKind::Type: {
|
||||
optional<QueryType>& type = db->types[sym.idx.idx];
|
||||
if (!type)
|
||||
QueryType& type = db->types[sym.idx.idx];
|
||||
if (!type.def)
|
||||
break;
|
||||
|
||||
int num_edits = 0;
|
||||
@ -2385,16 +2375,16 @@ bool QueryDbMainLoop(Config* config,
|
||||
// Get implementation file.
|
||||
Out_TextDocumentCodeAction::Command command;
|
||||
|
||||
for (QueryFuncId func_id : type->def.funcs) {
|
||||
optional<QueryFunc>& func_def = db->funcs[func_id.id];
|
||||
if (!func_def || func_def->def.definition_extent)
|
||||
for (QueryFuncId func_id : type.def->funcs) {
|
||||
QueryFunc& func_def = db->funcs[func_id.id];
|
||||
if (!func_def.def || func_def.def->definition_extent)
|
||||
continue;
|
||||
|
||||
EnsureImplFile(db, file_id, impl_uri /*out*/,
|
||||
impl_file_id /*out*/);
|
||||
optional<lsTextEdit> edit = BuildAutoImplementForFunction(
|
||||
db, working_files, working_file, default_line, file_id,
|
||||
*impl_file_id, *func_def);
|
||||
*impl_file_id, func_def);
|
||||
if (!edit)
|
||||
continue;
|
||||
|
||||
@ -2423,15 +2413,15 @@ bool QueryDbMainLoop(Config* config,
|
||||
|
||||
command.arguments.textDocumentUri = *impl_uri;
|
||||
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";
|
||||
response.result.push_back(command);
|
||||
break;
|
||||
}
|
||||
|
||||
case SymbolKind::Func: {
|
||||
optional<QueryFunc>& func = db->funcs[sym.idx.idx];
|
||||
if (!func || func->def.definition_extent)
|
||||
QueryFunc& func = db->funcs[sym.idx.idx];
|
||||
if (!func.def || func.def->definition_extent)
|
||||
break;
|
||||
|
||||
EnsureImplFile(db, file_id, impl_uri /*out*/,
|
||||
@ -2439,12 +2429,12 @@ bool QueryDbMainLoop(Config* config,
|
||||
|
||||
// Get implementation file.
|
||||
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.arguments.textDocumentUri = *impl_uri;
|
||||
optional<lsTextEdit> edit = BuildAutoImplementForFunction(
|
||||
db, working_files, working_file, default_line, file_id,
|
||||
*impl_file_id, *func);
|
||||
*impl_file_id, func);
|
||||
if (!edit)
|
||||
break;
|
||||
|
||||
@ -2496,11 +2486,11 @@ bool QueryDbMainLoop(Config* config,
|
||||
if (!decl_file_id)
|
||||
continue;
|
||||
|
||||
optional<QueryFile>& decl_file = db->files[decl_file_id->id];
|
||||
if (!decl_file)
|
||||
QueryFile& decl_file = db->files[decl_file_id->id];
|
||||
if (!decl_file.def)
|
||||
continue;
|
||||
|
||||
include_absolute_paths.insert(decl_file->def.path);
|
||||
include_absolute_paths.insert(decl_file.def->path);
|
||||
}
|
||||
|
||||
// Build include strings.
|
||||
@ -2591,50 +2581,50 @@ bool QueryDbMainLoop(Config* config,
|
||||
common.result = &response.result;
|
||||
common.db = db;
|
||||
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
|
||||
// predictable order. Otherwise, the client may randomize it.
|
||||
|
||||
SymbolIdx symbol = ref.idx;
|
||||
switch (symbol.kind) {
|
||||
case SymbolKind::Type: {
|
||||
optional<QueryType>& type = db->types[symbol.idx];
|
||||
if (!type)
|
||||
QueryType& type = db->types[symbol.idx];
|
||||
if (!type.def)
|
||||
continue;
|
||||
AddCodeLens("ref", "refs", &common, ref.loc.OffsetStartColumn(0),
|
||||
type->uses, type->def.definition_spelling,
|
||||
type.uses, type.def->definition_spelling,
|
||||
true /*force_display*/);
|
||||
AddCodeLens("derived", "derived", &common,
|
||||
ref.loc.OffsetStartColumn(1),
|
||||
ToQueryLocation(db, type->derived), nullopt,
|
||||
ToQueryLocation(db, type.derived), nullopt,
|
||||
false /*force_display*/);
|
||||
AddCodeLens("var", "vars", &common, ref.loc.OffsetStartColumn(2),
|
||||
ToQueryLocation(db, type->instances), nullopt,
|
||||
ToQueryLocation(db, type.instances), nullopt,
|
||||
false /*force_display*/);
|
||||
break;
|
||||
}
|
||||
case SymbolKind::Func: {
|
||||
optional<QueryFunc>& func = db->funcs[symbol.idx];
|
||||
if (!func)
|
||||
QueryFunc& func = db->funcs[symbol.idx];
|
||||
if (!func.def)
|
||||
continue;
|
||||
|
||||
int16_t offset = 0;
|
||||
|
||||
std::vector<QueryFuncRef> base_callers =
|
||||
GetCallersForAllBaseFunctions(db, *func);
|
||||
GetCallersForAllBaseFunctions(db, func);
|
||||
std::vector<QueryFuncRef> derived_callers =
|
||||
GetCallersForAllDerivedFunctions(db, *func);
|
||||
GetCallersForAllDerivedFunctions(db, func);
|
||||
if (base_callers.empty() && derived_callers.empty()) {
|
||||
AddCodeLens("call", "calls", &common,
|
||||
ref.loc.OffsetStartColumn(offset++),
|
||||
ToQueryLocation(db, func->callers), nullopt,
|
||||
ToQueryLocation(db, func.callers), nullopt,
|
||||
true /*force_display*/);
|
||||
} else {
|
||||
AddCodeLens("direct call", "direct calls", &common,
|
||||
ref.loc.OffsetStartColumn(offset++),
|
||||
ToQueryLocation(db, func->callers), nullopt,
|
||||
ToQueryLocation(db, func.callers), nullopt,
|
||||
false /*force_display*/);
|
||||
if (!base_callers.empty())
|
||||
AddCodeLens("base call", "base calls", &common,
|
||||
@ -2650,12 +2640,12 @@ bool QueryDbMainLoop(Config* config,
|
||||
|
||||
AddCodeLens("derived", "derived", &common,
|
||||
ref.loc.OffsetStartColumn(offset++),
|
||||
ToQueryLocation(db, func->derived), nullopt,
|
||||
ToQueryLocation(db, func.derived), nullopt,
|
||||
false /*force_display*/);
|
||||
|
||||
// "Base"
|
||||
optional<QueryLocation> base_loc =
|
||||
GetBaseDefinitionOrDeclarationSpelling(db, *func);
|
||||
GetBaseDefinitionOrDeclarationSpelling(db, func);
|
||||
if (base_loc) {
|
||||
optional<lsLocation> ls_base =
|
||||
GetLsLocation(db, working_files, *base_loc);
|
||||
@ -2680,21 +2670,21 @@ bool QueryDbMainLoop(Config* config,
|
||||
break;
|
||||
}
|
||||
case SymbolKind::Var: {
|
||||
optional<QueryVar>& var = db->vars[symbol.idx];
|
||||
if (!var)
|
||||
QueryVar& var = db->vars[symbol.idx];
|
||||
if (!var.def)
|
||||
continue;
|
||||
|
||||
if (var->def.is_local && !config->codeLensOnLocalVariables)
|
||||
if (var.def->is_local && !config->codeLensOnLocalVariables)
|
||||
continue;
|
||||
|
||||
bool force_display = true;
|
||||
// Do not show 0 refs on macro with no uses, as it is most likely
|
||||
// a header guard.
|
||||
if (var->def.is_macro)
|
||||
if (var.def->is_macro)
|
||||
force_display = false;
|
||||
|
||||
AddCodeLens("ref", "refs", &common, ref.loc.OffsetStartColumn(0),
|
||||
var->uses, var->def.definition_spelling,
|
||||
var.uses, var.def->definition_spelling,
|
||||
force_display);
|
||||
break;
|
||||
}
|
||||
|
75
src/query.cc
75
src/query.cc
@ -6,7 +6,6 @@
|
||||
#include <optional.h>
|
||||
#include <loguru.hpp>
|
||||
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
@ -15,7 +14,6 @@
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
|
||||
// TODO: Make all copy constructors explicit.
|
||||
|
||||
namespace {
|
||||
@ -665,22 +663,22 @@ void QueryDatabase::RemoveUsrs(SymbolKind usr_kind,
|
||||
switch (usr_kind) {
|
||||
case SymbolKind::File: {
|
||||
for (const Usr& usr : to_remove)
|
||||
files[usr_to_file[LowerPathIfCaseInsensitive(usr)].id] = nullopt;
|
||||
files[usr_to_file[LowerPathIfCaseInsensitive(usr)].id].def = nullopt;
|
||||
break;
|
||||
}
|
||||
case SymbolKind::Type: {
|
||||
for (const Usr& usr : to_remove)
|
||||
types[usr_to_type[usr].id] = nullopt;
|
||||
types[usr_to_type[usr].id].def = nullopt;
|
||||
break;
|
||||
}
|
||||
case SymbolKind::Func: {
|
||||
for (const Usr& usr : to_remove)
|
||||
funcs[usr_to_func[usr].id] = nullopt;
|
||||
funcs[usr_to_func[usr].id].def = nullopt;
|
||||
break;
|
||||
}
|
||||
case SymbolKind::Var: {
|
||||
for (const Usr& usr : to_remove)
|
||||
vars[usr_to_var[usr].id] = nullopt;
|
||||
vars[usr_to_var[usr].id].def = nullopt;
|
||||
break;
|
||||
}
|
||||
case SymbolKind::Invalid:
|
||||
@ -696,13 +694,11 @@ void QueryDatabase::ApplyIndexUpdate(IndexUpdate* update) {
|
||||
// merge_update => QueryType::DerivedUpdate =>
|
||||
// MergeableUpdate<QueryTypeId, QueryTypeId> def => QueryType
|
||||
// def->def_var_name => std::vector<QueryTypeId>
|
||||
#define HANDLE_MERGEABLE(update_var_name, def_var_name, storage_name) \
|
||||
for (auto merge_update : update->update_var_name) { \
|
||||
auto& def = storage_name[merge_update.id.id]; \
|
||||
if (!def) \
|
||||
continue; /* TODO: Should we continue or create an empty def? */ \
|
||||
AddRange(&def->def_var_name, merge_update.to_add); \
|
||||
RemoveRange(&def->def_var_name, merge_update.to_remove); \
|
||||
#define HANDLE_MERGEABLE(update_var_name, def_var_name, storage_name) \
|
||||
for (auto merge_update : update->update_var_name) { \
|
||||
auto& def = storage_name[merge_update.id.id]; \
|
||||
AddRange(&def.def_var_name, merge_update.to_add); \
|
||||
RemoveRange(&def.def_var_name, merge_update.to_remove); \
|
||||
}
|
||||
|
||||
RemoveUsrs(SymbolKind::File, update->files_removed);
|
||||
@ -735,12 +731,10 @@ void QueryDatabase::ImportOrUpdate(
|
||||
auto it = usr_to_file.find(LowerPathIfCaseInsensitive(def.path));
|
||||
assert(it != usr_to_file.end());
|
||||
|
||||
optional<QueryFile>& existing = files[it->second.id];
|
||||
if (!existing)
|
||||
existing = QueryFile(def.path);
|
||||
QueryFile& existing = files[it->second.id];
|
||||
|
||||
existing->def = def;
|
||||
UpdateDetailedNames(&existing->detailed_name_idx, SymbolKind::File,
|
||||
existing.def = def;
|
||||
UpdateDetailedNames(&existing.detailed_name_idx, SymbolKind::File,
|
||||
it->second.id, def.path);
|
||||
}
|
||||
}
|
||||
@ -756,16 +750,15 @@ void QueryDatabase::ImportOrUpdate(
|
||||
assert(it != usr_to_type.end());
|
||||
|
||||
assert(it->second.id >= 0 && it->second.id < types.size());
|
||||
optional<QueryType>& existing = types[it->second.id];
|
||||
if (!existing)
|
||||
existing = QueryType(def.usr);
|
||||
QueryType& existing = types[it->second.id];
|
||||
|
||||
// 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;
|
||||
|
||||
existing->def = def;
|
||||
UpdateDetailedNames(&existing->detailed_name_idx, SymbolKind::Type,
|
||||
existing.def = def;
|
||||
UpdateDetailedNames(&existing.detailed_name_idx, SymbolKind::Type,
|
||||
it->second.id, def.detailed_name);
|
||||
}
|
||||
}
|
||||
@ -781,16 +774,15 @@ void QueryDatabase::ImportOrUpdate(
|
||||
assert(it != usr_to_func.end());
|
||||
|
||||
assert(it->second.id >= 0 && it->second.id < funcs.size());
|
||||
optional<QueryFunc>& existing = funcs[it->second.id];
|
||||
if (!existing)
|
||||
existing = QueryFunc(def.usr);
|
||||
QueryFunc& existing = funcs[it->second.id];
|
||||
|
||||
// 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;
|
||||
|
||||
existing->def = def;
|
||||
UpdateDetailedNames(&existing->detailed_name_idx, SymbolKind::Func,
|
||||
existing.def = def;
|
||||
UpdateDetailedNames(&existing.detailed_name_idx, SymbolKind::Func,
|
||||
it->second.id, def.detailed_name);
|
||||
}
|
||||
}
|
||||
@ -806,17 +798,16 @@ void QueryDatabase::ImportOrUpdate(
|
||||
assert(it != usr_to_var.end());
|
||||
|
||||
assert(it->second.id >= 0 && it->second.id < vars.size());
|
||||
optional<QueryVar>& existing = vars[it->second.id];
|
||||
if (!existing)
|
||||
existing = QueryVar(def.usr);
|
||||
QueryVar& existing = vars[it->second.id];
|
||||
|
||||
// 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;
|
||||
|
||||
existing->def = def;
|
||||
existing.def = def;
|
||||
if (!def.is_local)
|
||||
UpdateDetailedNames(&existing->detailed_name_idx, SymbolKind::Var,
|
||||
UpdateDetailedNames(&existing.detailed_name_idx, SymbolKind::Var,
|
||||
it->second.id, def.detailed_name);
|
||||
}
|
||||
}
|
||||
@ -952,14 +943,14 @@ TEST_CASE("apply delta") {
|
||||
&previous_map, ¤t_map, &previous, ¤t);
|
||||
|
||||
db.ApplyIndexUpdate(&import_update);
|
||||
REQUIRE(db.funcs[0]->callers.size() == 2);
|
||||
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.size() == 2);
|
||||
REQUIRE(db.funcs[0].callers[0].loc.range == Range(Position(1, 0)));
|
||||
REQUIRE(db.funcs[0].callers[1].loc.range == Range(Position(2, 0)));
|
||||
|
||||
db.ApplyIndexUpdate(&delta_update);
|
||||
REQUIRE(db.funcs[0]->callers.size() == 2);
|
||||
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.size() == 2);
|
||||
REQUIRE(db.funcs[0].callers[0].loc.range == Range(Position(4, 0)));
|
||||
REQUIRE(db.funcs[0].callers[1].loc.range == Range(Position(5, 0)));
|
||||
}
|
||||
|
||||
TEST_SUITE_END();
|
21
src/query.h
21
src/query.h
@ -169,10 +169,13 @@ struct QueryFile {
|
||||
|
||||
using DefUpdate = Def;
|
||||
|
||||
DefUpdate def;
|
||||
optional<DefUpdate> def;
|
||||
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);
|
||||
|
||||
@ -185,7 +188,7 @@ struct QueryType {
|
||||
using InstancesUpdate = MergeableUpdate<QueryTypeId, QueryVarId>;
|
||||
using UsesUpdate = MergeableUpdate<QueryTypeId, QueryLocation>;
|
||||
|
||||
DefUpdate def;
|
||||
optional<DefUpdate> def;
|
||||
std::vector<QueryTypeId> derived;
|
||||
std::vector<QueryVarId> instances;
|
||||
std::vector<QueryLocation> uses;
|
||||
@ -204,7 +207,7 @@ struct QueryFunc {
|
||||
using DerivedUpdate = MergeableUpdate<QueryFuncId, QueryFuncId>;
|
||||
using CallersUpdate = MergeableUpdate<QueryFuncId, QueryFuncRef>;
|
||||
|
||||
DefUpdate def;
|
||||
optional<DefUpdate> def;
|
||||
std::vector<QueryLocation> declarations;
|
||||
std::vector<QueryFuncId> derived;
|
||||
std::vector<QueryFuncRef> callers;
|
||||
@ -218,7 +221,7 @@ struct QueryVar {
|
||||
VarDefDefinitionData<QueryTypeId, QueryFuncId, QueryVarId, QueryLocation>;
|
||||
using UsesUpdate = MergeableUpdate<QueryVarId, QueryLocation>;
|
||||
|
||||
DefUpdate def;
|
||||
optional<DefUpdate> def;
|
||||
std::vector<QueryLocation> uses;
|
||||
size_t detailed_name_idx = (size_t)-1;
|
||||
|
||||
@ -298,10 +301,10 @@ struct QueryDatabase {
|
||||
std::vector<SymbolIdx> symbols;
|
||||
|
||||
// Raw data storage. Accessible via SymbolIdx instances.
|
||||
std::vector<optional<QueryFile>> files;
|
||||
std::vector<optional<QueryType>> types;
|
||||
std::vector<optional<QueryFunc>> funcs;
|
||||
std::vector<optional<QueryVar>> vars;
|
||||
std::vector<QueryFile> files;
|
||||
std::vector<QueryType> types;
|
||||
std::vector<QueryFunc> funcs;
|
||||
std::vector<QueryVar> vars;
|
||||
|
||||
// Lookup symbol based on a usr.
|
||||
// NOTE: For usr_to_file make sure to call LowerPathIfCaseInsensitive on key.
|
||||
|
@ -15,25 +15,25 @@ int ComputeRangeSize(const Range& range) {
|
||||
|
||||
optional<QueryLocation> GetDefinitionSpellingOfSymbol(QueryDatabase* db,
|
||||
const QueryTypeId& id) {
|
||||
optional<QueryType>& type = db->types[id.id];
|
||||
if (type)
|
||||
return type->def.definition_spelling;
|
||||
QueryType& type = db->types[id.id];
|
||||
if (type.def)
|
||||
return type.def->definition_spelling;
|
||||
return nullopt;
|
||||
}
|
||||
|
||||
optional<QueryLocation> GetDefinitionSpellingOfSymbol(QueryDatabase* db,
|
||||
const QueryFuncId& id) {
|
||||
optional<QueryFunc>& func = db->funcs[id.id];
|
||||
if (func)
|
||||
return func->def.definition_spelling;
|
||||
QueryFunc& func = db->funcs[id.id];
|
||||
if (func.def)
|
||||
return func.def->definition_spelling;
|
||||
return nullopt;
|
||||
}
|
||||
|
||||
optional<QueryLocation> GetDefinitionSpellingOfSymbol(QueryDatabase* db,
|
||||
const QueryVarId& id) {
|
||||
optional<QueryVar>& var = db->vars[id.id];
|
||||
if (var)
|
||||
return var->def.definition_spelling;
|
||||
QueryVar& var = db->vars[id.id];
|
||||
if (var.def)
|
||||
return var.def->definition_spelling;
|
||||
return nullopt;
|
||||
}
|
||||
|
||||
@ -41,21 +41,21 @@ optional<QueryLocation> GetDefinitionSpellingOfSymbol(QueryDatabase* db,
|
||||
const SymbolIdx& symbol) {
|
||||
switch (symbol.kind) {
|
||||
case SymbolKind::Type: {
|
||||
optional<QueryType>& type = db->types[symbol.idx];
|
||||
if (type)
|
||||
return type->def.definition_spelling;
|
||||
QueryType& type = db->types[symbol.idx];
|
||||
if (type.def)
|
||||
return type.def->definition_spelling;
|
||||
break;
|
||||
}
|
||||
case SymbolKind::Func: {
|
||||
optional<QueryFunc>& func = db->funcs[symbol.idx];
|
||||
if (func)
|
||||
return func->def.definition_spelling;
|
||||
QueryFunc& func = db->funcs[symbol.idx];
|
||||
if (func.def)
|
||||
return func.def->definition_spelling;
|
||||
break;
|
||||
}
|
||||
case SymbolKind::Var: {
|
||||
optional<QueryVar>& var = db->vars[symbol.idx];
|
||||
if (var)
|
||||
return var->def.definition_spelling;
|
||||
QueryVar& var = db->vars[symbol.idx];
|
||||
if (var.def)
|
||||
return var.def->definition_spelling;
|
||||
break;
|
||||
}
|
||||
case SymbolKind::File:
|
||||
@ -71,21 +71,21 @@ optional<QueryLocation> GetDefinitionExtentOfSymbol(QueryDatabase* db,
|
||||
const SymbolIdx& symbol) {
|
||||
switch (symbol.kind) {
|
||||
case SymbolKind::Type: {
|
||||
optional<QueryType>& type = db->types[symbol.idx];
|
||||
if (type)
|
||||
return type->def.definition_extent;
|
||||
QueryType& type = db->types[symbol.idx];
|
||||
if (type.def)
|
||||
return type.def->definition_extent;
|
||||
break;
|
||||
}
|
||||
case SymbolKind::Func: {
|
||||
optional<QueryFunc>& func = db->funcs[symbol.idx];
|
||||
if (func)
|
||||
return func->def.definition_extent;
|
||||
QueryFunc& func = db->funcs[symbol.idx];
|
||||
if (func.def)
|
||||
return func.def->definition_extent;
|
||||
break;
|
||||
}
|
||||
case SymbolKind::Var: {
|
||||
optional<QueryVar>& var = db->vars[symbol.idx];
|
||||
if (var)
|
||||
return var->def.definition_extent;
|
||||
QueryVar& var = db->vars[symbol.idx];
|
||||
if (var.def)
|
||||
return var.def->definition_extent;
|
||||
break;
|
||||
}
|
||||
case SymbolKind::File: {
|
||||
@ -103,21 +103,21 @@ optional<QueryLocation> GetDefinitionExtentOfSymbol(QueryDatabase* db,
|
||||
std::string GetHoverForSymbol(QueryDatabase* db, const SymbolIdx& symbol) {
|
||||
switch (symbol.kind) {
|
||||
case SymbolKind::Type: {
|
||||
optional<QueryType>& type = db->types[symbol.idx];
|
||||
if (type)
|
||||
return type->def.detailed_name;
|
||||
QueryType& type = db->types[symbol.idx];
|
||||
if (type.def)
|
||||
return type.def->detailed_name;
|
||||
break;
|
||||
}
|
||||
case SymbolKind::Func: {
|
||||
optional<QueryFunc>& func = db->funcs[symbol.idx];
|
||||
if (func)
|
||||
return func->def.detailed_name;
|
||||
QueryFunc& func = db->funcs[symbol.idx];
|
||||
if (func.def)
|
||||
return func.def->detailed_name;
|
||||
break;
|
||||
}
|
||||
case SymbolKind::Var: {
|
||||
optional<QueryVar>& var = db->vars[symbol.idx];
|
||||
if (var)
|
||||
return var->def.detailed_name;
|
||||
QueryVar& var = db->vars[symbol.idx];
|
||||
if (var.def)
|
||||
return var.def->detailed_name;
|
||||
break;
|
||||
}
|
||||
case SymbolKind::File:
|
||||
@ -133,25 +133,23 @@ optional<QueryFileId> GetDeclarationFileForSymbol(QueryDatabase* db,
|
||||
const SymbolIdx& symbol) {
|
||||
switch (symbol.kind) {
|
||||
case SymbolKind::Type: {
|
||||
optional<QueryType>& type = db->types[symbol.idx];
|
||||
if (type && type->def.definition_spelling)
|
||||
return type->def.definition_spelling->path;
|
||||
QueryType& type = db->types[symbol.idx];
|
||||
if (type.def && type.def->definition_spelling)
|
||||
return type.def->definition_spelling->path;
|
||||
break;
|
||||
}
|
||||
case SymbolKind::Func: {
|
||||
optional<QueryFunc>& func = db->funcs[symbol.idx];
|
||||
if (func) {
|
||||
if (!func->declarations.empty())
|
||||
return func->declarations[0].path;
|
||||
if (func->def.definition_spelling)
|
||||
return func->def.definition_spelling->path;
|
||||
}
|
||||
QueryFunc& func = db->funcs[symbol.idx];
|
||||
if (!func.declarations.empty())
|
||||
return func.declarations[0].path;
|
||||
if (func.def && func.def->definition_spelling)
|
||||
return func.def->definition_spelling->path;
|
||||
break;
|
||||
}
|
||||
case SymbolKind::Var: {
|
||||
optional<QueryVar>& var = db->vars[symbol.idx];
|
||||
if (var && var->def.definition_spelling)
|
||||
return var->def.definition_spelling->path;
|
||||
QueryVar& var = db->vars[symbol.idx];
|
||||
if (var.def && var.def->definition_spelling)
|
||||
return var.def->definition_spelling->path;
|
||||
break;
|
||||
}
|
||||
case SymbolKind::File: {
|
||||
@ -214,28 +212,21 @@ std::vector<QueryLocation> GetUsesOfSymbol(QueryDatabase* db,
|
||||
const SymbolIdx& symbol) {
|
||||
switch (symbol.kind) {
|
||||
case SymbolKind::Type: {
|
||||
optional<QueryType>& type = db->types[symbol.idx];
|
||||
if (type)
|
||||
return type->uses;
|
||||
break;
|
||||
QueryType& type = db->types[symbol.idx];
|
||||
return type.uses;
|
||||
}
|
||||
case SymbolKind::Func: {
|
||||
// TODO: the vector allocation could be avoided.
|
||||
optional<QueryFunc>& func = db->funcs[symbol.idx];
|
||||
if (func) {
|
||||
std::vector<QueryLocation> result = ToQueryLocation(db, func->callers);
|
||||
AddRange(&result, func->declarations);
|
||||
if (func->def.definition_spelling)
|
||||
result.push_back(*func->def.definition_spelling);
|
||||
return result;
|
||||
}
|
||||
break;
|
||||
QueryFunc& func = db->funcs[symbol.idx];
|
||||
std::vector<QueryLocation> result = ToQueryLocation(db, func.callers);
|
||||
AddRange(&result, func.declarations);
|
||||
if (func.def && func.def->definition_spelling)
|
||||
result.push_back(*func.def->definition_spelling);
|
||||
return result;
|
||||
}
|
||||
case SymbolKind::Var: {
|
||||
optional<QueryVar>& var = db->vars[symbol.idx];
|
||||
if (var)
|
||||
return var->uses;
|
||||
break;
|
||||
QueryVar& var = db->vars[symbol.idx];
|
||||
return var.uses;
|
||||
}
|
||||
case SymbolKind::File:
|
||||
case SymbolKind::Invalid: {
|
||||
@ -255,24 +246,22 @@ std::vector<QueryLocation> GetDeclarationsOfSymbolForGotoDefinition(
|
||||
// function has the postfix `ForGotoDefintion`, but it lets the user
|
||||
// jump to the start of a type if clicking goto-definition on the same
|
||||
// type from within the type definition.
|
||||
optional<QueryType>& type = db->types[symbol.idx];
|
||||
if (type) {
|
||||
optional<QueryLocation> declaration = type->def.definition_spelling;
|
||||
QueryType& type = db->types[symbol.idx];
|
||||
if (type.def) {
|
||||
optional<QueryLocation> declaration = type.def->definition_spelling;
|
||||
if (declaration)
|
||||
return {*declaration};
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SymbolKind::Func: {
|
||||
optional<QueryFunc>& func = db->funcs[symbol.idx];
|
||||
if (func)
|
||||
return func->declarations;
|
||||
break;
|
||||
QueryFunc& func = db->funcs[symbol.idx];
|
||||
return func.declarations;
|
||||
}
|
||||
case SymbolKind::Var: {
|
||||
optional<QueryVar>& var = db->vars[symbol.idx];
|
||||
if (var) {
|
||||
optional<QueryLocation> declaration = var->def.declaration;
|
||||
QueryVar& var = db->vars[symbol.idx];
|
||||
if (var.def) {
|
||||
optional<QueryLocation> declaration = var.def->declaration;
|
||||
if (declaration)
|
||||
return {*declaration};
|
||||
}
|
||||
@ -288,15 +277,15 @@ std::vector<QueryLocation> GetDeclarationsOfSymbolForGotoDefinition(
|
||||
optional<QueryLocation> GetBaseDefinitionOrDeclarationSpelling(
|
||||
QueryDatabase* db,
|
||||
QueryFunc& func) {
|
||||
if (!func.def.base)
|
||||
return nullopt;
|
||||
optional<QueryFunc>& base = db->funcs[func.def.base->id];
|
||||
if (!base)
|
||||
if (!func.def->base)
|
||||
return nullopt;
|
||||
QueryFunc& base = db->funcs[func.def->base->id];
|
||||
|
||||
auto def = base->def.definition_spelling;
|
||||
if (!def && !base->declarations.empty())
|
||||
def = base->declarations[0];
|
||||
optional<QueryLocation> def;
|
||||
if (base.def)
|
||||
def = base.def->definition_spelling;
|
||||
if (!def && !base.declarations.empty())
|
||||
def = base.declarations[0];
|
||||
return def;
|
||||
}
|
||||
|
||||
@ -306,28 +295,25 @@ bool HasCallersOnSelfOrBaseOrDerived(QueryDatabase* db, QueryFunc& root) {
|
||||
return true;
|
||||
|
||||
// Check for base calls.
|
||||
optional<QueryFuncId> func_id = root.def.base;
|
||||
optional<QueryFuncId> func_id = root.def->base;
|
||||
while (func_id) {
|
||||
optional<QueryFunc>& func = db->funcs[func_id->id];
|
||||
if (!func)
|
||||
break;
|
||||
if (!func->callers.empty())
|
||||
QueryFunc& func = db->funcs[func_id->id];
|
||||
if (!func.callers.empty())
|
||||
return true;
|
||||
func_id = func->def.base;
|
||||
if (!func.def)
|
||||
break;
|
||||
func_id = func.def->base;
|
||||
}
|
||||
|
||||
// Check for derived calls.
|
||||
std::queue<QueryFuncId> queue;
|
||||
PushRange(&queue, root.derived);
|
||||
while (!queue.empty()) {
|
||||
optional<QueryFunc>& func = db->funcs[queue.front().id];
|
||||
QueryFunc& func = db->funcs[queue.front().id];
|
||||
queue.pop();
|
||||
if (!func)
|
||||
continue;
|
||||
|
||||
if (!func->derived.empty())
|
||||
if (!func.callers.empty())
|
||||
return true;
|
||||
PushRange(&queue, func->derived);
|
||||
PushRange(&queue, func.derived);
|
||||
}
|
||||
|
||||
return false;
|
||||
@ -337,14 +323,14 @@ std::vector<QueryFuncRef> GetCallersForAllBaseFunctions(QueryDatabase* db,
|
||||
QueryFunc& root) {
|
||||
std::vector<QueryFuncRef> callers;
|
||||
|
||||
optional<QueryFuncId> func_id = root.def.base;
|
||||
optional<QueryFuncId> func_id = root.def->base;
|
||||
while (func_id) {
|
||||
optional<QueryFunc>& func = db->funcs[func_id->id];
|
||||
if (!func)
|
||||
break;
|
||||
QueryFunc& func = db->funcs[func_id->id];
|
||||
AddRange(&callers, func.callers);
|
||||
|
||||
AddRange(&callers, func->callers);
|
||||
func_id = func->def.base;
|
||||
if (!func.def)
|
||||
break;
|
||||
func_id = func.def->base;
|
||||
}
|
||||
|
||||
return callers;
|
||||
@ -358,13 +344,11 @@ std::vector<QueryFuncRef> GetCallersForAllDerivedFunctions(QueryDatabase* db,
|
||||
PushRange(&queue, root.derived);
|
||||
|
||||
while (!queue.empty()) {
|
||||
optional<QueryFunc>& func = db->funcs[queue.front().id];
|
||||
QueryFunc& func = db->funcs[queue.front().id];
|
||||
queue.pop();
|
||||
if (!func)
|
||||
continue;
|
||||
|
||||
PushRange(&queue, func->derived);
|
||||
AddRange(&callers, func->callers);
|
||||
PushRange(&queue, func.derived);
|
||||
AddRange(&callers, func.callers);
|
||||
}
|
||||
|
||||
return callers;
|
||||
@ -412,9 +396,9 @@ optional<lsRange> GetLsRange(WorkingFile* working_file, const Range& location) {
|
||||
lsDocumentUri GetLsDocumentUri(QueryDatabase* db,
|
||||
QueryFileId file_id,
|
||||
std::string* path) {
|
||||
optional<QueryFile>& file = db->files[file_id.id];
|
||||
if (file) {
|
||||
*path = file->def.path;
|
||||
QueryFile& file = db->files[file_id.id];
|
||||
if (file.def) {
|
||||
*path = file.def->path;
|
||||
return lsDocumentUri::FromPath(*path);
|
||||
} else {
|
||||
*path = "";
|
||||
@ -423,9 +407,9 @@ lsDocumentUri GetLsDocumentUri(QueryDatabase* db,
|
||||
}
|
||||
|
||||
lsDocumentUri GetLsDocumentUri(QueryDatabase* db, QueryFileId file_id) {
|
||||
optional<QueryFile>& file = db->files[file_id.id];
|
||||
if (file) {
|
||||
return lsDocumentUri::FromPath(file->def.path);
|
||||
QueryFile& file = db->files[file_id.id];
|
||||
if (file.def) {
|
||||
return lsDocumentUri::FromPath(file.def->path);
|
||||
} else {
|
||||
return lsDocumentUri::FromPath("");
|
||||
}
|
||||
@ -468,54 +452,54 @@ optional<lsSymbolInformation> GetSymbolInfo(QueryDatabase* db,
|
||||
SymbolIdx symbol) {
|
||||
switch (symbol.kind) {
|
||||
case SymbolKind::File: {
|
||||
optional<QueryFile>& file = db->files[symbol.idx];
|
||||
if (!file)
|
||||
QueryFile& file = db->files[symbol.idx];
|
||||
if (!file.def)
|
||||
return nullopt;
|
||||
|
||||
lsSymbolInformation info;
|
||||
info.name = file->def.path;
|
||||
info.name = file.def->path;
|
||||
info.kind = lsSymbolKind::File;
|
||||
return info;
|
||||
}
|
||||
case SymbolKind::Type: {
|
||||
optional<QueryType>& type = db->types[symbol.idx];
|
||||
if (!type)
|
||||
QueryType& type = db->types[symbol.idx];
|
||||
if (!type.def)
|
||||
return nullopt;
|
||||
|
||||
lsSymbolInformation info;
|
||||
info.name = type->def.short_name;
|
||||
if (type->def.detailed_name != type->def.short_name)
|
||||
info.containerName = type->def.detailed_name;
|
||||
info.name = type.def->short_name;
|
||||
if (type.def->detailed_name != type.def->short_name)
|
||||
info.containerName = type.def->detailed_name;
|
||||
info.kind = lsSymbolKind::Class;
|
||||
return info;
|
||||
}
|
||||
case SymbolKind::Func: {
|
||||
optional<QueryFunc>& func = db->funcs[symbol.idx];
|
||||
if (!func)
|
||||
QueryFunc& func = db->funcs[symbol.idx];
|
||||
if (!func.def)
|
||||
return nullopt;
|
||||
|
||||
lsSymbolInformation info;
|
||||
info.name = func->def.short_name;
|
||||
info.containerName = func->def.detailed_name;
|
||||
info.name = func.def->short_name;
|
||||
info.containerName = func.def->detailed_name;
|
||||
info.kind = lsSymbolKind::Function;
|
||||
|
||||
if (func->def.declaring_type.has_value()) {
|
||||
optional<QueryType>& container =
|
||||
db->types[func->def.declaring_type->id];
|
||||
if (container)
|
||||
if (func.def->declaring_type.has_value()) {
|
||||
QueryType& container =
|
||||
db->types[func.def->declaring_type->id];
|
||||
if (container.def)
|
||||
info.kind = lsSymbolKind::Method;
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
case SymbolKind::Var: {
|
||||
optional<QueryVar>& var = db->vars[symbol.idx];
|
||||
if (!var)
|
||||
QueryVar& var = db->vars[symbol.idx];
|
||||
if (!var.def)
|
||||
return nullopt;
|
||||
|
||||
lsSymbolInformation info;
|
||||
info.name += var->def.short_name;
|
||||
info.containerName = var->def.detailed_name;
|
||||
info.name += var.def->short_name;
|
||||
info.containerName = var.def->detailed_name;
|
||||
info.kind = lsSymbolKind::Variable;
|
||||
return info;
|
||||
}
|
||||
@ -585,11 +569,11 @@ lsWorkspaceEdit BuildWorkspaceEdit(QueryDatabase* db,
|
||||
if (path_to_edit.find(location.path) == path_to_edit.end()) {
|
||||
path_to_edit[location.path] = lsTextDocumentEdit();
|
||||
|
||||
optional<QueryFile>& file = db->files[location.path.id];
|
||||
if (!file)
|
||||
QueryFile& file = db->files[location.path.id];
|
||||
if (!file.def)
|
||||
continue;
|
||||
|
||||
const std::string& path = file->def.path;
|
||||
const std::string& path = file.def->path;
|
||||
path_to_edit[location.path].textDocument.uri =
|
||||
lsDocumentUri::FromPath(path);
|
||||
|
||||
@ -630,7 +614,7 @@ std::vector<SymbolRef> FindSymbolsAtLocation(WorkingFile* working_file,
|
||||
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))
|
||||
symbols.push_back(ref);
|
||||
}
|
||||
@ -660,23 +644,23 @@ NonElidedVector<Out_CqueryTypeHierarchyTree::TypeEntry>
|
||||
BuildParentInheritanceHierarchyForType(QueryDatabase* db,
|
||||
WorkingFiles* working_files,
|
||||
QueryTypeId root) {
|
||||
optional<QueryType>& root_type = db->types[root.id];
|
||||
if (!root_type)
|
||||
QueryType& root_type = db->types[root.id];
|
||||
if (!root_type.def)
|
||||
return {};
|
||||
|
||||
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) {
|
||||
optional<QueryType>& parent_type = db->types[parent_id.id];
|
||||
if (!parent_type)
|
||||
for (QueryTypeId parent_id : root_type.def->parents) {
|
||||
QueryType& parent_type = db->types[parent_id.id];
|
||||
if (!parent_type.def)
|
||||
continue;
|
||||
|
||||
Out_CqueryTypeHierarchyTree::TypeEntry parent_entry;
|
||||
parent_entry.name = parent_type->def.detailed_name;
|
||||
if (parent_type->def.definition_spelling)
|
||||
parent_entry.name = parent_type.def->detailed_name;
|
||||
if (parent_type.def->definition_spelling)
|
||||
parent_entry.location = GetLsLocation(
|
||||
db, working_files, *parent_type->def.definition_spelling);
|
||||
db, working_files, *parent_type.def->definition_spelling);
|
||||
parent_entry.children =
|
||||
BuildParentInheritanceHierarchyForType(db, working_files, parent_id);
|
||||
|
||||
@ -690,19 +674,19 @@ optional<Out_CqueryTypeHierarchyTree::TypeEntry>
|
||||
BuildInheritanceHierarchyForType(QueryDatabase* db,
|
||||
WorkingFiles* working_files,
|
||||
QueryTypeId root_id) {
|
||||
optional<QueryType>& root_type = db->types[root_id.id];
|
||||
if (!root_type)
|
||||
QueryType& root_type = db->types[root_id.id];
|
||||
if (!root_type.def)
|
||||
return nullopt;
|
||||
|
||||
Out_CqueryTypeHierarchyTree::TypeEntry entry;
|
||||
|
||||
// Name and location.
|
||||
entry.name = root_type->def.detailed_name;
|
||||
if (root_type->def.definition_spelling)
|
||||
entry.name = root_type.def->detailed_name;
|
||||
if (root_type.def->definition_spelling)
|
||||
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.
|
||||
Out_CqueryTypeHierarchyTree::TypeEntry base;
|
||||
@ -714,7 +698,7 @@ BuildInheritanceHierarchyForType(QueryDatabase* db,
|
||||
entry.children.push_back(base);
|
||||
|
||||
// Add derived.
|
||||
for (QueryTypeId derived : root_type->derived) {
|
||||
for (QueryTypeId derived : root_type.derived) {
|
||||
auto derived_entry =
|
||||
BuildInheritanceHierarchyForType(db, working_files, derived);
|
||||
if (derived_entry)
|
||||
@ -728,21 +712,21 @@ NonElidedVector<Out_CqueryTypeHierarchyTree::TypeEntry>
|
||||
BuildParentInheritanceHierarchyForFunc(QueryDatabase* db,
|
||||
WorkingFiles* working_files,
|
||||
QueryFuncId root) {
|
||||
optional<QueryFunc>& root_func = db->funcs[root.id];
|
||||
if (!root_func || !root_func->def.base)
|
||||
QueryFunc& root_func = db->funcs[root.id];
|
||||
if (!root_func.def || !root_func.def->base)
|
||||
return {};
|
||||
|
||||
optional<QueryFunc>& parent_func = db->funcs[root_func->def.base->id];
|
||||
if (!parent_func)
|
||||
QueryFunc& parent_func = db->funcs[root_func.def->base->id];
|
||||
if (!parent_func.def)
|
||||
return {};
|
||||
|
||||
Out_CqueryTypeHierarchyTree::TypeEntry parent_entry;
|
||||
parent_entry.name = parent_func->def.detailed_name;
|
||||
if (parent_func->def.definition_spelling)
|
||||
parent_entry.name = parent_func.def->detailed_name;
|
||||
if (parent_func.def->definition_spelling)
|
||||
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(
|
||||
db, working_files, *root_func->def.base);
|
||||
db, working_files, *root_func.def->base);
|
||||
|
||||
NonElidedVector<Out_CqueryTypeHierarchyTree::TypeEntry> entries;
|
||||
entries.push_back(parent_entry);
|
||||
@ -753,19 +737,19 @@ optional<Out_CqueryTypeHierarchyTree::TypeEntry>
|
||||
BuildInheritanceHierarchyForFunc(QueryDatabase* db,
|
||||
WorkingFiles* working_files,
|
||||
QueryFuncId root_id) {
|
||||
optional<QueryFunc>& root_func = db->funcs[root_id.id];
|
||||
if (!root_func)
|
||||
QueryFunc& root_func = db->funcs[root_id.id];
|
||||
if (!root_func.def)
|
||||
return nullopt;
|
||||
|
||||
Out_CqueryTypeHierarchyTree::TypeEntry entry;
|
||||
|
||||
// Name and location.
|
||||
entry.name = root_func->def.detailed_name;
|
||||
if (root_func->def.definition_spelling)
|
||||
entry.name = root_func.def->detailed_name;
|
||||
if (root_func.def->definition_spelling)
|
||||
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.
|
||||
Out_CqueryTypeHierarchyTree::TypeEntry base;
|
||||
@ -777,7 +761,7 @@ BuildInheritanceHierarchyForFunc(QueryDatabase* db,
|
||||
entry.children.push_back(base);
|
||||
|
||||
// Add derived.
|
||||
for (QueryFuncId derived : root_func->derived) {
|
||||
for (QueryFuncId derived : root_func.derived) {
|
||||
auto derived_entry =
|
||||
BuildInheritanceHierarchyForFunc(db, working_files, derived);
|
||||
if (derived_entry)
|
||||
@ -791,21 +775,19 @@ NonElidedVector<Out_CqueryCallTree::CallEntry> BuildInitialCallTree(
|
||||
QueryDatabase* db,
|
||||
WorkingFiles* working_files,
|
||||
QueryFuncId root) {
|
||||
optional<QueryFunc>& root_func = db->funcs[root.id];
|
||||
if (!root_func)
|
||||
return {};
|
||||
if (!root_func->def.definition_spelling)
|
||||
QueryFunc& root_func = db->funcs[root.id];
|
||||
if (!root_func.def || !root_func.def->definition_spelling)
|
||||
return {};
|
||||
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)
|
||||
return {};
|
||||
|
||||
Out_CqueryCallTree::CallEntry entry;
|
||||
entry.name = root_func->def.short_name;
|
||||
entry.usr = root_func->def.usr;
|
||||
entry.name = root_func.def->short_name;
|
||||
entry.usr = root_func.def->usr;
|
||||
entry.location = *def_loc;
|
||||
entry.hasCallers = HasCallersOnSelfOrBaseOrDerived(db, *root_func);
|
||||
entry.hasCallers = HasCallersOnSelfOrBaseOrDerived(db, root_func);
|
||||
NonElidedVector<Out_CqueryCallTree::CallEntry> result;
|
||||
result.push_back(entry);
|
||||
return result;
|
||||
@ -815,8 +797,8 @@ NonElidedVector<Out_CqueryCallTree::CallEntry> BuildExpandCallTree(
|
||||
QueryDatabase* db,
|
||||
WorkingFiles* working_files,
|
||||
QueryFuncId root) {
|
||||
optional<QueryFunc>& root_func = db->funcs[root.id];
|
||||
if (!root_func)
|
||||
QueryFunc& root_func = db->funcs[root.id];
|
||||
if (!root_func.def)
|
||||
return {};
|
||||
|
||||
auto format_location =
|
||||
@ -825,9 +807,9 @@ NonElidedVector<Out_CqueryCallTree::CallEntry> BuildExpandCallTree(
|
||||
std::string base;
|
||||
|
||||
if (declaring_type) {
|
||||
optional<QueryType> type = db->types[declaring_type->id];
|
||||
if (type)
|
||||
base = type->def.detailed_name;
|
||||
QueryType type = db->types[declaring_type->id];
|
||||
if (type.def)
|
||||
base = type.def->detailed_name;
|
||||
}
|
||||
|
||||
if (base.empty()) {
|
||||
@ -869,17 +851,17 @@ NonElidedVector<Out_CqueryCallTree::CallEntry> BuildExpandCallTree(
|
||||
}
|
||||
|
||||
if (caller.has_id()) {
|
||||
optional<QueryFunc>& call_func = db->funcs[caller.id_.id];
|
||||
if (!call_func)
|
||||
QueryFunc& call_func = db->funcs[caller.id_.id];
|
||||
if (!call_func.def)
|
||||
return;
|
||||
|
||||
Out_CqueryCallTree::CallEntry call_entry;
|
||||
call_entry.name =
|
||||
call_func->def.short_name + " (" +
|
||||
format_location(*call_location, call_func->def.declaring_type) + ")";
|
||||
call_entry.usr = call_func->def.usr;
|
||||
call_func.def->short_name + " (" +
|
||||
format_location(*call_location, call_func.def->declaring_type) + ")";
|
||||
call_entry.usr = call_func.def->usr;
|
||||
call_entry.location = *call_location;
|
||||
call_entry.hasCallers = HasCallersOnSelfOrBaseOrDerived(db, *call_func);
|
||||
call_entry.hasCallers = HasCallersOnSelfOrBaseOrDerived(db, call_func);
|
||||
call_entry.callType = call_type;
|
||||
result.push_back(call_entry);
|
||||
} else {
|
||||
@ -896,13 +878,13 @@ NonElidedVector<Out_CqueryCallTree::CallEntry> BuildExpandCallTree(
|
||||
};
|
||||
|
||||
std::vector<QueryFuncRef> base_callers =
|
||||
GetCallersForAllBaseFunctions(db, *root_func);
|
||||
GetCallersForAllBaseFunctions(db, root_func);
|
||||
std::vector<QueryFuncRef> derived_callers =
|
||||
GetCallersForAllDerivedFunctions(db, *root_func);
|
||||
result.reserve(root_func->callers.size() + base_callers.size() +
|
||||
GetCallersForAllDerivedFunctions(db, root_func);
|
||||
result.reserve(root_func.callers.size() + base_callers.size() +
|
||||
derived_callers.size());
|
||||
|
||||
for (QueryFuncRef caller : root_func->callers)
|
||||
for (QueryFuncRef caller : root_func.callers)
|
||||
handle_caller(caller, Out_CqueryCallTree::CallType::Direct);
|
||||
for (QueryFuncRef caller : base_callers) {
|
||||
// Do not show calls to the base function coming from this function.
|
||||
|
Loading…
Reference in New Issue
Block a user