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
|
|
|
|
2017-12-06 05:03:38 +00:00
|
|
|
namespace {
|
2018-02-22 05:50:36 +00:00
|
|
|
struct Ipc_CqueryInheritanceHierarchy
|
|
|
|
: public RequestMessage<Ipc_CqueryInheritanceHierarchy> {
|
|
|
|
const static IpcId kIpcId = IpcId::CqueryInheritanceHierarchy;
|
2017-12-06 04:39:44 +00:00
|
|
|
lsTextDocumentPositionParams params;
|
|
|
|
};
|
2018-02-22 05:50:36 +00:00
|
|
|
MAKE_REFLECT_STRUCT(Ipc_CqueryInheritanceHierarchy, id, params);
|
|
|
|
REGISTER_IPC_MESSAGE(Ipc_CqueryInheritanceHierarchy);
|
2017-12-06 04:39:44 +00:00
|
|
|
|
2018-02-22 05:50:36 +00:00
|
|
|
struct Out_CqueryInheritanceHierarchy
|
|
|
|
: public lsOutMessage<Out_CqueryInheritanceHierarchy> {
|
2017-12-06 04:39:44 +00:00
|
|
|
struct TypeEntry {
|
2018-02-11 05:36:15 +00:00
|
|
|
std::string_view name;
|
2017-12-06 04:39:44 +00:00
|
|
|
optional<lsLocation> location;
|
2017-12-12 05:20:29 +00:00
|
|
|
std::vector<TypeEntry> children;
|
2017-12-06 04:39:44 +00:00
|
|
|
};
|
|
|
|
lsRequestId id;
|
|
|
|
optional<TypeEntry> result;
|
|
|
|
};
|
2018-02-22 05:50:36 +00:00
|
|
|
MAKE_REFLECT_STRUCT(Out_CqueryInheritanceHierarchy::TypeEntry,
|
2017-12-06 04:39:44 +00:00
|
|
|
name,
|
|
|
|
location,
|
|
|
|
children);
|
2018-02-22 05:50:36 +00:00
|
|
|
MAKE_REFLECT_STRUCT(Out_CqueryInheritanceHierarchy, jsonrpc, id, result);
|
2017-12-06 04:39:44 +00:00
|
|
|
|
2018-02-22 05:50:36 +00:00
|
|
|
std::vector<Out_CqueryInheritanceHierarchy::TypeEntry>
|
2017-12-06 04:39:44 +00:00
|
|
|
BuildParentInheritanceHierarchyForType(QueryDatabase* db,
|
|
|
|
WorkingFiles* working_files,
|
2018-02-04 00:20:14 +00:00
|
|
|
QueryType& root_type) {
|
2018-02-22 05:50:36 +00:00
|
|
|
std::vector<Out_CqueryInheritanceHierarchy::TypeEntry> parent_entries;
|
2018-02-18 07:09:05 +00:00
|
|
|
const QueryType::Def* def = root_type.AnyDef();
|
|
|
|
parent_entries.reserve(def->parents.size());
|
2017-12-06 04:39:44 +00:00
|
|
|
|
2018-02-21 01:50:48 +00:00
|
|
|
EachDefinedEntity(db->types, def->parents, [&](QueryType& parent_type) {
|
2018-02-22 05:50:36 +00:00
|
|
|
Out_CqueryInheritanceHierarchy::TypeEntry parent_entry;
|
2018-02-18 07:09:05 +00:00
|
|
|
const QueryType::Def* def1 = parent_type.AnyDef();
|
|
|
|
parent_entry.name = def1->detailed_name.c_str();
|
|
|
|
if (def1->spell)
|
|
|
|
parent_entry.location = GetLsLocation(db, working_files, *def1->spell);
|
2018-02-04 21:43:29 +00:00
|
|
|
parent_entry.children =
|
|
|
|
BuildParentInheritanceHierarchyForType(db, working_files, parent_type);
|
2017-12-06 04:39:44 +00:00
|
|
|
|
2018-02-04 21:43:29 +00:00
|
|
|
parent_entries.push_back(parent_entry);
|
|
|
|
});
|
2017-12-06 04:39:44 +00:00
|
|
|
|
|
|
|
return parent_entries;
|
|
|
|
}
|
|
|
|
|
2018-02-22 05:50:36 +00:00
|
|
|
optional<Out_CqueryInheritanceHierarchy::TypeEntry>
|
2017-12-06 04:39:44 +00:00
|
|
|
BuildInheritanceHierarchyForType(QueryDatabase* db,
|
|
|
|
WorkingFiles* working_files,
|
2018-02-04 00:20:14 +00:00
|
|
|
QueryType& root_type) {
|
2018-02-22 05:50:36 +00:00
|
|
|
Out_CqueryInheritanceHierarchy::TypeEntry entry;
|
2018-02-18 07:09:05 +00:00
|
|
|
const QueryType::Def* def = root_type.AnyDef();
|
2017-12-06 04:39:44 +00:00
|
|
|
|
|
|
|
// Name and location.
|
2018-02-18 07:09:05 +00:00
|
|
|
entry.name = def->detailed_name;
|
|
|
|
if (def->spell)
|
|
|
|
entry.location = GetLsLocation(db, working_files, *def->spell);
|
2017-12-06 04:39:44 +00:00
|
|
|
|
|
|
|
entry.children.reserve(root_type.derived.size());
|
|
|
|
|
|
|
|
// Base types.
|
2018-02-22 05:50:36 +00:00
|
|
|
Out_CqueryInheritanceHierarchy::TypeEntry base;
|
2017-12-06 04:39:44 +00:00
|
|
|
base.name = "[[Base]]";
|
|
|
|
base.location = entry.location;
|
|
|
|
base.children =
|
2018-02-04 00:20:14 +00:00
|
|
|
BuildParentInheritanceHierarchyForType(db, working_files, root_type);
|
2017-12-06 04:39:44 +00:00
|
|
|
if (!base.children.empty())
|
|
|
|
entry.children.push_back(base);
|
|
|
|
|
|
|
|
// Add derived.
|
2018-02-21 01:50:48 +00:00
|
|
|
EachDefinedEntity(db->types, root_type.derived, [&](QueryType& type) {
|
2018-02-04 00:20:14 +00:00
|
|
|
auto derived_entry =
|
|
|
|
BuildInheritanceHierarchyForType(db, working_files, type);
|
|
|
|
if (derived_entry)
|
|
|
|
entry.children.push_back(*derived_entry);
|
|
|
|
});
|
2017-12-06 04:39:44 +00:00
|
|
|
|
|
|
|
return entry;
|
|
|
|
}
|
|
|
|
|
2018-02-22 05:50:36 +00:00
|
|
|
std::vector<Out_CqueryInheritanceHierarchy::TypeEntry>
|
2017-12-06 04:39:44 +00:00
|
|
|
BuildParentInheritanceHierarchyForFunc(QueryDatabase* db,
|
|
|
|
WorkingFiles* working_files,
|
|
|
|
QueryFuncId root) {
|
2018-02-22 05:50:36 +00:00
|
|
|
std::vector<Out_CqueryInheritanceHierarchy::TypeEntry> entries;
|
2017-12-19 06:15:46 +00:00
|
|
|
|
2017-12-06 04:39:44 +00:00
|
|
|
QueryFunc& root_func = db->funcs[root.id];
|
2018-02-18 07:09:05 +00:00
|
|
|
const QueryFunc::Def* def = root_func.AnyDef();
|
|
|
|
if (!def || def->base.empty())
|
2017-12-06 04:39:44 +00:00
|
|
|
return {};
|
|
|
|
|
2018-02-18 07:09:05 +00:00
|
|
|
for (auto parent_id : def->base) {
|
2018-02-05 18:12:28 +00:00
|
|
|
QueryFunc& parent_func = db->funcs[parent_id.id];
|
2018-02-18 07:09:05 +00:00
|
|
|
const QueryFunc::Def* def1 = parent_func.AnyDef();
|
|
|
|
if (!def1)
|
2017-12-19 06:15:46 +00:00
|
|
|
continue;
|
2017-12-06 04:39:44 +00:00
|
|
|
|
2018-02-22 05:50:36 +00:00
|
|
|
Out_CqueryInheritanceHierarchy::TypeEntry parent_entry;
|
2018-02-18 07:09:05 +00:00
|
|
|
parent_entry.name = def1->detailed_name;
|
|
|
|
if (def1->spell)
|
|
|
|
parent_entry.location = GetLsLocation(db, working_files, *def1->spell);
|
2017-12-23 16:01:43 +00:00
|
|
|
parent_entry.children =
|
2018-02-05 18:12:28 +00:00
|
|
|
BuildParentInheritanceHierarchyForFunc(db, working_files, parent_id);
|
2017-12-19 06:15:46 +00:00
|
|
|
|
|
|
|
entries.push_back(parent_entry);
|
|
|
|
}
|
2017-12-06 04:39:44 +00:00
|
|
|
|
|
|
|
return entries;
|
|
|
|
}
|
|
|
|
|
2018-02-22 05:50:36 +00:00
|
|
|
optional<Out_CqueryInheritanceHierarchy::TypeEntry>
|
2017-12-06 04:39:44 +00:00
|
|
|
BuildInheritanceHierarchyForFunc(QueryDatabase* db,
|
|
|
|
WorkingFiles* working_files,
|
|
|
|
QueryFuncId root_id) {
|
|
|
|
QueryFunc& root_func = db->funcs[root_id.id];
|
2018-02-18 07:09:05 +00:00
|
|
|
const QueryFunc::Def* def = root_func.AnyDef();
|
|
|
|
if (!def)
|
2017-12-06 04:39:44 +00:00
|
|
|
return nullopt;
|
|
|
|
|
2018-02-22 05:50:36 +00:00
|
|
|
Out_CqueryInheritanceHierarchy::TypeEntry entry;
|
2017-12-06 04:39:44 +00:00
|
|
|
|
|
|
|
// Name and location.
|
2018-02-18 07:09:05 +00:00
|
|
|
entry.name = def->detailed_name;
|
|
|
|
if (def->spell)
|
2017-12-06 04:39:44 +00:00
|
|
|
entry.location =
|
2018-02-18 07:09:05 +00:00
|
|
|
GetLsLocation(db, working_files, *def->spell);
|
2017-12-06 04:39:44 +00:00
|
|
|
|
|
|
|
entry.children.reserve(root_func.derived.size());
|
|
|
|
|
|
|
|
// Base types.
|
2018-02-22 05:50:36 +00:00
|
|
|
Out_CqueryInheritanceHierarchy::TypeEntry base;
|
2017-12-06 04:39:44 +00:00
|
|
|
base.name = "[[Base]]";
|
|
|
|
base.location = entry.location;
|
|
|
|
base.children =
|
|
|
|
BuildParentInheritanceHierarchyForFunc(db, working_files, root_id);
|
|
|
|
if (!base.children.empty())
|
|
|
|
entry.children.push_back(base);
|
|
|
|
|
|
|
|
// Add derived.
|
2018-02-04 00:20:14 +00:00
|
|
|
for (auto derived : root_func.derived) {
|
2017-12-06 04:39:44 +00:00
|
|
|
auto derived_entry =
|
2018-02-05 18:12:28 +00:00
|
|
|
BuildInheritanceHierarchyForFunc(db, working_files, derived);
|
2017-12-06 04:39:44 +00:00
|
|
|
if (derived_entry)
|
|
|
|
entry.children.push_back(*derived_entry);
|
|
|
|
}
|
|
|
|
|
|
|
|
return entry;
|
|
|
|
}
|
|
|
|
|
2018-02-22 05:50:36 +00:00
|
|
|
struct CqueryInheritanceHierarchyHandler
|
|
|
|
: BaseMessageHandler<Ipc_CqueryInheritanceHierarchy> {
|
|
|
|
void Run(Ipc_CqueryInheritanceHierarchy* request) override {
|
2017-12-06 03:32:33 +00:00
|
|
|
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);
|
|
|
|
|
2018-02-22 05:50:36 +00:00
|
|
|
Out_CqueryInheritanceHierarchy out;
|
2017-12-06 03:32:33 +00:00
|
|
|
out.id = request->id;
|
|
|
|
|
2018-02-09 17:42:10 +00:00
|
|
|
for (const SymbolRef& sym :
|
2017-12-06 03:32:33 +00:00
|
|
|
FindSymbolsAtLocation(working_file, file, request->params.position)) {
|
2018-02-09 17:42:10 +00:00
|
|
|
if (sym.kind == SymbolKind::Type) {
|
2018-02-10 03:07:45 +00:00
|
|
|
QueryType& type = db->GetType(sym);
|
2018-02-18 07:09:05 +00:00
|
|
|
if (type.AnyDef())
|
2018-02-04 00:20:14 +00:00
|
|
|
out.result =
|
|
|
|
BuildInheritanceHierarchyForType(db, working_files, type);
|
2017-12-06 03:32:33 +00:00
|
|
|
break;
|
|
|
|
}
|
2018-02-09 17:42:10 +00:00
|
|
|
if (sym.kind == SymbolKind::Func) {
|
2017-12-06 03:32:33 +00:00
|
|
|
out.result = BuildInheritanceHierarchyForFunc(db, working_files,
|
2018-02-09 17:42:10 +00:00
|
|
|
QueryFuncId(sym.id));
|
2017-12-06 03:32:33 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-22 05:50:36 +00:00
|
|
|
QueueManager::WriteStdout(IpcId::CqueryInheritanceHierarchy, out);
|
2017-12-06 03:32:33 +00:00
|
|
|
}
|
|
|
|
};
|
2018-02-22 05:50:36 +00:00
|
|
|
REGISTER_MESSAGE_HANDLER(CqueryInheritanceHierarchyHandler);
|
2017-12-31 03:18:33 +00:00
|
|
|
} // namespace
|