#include "message_handler.h" #include "query_utils.h" #include "queue_manager.h" namespace { struct Ipc_CqueryMemberHierarchyInitial : public RequestMessage { const static IpcId kIpcId = IpcId::CqueryMemberHierarchyInitial; lsTextDocumentPositionParams params; }; MAKE_REFLECT_STRUCT(Ipc_CqueryMemberHierarchyInitial, id, params); REGISTER_IPC_MESSAGE(Ipc_CqueryMemberHierarchyInitial); struct Ipc_CqueryMemberHierarchyExpand : public RequestMessage { const static IpcId kIpcId = IpcId::CqueryMemberHierarchyExpand; struct Params { QueryTypeId type_id; }; Params params; }; MAKE_REFLECT_STRUCT(Ipc_CqueryMemberHierarchyExpand::Params, type_id); MAKE_REFLECT_STRUCT(Ipc_CqueryMemberHierarchyExpand, id, params); REGISTER_IPC_MESSAGE(Ipc_CqueryMemberHierarchyExpand); struct Out_CqueryMemberHierarchy : public lsOutMessage { struct Entry { std::string_view name; QueryTypeId type_id; lsLocation location; }; lsRequestId id; std::vector result; }; MAKE_REFLECT_STRUCT(Out_CqueryMemberHierarchy::Entry, name, type_id, location); MAKE_REFLECT_STRUCT(Out_CqueryMemberHierarchy, jsonrpc, id, result); std::vector BuildInitial(QueryDatabase* db, WorkingFiles* working_files, QueryTypeId root) { QueryType& root_type = db->types[root.id]; if (!root_type.def || !root_type.def->spell) return {}; optional def_loc = GetLsLocation(db, working_files, *root_type.def->spell); if (!def_loc) return {}; Out_CqueryMemberHierarchy::Entry entry; entry.type_id = root; entry.name = root_type.def->ShortName(); entry.location = *def_loc; return {entry}; } std::vector ExpandNode(QueryDatabase* db, WorkingFiles* working_files, QueryTypeId root) { QueryType& root_type = db->types[root.id]; if (!root_type.def) return {}; std::vector ret; EachWithGen(db->vars, root_type.def->vars, [&](QueryVar& var) { Out_CqueryMemberHierarchy::Entry entry; entry.name = var.def->ShortName(); entry.type_id = var.def->type ? *var.def->type : QueryTypeId(); if (var.def->spell) { optional loc = GetLsLocation(db, working_files, *var.def->spell); // TODO invalid location if (loc) entry.location = *loc; } ret.push_back(std::move(entry)); }); return ret; } struct CqueryMemberHierarchyInitialHandler : BaseMessageHandler { void Run(Ipc_CqueryMemberHierarchyInitial* request) override { QueryFile* file; if (!FindFileOrFail(db, project, request->id, request->params.textDocument.uri.GetPath(), &file)) return; WorkingFile* working_file = working_files->GetFileByFilename(file->def->path); Out_CqueryMemberHierarchy out; out.id = request->id; for (const SymbolRef& sym : FindSymbolsAtLocation(working_file, file, request->params.position)) { if (sym.kind == SymbolKind::Type) { out.result = BuildInitial(db, working_files, QueryTypeId(sym.id)); break; } if (sym.kind == SymbolKind::Var) { QueryVar& var = db->GetVar(sym); if (var.def && var.def->type) out.result = BuildInitial(db, working_files, *var.def->type); break; } } QueueManager::WriteStdout(IpcId::CqueryMemberHierarchyInitial, out); } }; REGISTER_MESSAGE_HANDLER(CqueryMemberHierarchyInitialHandler); struct CqueryMemberHierarchyExpandHandler : BaseMessageHandler { void Run(Ipc_CqueryMemberHierarchyExpand* request) override { Out_CqueryMemberHierarchy out; out.id = request->id; // |ExpandNode| uses -1 to indicate invalid |type_id|. if (request->params.type_id.HasValue()) out.result = ExpandNode(db, working_files, request->params.type_id); QueueManager::WriteStdout(IpcId::CqueryMemberHierarchyExpand, out); } }; REGISTER_MESSAGE_HANDLER(CqueryMemberHierarchyExpandHandler); } // namespace