2017-12-06 03:32:33 +00:00
|
|
|
#include "message_handler.h"
|
|
|
|
#include "query_utils.h"
|
2017-12-29 16:29:47 +00:00
|
|
|
#include "queue_manager.h"
|
2017-12-06 03:32:33 +00:00
|
|
|
|
2018-01-10 08:21:55 +00:00
|
|
|
#include <loguru.hpp>
|
|
|
|
|
2018-01-13 06:13:08 +00:00
|
|
|
// FIXME Interop with VSCode, change std::string usr to Usr (uint64_t)
|
2017-12-06 05:03:38 +00:00
|
|
|
namespace {
|
2017-12-06 04:39:44 +00:00
|
|
|
struct Ipc_CqueryCallTreeInitial
|
2018-01-19 09:01:56 +00:00
|
|
|
: public RequestMessage<Ipc_CqueryCallTreeInitial> {
|
2017-12-06 04:39:44 +00:00
|
|
|
const static IpcId kIpcId = IpcId::CqueryCallTreeInitial;
|
|
|
|
lsTextDocumentPositionParams params;
|
|
|
|
};
|
|
|
|
MAKE_REFLECT_STRUCT(Ipc_CqueryCallTreeInitial, id, params);
|
|
|
|
REGISTER_IPC_MESSAGE(Ipc_CqueryCallTreeInitial);
|
|
|
|
|
2018-01-19 09:01:56 +00:00
|
|
|
struct Ipc_CqueryCallTreeExpand : public RequestMessage<Ipc_CqueryCallTreeExpand> {
|
|
|
|
const static IpcId kIpcId = IpcId::CqueryCallTreeExpand;
|
2017-12-06 04:39:44 +00:00
|
|
|
struct Params {
|
|
|
|
std::string usr;
|
|
|
|
};
|
|
|
|
Params params;
|
|
|
|
};
|
|
|
|
MAKE_REFLECT_STRUCT(Ipc_CqueryCallTreeExpand::Params, usr);
|
|
|
|
MAKE_REFLECT_STRUCT(Ipc_CqueryCallTreeExpand, id, params);
|
|
|
|
REGISTER_IPC_MESSAGE(Ipc_CqueryCallTreeExpand);
|
|
|
|
|
|
|
|
struct Out_CqueryCallTree : public lsOutMessage<Out_CqueryCallTree> {
|
|
|
|
enum class CallType { Direct = 0, Base = 1, Derived = 2 };
|
|
|
|
struct CallEntry {
|
|
|
|
std::string name;
|
|
|
|
std::string usr;
|
|
|
|
lsLocation location;
|
|
|
|
bool hasCallers = true;
|
|
|
|
CallType callType = CallType::Direct;
|
|
|
|
};
|
|
|
|
|
|
|
|
lsRequestId id;
|
2017-12-12 05:20:29 +00:00
|
|
|
std::vector<CallEntry> result;
|
2017-12-06 04:39:44 +00:00
|
|
|
};
|
|
|
|
MAKE_REFLECT_TYPE_PROXY(Out_CqueryCallTree::CallType, int);
|
|
|
|
MAKE_REFLECT_STRUCT(Out_CqueryCallTree::CallEntry,
|
|
|
|
name,
|
|
|
|
usr,
|
|
|
|
location,
|
|
|
|
hasCallers,
|
|
|
|
callType);
|
|
|
|
MAKE_REFLECT_STRUCT(Out_CqueryCallTree, jsonrpc, id, result);
|
|
|
|
|
2017-12-12 05:20:29 +00:00
|
|
|
std::vector<Out_CqueryCallTree::CallEntry> BuildInitialCallTree(
|
2017-12-06 04:39:44 +00:00
|
|
|
QueryDatabase* db,
|
|
|
|
WorkingFiles* working_files,
|
|
|
|
QueryFuncId root) {
|
|
|
|
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);
|
|
|
|
if (!def_loc)
|
|
|
|
return {};
|
|
|
|
|
|
|
|
Out_CqueryCallTree::CallEntry entry;
|
|
|
|
entry.name = root_func.def->short_name;
|
2018-01-13 06:13:08 +00:00
|
|
|
entry.usr = std::to_string(root_func.usr);
|
2017-12-06 04:39:44 +00:00
|
|
|
entry.location = *def_loc;
|
|
|
|
entry.hasCallers = HasCallersOnSelfOrBaseOrDerived(db, root_func);
|
2017-12-12 05:20:29 +00:00
|
|
|
std::vector<Out_CqueryCallTree::CallEntry> result;
|
2017-12-06 04:39:44 +00:00
|
|
|
result.push_back(entry);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2017-12-12 05:20:29 +00:00
|
|
|
std::vector<Out_CqueryCallTree::CallEntry> BuildExpandCallTree(
|
2017-12-06 04:39:44 +00:00
|
|
|
QueryDatabase* db,
|
|
|
|
WorkingFiles* working_files,
|
|
|
|
QueryFuncId root) {
|
|
|
|
QueryFunc& root_func = db->funcs[root.id];
|
|
|
|
if (!root_func.def)
|
|
|
|
return {};
|
|
|
|
|
2017-12-12 05:20:29 +00:00
|
|
|
std::vector<Out_CqueryCallTree::CallEntry> result;
|
2017-12-06 04:39:44 +00:00
|
|
|
std::unordered_set<QueryLocation> seen_locations;
|
|
|
|
|
|
|
|
auto handle_caller = [&](QueryFuncRef caller,
|
|
|
|
Out_CqueryCallTree::CallType call_type) {
|
|
|
|
optional<lsLocation> call_location =
|
|
|
|
GetLsLocation(db, working_files, caller.loc);
|
|
|
|
if (!call_location)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// TODO: REMOVE |seen_locations| once we fix the querydb update bugs
|
|
|
|
// TODO: REMOVE |seen_locations| once we fix the querydb update bugs
|
|
|
|
// TODO: REMOVE |seen_locations| once we fix the querydb update bugs
|
|
|
|
// TODO: REMOVE |seen_locations| once we fix the querydb update bugs
|
|
|
|
// TODO: REMOVE |seen_locations| once we fix the querydb update bugs
|
|
|
|
// TODO: REMOVE |seen_locations| once we fix the querydb update bugs
|
|
|
|
// TODO: REMOVE |seen_locations| once we fix the querydb update bugs
|
|
|
|
// TODO: REMOVE |seen_locations| once we fix the querydb update bugs
|
|
|
|
// TODO: REMOVE |seen_locations| once we fix the querydb update bugs
|
|
|
|
// TODO: REMOVE |seen_locations| once we fix the querydb update bugs
|
|
|
|
// TODO: REMOVE |seen_locations| once we fix the querydb update bugs
|
|
|
|
// TODO: REMOVE |seen_locations| once we fix the querydb update bugs
|
|
|
|
// TODO: basically, querydb gets duplicate references inserted into it.
|
2018-01-11 05:16:46 +00:00
|
|
|
// if (!seen_locations.insert(caller.loc).second) {
|
|
|
|
// LOG_S(ERROR) << "!!!! FIXME DUPLICATE REFERENCE IN QUERYDB" <<
|
|
|
|
// std::endl; return;
|
|
|
|
//}
|
2017-12-06 04:39:44 +00:00
|
|
|
|
|
|
|
if (caller.has_id()) {
|
|
|
|
QueryFunc& call_func = db->funcs[caller.id_.id];
|
|
|
|
if (!call_func.def)
|
|
|
|
return;
|
|
|
|
|
|
|
|
Out_CqueryCallTree::CallEntry call_entry;
|
2018-01-07 19:18:07 +00:00
|
|
|
call_entry.name = call_func.def->short_name;
|
2018-01-13 06:13:08 +00:00
|
|
|
call_entry.usr = std::to_string(call_func.usr);
|
2017-12-06 04:39:44 +00:00
|
|
|
call_entry.location = *call_location;
|
|
|
|
call_entry.hasCallers = HasCallersOnSelfOrBaseOrDerived(db, call_func);
|
|
|
|
call_entry.callType = call_type;
|
|
|
|
result.push_back(call_entry);
|
|
|
|
} else {
|
|
|
|
// TODO: See if we can do a better job here. Need more information from
|
|
|
|
// the indexer.
|
|
|
|
Out_CqueryCallTree::CallEntry call_entry;
|
|
|
|
call_entry.name = "Likely Constructor";
|
|
|
|
call_entry.usr = "no_usr";
|
|
|
|
call_entry.location = *call_location;
|
|
|
|
call_entry.hasCallers = false;
|
|
|
|
call_entry.callType = call_type;
|
|
|
|
result.push_back(call_entry);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
std::vector<QueryFuncRef> base_callers =
|
|
|
|
GetCallersForAllBaseFunctions(db, root_func);
|
|
|
|
std::vector<QueryFuncRef> derived_callers =
|
|
|
|
GetCallersForAllDerivedFunctions(db, root_func);
|
|
|
|
result.reserve(root_func.callers.size() + base_callers.size() +
|
|
|
|
derived_callers.size());
|
|
|
|
|
|
|
|
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.
|
|
|
|
if (caller.id_ == root)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
handle_caller(caller, Out_CqueryCallTree::CallType::Base);
|
|
|
|
}
|
|
|
|
for (QueryFuncRef caller : derived_callers)
|
|
|
|
handle_caller(caller, Out_CqueryCallTree::CallType::Derived);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2017-12-06 03:32:33 +00:00
|
|
|
struct CqueryCallTreeInitialHandler
|
|
|
|
: BaseMessageHandler<Ipc_CqueryCallTreeInitial> {
|
|
|
|
void Run(Ipc_CqueryCallTreeInitial* request) override {
|
|
|
|
QueryFile* file;
|
2017-12-31 03:18:33 +00:00
|
|
|
if (!FindFileOrFail(db, project, request->id,
|
2017-12-06 03:32:33 +00:00
|
|
|
request->params.textDocument.uri.GetPath(), &file)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
WorkingFile* working_file =
|
|
|
|
working_files->GetFileByFilename(file->def->path);
|
|
|
|
|
|
|
|
Out_CqueryCallTree out;
|
|
|
|
out.id = request->id;
|
|
|
|
|
|
|
|
for (const SymbolRef& ref :
|
|
|
|
FindSymbolsAtLocation(working_file, file, request->params.position)) {
|
|
|
|
if (ref.idx.kind == SymbolKind::Func) {
|
|
|
|
out.result =
|
|
|
|
BuildInitialCallTree(db, working_files, QueryFuncId(ref.idx.idx));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-24 00:25:18 +00:00
|
|
|
QueueManager::WriteStdout(IpcId::CqueryCallTreeInitial, out);
|
2017-12-06 03:32:33 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
REGISTER_MESSAGE_HANDLER(CqueryCallTreeInitialHandler);
|
|
|
|
|
|
|
|
struct CqueryCallTreeExpandHandler
|
|
|
|
: BaseMessageHandler<Ipc_CqueryCallTreeExpand> {
|
|
|
|
void Run(Ipc_CqueryCallTreeExpand* request) override {
|
|
|
|
Out_CqueryCallTree out;
|
|
|
|
out.id = request->id;
|
|
|
|
|
2018-01-19 15:55:48 +00:00
|
|
|
// FIXME Change VSCode plugin to use number representation of USR hash
|
|
|
|
QueryFuncId func_id = db->GetQueryFuncIdFromUsr(std::stoull(request->params.usr));
|
|
|
|
if (func_id.id != QueryFuncId::INVALID_ID)
|
|
|
|
out.result = BuildExpandCallTree(db, working_files, func_id);
|
2017-12-06 03:32:33 +00:00
|
|
|
|
2017-12-24 00:25:18 +00:00
|
|
|
QueueManager::WriteStdout(IpcId::CqueryCallTreeExpand, out);
|
2017-12-06 03:32:33 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
REGISTER_MESSAGE_HANDLER(CqueryCallTreeExpandHandler);
|
2017-12-31 03:18:33 +00:00
|
|
|
} // namespace
|