2017-06-15 05:32:23 +00:00
|
|
|
#include "query_utils.h"
|
|
|
|
|
2017-12-24 01:30:52 +00:00
|
|
|
#include "queue_manager.h"
|
|
|
|
|
2018-02-10 00:42:33 +00:00
|
|
|
#include <loguru.hpp>
|
|
|
|
|
2017-06-16 17:14:09 +00:00
|
|
|
#include <climits>
|
2018-02-07 05:26:38 +00:00
|
|
|
#include <queue>
|
2017-06-16 17:14:09 +00:00
|
|
|
|
2017-06-16 06:43:02 +00:00
|
|
|
namespace {
|
|
|
|
|
|
|
|
// Computes roughly how long |range| is.
|
|
|
|
int ComputeRangeSize(const Range& range) {
|
|
|
|
if (range.start.line != range.end.line)
|
|
|
|
return INT_MAX;
|
|
|
|
return range.end.column - range.start.column;
|
|
|
|
}
|
|
|
|
|
2018-02-09 05:11:35 +00:00
|
|
|
} // namespace
|
|
|
|
|
2017-09-22 01:14:57 +00:00
|
|
|
optional<QueryLocation> GetDefinitionSpellingOfSymbol(QueryDatabase* db,
|
|
|
|
const QueryTypeId& id) {
|
2017-10-17 05:44:58 +00:00
|
|
|
QueryType& type = db->types[id.id];
|
|
|
|
if (type.def)
|
|
|
|
return type.def->definition_spelling;
|
2017-06-15 05:32:23 +00:00
|
|
|
return nullopt;
|
|
|
|
}
|
|
|
|
|
2017-09-22 01:14:57 +00:00
|
|
|
optional<QueryLocation> GetDefinitionSpellingOfSymbol(QueryDatabase* db,
|
|
|
|
const QueryFuncId& id) {
|
2017-10-17 05:44:58 +00:00
|
|
|
QueryFunc& func = db->funcs[id.id];
|
|
|
|
if (func.def)
|
|
|
|
return func.def->definition_spelling;
|
2017-06-15 05:32:23 +00:00
|
|
|
return nullopt;
|
|
|
|
}
|
|
|
|
|
2017-09-22 01:14:57 +00:00
|
|
|
optional<QueryLocation> GetDefinitionSpellingOfSymbol(QueryDatabase* db,
|
|
|
|
const QueryVarId& id) {
|
2017-10-17 05:44:58 +00:00
|
|
|
QueryVar& var = db->vars[id.id];
|
|
|
|
if (var.def)
|
|
|
|
return var.def->definition_spelling;
|
2017-06-15 05:32:23 +00:00
|
|
|
return nullopt;
|
|
|
|
}
|
|
|
|
|
2017-09-22 01:14:57 +00:00
|
|
|
optional<QueryLocation> GetDefinitionSpellingOfSymbol(QueryDatabase* db,
|
2018-02-09 17:42:10 +00:00
|
|
|
SymbolRef sym) {
|
|
|
|
switch (sym.kind) {
|
2017-09-22 01:14:57 +00:00
|
|
|
case SymbolKind::Type: {
|
2018-02-09 17:42:10 +00:00
|
|
|
QueryType& type = sym.Type(db);
|
2017-10-17 05:44:58 +00:00
|
|
|
if (type.def)
|
2018-02-02 05:31:56 +00:00
|
|
|
return *type.def->definition_spelling;
|
2017-09-22 01:14:57 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case SymbolKind::Func: {
|
2018-02-09 17:42:10 +00:00
|
|
|
QueryFunc& func = sym.Func(db);
|
2017-10-17 05:44:58 +00:00
|
|
|
if (func.def)
|
|
|
|
return func.def->definition_spelling;
|
2017-09-22 01:14:57 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case SymbolKind::Var: {
|
2018-02-09 17:42:10 +00:00
|
|
|
QueryVar& var = sym.Var(db);
|
2017-10-17 05:44:58 +00:00
|
|
|
if (var.def)
|
|
|
|
return var.def->definition_spelling;
|
2017-09-22 01:14:57 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case SymbolKind::File:
|
|
|
|
case SymbolKind::Invalid: {
|
|
|
|
assert(false && "unexpected");
|
|
|
|
break;
|
|
|
|
}
|
2017-06-15 05:32:23 +00:00
|
|
|
}
|
|
|
|
return nullopt;
|
|
|
|
}
|
|
|
|
|
2017-09-22 01:14:57 +00:00
|
|
|
optional<QueryLocation> GetDefinitionExtentOfSymbol(QueryDatabase* db,
|
2018-02-09 17:42:10 +00:00
|
|
|
SymbolRef sym) {
|
|
|
|
switch (sym.kind) {
|
2017-09-22 01:14:57 +00:00
|
|
|
case SymbolKind::Type: {
|
2018-02-09 17:42:10 +00:00
|
|
|
QueryType& type = sym.Type(db);
|
2017-10-17 05:44:58 +00:00
|
|
|
if (type.def)
|
|
|
|
return type.def->definition_extent;
|
2017-09-22 01:14:57 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case SymbolKind::Func: {
|
2018-02-09 17:42:10 +00:00
|
|
|
QueryFunc& func = sym.Func(db);
|
2017-10-17 05:44:58 +00:00
|
|
|
if (func.def)
|
|
|
|
return func.def->definition_extent;
|
2017-09-22 01:14:57 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case SymbolKind::Var: {
|
2018-02-09 17:42:10 +00:00
|
|
|
QueryVar& var = sym.Var(db);
|
2017-10-17 05:44:58 +00:00
|
|
|
if (var.def)
|
|
|
|
return var.def->definition_extent;
|
2017-09-22 01:14:57 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case SymbolKind::File: {
|
2018-02-08 03:14:44 +00:00
|
|
|
return QueryLocation{Range(Position(0, 0), Position(0, 0)),
|
2018-02-09 17:42:10 +00:00
|
|
|
QueryFileId(sym.Idx()), SymbolRole::None};
|
2017-09-22 01:14:57 +00:00
|
|
|
}
|
|
|
|
case SymbolKind::Invalid: {
|
|
|
|
assert(false && "unexpected");
|
|
|
|
break;
|
|
|
|
}
|
2017-06-15 05:32:23 +00:00
|
|
|
}
|
|
|
|
return nullopt;
|
|
|
|
}
|
|
|
|
|
2017-09-22 01:14:57 +00:00
|
|
|
optional<QueryFileId> GetDeclarationFileForSymbol(QueryDatabase* db,
|
2018-02-09 17:42:10 +00:00
|
|
|
SymbolRef sym) {
|
|
|
|
switch (sym.kind) {
|
2017-09-22 01:14:57 +00:00
|
|
|
case SymbolKind::Type: {
|
2018-02-09 17:42:10 +00:00
|
|
|
QueryType& type = sym.Type(db);
|
2017-10-17 05:44:58 +00:00
|
|
|
if (type.def && type.def->definition_spelling)
|
2018-02-08 03:14:44 +00:00
|
|
|
return type.def->definition_spelling->FileId();
|
2017-09-22 01:14:57 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case SymbolKind::Func: {
|
2018-02-09 17:42:10 +00:00
|
|
|
QueryFunc& func = sym.Func(db);
|
2017-10-17 05:44:58 +00:00
|
|
|
if (!func.declarations.empty())
|
2018-02-09 05:11:35 +00:00
|
|
|
return GetFileId(db, func.declarations[0]);
|
2017-10-17 05:44:58 +00:00
|
|
|
if (func.def && func.def->definition_spelling)
|
2018-02-08 03:14:44 +00:00
|
|
|
return func.def->definition_spelling->FileId();
|
2017-09-22 01:14:57 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case SymbolKind::Var: {
|
2018-02-09 17:42:10 +00:00
|
|
|
QueryVar& var = sym.Var(db);
|
2017-10-17 05:44:58 +00:00
|
|
|
if (var.def && var.def->definition_spelling)
|
2018-02-08 03:14:44 +00:00
|
|
|
return var.def->definition_spelling->FileId();
|
2017-09-22 01:14:57 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case SymbolKind::File: {
|
2018-02-09 17:42:10 +00:00
|
|
|
return QueryFileId(sym.Idx());
|
2017-09-22 01:14:57 +00:00
|
|
|
}
|
|
|
|
case SymbolKind::Invalid: {
|
|
|
|
assert(false && "unexpected");
|
|
|
|
break;
|
|
|
|
}
|
2017-06-15 05:32:23 +00:00
|
|
|
}
|
|
|
|
return nullopt;
|
|
|
|
}
|
|
|
|
|
2018-02-09 05:11:35 +00:00
|
|
|
std::vector<Reference> ToReference(QueryDatabase* db,
|
|
|
|
const std::vector<QueryFuncRef>& refs) {
|
|
|
|
std::vector<Reference> ret;
|
|
|
|
ret.reserve(refs.size());
|
|
|
|
for (auto& ref : refs)
|
2018-02-09 07:10:54 +00:00
|
|
|
ret.push_back(ref);
|
2018-02-09 05:11:35 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<Reference> GetUsesOfSymbol(QueryDatabase* db,
|
2018-02-09 17:42:10 +00:00
|
|
|
SymbolRef sym,
|
2018-02-09 05:11:35 +00:00
|
|
|
bool include_decl) {
|
2018-02-09 17:42:10 +00:00
|
|
|
switch (sym.kind) {
|
2017-09-22 01:14:57 +00:00
|
|
|
case SymbolKind::Type: {
|
2018-02-09 17:42:10 +00:00
|
|
|
QueryType& type = db->types[sym.Idx()];
|
2018-02-09 05:11:35 +00:00
|
|
|
std::vector<Reference> ret = type.uses;
|
2018-01-30 03:08:19 +00:00
|
|
|
if (include_decl && type.def && type.def->definition_spelling)
|
2018-01-29 07:05:51 +00:00
|
|
|
ret.push_back(*type.def->definition_spelling);
|
|
|
|
return ret;
|
2017-09-22 01:14:57 +00:00
|
|
|
}
|
|
|
|
case SymbolKind::Func: {
|
|
|
|
// TODO: the vector allocation could be avoided.
|
2018-02-09 17:42:10 +00:00
|
|
|
QueryFunc& func = db->funcs[sym.Idx()];
|
2018-02-09 05:11:35 +00:00
|
|
|
std::vector<Reference> ret = ToReference(db, func.callers);
|
2018-01-27 01:31:50 +00:00
|
|
|
if (include_decl) {
|
2018-02-09 05:11:35 +00:00
|
|
|
AddRange(&ret, func.declarations);
|
2018-01-27 01:31:50 +00:00
|
|
|
if (func.def && func.def->definition_spelling)
|
2018-02-09 05:11:35 +00:00
|
|
|
ret.push_back(*func.def->definition_spelling);
|
2018-01-27 01:31:50 +00:00
|
|
|
}
|
2018-02-09 05:11:35 +00:00
|
|
|
return ret;
|
2017-09-22 01:14:57 +00:00
|
|
|
}
|
|
|
|
case SymbolKind::Var: {
|
2018-02-09 17:42:10 +00:00
|
|
|
QueryVar& var = db->vars[sym.Idx()];
|
2018-02-09 05:11:35 +00:00
|
|
|
std::vector<Reference> ret = var.uses;
|
2018-01-27 05:50:17 +00:00
|
|
|
if (include_decl) {
|
|
|
|
if (var.def && var.def->definition_spelling)
|
2018-01-27 02:20:17 +00:00
|
|
|
ret.push_back(*var.def->definition_spelling);
|
2018-01-30 00:27:43 +00:00
|
|
|
ret.insert(ret.end(), var.declarations.begin(), var.declarations.end());
|
2018-01-27 02:20:17 +00:00
|
|
|
}
|
2018-01-27 01:51:33 +00:00
|
|
|
return ret;
|
2017-09-22 01:14:57 +00:00
|
|
|
}
|
|
|
|
case SymbolKind::File:
|
|
|
|
case SymbolKind::Invalid: {
|
|
|
|
assert(false && "unexpected");
|
2018-02-09 05:11:35 +00:00
|
|
|
return {};
|
2017-09-22 01:14:57 +00:00
|
|
|
}
|
2017-06-15 05:32:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-09 05:11:35 +00:00
|
|
|
std::vector<Reference> GetDeclarationsOfSymbolForGotoDefinition(
|
2017-09-22 01:14:57 +00:00
|
|
|
QueryDatabase* db,
|
2018-02-09 17:42:10 +00:00
|
|
|
SymbolRef sym) {
|
|
|
|
switch (sym.kind) {
|
2017-09-22 01:14:57 +00:00
|
|
|
case SymbolKind::Type: {
|
|
|
|
// Returning the definition spelling of a type is a hack (and is why the
|
|
|
|
// 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.
|
2018-02-09 17:42:10 +00:00
|
|
|
QueryType& type = sym.Type(db);
|
2017-10-17 05:44:58 +00:00
|
|
|
if (type.def) {
|
|
|
|
optional<QueryLocation> declaration = type.def->definition_spelling;
|
2017-09-22 01:14:57 +00:00
|
|
|
if (declaration)
|
2018-02-09 05:11:35 +00:00
|
|
|
return {Reference(*declaration)};
|
2017-09-22 01:14:57 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2018-02-09 05:11:35 +00:00
|
|
|
case SymbolKind::Func:
|
2018-02-09 17:42:10 +00:00
|
|
|
return sym.Func(db).declarations;
|
2018-02-09 05:11:35 +00:00
|
|
|
case SymbolKind::Var:
|
2018-02-09 17:42:10 +00:00
|
|
|
return sym.Var(db).declarations;
|
2017-09-22 01:14:57 +00:00
|
|
|
default:
|
|
|
|
break;
|
2017-06-15 05:32:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
2017-07-19 07:17:38 +00:00
|
|
|
bool HasCallersOnSelfOrBaseOrDerived(QueryDatabase* db, QueryFunc& root) {
|
|
|
|
// Check self.
|
|
|
|
if (!root.callers.empty())
|
|
|
|
return true;
|
|
|
|
|
|
|
|
// Check for base calls.
|
2018-02-04 00:20:14 +00:00
|
|
|
std::queue<QueryFunc*> queue;
|
|
|
|
EachWithGen<QueryFunc>(db->funcs, root.def->base, [&](QueryFunc& func) {
|
|
|
|
queue.push(&func);
|
|
|
|
});
|
2017-12-19 06:15:46 +00:00
|
|
|
while (!queue.empty()) {
|
2018-02-04 00:20:14 +00:00
|
|
|
QueryFunc& func = *queue.front();
|
2017-12-19 06:15:46 +00:00
|
|
|
queue.pop();
|
2017-10-17 05:44:58 +00:00
|
|
|
if (!func.callers.empty())
|
2017-07-19 07:17:38 +00:00
|
|
|
return true;
|
2017-12-19 06:15:46 +00:00
|
|
|
if (func.def)
|
2018-02-04 00:20:14 +00:00
|
|
|
EachWithGen<QueryFunc>(db->funcs, func.def->base, [&](QueryFunc& func1) {
|
|
|
|
queue.push(&func1);
|
|
|
|
});
|
2017-07-19 07:17:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Check for derived calls.
|
2018-02-04 00:20:14 +00:00
|
|
|
EachWithGen<QueryFunc>(db->funcs, root.derived, [&](QueryFunc& func1) {
|
|
|
|
queue.push(&func1);
|
|
|
|
});
|
2017-07-19 07:17:38 +00:00
|
|
|
while (!queue.empty()) {
|
2018-02-04 00:20:14 +00:00
|
|
|
QueryFunc& func = *queue.front();
|
2017-07-19 07:17:38 +00:00
|
|
|
queue.pop();
|
2017-10-17 05:44:58 +00:00
|
|
|
if (!func.callers.empty())
|
2017-07-19 07:17:38 +00:00
|
|
|
return true;
|
2018-02-04 00:20:14 +00:00
|
|
|
EachWithGen<QueryFunc>(db->funcs, func.derived, [&](QueryFunc& func1) {
|
|
|
|
queue.push(&func1);
|
|
|
|
});
|
2017-07-19 07:17:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-09-22 01:14:57 +00:00
|
|
|
std::vector<QueryFuncRef> GetCallersForAllBaseFunctions(QueryDatabase* db,
|
|
|
|
QueryFunc& root) {
|
2017-06-15 05:32:23 +00:00
|
|
|
std::vector<QueryFuncRef> callers;
|
2018-01-30 04:18:08 +00:00
|
|
|
if (!root.def)
|
|
|
|
return callers;
|
2017-06-15 05:32:23 +00:00
|
|
|
|
2018-02-04 00:20:14 +00:00
|
|
|
std::queue<QueryFunc*> queue;
|
|
|
|
EachWithGen<QueryFunc>(db->funcs, root.def->base, [&](QueryFunc& func1) {
|
|
|
|
queue.push(&func1);
|
|
|
|
});
|
2017-12-19 06:15:46 +00:00
|
|
|
while (!queue.empty()) {
|
2018-02-04 00:20:14 +00:00
|
|
|
QueryFunc& func = *queue.front();
|
2017-12-19 06:15:46 +00:00
|
|
|
queue.pop();
|
2017-06-15 05:32:23 +00:00
|
|
|
|
2017-12-19 06:15:46 +00:00
|
|
|
AddRange(&callers, func.callers);
|
|
|
|
if (func.def)
|
2018-02-04 00:20:14 +00:00
|
|
|
EachWithGen<QueryFunc>(db->funcs, func.def->base, [&](QueryFunc& func1) {
|
|
|
|
queue.push(&func1);
|
|
|
|
});
|
2017-06-15 05:32:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return callers;
|
|
|
|
}
|
|
|
|
|
2017-09-22 01:14:57 +00:00
|
|
|
std::vector<QueryFuncRef> GetCallersForAllDerivedFunctions(QueryDatabase* db,
|
|
|
|
QueryFunc& root) {
|
2017-06-15 05:32:23 +00:00
|
|
|
std::vector<QueryFuncRef> callers;
|
|
|
|
|
2018-02-04 00:20:14 +00:00
|
|
|
std::queue<QueryFunc*> queue;
|
|
|
|
EachWithGen<QueryFunc>(db->funcs, root.derived, [&](QueryFunc& func) {
|
|
|
|
queue.push(&func);
|
|
|
|
});
|
2017-06-15 05:32:23 +00:00
|
|
|
|
|
|
|
while (!queue.empty()) {
|
2018-02-04 00:20:14 +00:00
|
|
|
QueryFunc& func = *queue.front();
|
2017-06-15 05:32:23 +00:00
|
|
|
queue.pop();
|
|
|
|
|
2018-02-04 00:20:14 +00:00
|
|
|
EachWithGen<QueryFunc>(db->funcs, func.derived, [&](QueryFunc& func1) {
|
|
|
|
queue.push(&func1);
|
|
|
|
});
|
2017-10-17 05:44:58 +00:00
|
|
|
AddRange(&callers, func.callers);
|
2017-06-15 05:32:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return callers;
|
|
|
|
}
|
|
|
|
|
2017-09-22 01:14:57 +00:00
|
|
|
optional<lsPosition> GetLsPosition(WorkingFile* working_file,
|
|
|
|
const Position& position) {
|
2017-06-15 05:32:23 +00:00
|
|
|
if (!working_file)
|
2018-01-14 19:39:29 +00:00
|
|
|
return lsPosition(position.line, position.column);
|
2017-06-15 05:32:23 +00:00
|
|
|
|
2018-01-14 22:24:47 +00:00
|
|
|
int column = position.column;
|
2018-01-30 00:27:43 +00:00
|
|
|
optional<int> start =
|
|
|
|
working_file->GetBufferPosFromIndexPos(position.line, &column, false);
|
2017-06-15 05:32:23 +00:00
|
|
|
if (!start)
|
|
|
|
return nullopt;
|
|
|
|
|
2018-01-14 22:24:47 +00:00
|
|
|
return lsPosition(*start, column);
|
2017-06-15 05:32:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
optional<lsRange> GetLsRange(WorkingFile* working_file, const Range& location) {
|
|
|
|
if (!working_file) {
|
2018-01-30 00:27:43 +00:00
|
|
|
return lsRange(lsPosition(location.start.line, location.start.column),
|
|
|
|
lsPosition(location.end.line, location.end.column));
|
2017-06-15 05:32:23 +00:00
|
|
|
}
|
|
|
|
|
2018-01-14 22:24:47 +00:00
|
|
|
int start_column = location.start.column, end_column = location.end.column;
|
2018-01-30 00:27:43 +00:00
|
|
|
optional<int> start = working_file->GetBufferPosFromIndexPos(
|
|
|
|
location.start.line, &start_column, false);
|
|
|
|
optional<int> end = working_file->GetBufferPosFromIndexPos(location.end.line,
|
|
|
|
&end_column, true);
|
2017-06-15 05:32:23 +00:00
|
|
|
if (!start || !end)
|
|
|
|
return nullopt;
|
|
|
|
|
|
|
|
// If remapping end fails (end can never be < start), just guess that the
|
|
|
|
// final location didn't move. This only screws up the highlighted code
|
|
|
|
// region if we guess wrong, so not a big deal.
|
|
|
|
//
|
|
|
|
// Remapping fails often in C++ since there are a lot of "};" at the end of
|
|
|
|
// class/struct definitions.
|
|
|
|
if (*end < *start)
|
|
|
|
*end = *start + (location.end.line - location.start.line);
|
2018-01-15 06:53:51 +00:00
|
|
|
if (*start == *end && start_column > end_column)
|
|
|
|
end_column = start_column;
|
2017-06-15 05:32:23 +00:00
|
|
|
|
2018-01-14 22:24:47 +00:00
|
|
|
return lsRange(lsPosition(*start, start_column),
|
|
|
|
lsPosition(*end, end_column));
|
2017-06-15 05:32:23 +00:00
|
|
|
}
|
|
|
|
|
2017-09-22 01:14:57 +00:00
|
|
|
lsDocumentUri GetLsDocumentUri(QueryDatabase* db,
|
|
|
|
QueryFileId file_id,
|
|
|
|
std::string* path) {
|
2017-10-17 05:44:58 +00:00
|
|
|
QueryFile& file = db->files[file_id.id];
|
|
|
|
if (file.def) {
|
|
|
|
*path = file.def->path;
|
2017-06-15 05:32:23 +00:00
|
|
|
return lsDocumentUri::FromPath(*path);
|
2017-09-22 01:14:57 +00:00
|
|
|
} else {
|
2017-06-15 05:32:23 +00:00
|
|
|
*path = "";
|
|
|
|
return lsDocumentUri::FromPath("");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
lsDocumentUri GetLsDocumentUri(QueryDatabase* db, QueryFileId file_id) {
|
2017-10-17 05:44:58 +00:00
|
|
|
QueryFile& file = db->files[file_id.id];
|
|
|
|
if (file.def) {
|
|
|
|
return lsDocumentUri::FromPath(file.def->path);
|
2017-09-22 01:14:57 +00:00
|
|
|
} else {
|
2017-06-15 05:32:23 +00:00
|
|
|
return lsDocumentUri::FromPath("");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-22 01:14:57 +00:00
|
|
|
optional<lsLocation> GetLsLocation(QueryDatabase* db,
|
|
|
|
WorkingFiles* working_files,
|
2018-02-09 05:11:35 +00:00
|
|
|
Reference ref) {
|
2017-06-15 05:32:23 +00:00
|
|
|
std::string path;
|
2018-02-10 00:42:33 +00:00
|
|
|
QueryFileId file_id = GetFileId(db, ref);
|
|
|
|
if (!file_id.HasValue())
|
|
|
|
return nullopt;
|
|
|
|
lsDocumentUri uri = GetLsDocumentUri(db, file_id, &path);
|
2017-09-22 01:14:57 +00:00
|
|
|
optional<lsRange> range =
|
2018-02-09 05:11:35 +00:00
|
|
|
GetLsRange(working_files->GetFileByFilename(path), ref.range);
|
2017-06-15 05:32:23 +00:00
|
|
|
if (!range)
|
|
|
|
return nullopt;
|
|
|
|
return lsLocation(uri, *range);
|
|
|
|
}
|
|
|
|
|
2017-12-12 05:20:29 +00:00
|
|
|
std::vector<lsLocation> GetLsLocations(
|
2017-09-22 01:14:57 +00:00
|
|
|
QueryDatabase* db,
|
|
|
|
WorkingFiles* working_files,
|
2018-02-09 07:10:54 +00:00
|
|
|
const std::vector<Reference>& refs) {
|
2017-06-15 05:32:23 +00:00
|
|
|
std::unordered_set<lsLocation> unique_locations;
|
2018-02-09 07:10:54 +00:00
|
|
|
for (Reference ref : refs) {
|
2017-09-22 01:14:57 +00:00
|
|
|
optional<lsLocation> location =
|
2018-02-09 07:10:54 +00:00
|
|
|
GetLsLocation(db, working_files, ref);
|
2017-06-15 05:32:23 +00:00
|
|
|
if (!location)
|
|
|
|
continue;
|
|
|
|
unique_locations.insert(*location);
|
|
|
|
}
|
|
|
|
|
2017-12-12 05:20:29 +00:00
|
|
|
std::vector<lsLocation> result;
|
2017-06-15 05:32:23 +00:00
|
|
|
result.reserve(unique_locations.size());
|
|
|
|
result.assign(unique_locations.begin(), unique_locations.end());
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Returns a symbol. The symbol will have *NOT* have a location assigned.
|
2017-09-22 01:14:57 +00:00
|
|
|
optional<lsSymbolInformation> GetSymbolInfo(QueryDatabase* db,
|
|
|
|
WorkingFiles* working_files,
|
2018-02-09 17:42:10 +00:00
|
|
|
SymbolRef sym,
|
2017-12-19 05:31:19 +00:00
|
|
|
bool use_short_name) {
|
2018-02-09 17:42:10 +00:00
|
|
|
switch (sym.kind) {
|
2017-09-22 01:14:57 +00:00
|
|
|
case SymbolKind::File: {
|
2018-02-09 17:42:10 +00:00
|
|
|
QueryFile& file = db->files[sym.Idx()];
|
2017-10-17 05:44:58 +00:00
|
|
|
if (!file.def)
|
2018-02-09 17:42:10 +00:00
|
|
|
break;
|
2017-06-15 05:32:23 +00:00
|
|
|
|
2017-09-22 01:14:57 +00:00
|
|
|
lsSymbolInformation info;
|
2017-10-17 05:44:58 +00:00
|
|
|
info.name = file.def->path;
|
2017-09-22 01:14:57 +00:00
|
|
|
info.kind = lsSymbolKind::File;
|
|
|
|
return info;
|
2017-06-15 05:32:23 +00:00
|
|
|
}
|
2017-09-22 01:14:57 +00:00
|
|
|
case SymbolKind::Type: {
|
2018-02-09 17:42:10 +00:00
|
|
|
QueryType& type = sym.Type(db);
|
2017-10-17 05:44:58 +00:00
|
|
|
if (!type.def)
|
2018-02-09 17:42:10 +00:00
|
|
|
break;
|
2017-09-22 01:14:57 +00:00
|
|
|
|
|
|
|
lsSymbolInformation info;
|
2018-02-01 05:40:40 +00:00
|
|
|
if (use_short_name)
|
|
|
|
info.name = type.def->ShortName();
|
|
|
|
else
|
|
|
|
info.name = type.def->detailed_name;
|
2018-01-31 07:01:45 +00:00
|
|
|
if (type.def->detailed_name != type.def->ShortName())
|
2017-10-17 05:44:58 +00:00
|
|
|
info.containerName = type.def->detailed_name;
|
2018-01-24 08:19:42 +00:00
|
|
|
// TODO ClangSymbolKind -> lsSymbolKind
|
|
|
|
switch (type.def->kind) {
|
2018-01-30 00:27:43 +00:00
|
|
|
default:
|
|
|
|
info.kind = lsSymbolKind::Class;
|
|
|
|
break;
|
|
|
|
case ClangSymbolKind::Namespace:
|
|
|
|
info.kind = lsSymbolKind::Namespace;
|
|
|
|
break;
|
2018-01-24 08:19:42 +00:00
|
|
|
}
|
2017-09-22 01:14:57 +00:00
|
|
|
return info;
|
|
|
|
}
|
|
|
|
case SymbolKind::Func: {
|
2018-02-09 17:42:10 +00:00
|
|
|
QueryFunc& func = sym.Func(db);
|
2017-10-17 05:44:58 +00:00
|
|
|
if (!func.def)
|
2018-02-09 17:42:10 +00:00
|
|
|
break;
|
2017-09-22 01:14:57 +00:00
|
|
|
|
|
|
|
lsSymbolInformation info;
|
2018-02-01 05:40:40 +00:00
|
|
|
if (use_short_name)
|
|
|
|
info.name = func.def->ShortName();
|
|
|
|
else
|
|
|
|
info.name = func.def->detailed_name;
|
2017-10-17 05:44:58 +00:00
|
|
|
info.containerName = func.def->detailed_name;
|
2017-09-22 01:14:57 +00:00
|
|
|
info.kind = lsSymbolKind::Function;
|
|
|
|
|
2017-10-17 05:44:58 +00:00
|
|
|
if (func.def->declaring_type.has_value()) {
|
2018-02-05 18:12:28 +00:00
|
|
|
QueryType& container = db->types[func.def->declaring_type->id];
|
2017-10-17 05:44:58 +00:00
|
|
|
if (container.def)
|
2017-09-22 01:14:57 +00:00
|
|
|
info.kind = lsSymbolKind::Method;
|
|
|
|
}
|
|
|
|
|
|
|
|
return info;
|
|
|
|
}
|
|
|
|
case SymbolKind::Var: {
|
2018-02-09 17:42:10 +00:00
|
|
|
QueryVar& var = sym.Var(db);
|
2017-10-17 05:44:58 +00:00
|
|
|
if (!var.def)
|
2018-02-09 17:42:10 +00:00
|
|
|
break;
|
2017-09-22 01:14:57 +00:00
|
|
|
|
|
|
|
lsSymbolInformation info;
|
2018-02-01 05:40:40 +00:00
|
|
|
if (use_short_name)
|
|
|
|
info.name = var.def->ShortName();
|
|
|
|
else
|
|
|
|
info.name = var.def->detailed_name;
|
2017-10-17 05:44:58 +00:00
|
|
|
info.containerName = var.def->detailed_name;
|
2017-09-22 01:14:57 +00:00
|
|
|
info.kind = lsSymbolKind::Variable;
|
|
|
|
return info;
|
|
|
|
}
|
2018-02-09 17:42:10 +00:00
|
|
|
case SymbolKind::Invalid:
|
|
|
|
break;
|
|
|
|
}
|
2017-06-15 05:32:23 +00:00
|
|
|
|
|
|
|
return nullopt;
|
|
|
|
}
|
|
|
|
|
2018-01-29 04:39:41 +00:00
|
|
|
// TODO Sort only by range length, not |kind| or |idx|
|
2017-09-22 01:14:57 +00:00
|
|
|
std::vector<SymbolRef> FindSymbolsAtLocation(WorkingFile* working_file,
|
|
|
|
QueryFile* file,
|
|
|
|
lsPosition position) {
|
2017-06-15 05:32:23 +00:00
|
|
|
std::vector<SymbolRef> symbols;
|
|
|
|
symbols.reserve(1);
|
|
|
|
|
2018-01-14 19:39:29 +00:00
|
|
|
int target_line = position.line;
|
|
|
|
int target_column = position.character;
|
2017-06-15 05:32:23 +00:00
|
|
|
if (working_file) {
|
2018-01-15 01:16:24 +00:00
|
|
|
optional<int> index_line = working_file->GetIndexPosFromBufferPos(
|
|
|
|
target_line, &target_column, false);
|
2017-06-15 05:32:23 +00:00
|
|
|
if (index_line)
|
|
|
|
target_line = *index_line;
|
|
|
|
}
|
|
|
|
|
2018-02-09 17:42:10 +00:00
|
|
|
for (const SymbolRef& sym : file->def->all_symbols) {
|
|
|
|
if (sym.range.Contains(target_line, target_column))
|
|
|
|
symbols.push_back(sym);
|
2017-06-15 05:32:23 +00:00
|
|
|
}
|
|
|
|
|
2017-06-16 06:43:02 +00:00
|
|
|
// Order shorter ranges first, since they are more detailed/precise. This is
|
|
|
|
// important for macros which generate code so that we can resolving the
|
|
|
|
// macro argument takes priority over the entire macro body.
|
|
|
|
//
|
2017-12-23 16:01:43 +00:00
|
|
|
// Order SymbolKind::Var before SymbolKind::Type. Macro calls are treated as
|
|
|
|
// Var currently. If a macro expands to tokens led by a SymbolKind::Type, the
|
2017-12-18 01:50:19 +00:00
|
|
|
// macro and the Type have the same range. We want to find the macro
|
|
|
|
// definition instead of the Type definition.
|
|
|
|
//
|
|
|
|
// Then order functions before other types, which makes goto definition work
|
2017-06-16 06:43:02 +00:00
|
|
|
// better on constructors.
|
2018-01-30 00:27:43 +00:00
|
|
|
std::sort(symbols.begin(), symbols.end(),
|
|
|
|
[](const SymbolRef& a, const SymbolRef& b) {
|
2018-02-09 17:42:10 +00:00
|
|
|
int a_size = ComputeRangeSize(a.range);
|
|
|
|
int b_size = ComputeRangeSize(b.range);
|
2018-01-30 00:27:43 +00:00
|
|
|
|
|
|
|
if (a_size != b_size)
|
|
|
|
return a_size < b_size;
|
|
|
|
// operator> orders Var/Func before Type.
|
2018-02-09 17:42:10 +00:00
|
|
|
int t = static_cast<int>(a.kind) - static_cast<int>(b.kind);
|
2018-01-30 00:27:43 +00:00
|
|
|
if (t)
|
|
|
|
return t > 0;
|
2018-02-09 17:42:10 +00:00
|
|
|
return a.Idx() < b.Idx();
|
2018-01-30 00:27:43 +00:00
|
|
|
});
|
2017-06-15 05:32:23 +00:00
|
|
|
|
|
|
|
return symbols;
|
2017-12-20 06:20:44 +00:00
|
|
|
}
|
2017-12-24 01:30:52 +00:00
|
|
|
|
|
|
|
void EmitDiagnostics(WorkingFiles* working_files,
|
|
|
|
std::string path,
|
|
|
|
std::vector<lsDiagnostic> diagnostics) {
|
|
|
|
// Emit diagnostics.
|
|
|
|
Out_TextDocumentPublishDiagnostics out;
|
|
|
|
out.params.uri = lsDocumentUri::FromPath(path);
|
|
|
|
out.params.diagnostics = diagnostics;
|
|
|
|
QueueManager::WriteStdout(IpcId::TextDocumentPublishDiagnostics, out);
|
|
|
|
|
|
|
|
// Cache diagnostics so we can show fixits.
|
|
|
|
working_files->DoActionOnFile(path, [&](WorkingFile* working_file) {
|
|
|
|
if (working_file)
|
|
|
|
working_file->diagnostics_ = diagnostics;
|
|
|
|
});
|
2018-01-11 07:16:33 +00:00
|
|
|
}
|