Support textDocument/hover (ie, hover over symbol to see type)

This commit is contained in:
Jacob Dufault 2017-04-13 22:18:02 -07:00
parent fe0b5cb79c
commit 4f770befee
10 changed files with 104 additions and 4 deletions

View File

@ -128,6 +128,23 @@ optional<QueryableLocation> 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<QueryableLocation> ToQueryableLocation(QueryableDatabase* db, const std::vector<QueryFuncRef>& refs) { std::vector<QueryableLocation> ToQueryableLocation(QueryableDatabase* db, const std::vector<QueryFuncRef>& refs) {
std::vector<QueryableLocation> locs; std::vector<QueryableLocation> locs;
locs.reserve(refs.size()); locs.reserve(refs.size());
@ -521,6 +538,7 @@ std::unique_ptr<IpcMessageQueue> BuildIpcMessageQueue(const std::string& name, s
RegisterId<Ipc_TextDocumentDidSave>(ipc.get()); RegisterId<Ipc_TextDocumentDidSave>(ipc.get());
RegisterId<Ipc_TextDocumentComplete>(ipc.get()); RegisterId<Ipc_TextDocumentComplete>(ipc.get());
RegisterId<Ipc_TextDocumentDefinition>(ipc.get()); RegisterId<Ipc_TextDocumentDefinition>(ipc.get());
RegisterId<Ipc_TextDocumentHover>(ipc.get());
RegisterId<Ipc_TextDocumentReferences>(ipc.get()); RegisterId<Ipc_TextDocumentReferences>(ipc.get());
RegisterId<Ipc_TextDocumentDocumentSymbol>(ipc.get()); RegisterId<Ipc_TextDocumentDocumentSymbol>(ipc.get());
RegisterId<Ipc_TextDocumentCodeLens>(ipc.get()); RegisterId<Ipc_TextDocumentCodeLens>(ipc.get());
@ -543,6 +561,7 @@ void RegisterMessageTypes() {
MessageRegistry::instance()->Register<Ipc_TextDocumentDidSave>(); MessageRegistry::instance()->Register<Ipc_TextDocumentDidSave>();
MessageRegistry::instance()->Register<Ipc_TextDocumentComplete>(); MessageRegistry::instance()->Register<Ipc_TextDocumentComplete>();
MessageRegistry::instance()->Register<Ipc_TextDocumentDefinition>(); MessageRegistry::instance()->Register<Ipc_TextDocumentDefinition>();
MessageRegistry::instance()->Register<Ipc_TextDocumentHover>();
MessageRegistry::instance()->Register<Ipc_TextDocumentReferences>(); MessageRegistry::instance()->Register<Ipc_TextDocumentReferences>();
MessageRegistry::instance()->Register<Ipc_TextDocumentDocumentSymbol>(); MessageRegistry::instance()->Register<Ipc_TextDocumentDocumentSymbol>();
MessageRegistry::instance()->Register<Ipc_TextDocumentCodeLens>(); MessageRegistry::instance()->Register<Ipc_TextDocumentCodeLens>();
@ -899,6 +918,38 @@ void QueryDbMainLoop(
break; break;
} }
case IpcId::TextDocumentHover: {
auto msg = static_cast<Ipc_TextDocumentHover*>(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<lsRange> 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: { case IpcId::TextDocumentReferences: {
auto msg = static_cast<Ipc_TextDocumentReferences*>(message.get()); auto msg = static_cast<Ipc_TextDocumentReferences*>(message.get());
@ -911,11 +962,9 @@ void QueryDbMainLoop(
Out_TextDocumentReferences response; Out_TextDocumentReferences response;
response.id = msg->id; response.id = msg->id;
// TODO: Edge cases (whitespace, etc) will work a lot better // TODO: consider refactoring into FindSymbolsAtLocation(file);
// if we store range information instead of hacking it.
int target_line = msg->params.position.line + 1; int target_line = msg->params.position.line + 1;
int target_column = msg->params.position.character + 1; int target_column = msg->params.position.character + 1;
for (const SymbolRef& ref : file->def.all_symbols) { for (const SymbolRef& ref : file->def.all_symbols) {
if (ref.loc.range.start.line >= target_line && ref.loc.range.end.line <= target_line && 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) { 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.codeLensProvider->resolveProvider = false;
response.result.capabilities.definitionProvider = true; response.result.capabilities.definitionProvider = true;
response.result.capabilities.hoverProvider = true;
response.result.capabilities.referencesProvider = true; response.result.capabilities.referencesProvider = true;
response.result.capabilities.documentSymbolProvider = true; response.result.capabilities.documentSymbolProvider = true;
response.result.capabilities.workspaceSymbolProvider = true; response.result.capabilities.workspaceSymbolProvider = true;
@ -1258,6 +1310,7 @@ void LanguageServerStdinLoop(IpcMessageQueue* ipc) {
case IpcId::TextDocumentDidSave: case IpcId::TextDocumentDidSave:
case IpcId::TextDocumentCompletion: case IpcId::TextDocumentCompletion:
case IpcId::TextDocumentDefinition: case IpcId::TextDocumentDefinition:
case IpcId::TextDocumentHover:
case IpcId::TextDocumentReferences: case IpcId::TextDocumentReferences:
case IpcId::TextDocumentDocumentSymbol: case IpcId::TextDocumentDocumentSymbol:
case IpcId::TextDocumentCodeLens: case IpcId::TextDocumentCodeLens:

View File

@ -781,6 +781,8 @@ void indexDeclaration(CXClientData client_data, const CXIdxDeclInfo* decl) {
var_def->def.short_name = decl->entityInfo->name; var_def->def.short_name = decl->entityInfo->name;
var_def->def.qualified_name = var_def->def.qualified_name =
ns->QualifiedName(decl->semanticContainer, var_def->def.short_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) { if (decl->isDefinition) {
@ -885,6 +887,13 @@ void indexDeclaration(CXClientData client_data, const CXIdxDeclInfo* decl) {
decl->semanticContainer, func_def->def.short_name); 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_pure_virtual = clang_CXXMethod_isPureVirtual(decl->cursor);
bool is_ctor_or_dtor = bool is_ctor_or_dtor =
decl->entityInfo->kind == CXIdxEntity_CXXConstructor || decl->entityInfo->kind == CXIdxEntity_CXXConstructor ||

View File

@ -221,6 +221,7 @@ struct FuncDefDefinitionData {
std::string usr; std::string usr;
std::string short_name; std::string short_name;
std::string qualified_name; std::string qualified_name;
std::string hover;
optional<Range> definition_spelling; optional<Range> definition_spelling;
optional<Range> definition_extent; optional<Range> definition_extent;
@ -246,6 +247,7 @@ struct FuncDefDefinitionData {
other) const { other) const {
return usr == other.usr && short_name == other.short_name && return usr == other.usr && short_name == other.short_name &&
qualified_name == other.qualified_name && qualified_name == other.qualified_name &&
hover == other.hover &&
definition_spelling == other.definition_spelling && definition_spelling == other.definition_spelling &&
definition_extent == other.definition_extent && definition_extent == other.definition_extent &&
declaring_type == other.declaring_type && base == other.base && declaring_type == other.declaring_type && base == other.base &&
@ -271,6 +273,7 @@ void Reflect(
REFLECT_MEMBER(usr); REFLECT_MEMBER(usr);
REFLECT_MEMBER(short_name); REFLECT_MEMBER(short_name);
REFLECT_MEMBER(qualified_name); REFLECT_MEMBER(qualified_name);
REFLECT_MEMBER(hover);
REFLECT_MEMBER(definition); REFLECT_MEMBER(definition);
REFLECT_MEMBER(declaring_type); REFLECT_MEMBER(declaring_type);
REFLECT_MEMBER(base); REFLECT_MEMBER(base);
@ -328,6 +331,7 @@ struct VarDefDefinitionData {
std::string usr; std::string usr;
std::string short_name; std::string short_name;
std::string qualified_name; std::string qualified_name;
std::string hover;
optional<Range> declaration; optional<Range> declaration;
// TODO: definitions should be a list of ranges, since there can be more // TODO: definitions should be a list of ranges, since there can be more
// than one - when?? // than one - when??
@ -347,6 +351,7 @@ struct VarDefDefinitionData {
other) const { other) const {
return usr == other.usr && short_name == other.short_name && return usr == other.usr && short_name == other.short_name &&
qualified_name == other.qualified_name && qualified_name == other.qualified_name &&
hover == other.hover &&
declaration == other.declaration && declaration == other.declaration &&
definition_spelling == other.definition_spelling && definition_spelling == other.definition_spelling &&
definition_extent == other.definition_extent && definition_extent == other.definition_extent &&
@ -370,6 +375,7 @@ void Reflect(TVisitor& visitor,
REFLECT_MEMBER(usr); REFLECT_MEMBER(usr);
REFLECT_MEMBER(short_name); REFLECT_MEMBER(short_name);
REFLECT_MEMBER(qualified_name); REFLECT_MEMBER(qualified_name);
REFLECT_MEMBER(hover);
REFLECT_MEMBER(definition_spelling); REFLECT_MEMBER(definition_spelling);
REFLECT_MEMBER(definition_extent); REFLECT_MEMBER(definition_extent);
REFLECT_MEMBER(variable_type); REFLECT_MEMBER(variable_type);

View File

@ -22,6 +22,8 @@ const char* IpcIdToString(IpcId id) {
return "textDocument/completion"; return "textDocument/completion";
case IpcId::TextDocumentDefinition: case IpcId::TextDocumentDefinition:
return "textDocument/definition"; return "textDocument/definition";
case IpcId::TextDocumentHover:
return "textDocument/hover";
case IpcId::TextDocumentReferences: case IpcId::TextDocumentReferences:
return "textDocument/references"; return "textDocument/references";
case IpcId::TextDocumentDocumentSymbol: case IpcId::TextDocumentDocumentSymbol:

View File

@ -16,6 +16,7 @@ enum class IpcId : int {
TextDocumentDidSave, TextDocumentDidSave,
TextDocumentCompletion, TextDocumentCompletion,
TextDocumentDefinition, TextDocumentDefinition,
TextDocumentHover,
TextDocumentReferences, TextDocumentReferences,
TextDocumentDocumentSymbol, TextDocumentDocumentSymbol,
TextDocumentCodeLens, TextDocumentCodeLens,

View File

@ -1131,6 +1131,26 @@ struct Out_TextDocumentDefinition : public lsOutMessage<Out_TextDocumentDefiniti
}; };
MAKE_REFLECT_STRUCT(Out_TextDocumentDefinition, jsonrpc, id, result); MAKE_REFLECT_STRUCT(Out_TextDocumentDefinition, jsonrpc, id, result);
// Hover
struct Ipc_TextDocumentHover : public IpcMessage<Ipc_TextDocumentHover> {
const static IpcId kIpcId = IpcId::TextDocumentHover;
lsRequestId id;
lsTextDocumentPositionParams params;
};
MAKE_REFLECT_STRUCT(Ipc_TextDocumentHover, id, params);
struct Out_TextDocumentHover : public lsOutMessage<Out_TextDocumentHover> {
struct Result {
std::string contents;
optional<lsRange> range;
};
lsRequestId id;
Result result;
};
MAKE_REFLECT_STRUCT(Out_TextDocumentHover::Result, contents, range);
MAKE_REFLECT_STRUCT(Out_TextDocumentHover, jsonrpc, id, result);
// References // References
struct Ipc_TextDocumentReferences : public IpcMessage<Ipc_TextDocumentReferences> { struct Ipc_TextDocumentReferences : public IpcMessage<Ipc_TextDocumentReferences> {
struct lsReferenceContext { struct lsReferenceContext {

View File

@ -186,6 +186,11 @@ bool Cursor::is_valid_kind() const {
} }
std::string Cursor::get_type_description() const { std::string Cursor::get_type_description() const {
auto type = clang_getCursorType(cx_cursor);
return clang::ToString(clang_getTypeSpelling(type));
std::string spelling; std::string spelling;
auto referenced = clang_getCursorReferenced(cx_cursor); auto referenced = clang_getCursorReferenced(cx_cursor);

View File

@ -134,7 +134,7 @@ struct MessageQueue::BufferMetadata {
// Reset buffer. // Reset buffer.
void reset() { total_message_bytes_ = 0; } 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; } void add_used_bytes(size_t used_bytes) { total_message_bytes_ += used_bytes; }
// The total number of bytes in use. // The total number of bytes in use.

View File

@ -36,6 +36,7 @@ QueryableFuncDef::DefUpdate ToQuery(const IdMap& id_map, const IndexedFuncDef::D
QueryableFuncDef::DefUpdate result(func.usr); QueryableFuncDef::DefUpdate result(func.usr);
result.short_name = func.short_name; result.short_name = func.short_name;
result.qualified_name = func.qualified_name; result.qualified_name = func.qualified_name;
result.hover = func.hover;
result.definition_spelling = id_map.ToQuery(func.definition_spelling); result.definition_spelling = id_map.ToQuery(func.definition_spelling);
result.definition_extent = id_map.ToQuery(func.definition_extent); result.definition_extent = id_map.ToQuery(func.definition_extent);
result.declaring_type = id_map.ToQuery(func.declaring_type); 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); QueryableVarDef::DefUpdate result(var.usr);
result.short_name = var.short_name; result.short_name = var.short_name;
result.qualified_name = var.qualified_name; result.qualified_name = var.qualified_name;
result.hover = var.hover;
result.declaration = id_map.ToQuery(var.declaration); result.declaration = id_map.ToQuery(var.declaration);
result.definition_spelling = id_map.ToQuery(var.definition_spelling); result.definition_spelling = id_map.ToQuery(var.definition_spelling);
result.definition_extent = id_map.ToQuery(var.definition_extent); result.definition_extent = id_map.ToQuery(var.definition_extent);

View File

@ -153,6 +153,7 @@ void Reflect(TVisitor& visitor, IndexedFuncDef& value) {
REFLECT_MEMBER2("usr", value.def.usr); REFLECT_MEMBER2("usr", value.def.usr);
REFLECT_MEMBER2("short_name", value.def.short_name); REFLECT_MEMBER2("short_name", value.def.short_name);
REFLECT_MEMBER2("qualified_name", value.def.qualified_name); REFLECT_MEMBER2("qualified_name", value.def.qualified_name);
REFLECT_MEMBER2("hover", value.def.hover);
REFLECT_MEMBER2("declarations", value.declarations); REFLECT_MEMBER2("declarations", value.declarations);
REFLECT_MEMBER2("definition_spelling", value.def.definition_spelling); REFLECT_MEMBER2("definition_spelling", value.def.definition_spelling);
REFLECT_MEMBER2("definition_extent", value.def.definition_extent); 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("usr", value.def.usr);
REFLECT_MEMBER2("short_name", value.def.short_name); REFLECT_MEMBER2("short_name", value.def.short_name);
REFLECT_MEMBER2("qualified_name", value.def.qualified_name); REFLECT_MEMBER2("qualified_name", value.def.qualified_name);
REFLECT_MEMBER2("hover", value.def.hover);
REFLECT_MEMBER2("declaration", value.def.declaration); REFLECT_MEMBER2("declaration", value.def.declaration);
REFLECT_MEMBER2("definition_spelling", value.def.definition_spelling); REFLECT_MEMBER2("definition_spelling", value.def.definition_spelling);
REFLECT_MEMBER2("definition_extent", value.def.definition_extent); REFLECT_MEMBER2("definition_extent", value.def.definition_extent);