ccls/src/messages/cquery_inheritance_hierarchy.cc

190 lines
6.2 KiB
C++
Raw Normal View History

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
namespace {
struct Ipc_CqueryInheritanceHierarchy
: public RequestMessage<Ipc_CqueryInheritanceHierarchy> {
const static IpcId kIpcId = IpcId::CqueryInheritanceHierarchy;
2017-12-06 04:39:44 +00:00
lsTextDocumentPositionParams params;
};
MAKE_REFLECT_STRUCT(Ipc_CqueryInheritanceHierarchy, id, params);
REGISTER_IPC_MESSAGE(Ipc_CqueryInheritanceHierarchy);
2017-12-06 04:39:44 +00:00
struct Out_CqueryInheritanceHierarchy
: public lsOutMessage<Out_CqueryInheritanceHierarchy> {
2017-12-06 04:39:44 +00:00
struct TypeEntry {
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;
};
MAKE_REFLECT_STRUCT(Out_CqueryInheritanceHierarchy::TypeEntry,
2017-12-06 04:39:44 +00:00
name,
location,
children);
MAKE_REFLECT_STRUCT(Out_CqueryInheritanceHierarchy, jsonrpc, id, result);
2017-12-06 04:39:44 +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) {
std::vector<Out_CqueryInheritanceHierarchy::TypeEntry> parent_entries;
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) {
Out_CqueryInheritanceHierarchy::TypeEntry parent_entry;
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;
}
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) {
Out_CqueryInheritanceHierarchy::TypeEntry entry;
const QueryType::Def* def = root_type.AnyDef();
2017-12-06 04:39:44 +00:00
// Name and location.
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.
Out_CqueryInheritanceHierarchy::TypeEntry base;
2017-12-06 04:39:44 +00:00
base.name = "[[Base]]";
base.location = entry.location;
base.children =
2018-02-22 07:34:32 +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;
}
std::vector<Out_CqueryInheritanceHierarchy::TypeEntry>
2017-12-06 04:39:44 +00:00
BuildParentInheritanceHierarchyForFunc(QueryDatabase* db,
WorkingFiles* working_files,
QueryFuncId root) {
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];
const QueryFunc::Def* def = root_func.AnyDef();
if (!def || def->base.empty())
2017-12-06 04:39:44 +00:00
return {};
for (auto parent_id : def->base) {
QueryFunc& parent_func = db->funcs[parent_id.id];
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
Out_CqueryInheritanceHierarchy::TypeEntry parent_entry;
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 =
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;
}
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];
const QueryFunc::Def* def = root_func.AnyDef();
if (!def)
2017-12-06 04:39:44 +00:00
return nullopt;
Out_CqueryInheritanceHierarchy::TypeEntry entry;
2017-12-06 04:39:44 +00:00
// Name and location.
entry.name = def->detailed_name;
if (def->spell)
2018-02-22 07:34:32 +00:00
entry.location = GetLsLocation(db, working_files, *def->spell);
2017-12-06 04:39:44 +00:00
entry.children.reserve(root_func.derived.size());
// Base types.
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 =
BuildInheritanceHierarchyForFunc(db, working_files, derived);
2017-12-06 04:39:44 +00:00
if (derived_entry)
entry.children.push_back(*derived_entry);
}
return entry;
}
struct CqueryInheritanceHierarchyHandler
: BaseMessageHandler<Ipc_CqueryInheritanceHierarchy> {
void Run(Ipc_CqueryInheritanceHierarchy* request) override {
2017-12-06 03:32:33 +00:00
QueryFile* file;
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_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);
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;
}
}
QueueManager::WriteStdout(IpcId::CqueryInheritanceHierarchy, out);
2017-12-06 03:32:33 +00:00
}
};
REGISTER_MESSAGE_HANDLER(CqueryInheritanceHierarchyHandler);
} // namespace