diff --git a/src/command_line.cc b/src/command_line.cc index fd975b21..38b73374 100644 --- a/src/command_line.cc +++ b/src/command_line.cc @@ -128,6 +128,23 @@ optional GetDefinitionSpellingOfSymbol(QueryableDatabase* db, } +std::string GetHoverForSymbol(QueryableDatabase* db, const SymbolIdx& symbol) { + switch (symbol.kind) { + case SymbolKind::Type: + return db->types[symbol.idx].def.qualified_name; + case SymbolKind::Func: + return db->funcs[symbol.idx].def.hover; + case SymbolKind::Var: + return db->vars[symbol.idx].def.hover; + case SymbolKind::File: + case SymbolKind::Invalid: { + assert(false && "unexpected"); + break; + } + } + return ""; +} + std::vector ToQueryableLocation(QueryableDatabase* db, const std::vector& refs) { std::vector locs; locs.reserve(refs.size()); @@ -521,6 +538,7 @@ std::unique_ptr BuildIpcMessageQueue(const std::string& name, s RegisterId(ipc.get()); RegisterId(ipc.get()); RegisterId(ipc.get()); + RegisterId(ipc.get()); RegisterId(ipc.get()); RegisterId(ipc.get()); RegisterId(ipc.get()); @@ -543,6 +561,7 @@ void RegisterMessageTypes() { MessageRegistry::instance()->Register(); MessageRegistry::instance()->Register(); MessageRegistry::instance()->Register(); + MessageRegistry::instance()->Register(); MessageRegistry::instance()->Register(); MessageRegistry::instance()->Register(); MessageRegistry::instance()->Register(); @@ -899,6 +918,38 @@ void QueryDbMainLoop( break; } + case IpcId::TextDocumentHover: { + auto msg = static_cast(message.get()); + + QueryableFile* file = FindFile(db, msg->params.textDocument.uri.GetPath()); + if (!file) { + std::cerr << "Unable to find file " << msg->params.textDocument.uri.GetPath() << std::endl; + break; + } + Out_TextDocumentHover response; + response.id = msg->id; + + int target_line = msg->params.position.line + 1; + int target_column = msg->params.position.character + 1; + for (const SymbolRef& ref : file->def.all_symbols) { + if (ref.loc.range.start.line >= target_line && ref.loc.range.end.line <= target_line && + ref.loc.range.start.column <= target_column && ref.loc.range.end.column >= target_column) { + + // Found symbol. Return references. + optional ls_range = GetLsRange(working_files->GetFileByFilename(file->def.usr), ref.loc.range); + if (!ls_range) + continue; + + response.result.contents = GetHoverForSymbol(db, ref.idx); + response.result.range = *ls_range; + break; + } + } + + SendOutMessageToClient(language_client, response); + break; + } + case IpcId::TextDocumentReferences: { auto msg = static_cast(message.get()); @@ -911,11 +962,9 @@ void QueryDbMainLoop( Out_TextDocumentReferences response; response.id = msg->id; - // TODO: Edge cases (whitespace, etc) will work a lot better - // if we store range information instead of hacking it. + // TODO: consider refactoring into FindSymbolsAtLocation(file); int target_line = msg->params.position.line + 1; int target_column = msg->params.position.character + 1; - for (const SymbolRef& ref : file->def.all_symbols) { if (ref.loc.range.start.line >= target_line && ref.loc.range.end.line <= target_line && ref.loc.range.start.column <= target_column && ref.loc.range.end.column >= target_column) { @@ -1233,7 +1282,10 @@ void LanguageServerStdinLoop(IpcMessageQueue* ipc) { response.result.capabilities.codeLensProvider->resolveProvider = false; response.result.capabilities.definitionProvider = true; + response.result.capabilities.hoverProvider = true; + response.result.capabilities.referencesProvider = true; + response.result.capabilities.documentSymbolProvider = true; response.result.capabilities.workspaceSymbolProvider = true; @@ -1258,6 +1310,7 @@ void LanguageServerStdinLoop(IpcMessageQueue* ipc) { case IpcId::TextDocumentDidSave: case IpcId::TextDocumentCompletion: case IpcId::TextDocumentDefinition: + case IpcId::TextDocumentHover: case IpcId::TextDocumentReferences: case IpcId::TextDocumentDocumentSymbol: case IpcId::TextDocumentCodeLens: diff --git a/src/indexer.cc b/src/indexer.cc index 3143b992..552081e4 100644 --- a/src/indexer.cc +++ b/src/indexer.cc @@ -781,6 +781,8 @@ void indexDeclaration(CXClientData client_data, const CXIdxDeclInfo* decl) { var_def->def.short_name = decl->entityInfo->name; var_def->def.qualified_name = ns->QualifiedName(decl->semanticContainer, var_def->def.short_name); + var_def->def.hover = clang::ToString(clang_getTypeSpelling(clang_getCursorType(decl->cursor))); + //} if (decl->isDefinition) { @@ -885,6 +887,13 @@ void indexDeclaration(CXClientData client_data, const CXIdxDeclInfo* decl) { decl->semanticContainer, func_def->def.short_name); //} + // TODO: we should build this ourselves. It doesn't include parameter names for functions. + func_def->def.hover = decl_cursor.get_type_description(); + + // TODO: return type + //decl_cursor.get_type_description() + //func_def->def.return_type = + bool is_pure_virtual = clang_CXXMethod_isPureVirtual(decl->cursor); bool is_ctor_or_dtor = decl->entityInfo->kind == CXIdxEntity_CXXConstructor || diff --git a/src/indexer.h b/src/indexer.h index 6e9042bc..2d04718c 100644 --- a/src/indexer.h +++ b/src/indexer.h @@ -221,6 +221,7 @@ struct FuncDefDefinitionData { std::string usr; std::string short_name; std::string qualified_name; + std::string hover; optional definition_spelling; optional definition_extent; @@ -246,6 +247,7 @@ struct FuncDefDefinitionData { other) const { return usr == other.usr && short_name == other.short_name && qualified_name == other.qualified_name && + hover == other.hover && definition_spelling == other.definition_spelling && definition_extent == other.definition_extent && declaring_type == other.declaring_type && base == other.base && @@ -271,6 +273,7 @@ void Reflect( REFLECT_MEMBER(usr); REFLECT_MEMBER(short_name); REFLECT_MEMBER(qualified_name); + REFLECT_MEMBER(hover); REFLECT_MEMBER(definition); REFLECT_MEMBER(declaring_type); REFLECT_MEMBER(base); @@ -328,6 +331,7 @@ struct VarDefDefinitionData { std::string usr; std::string short_name; std::string qualified_name; + std::string hover; optional declaration; // TODO: definitions should be a list of ranges, since there can be more // than one - when?? @@ -347,6 +351,7 @@ struct VarDefDefinitionData { other) const { return usr == other.usr && short_name == other.short_name && qualified_name == other.qualified_name && + hover == other.hover && declaration == other.declaration && definition_spelling == other.definition_spelling && definition_extent == other.definition_extent && @@ -370,6 +375,7 @@ void Reflect(TVisitor& visitor, REFLECT_MEMBER(usr); REFLECT_MEMBER(short_name); REFLECT_MEMBER(qualified_name); + REFLECT_MEMBER(hover); REFLECT_MEMBER(definition_spelling); REFLECT_MEMBER(definition_extent); REFLECT_MEMBER(variable_type); diff --git a/src/ipc.cc b/src/ipc.cc index 6047b90a..3a3eb633 100644 --- a/src/ipc.cc +++ b/src/ipc.cc @@ -22,6 +22,8 @@ const char* IpcIdToString(IpcId id) { return "textDocument/completion"; case IpcId::TextDocumentDefinition: return "textDocument/definition"; + case IpcId::TextDocumentHover: + return "textDocument/hover"; case IpcId::TextDocumentReferences: return "textDocument/references"; case IpcId::TextDocumentDocumentSymbol: diff --git a/src/ipc.h b/src/ipc.h index 41f4af5e..388b8bd7 100644 --- a/src/ipc.h +++ b/src/ipc.h @@ -16,6 +16,7 @@ enum class IpcId : int { TextDocumentDidSave, TextDocumentCompletion, TextDocumentDefinition, + TextDocumentHover, TextDocumentReferences, TextDocumentDocumentSymbol, TextDocumentCodeLens, diff --git a/src/language_server_api.h b/src/language_server_api.h index 6092f246..9b79d582 100644 --- a/src/language_server_api.h +++ b/src/language_server_api.h @@ -1131,6 +1131,26 @@ struct Out_TextDocumentDefinition : public lsOutMessage { + const static IpcId kIpcId = IpcId::TextDocumentHover; + + lsRequestId id; + lsTextDocumentPositionParams params; +}; +MAKE_REFLECT_STRUCT(Ipc_TextDocumentHover, id, params); +struct Out_TextDocumentHover : public lsOutMessage { + struct Result { + std::string contents; + optional range; + }; + + lsRequestId id; + Result result; +}; +MAKE_REFLECT_STRUCT(Out_TextDocumentHover::Result, contents, range); +MAKE_REFLECT_STRUCT(Out_TextDocumentHover, jsonrpc, id, result); + // References struct Ipc_TextDocumentReferences : public IpcMessage { struct lsReferenceContext { diff --git a/src/libclangmm/Cursor.cc b/src/libclangmm/Cursor.cc index b8299ab0..5e27d4a1 100644 --- a/src/libclangmm/Cursor.cc +++ b/src/libclangmm/Cursor.cc @@ -186,6 +186,11 @@ bool Cursor::is_valid_kind() const { } std::string Cursor::get_type_description() const { + auto type = clang_getCursorType(cx_cursor); + return clang::ToString(clang_getTypeSpelling(type)); + + + std::string spelling; auto referenced = clang_getCursorReferenced(cx_cursor); diff --git a/src/message_queue.cc b/src/message_queue.cc index 9db91a24..ad84e5a8 100644 --- a/src/message_queue.cc +++ b/src/message_queue.cc @@ -134,7 +134,7 @@ struct MessageQueue::BufferMetadata { // Reset buffer. void reset() { total_message_bytes_ = 0; } - // Total number of used bytes exluding the sizeof this metadata object. + // Total number of used bytes excluding the sizeof this metadata object. void add_used_bytes(size_t used_bytes) { total_message_bytes_ += used_bytes; } // The total number of bytes in use. diff --git a/src/query.cc b/src/query.cc index 2f7f2d8e..8b4289d5 100644 --- a/src/query.cc +++ b/src/query.cc @@ -36,6 +36,7 @@ QueryableFuncDef::DefUpdate ToQuery(const IdMap& id_map, const IndexedFuncDef::D QueryableFuncDef::DefUpdate result(func.usr); result.short_name = func.short_name; result.qualified_name = func.qualified_name; + result.hover = func.hover; result.definition_spelling = id_map.ToQuery(func.definition_spelling); result.definition_extent = id_map.ToQuery(func.definition_extent); result.declaring_type = id_map.ToQuery(func.declaring_type); @@ -50,6 +51,7 @@ QueryableVarDef::DefUpdate ToQuery(const IdMap& id_map, const IndexedVarDef::Def QueryableVarDef::DefUpdate result(var.usr); result.short_name = var.short_name; result.qualified_name = var.qualified_name; + result.hover = var.hover; result.declaration = id_map.ToQuery(var.declaration); result.definition_spelling = id_map.ToQuery(var.definition_spelling); result.definition_extent = id_map.ToQuery(var.definition_extent); diff --git a/src/serializer.cc b/src/serializer.cc index 3a1f5299..32428943 100644 --- a/src/serializer.cc +++ b/src/serializer.cc @@ -153,6 +153,7 @@ void Reflect(TVisitor& visitor, IndexedFuncDef& value) { REFLECT_MEMBER2("usr", value.def.usr); REFLECT_MEMBER2("short_name", value.def.short_name); REFLECT_MEMBER2("qualified_name", value.def.qualified_name); + REFLECT_MEMBER2("hover", value.def.hover); REFLECT_MEMBER2("declarations", value.declarations); REFLECT_MEMBER2("definition_spelling", value.def.definition_spelling); REFLECT_MEMBER2("definition_extent", value.def.definition_extent); @@ -188,6 +189,7 @@ void Reflect(TVisitor& visitor, IndexedVarDef& value) { REFLECT_MEMBER2("usr", value.def.usr); REFLECT_MEMBER2("short_name", value.def.short_name); REFLECT_MEMBER2("qualified_name", value.def.qualified_name); + REFLECT_MEMBER2("hover", value.def.hover); REFLECT_MEMBER2("declaration", value.def.declaration); REFLECT_MEMBER2("definition_spelling", value.def.definition_spelling); REFLECT_MEMBER2("definition_extent", value.def.definition_extent);