diff --git a/src/command_line.cc b/src/command_line.cc index 6f73aba6..1d9782bd 100644 --- a/src/command_line.cc +++ b/src/command_line.cc @@ -526,6 +526,21 @@ optional GetLsLocation(QueryDatabase* db, WorkingFiles* working_file return lsLocation(uri, *range); } +NonElidedVector GetLsLocations(QueryDatabase* db, WorkingFiles* working_files, const std::vector& locations) { + std::unordered_set unique_locations; + for (const QueryLocation& query_location : locations) { + optional location = GetLsLocation(db, working_files, query_location); + if (!location) + continue; + unique_locations.insert(*location); + } + + NonElidedVector result; + 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. optional GetSymbolInfo(QueryDatabase* db, WorkingFiles* working_files, SymbolIdx symbol) { switch (symbol.kind) { @@ -606,7 +621,7 @@ void AddCodeLens( return; code_lens.range = *range; code_lens.command = lsCommand(); - code_lens.command->command = "superindex.showReferences"; + code_lens.command->command = "cquery.showReferences"; code_lens.command->arguments.uri = GetLsDocumentUri(common->db, loc.path); code_lens.command->arguments.position = code_lens.range.start; @@ -806,6 +821,10 @@ void RegisterMessageTypes() { MessageRegistry::instance()->Register(); MessageRegistry::instance()->Register(); MessageRegistry::instance()->Register(); + MessageRegistry::instance()->Register(); + MessageRegistry::instance()->Register(); + MessageRegistry::instance()->Register(); + MessageRegistry::instance()->Register(); } @@ -1344,6 +1363,126 @@ bool QueryDbMainLoop( break; } + case IpcId::CqueryVars: { + auto msg = static_cast(message.get()); + + QueryFile* file = FindFile(db, msg->params.textDocument.uri.GetPath()); + if (!file) { + std::cerr << "Unable to find file " << msg->params.textDocument.uri.GetPath() << std::endl; + break; + } + WorkingFile* working_file = working_files->GetFileByFilename(file->def.path); + + Out_LocationList response; + response.id = msg->id; + for (const SymbolRef& ref : FindSymbolsAtLocation(working_file, file, msg->params.position)) { + if (ref.idx.kind == SymbolKind::Type) { + optional& type = db->types[ref.idx.idx]; + if (!type) continue; + std::vector locations = ToQueryLocation(db, type->instances); + response.result = GetLsLocations(db, working_files, locations); + } + } + ipc->SendOutMessageToClient(IpcId::TextDocumentReferences, response); + break; + } + + case IpcId::CqueryCallers: { + auto msg = static_cast(message.get()); + + QueryFile* file = FindFile(db, msg->params.textDocument.uri.GetPath()); + if (!file) { + std::cerr << "Unable to find file " << msg->params.textDocument.uri.GetPath() << std::endl; + break; + } + WorkingFile* working_file = working_files->GetFileByFilename(file->def.path); + + Out_LocationList response; + response.id = msg->id; + for (const SymbolRef& ref : FindSymbolsAtLocation(working_file, file, msg->params.position)) { + if (ref.idx.kind == SymbolKind::Func) { + optional& func = db->funcs[ref.idx.idx]; + if (!func) continue; + std::vector locations = ToQueryLocation(db, func->callers); + response.result = GetLsLocations(db, working_files, locations); + } + } + ipc->SendOutMessageToClient(IpcId::TextDocumentReferences, response); + break; + } + + case IpcId::CqueryBase: { + auto msg = static_cast(message.get()); + + QueryFile* file = FindFile(db, msg->params.textDocument.uri.GetPath()); + if (!file) { + std::cerr << "Unable to find file " << msg->params.textDocument.uri.GetPath() << std::endl; + break; + } + WorkingFile* working_file = working_files->GetFileByFilename(file->def.path); + + Out_LocationList response; + response.id = msg->id; + for (const SymbolRef& ref : FindSymbolsAtLocation(working_file, file, msg->params.position)) { + if (ref.idx.kind == SymbolKind::Type) { + optional& type = db->types[ref.idx.idx]; + if (!type) continue; + std::vector locations = ToQueryLocation(db, type->def.parents); + response.result = GetLsLocations(db, working_files, locations); + } + else if (ref.idx.kind == SymbolKind::Func) { + optional& func = db->funcs[ref.idx.idx]; + if (!func) continue; + optional location = GetBaseDefinitionOrDeclarationSpelling(db, *func); + if (!location) continue; + optional ls_loc = GetLsLocation(db, working_files, *location); + if (!ls_loc) continue; + response.result.push_back(*ls_loc); + } + } + ipc->SendOutMessageToClient(IpcId::TextDocumentReferences, response); + break; + } + + case IpcId::CqueryDerived: { + auto msg = static_cast(message.get()); + + QueryFile* file = FindFile(db, msg->params.textDocument.uri.GetPath()); + if (!file) { + std::cerr << "Unable to find file " << msg->params.textDocument.uri.GetPath() << std::endl; + break; + } + WorkingFile* working_file = working_files->GetFileByFilename(file->def.path); + + Out_LocationList response; + response.id = msg->id; + for (const SymbolRef& ref : FindSymbolsAtLocation(working_file, file, msg->params.position)) { + if (ref.idx.kind == SymbolKind::Type) { + optional& type = db->types[ref.idx.idx]; + if (!type) continue; + std::vector locations = ToQueryLocation(db, type->derived); + response.result = GetLsLocations(db, working_files, locations); + } + else if (ref.idx.kind == SymbolKind::Func) { + optional& func = db->funcs[ref.idx.idx]; + if (!func) continue; + std::vector locations = ToQueryLocation(db, func->derived); + response.result = GetLsLocations(db, working_files, locations); + } + } + ipc->SendOutMessageToClient(IpcId::TextDocumentReferences, response); + break; + } + + + + + + + + + + case IpcId::TextDocumentDidOpen: { // NOTE: This function blocks code lens. If it starts taking a long time // we will need to find a way to unblock the code lens request. @@ -1708,7 +1847,7 @@ bool QueryDbMainLoop( code_lens.range.start.character += offset++; code_lens.command = lsCommand(); code_lens.command->title = "Base"; - code_lens.command->command = "superindex.goto"; + code_lens.command->command = "cquery.goto"; code_lens.command->arguments.uri = ls_base->uri; code_lens.command->arguments.position = ls_base->range.start; response.result.push_back(code_lens); @@ -1992,7 +2131,11 @@ void LanguageServerStdinLoop(IndexerConfig* config, std::unordered_mapSendMessage(IpcManager::Destination::Server, std::move(message)); break; } diff --git a/src/ipc.cc b/src/ipc.cc index 368a4a9a..6027fd95 100644 --- a/src/ipc.cc +++ b/src/ipc.cc @@ -41,9 +41,17 @@ const char* IpcIdToString(IpcId id) { case IpcId::WorkspaceSymbol: return "workspace/symbol"; - case IpcId::CqueryFreshenIndex: { + case IpcId::CqueryFreshenIndex: return "$cquery/freshenIndex"; - } + + case IpcId::CqueryVars: + return "$cquery/vars"; + case IpcId::CqueryCallers: + return "$cquery/callers"; + case IpcId::CqueryBase: + return "$cquery/base"; + case IpcId::CqueryDerived: + return "$cquery/derived"; case IpcId::Cout: return "$cout"; diff --git a/src/ipc.h b/src/ipc.h index c09d9065..29ede301 100644 --- a/src/ipc.h +++ b/src/ipc.h @@ -29,6 +29,12 @@ enum class IpcId : int { // Custom messages CqueryFreshenIndex, + // These are like DocumentReferences but show different types of data. + CqueryVars, // Show all variables of a type. + CqueryCallers, // Show all callers of a function. + CqueryBase, // Show base types/method. + CqueryDerived, // Show all derived types/methods. + // Internal implementation detail. Cout }; diff --git a/src/language_server_api.h b/src/language_server_api.h index aa50b2c4..a79ac7a0 100644 --- a/src/language_server_api.h +++ b/src/language_server_api.h @@ -1399,4 +1399,36 @@ struct Ipc_CqueryFreshenIndex : public IpcMessage { const static IpcId kIpcId = IpcId::CqueryFreshenIndex; lsRequestId id; }; -MAKE_REFLECT_STRUCT(Ipc_CqueryFreshenIndex, id); \ No newline at end of file +MAKE_REFLECT_STRUCT(Ipc_CqueryFreshenIndex, id); + + +// Vars, Callers, Derived, GotoParent +struct Ipc_CqueryVars : public IpcMessage { + const static IpcId kIpcId = IpcId::CqueryVars; + lsRequestId id; + lsTextDocumentPositionParams params; +}; +MAKE_REFLECT_STRUCT(Ipc_CqueryVars, id, params); +struct Ipc_CqueryCallers : public IpcMessage { + const static IpcId kIpcId = IpcId::CqueryCallers; + lsRequestId id; + lsTextDocumentPositionParams params; +}; +struct Ipc_CqueryBase : public IpcMessage { + const static IpcId kIpcId = IpcId::CqueryBase; + lsRequestId id; + lsTextDocumentPositionParams params; +}; +MAKE_REFLECT_STRUCT(Ipc_CqueryBase, id, params); +MAKE_REFLECT_STRUCT(Ipc_CqueryCallers, id, params); +struct Ipc_CqueryDerived : public IpcMessage { + const static IpcId kIpcId = IpcId::CqueryDerived; + lsRequestId id; + lsTextDocumentPositionParams params; +}; +MAKE_REFLECT_STRUCT(Ipc_CqueryDerived, id, params); +struct Out_LocationList : public lsOutMessage { + lsRequestId id; + NonElidedVector result; +}; +MAKE_REFLECT_STRUCT(Out_LocationList, jsonrpc, id, result); \ No newline at end of file