From 214eded2cb7603859b5fbb229b2f651ad96458c2 Mon Sep 17 00:00:00 2001 From: Fangrui Song Date: Mon, 26 Feb 2018 20:31:08 -0800 Subject: [PATCH] Support listing local variables in memberHierarchy and better handling of locations for typedef; remove cquery_call_tree.cc --- src/command_line.cc | 2 - src/indexer.cc | 35 ++--- src/ipc.cc | 4 - src/ipc.h | 2 - src/messages/cquery_call_tree.cc | 198 ------------------------ src/messages/cquery_callers.cc | 4 +- src/messages/cquery_member_hierarchy.cc | 116 ++++++++++---- src/messages/text_document_code_lens.cc | 6 +- src/query_utils.cc | 66 ++------ src/query_utils.h | 7 +- 10 files changed, 123 insertions(+), 317 deletions(-) delete mode 100644 src/messages/cquery_call_tree.cc diff --git a/src/command_line.cc b/src/command_line.cc index 494477bc..3817f41d 100644 --- a/src/command_line.cc +++ b/src/command_line.cc @@ -344,8 +344,6 @@ void LaunchStdinLoop(Config* config, case IpcId::CqueryFreshenIndex: case IpcId::CqueryCallHierarchyInitial: case IpcId::CqueryCallHierarchyExpand: - case IpcId::CqueryCallTreeInitial: - case IpcId::CqueryCallTreeExpand: case IpcId::CqueryInheritanceHierarchyInitial: case IpcId::CqueryInheritanceHierarchyExpand: case IpcId::CqueryMemberHierarchyInitial: diff --git a/src/indexer.cc b/src/indexer.cc index 9f3a398e..49741676 100644 --- a/src/indexer.cc +++ b/src/indexer.cc @@ -499,6 +499,21 @@ Use SetUse(IndexFile* db, Range range, ClangCursor parent, Role role) { } } +const char* GetAnonName(CXCursorKind kind) { + switch (kind) { + case CXCursor_ClassDecl: + return "(anon class)"; + case CXCursor_EnumDecl: + return "(anon enum)"; + case CXCursor_StructDecl: + return "(anon struct)"; + case CXCursor_UnionDecl: + return "(anon union)"; + default: + return "(anon)"; + } +} + void SetTypeName(IndexType* type, const ClangCursor& cursor, const CXIdxContainerInfo* container, @@ -508,7 +523,7 @@ void SetTypeName(IndexType* type, // |name| can be null in an anonymous struct (see // tests/types/anonymous_struct.cc). if (!name) - name = "(anon)"; + name = GetAnonName(cursor.get_kind()); if (!container) parent.cursor = cursor.get_semantic_parent().cx_cursor; // Investigate why clang_getCursorPrettyPrinted gives `struct A {}` `namespace @@ -1443,23 +1458,7 @@ std::string NamespaceHelper::QualifiedName(const CXIdxContainerInfo* container, if (name.size()) qualifier += name; else - switch (namespaces[i].get_kind()) { - case CXCursor_ClassDecl: - qualifier += "(anon class)"; - break; - case CXCursor_EnumDecl: - qualifier += "(anon enum)"; - break; - case CXCursor_StructDecl: - qualifier += "(anon struct)"; - break; - case CXCursor_UnionDecl: - qualifier += "(anon union)"; - break; - default: - qualifier += "(anon)"; - break; - } + qualifier += GetAnonName(namespaces[i].get_kind()); qualifier += "::"; container_cursor_to_qualified_name[namespaces[i]] = qualifier; } diff --git a/src/ipc.cc b/src/ipc.cc index 6a71a865..0ecb5e8e 100644 --- a/src/ipc.cc +++ b/src/ipc.cc @@ -74,10 +74,6 @@ const char* IpcIdToString(IpcId id) { return "$cquery/callHierarchyInitial"; case IpcId::CqueryCallHierarchyExpand: return "$cquery/callHierarchyExpand"; - case IpcId::CqueryCallTreeInitial: - return "$cquery/callTreeInitial"; - case IpcId::CqueryCallTreeExpand: - return "$cquery/callTreeExpand"; case IpcId::CqueryInheritanceHierarchyInitial: return "$cquery/inheritanceHierarchyInitial"; case IpcId::CqueryInheritanceHierarchyExpand: diff --git a/src/ipc.h b/src/ipc.h index 989291d6..7987ae2a 100644 --- a/src/ipc.h +++ b/src/ipc.h @@ -50,8 +50,6 @@ enum class IpcId : int { // Messages used in tree views. CqueryCallHierarchyInitial, CqueryCallHierarchyExpand, - CqueryCallTreeInitial, - CqueryCallTreeExpand, CqueryInheritanceHierarchyInitial, CqueryInheritanceHierarchyExpand, CqueryMemberHierarchyInitial, diff --git a/src/messages/cquery_call_tree.cc b/src/messages/cquery_call_tree.cc deleted file mode 100644 index ee68e6cb..00000000 --- a/src/messages/cquery_call_tree.cc +++ /dev/null @@ -1,198 +0,0 @@ -#include "message_handler.h" -#include "query_utils.h" -#include "queue_manager.h" - -#include - -// FIXME Interop with VSCode, change std::string usr to Usr (uint64_t) -namespace { -struct Ipc_CqueryCallTreeInitial - : public RequestMessage { - const static IpcId kIpcId = IpcId::CqueryCallTreeInitial; - lsTextDocumentPositionParams params; -}; -MAKE_REFLECT_STRUCT(Ipc_CqueryCallTreeInitial, id, params); -REGISTER_IPC_MESSAGE(Ipc_CqueryCallTreeInitial); - -struct Ipc_CqueryCallTreeExpand - : public RequestMessage { - const static IpcId kIpcId = IpcId::CqueryCallTreeExpand; - struct Params { - std::string usr; - }; - Params params; -}; -MAKE_REFLECT_STRUCT(Ipc_CqueryCallTreeExpand::Params, usr); -MAKE_REFLECT_STRUCT(Ipc_CqueryCallTreeExpand, id, params); -REGISTER_IPC_MESSAGE(Ipc_CqueryCallTreeExpand); - -struct Out_CqueryCallTree : public lsOutMessage { - enum class CallType { Direct = 0, Base = 1, Derived = 2 }; - struct CallEntry { - std::string_view name; - std::string usr; - lsLocation location; - bool hasCallers = true; - CallType callType = CallType::Direct; - }; - - lsRequestId id; - std::vector result; -}; -MAKE_REFLECT_TYPE_PROXY(Out_CqueryCallTree::CallType); -MAKE_REFLECT_STRUCT(Out_CqueryCallTree::CallEntry, - name, - usr, - location, - hasCallers, - callType); -MAKE_REFLECT_STRUCT(Out_CqueryCallTree, jsonrpc, id, result); - -std::vector BuildInitialCallTree( - QueryDatabase* db, - WorkingFiles* working_files, - QueryFuncId root) { - QueryFunc& root_func = db->funcs[root.id]; - const QueryFunc::Def* def = root_func.AnyDef(); - if (!def || !def->spell) - return {}; - optional def_loc = GetLsLocation(db, working_files, *def->spell); - if (!def_loc) - return {}; - - Out_CqueryCallTree::CallEntry entry; - entry.name = def->ShortName(); - entry.usr = std::to_string(root_func.usr); - entry.location = *def_loc; - entry.hasCallers = HasCallersOnSelfOrBaseOrDerived(db, root_func); - std::vector result; - result.push_back(entry); - return result; -} - -std::vector BuildExpandCallTree( - QueryDatabase* db, - WorkingFiles* working_files, - QueryFuncId root) { - QueryFunc& root_func = db->funcs[root.id]; - const QueryFunc::Def* root_func_def = root_func.AnyDef(); - if (!root_func_def) - return {}; - - std::vector result; - - auto handle_caller = [&](Use caller, Out_CqueryCallTree::CallType call_type) { - optional call_location = - GetLsLocation(db, working_files, caller); - if (!call_location) - return; - - // TODO: REMOVE |seen_locations| once we fix the querydb update bugs - // TODO: REMOVE |seen_locations| once we fix the querydb update bugs - // TODO: REMOVE |seen_locations| once we fix the querydb update bugs - // TODO: REMOVE |seen_locations| once we fix the querydb update bugs - // TODO: REMOVE |seen_locations| once we fix the querydb update bugs - // TODO: REMOVE |seen_locations| once we fix the querydb update bugs - // TODO: REMOVE |seen_locations| once we fix the querydb update bugs - // TODO: REMOVE |seen_locations| once we fix the querydb update bugs - // TODO: REMOVE |seen_locations| once we fix the querydb update bugs - // TODO: REMOVE |seen_locations| once we fix the querydb update bugs - // TODO: REMOVE |seen_locations| once we fix the querydb update bugs - // TODO: REMOVE |seen_locations| once we fix the querydb update bugs - // TODO: basically, querydb gets duplicate references inserted into it. - // if (!seen_locations.insert(caller.loc).second) { - // LOG_S(ERROR) << "!!!! FIXME DUPLICATE REFERENCE IN QUERYDB" << - // std::endl; return; - //} - - if (caller.kind == SymbolKind::Func) { - QueryFunc& call_func = db->GetFunc(caller); - const QueryFunc::Def* def = call_func.AnyDef(); - if (!def) - return; - - Out_CqueryCallTree::CallEntry call_entry; - call_entry.name = def->ShortName(); - call_entry.usr = std::to_string(call_func.usr); - call_entry.location = *call_location; - call_entry.hasCallers = HasCallersOnSelfOrBaseOrDerived(db, call_func); - call_entry.callType = call_type; - result.push_back(call_entry); - } else { - // TODO: See if we can do a better job here. Need more information from - // the indexer. - Out_CqueryCallTree::CallEntry call_entry; - call_entry.name = "Likely Constructor"; - call_entry.usr = "no_usr"; - call_entry.location = *call_location; - call_entry.hasCallers = false; - call_entry.callType = call_type; - result.push_back(call_entry); - } - }; - - std::vector base_callers = GetCallersForAllBaseFunctions(db, root_func); - std::vector derived_callers = - GetCallersForAllDerivedFunctions(db, root_func); - result.reserve(root_func.uses.size() + base_callers.size() + - derived_callers.size()); - - for (Use caller : root_func.uses) - handle_caller(caller, Out_CqueryCallTree::CallType::Direct); - for (Use caller : base_callers) - if (caller.kind == SymbolKind::Func && caller.id != Id(root)) { - // Do not show calls to the base function coming from this function. - handle_caller(caller, Out_CqueryCallTree::CallType::Base); - } - for (Use caller : derived_callers) - handle_caller(caller, Out_CqueryCallTree::CallType::Derived); - - return result; -} - -struct CqueryCallTreeInitialHandler - : BaseMessageHandler { - void Run(Ipc_CqueryCallTreeInitial* 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_CqueryCallTree out; - out.id = request->id; - - for (SymbolRef sym : - FindSymbolsAtLocation(working_file, file, request->params.position)) { - if (sym.kind == SymbolKind::Func) { - out.result = - BuildInitialCallTree(db, working_files, QueryFuncId(sym.id)); - break; - } - } - - QueueManager::WriteStdout(IpcId::CqueryCallTreeInitial, out); - } -}; -REGISTER_MESSAGE_HANDLER(CqueryCallTreeInitialHandler); - -struct CqueryCallTreeExpandHandler - : BaseMessageHandler { - void Run(Ipc_CqueryCallTreeExpand* request) override { - Out_CqueryCallTree out; - out.id = request->id; - - // FIXME - Maybe func_id = - db->GetQueryFuncIdFromUsr(std::stoull(request->params.usr)); - if (func_id) - out.result = BuildExpandCallTree(db, working_files, *func_id); - - QueueManager::WriteStdout(IpcId::CqueryCallTreeExpand, out); - } -}; -REGISTER_MESSAGE_HANDLER(CqueryCallTreeExpandHandler); -} // namespace diff --git a/src/messages/cquery_callers.cc b/src/messages/cquery_callers.cc index b859eef4..088b9313 100644 --- a/src/messages/cquery_callers.cc +++ b/src/messages/cquery_callers.cc @@ -28,9 +28,9 @@ struct CqueryCallersHandler : BaseMessageHandler { if (sym.kind == SymbolKind::Func) { QueryFunc& func = db->GetFunc(sym); std::vector uses = func.uses; - for (Use func_ref : GetCallersForAllBaseFunctions(db, func)) + for (Use func_ref : GetUsesForAllBases(db, func)) uses.push_back(func_ref); - for (Use func_ref : GetCallersForAllDerivedFunctions(db, func)) + for (Use func_ref : GetUsesForAllDerived(db, func)) uses.push_back(func_ref); out.result = GetLsLocationExs(db, working_files, uses, config->xref.container, diff --git a/src/messages/cquery_member_hierarchy.cc b/src/messages/cquery_member_hierarchy.cc index d6aeb2cf..ff144dae 100644 --- a/src/messages/cquery_member_hierarchy.cc +++ b/src/messages/cquery_member_hierarchy.cc @@ -62,6 +62,41 @@ MAKE_REFLECT_STRUCT(Out_CqueryMemberHierarchy::Entry, children); MAKE_REFLECT_STRUCT(Out_CqueryMemberHierarchy, jsonrpc, id, result); +bool Expand(MessageHandler* m, + Out_CqueryMemberHierarchy::Entry* entry, + bool detailed_name, + int levels); + +// Add a field to |entry| which is a Func/Type. +void DoField(MessageHandler* m, + Out_CqueryMemberHierarchy::Entry* entry, + const QueryVar& var, + bool detailed_name, + int levels) { + const QueryVar::Def* def1 = var.AnyDef(); + if (!def1) + return; + Out_CqueryMemberHierarchy::Entry entry1; + if (detailed_name) + entry1.fieldName = def1->DetailedName(false); + else + entry1.fieldName = std::string(def1->ShortName()); + if (def1->spell) { + if (optional loc = + GetLsLocation(m->db, m->working_files, *def1->spell)) + entry1.location = *loc; + } + if (def1->type) { + entry1.id = *def1->type; + if (Expand(m, &entry1, detailed_name, levels)) + entry->children.push_back(std::move(entry1)); + } else { + entry1.id = QueryTypeId(); + entry->children.push_back(std::move(entry1)); + } +} + +// Expand a type node by adding members recursively to it. bool Expand(MessageHandler* m, Out_CqueryMemberHierarchy::Entry* entry, bool detailed_name, @@ -98,15 +133,20 @@ bool Expand(MessageHandler* m, const QueryType::Def* def1 = m->db->types[def->alias_of->id].AnyDef(); Out_CqueryMemberHierarchy::Entry entry1; entry1.id = *def->alias_of; - if (def1) { - if (def1->spell) { - if (optional loc = - GetLsLocation(m->db, m->working_files, *def1->spell)) - entry1.location = *loc; - } - if (detailed_name) - entry1.fieldName = def1->detailed_name; + if (def1 && def1->spell) { + // The declaration of target type. + if (optional loc = + GetLsLocation(m->db, m->working_files, *def1->spell)) + entry1.location = *loc; + } else if (def->spell) { + // Builtin types have no declaration but the typedef declaration + // itself is useful. + if (optional loc = + GetLsLocation(m->db, m->working_files, *def->spell)) + entry1.location = *loc; } + if (def1 && detailed_name) + entry1.fieldName = def1->detailed_name; if (Expand(m, &entry1, detailed_name, levels - 1)) { // For builtin types |name| is set. if (detailed_name && entry1.fieldName.empty()) @@ -115,27 +155,7 @@ bool Expand(MessageHandler* m, } } else { EachDefinedEntity(m->db->vars, def->vars, [&](QueryVar& var) { - const QueryVar::Def* def1 = var.AnyDef(); - if (!def1) - return; - Out_CqueryMemberHierarchy::Entry entry1; - if (detailed_name) - entry1.fieldName = def1->DetailedName(false); - else - entry1.fieldName = std::string(def1->ShortName()); - if (def1->spell) { - if (optional loc = - GetLsLocation(m->db, m->working_files, *def1->spell)) - entry1.location = *loc; - } - if (def1->type) { - entry1.id = *def1->type; - if (Expand(m, &entry1, detailed_name, levels - 1)) - entry->children.push_back(std::move(entry1)); - } else { - entry1.id = QueryTypeId(); - entry->children.push_back(std::move(entry1)); - } + DoField(m, entry, var, detailed_name, levels - 1); }); } } @@ -148,6 +168,30 @@ bool Expand(MessageHandler* m, struct CqueryMemberHierarchyInitialHandler : BaseMessageHandler { + optional BuildInitial(QueryFuncId root_id, + bool detailed_name, + int levels) { + const auto* def = db->funcs[root_id.id].AnyDef(); + if (!def) + return {}; + + Out_CqueryMemberHierarchy::Entry entry; + // Not type, |id| is invalid. + if (detailed_name) + entry.name = def->DetailedName(false); + else + entry.name = std::string(def->ShortName()); + if (def->spell) { + if (optional loc = + GetLsLocation(db, working_files, *def->spell)) + entry.location = *loc; + } + EachDefinedEntity(db->vars, def->vars, [&](QueryVar& var) { + DoField(this, &entry, var, detailed_name, levels - 1); + }); + return entry; + } + optional BuildInitial(QueryTypeId root_id, bool detailed_name, int levels) { @@ -180,18 +224,26 @@ struct CqueryMemberHierarchyInitialHandler for (SymbolRef sym : FindSymbolsAtLocation(working_file, file, params.position)) { - if (sym.kind == SymbolKind::Type) { + switch (sym.kind) { + case SymbolKind::Func: + out.result = BuildInitial(QueryFuncId(sym.id), params.detailedName, + params.levels); + break; + case SymbolKind::Type: out.result = BuildInitial(QueryTypeId(sym.id), params.detailedName, params.levels); break; - } - if (sym.kind == SymbolKind::Var) { + case SymbolKind::Var: { const QueryVar::Def* def = db->GetVar(sym).AnyDef(); if (def && def->type) out.result = BuildInitial(QueryTypeId(*def->type), params.detailedName, params.levels); break; } + default: + continue; + } + break; } QueueManager::WriteStdout(IpcId::CqueryMemberHierarchyInitial, out); diff --git a/src/messages/text_document_code_lens.cc b/src/messages/text_document_code_lens.cc index c60d6730..ea6f414a 100644 --- a/src/messages/text_document_code_lens.cc +++ b/src/messages/text_document_code_lens.cc @@ -184,10 +184,8 @@ struct TextDocumentCodeLensHandler return *def; }; - std::vector base_callers = - GetCallersForAllBaseFunctions(db, func); - std::vector derived_callers = - GetCallersForAllDerivedFunctions(db, func); + std::vector base_callers = GetUsesForAllBases(db, func); + std::vector derived_callers = GetUsesForAllDerived(db, func); if (base_callers.empty() && derived_callers.empty()) { Use loc = try_ensure_spelling(use); AddCodeLens("call", "calls", &common, diff --git a/src/query_utils.cc b/src/query_utils.cc index 0286b818..7361187e 100644 --- a/src/query_utils.cc +++ b/src/query_utils.cc @@ -5,8 +5,6 @@ #include #include -#include -#include #include namespace { @@ -116,78 +114,46 @@ std::vector GetNonDefDeclarations(QueryDatabase* db, } } -bool HasCallersOnSelfOrBaseOrDerived(QueryDatabase* db, QueryFunc& root) { +std::vector GetUsesForAllBases(QueryDatabase* db, QueryFunc& root) { + std::vector ret; + std::vector stack{&root}; std::unordered_set seen; - std::stack stack; seen.insert(root.usr); - stack.push(&root); while (!stack.empty()) { - QueryFunc& func = *stack.top(); - stack.pop(); - if (!func.uses.empty()) - return true; + QueryFunc& func = *stack.back(); + stack.pop_back(); if (auto* def = func.AnyDef()) { EachDefinedEntity(db->funcs, def->bases, [&](QueryFunc& func1) { if (!seen.count(func1.usr)) { seen.insert(func1.usr); - stack.push(&func1); - } - }); - EachDefinedEntity(db->funcs, func.derived, [&](QueryFunc& func1) { - if (!seen.count(func1.usr)) { - seen.insert(func1.usr); - stack.push(&func1); - } - }); - } - } - return false; -} - -std::vector GetCallersForAllBaseFunctions(QueryDatabase* db, - QueryFunc& root) { - std::vector callers; - std::unordered_set seen; - std::stack stack; - seen.insert(root.usr); - stack.push(&root); - while (!stack.empty()) { - QueryFunc& func = *stack.top(); - stack.pop(); - AddRange(&callers, func.uses); - if (auto* def = func.AnyDef()) { - EachDefinedEntity(db->funcs, def->bases, [&](QueryFunc& func1) { - if (!seen.count(func1.usr)) { - seen.insert(func1.usr); - stack.push(&func1); + stack.push_back(&func1); + AddRange(&ret, func1.uses); } }); } } - return callers; + return ret; } -std::vector GetCallersForAllDerivedFunctions(QueryDatabase* db, - QueryFunc& root) { - std::vector callers; +std::vector GetUsesForAllDerived(QueryDatabase* db, QueryFunc& root) { + std::vector ret; + std::vector stack{&root}; std::unordered_set seen; - std::stack stack; seen.insert(root.usr); - stack.push(&root); while (!stack.empty()) { - QueryFunc& func = *stack.top(); - stack.pop(); - AddRange(&callers, func.uses); + QueryFunc& func = *stack.back(); + stack.pop_back(); EachDefinedEntity(db->funcs, func.derived, [&](QueryFunc& func1) { if (!seen.count(func1.usr)) { seen.insert(func1.usr); - stack.push(&func1); + stack.push_back(&func1); + AddRange(&ret, func1.uses); } }); } - return callers; + return ret; } optional GetLsPosition(WorkingFile* working_file, diff --git a/src/query_utils.h b/src/query_utils.h index 1aea3256..cb5d936b 100644 --- a/src/query_utils.h +++ b/src/query_utils.h @@ -18,11 +18,8 @@ std::vector GetDeclarations(QueryDatabase* db, const std::vector GetNonDefDeclarations(QueryDatabase* db, SymbolIdx sym); -bool HasCallersOnSelfOrBaseOrDerived(QueryDatabase* db, QueryFunc& root); -std::vector GetCallersForAllBaseFunctions(QueryDatabase* db, - QueryFunc& root); -std::vector GetCallersForAllDerivedFunctions(QueryDatabase* db, - QueryFunc& root); +std::vector GetUsesForAllBases(QueryDatabase* db, QueryFunc& root); +std::vector GetUsesForAllDerived(QueryDatabase* db, QueryFunc& root); optional GetLsPosition(WorkingFile* working_file, const Position& position); optional GetLsRange(WorkingFile* working_file, const Range& location);