From c3c0feecb2e0bf6c5a32a67823a0c7b298ec4451 Mon Sep 17 00:00:00 2001 From: Fangrui Song Date: Fri, 22 Dec 2017 14:48:55 -0800 Subject: [PATCH] [indexer] Make `hover` optional (#176) On textDocument/hover requests, return `detailed_name` if `hover` is unavailable Don't include leading `type_name` in `detailed_name` for CXIdxEntityEnumConstant, i.e. `Foo Foo::a` -> `Foo::a` --- src/indexer.cc | 25 ++++++++++++++++--------- src/indexer.h | 6 +++--- src/messages/text_document_hover.cc | 21 +++++++++++++++------ 3 files changed, 34 insertions(+), 18 deletions(-) diff --git a/src/indexer.cc b/src/indexer.cc index 2ad815f9..308b1d37 100644 --- a/src/indexer.cc +++ b/src/indexer.cc @@ -61,6 +61,9 @@ bool IsLocalSemanticContainer(CXCursorKind kind) { case CXCursor_UnionDecl: case CXCursor_ClassDecl: case CXCursor_EnumDecl: + // TODO Add more Objective-C containers + case CXCursor_ObjCInterfaceDecl: + case CXCursor_ObjCImplementationDecl: return false; default: return true; @@ -87,7 +90,8 @@ struct NamespaceHelper { ClangCursor cursor = container->cursor; std::vector namespaces; std::string qualifier; - while (cursor.get_kind() != CXCursor_TranslationUnit) { + while (cursor.get_kind() != CXCursor_TranslationUnit && + !IsLocalSemanticContainer(cursor.get_kind())) { auto it = container_cursor_to_qualified_name.find(cursor); if (it != container_cursor_to_qualified_name.end()) { qualifier = it->second; @@ -99,6 +103,8 @@ struct NamespaceHelper { for (size_t i = namespaces.size(); i > 0; ) { i--; std::string name = namespaces[i].get_spelling(); + // Empty name indicates unnamed namespace, anonymous struct, anonymous + // union, ... qualifier += name.empty() ? "(anon)" : name; qualifier += "::"; container_cursor_to_qualified_name[namespaces[i]] = qualifier; @@ -1031,10 +1037,14 @@ void OnIndexDeclaration(CXClientData client_data, const CXIdxDeclInfo* decl) { if (type_name.find("(lambda at") != std::string::npos) type_name = "lambda"; - var->def.detailed_name = - type_name + " " + - ns->QualifiedName(decl->semanticContainer, var->def.short_name); - var->def.hover = type_name; + { + std::string qualified_name = + ns->QualifiedName(decl->semanticContainer, var->def.short_name); + if (decl->entityInfo->kind == CXIdxEntity_EnumConstant) + var->def.detailed_name = std::move(qualified_name); + else + var->def.detailed_name = type_name + " " + std::move(qualified_name); + } var->def.is_local = !decl->semanticContainer || @@ -1258,11 +1268,10 @@ void OnIndexDeclaration(CXClientData client_data, const CXIdxDeclInfo* decl) { type->def.detailed_name = ns->QualifiedName(decl->semanticContainer, type->def.short_name); - type->def.hover = type->def.detailed_name; - // For Typedef/CXXTypeAlias spanning a few lines, display the declaration line, // with spelling name replaced with qualified name. // TODO Think how to display multi-line declaration like `typedef struct { ... } foo;` + // https://github.com/jacobdufault/cquery/issues/29 if (extent.end.line - extent.start.line < kMaxLinesDisplayTypeAliasDeclarations) { FileContentsWithOffsets& fc = param->file_contents[db->path]; @@ -1312,7 +1321,6 @@ void OnIndexDeclaration(CXClientData client_data, const CXIdxDeclInfo* decl) { type->def.detailed_name = ns->QualifiedName(decl->semanticContainer, type->def.short_name); - type->def.hover = type->def.detailed_name; // } if (decl->isDefinition) { @@ -1445,7 +1453,6 @@ void OnIndexReference(CXClientData client_data, const CXIdxEntityRefInfo* ref) { std::string type_name = ToString( clang_getTypeSpelling(clang_getCursorType(referenced.cx_cursor))); var->def.detailed_name = type_name + " " + var->def.short_name; - var->def.hover = type_name; var->def.is_local = false; UniqueAdd(var->uses, ResolveSpelling(referenced.cx_cursor)); AddDeclInitializerUsages(db, referenced.cx_cursor); diff --git a/src/indexer.h b/src/indexer.h index 006d1feb..f8f38b6b 100644 --- a/src/indexer.h +++ b/src/indexer.h @@ -149,7 +149,7 @@ struct TypeDefDefinitionData { // General metadata. std::string short_name; std::string detailed_name; - std::string hover; + optional hover; // While a class/type can technically have a separate declaration/definition, // it doesn't really happen in practice. The declaration never contains @@ -247,7 +247,7 @@ struct FuncDefDefinitionData { // General metadata. std::string short_name; std::string detailed_name; - std::string hover; + optional hover; optional definition_spelling; optional definition_extent; @@ -362,7 +362,7 @@ struct VarDefDefinitionData { // General metadata. std::string short_name; std::string detailed_name; - std::string hover; + optional hover; optional declaration; // TODO: definitions should be a list of ranges, since there can be more // than one - when?? diff --git a/src/messages/text_document_hover.cc b/src/messages/text_document_hover.cc index 04669a8b..dfd677e5 100644 --- a/src/messages/text_document_hover.cc +++ b/src/messages/text_document_hover.cc @@ -7,20 +7,29 @@ std::string GetHoverForSymbol(QueryDatabase* db, const SymbolIdx& symbol) { switch (symbol.kind) { case SymbolKind::Type: { QueryType& type = db->types[symbol.idx]; - if (type.def) - return type.def->hover; + if (type.def) { + if (type.def->hover) + return *type.def->hover; + return type.def->detailed_name; + } break; } case SymbolKind::Func: { QueryFunc& func = db->funcs[symbol.idx]; - if (func.def) - return func.def->hover; + if (func.def) { + if (func.def->hover) + return *func.def->hover; + return func.def->detailed_name; + } break; } case SymbolKind::Var: { QueryVar& var = db->vars[symbol.idx]; - if (var.def) - return var.def->hover; + if (var.def) { + if (var.def->hover) + return *var.def->hover; + return var.def->detailed_name; + } break; } case SymbolKind::File: