mirror of
				https://github.com/MaskRay/ccls.git
				synced 2025-10-31 12:42:34 +00:00 
			
		
		
		
	Support listing local variables in memberHierarchy and better handling of locations for typedef; remove cquery_call_tree.cc
This commit is contained in:
		
							parent
							
								
									60c0267432
								
							
						
					
					
						commit
						214eded2cb
					
				| @ -344,8 +344,6 @@ void LaunchStdinLoop(Config* config, | |||||||
|         case IpcId::CqueryFreshenIndex: |         case IpcId::CqueryFreshenIndex: | ||||||
|         case IpcId::CqueryCallHierarchyInitial: |         case IpcId::CqueryCallHierarchyInitial: | ||||||
|         case IpcId::CqueryCallHierarchyExpand: |         case IpcId::CqueryCallHierarchyExpand: | ||||||
|         case IpcId::CqueryCallTreeInitial: |  | ||||||
|         case IpcId::CqueryCallTreeExpand: |  | ||||||
|         case IpcId::CqueryInheritanceHierarchyInitial: |         case IpcId::CqueryInheritanceHierarchyInitial: | ||||||
|         case IpcId::CqueryInheritanceHierarchyExpand: |         case IpcId::CqueryInheritanceHierarchyExpand: | ||||||
|         case IpcId::CqueryMemberHierarchyInitial: |         case IpcId::CqueryMemberHierarchyInitial: | ||||||
|  | |||||||
| @ -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, | void SetTypeName(IndexType* type, | ||||||
|                  const ClangCursor& cursor, |                  const ClangCursor& cursor, | ||||||
|                  const CXIdxContainerInfo* container, |                  const CXIdxContainerInfo* container, | ||||||
| @ -508,7 +523,7 @@ void SetTypeName(IndexType* type, | |||||||
|   // |name| can be null in an anonymous struct (see
 |   // |name| can be null in an anonymous struct (see
 | ||||||
|   // tests/types/anonymous_struct.cc).
 |   // tests/types/anonymous_struct.cc).
 | ||||||
|   if (!name) |   if (!name) | ||||||
|     name = "(anon)"; |     name = GetAnonName(cursor.get_kind()); | ||||||
|   if (!container) |   if (!container) | ||||||
|     parent.cursor = cursor.get_semantic_parent().cx_cursor; |     parent.cursor = cursor.get_semantic_parent().cx_cursor; | ||||||
|   // Investigate why clang_getCursorPrettyPrinted gives `struct A {}` `namespace
 |   // Investigate why clang_getCursorPrettyPrinted gives `struct A {}` `namespace
 | ||||||
| @ -1443,23 +1458,7 @@ std::string NamespaceHelper::QualifiedName(const CXIdxContainerInfo* container, | |||||||
|     if (name.size()) |     if (name.size()) | ||||||
|       qualifier += name; |       qualifier += name; | ||||||
|     else |     else | ||||||
|       switch (namespaces[i].get_kind()) { |       qualifier += GetAnonName(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 += "::"; |     qualifier += "::"; | ||||||
|     container_cursor_to_qualified_name[namespaces[i]] = qualifier; |     container_cursor_to_qualified_name[namespaces[i]] = qualifier; | ||||||
|   } |   } | ||||||
|  | |||||||
| @ -74,10 +74,6 @@ const char* IpcIdToString(IpcId id) { | |||||||
|       return "$cquery/callHierarchyInitial"; |       return "$cquery/callHierarchyInitial"; | ||||||
|     case IpcId::CqueryCallHierarchyExpand: |     case IpcId::CqueryCallHierarchyExpand: | ||||||
|       return "$cquery/callHierarchyExpand"; |       return "$cquery/callHierarchyExpand"; | ||||||
|     case IpcId::CqueryCallTreeInitial: |  | ||||||
|       return "$cquery/callTreeInitial"; |  | ||||||
|     case IpcId::CqueryCallTreeExpand: |  | ||||||
|       return "$cquery/callTreeExpand"; |  | ||||||
|     case IpcId::CqueryInheritanceHierarchyInitial: |     case IpcId::CqueryInheritanceHierarchyInitial: | ||||||
|       return "$cquery/inheritanceHierarchyInitial"; |       return "$cquery/inheritanceHierarchyInitial"; | ||||||
|     case IpcId::CqueryInheritanceHierarchyExpand: |     case IpcId::CqueryInheritanceHierarchyExpand: | ||||||
|  | |||||||
| @ -50,8 +50,6 @@ enum class IpcId : int { | |||||||
|   // Messages used in tree views.
 |   // Messages used in tree views.
 | ||||||
|   CqueryCallHierarchyInitial, |   CqueryCallHierarchyInitial, | ||||||
|   CqueryCallHierarchyExpand, |   CqueryCallHierarchyExpand, | ||||||
|   CqueryCallTreeInitial, |  | ||||||
|   CqueryCallTreeExpand, |  | ||||||
|   CqueryInheritanceHierarchyInitial, |   CqueryInheritanceHierarchyInitial, | ||||||
|   CqueryInheritanceHierarchyExpand, |   CqueryInheritanceHierarchyExpand, | ||||||
|   CqueryMemberHierarchyInitial, |   CqueryMemberHierarchyInitial, | ||||||
|  | |||||||
| @ -1,198 +0,0 @@ | |||||||
| #include "message_handler.h" |  | ||||||
| #include "query_utils.h" |  | ||||||
| #include "queue_manager.h" |  | ||||||
| 
 |  | ||||||
| #include <loguru.hpp> |  | ||||||
| 
 |  | ||||||
| // FIXME Interop with VSCode, change std::string usr to Usr (uint64_t)
 |  | ||||||
| namespace { |  | ||||||
| struct Ipc_CqueryCallTreeInitial |  | ||||||
|     : public RequestMessage<Ipc_CqueryCallTreeInitial> { |  | ||||||
|   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<Ipc_CqueryCallTreeExpand> { |  | ||||||
|   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<Out_CqueryCallTree> { |  | ||||||
|   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<CallEntry> 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<Out_CqueryCallTree::CallEntry> 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<lsLocation> 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<Out_CqueryCallTree::CallEntry> result; |  | ||||||
|   result.push_back(entry); |  | ||||||
|   return result; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| std::vector<Out_CqueryCallTree::CallEntry> 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<Out_CqueryCallTree::CallEntry> result; |  | ||||||
| 
 |  | ||||||
|   auto handle_caller = [&](Use caller, Out_CqueryCallTree::CallType call_type) { |  | ||||||
|     optional<lsLocation> 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<Use> base_callers = GetCallersForAllBaseFunctions(db, root_func); |  | ||||||
|   std::vector<Use> 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<void>(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<Ipc_CqueryCallTreeInitial> { |  | ||||||
|   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<Ipc_CqueryCallTreeExpand> { |  | ||||||
|   void Run(Ipc_CqueryCallTreeExpand* request) override { |  | ||||||
|     Out_CqueryCallTree out; |  | ||||||
|     out.id = request->id; |  | ||||||
| 
 |  | ||||||
|     // FIXME
 |  | ||||||
|     Maybe<QueryFuncId> 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
 |  | ||||||
| @ -28,9 +28,9 @@ struct CqueryCallersHandler : BaseMessageHandler<Ipc_CqueryCallers> { | |||||||
|       if (sym.kind == SymbolKind::Func) { |       if (sym.kind == SymbolKind::Func) { | ||||||
|         QueryFunc& func = db->GetFunc(sym); |         QueryFunc& func = db->GetFunc(sym); | ||||||
|         std::vector<Use> uses = func.uses; |         std::vector<Use> uses = func.uses; | ||||||
|         for (Use func_ref : GetCallersForAllBaseFunctions(db, func)) |         for (Use func_ref : GetUsesForAllBases(db, func)) | ||||||
|           uses.push_back(func_ref); |           uses.push_back(func_ref); | ||||||
|         for (Use func_ref : GetCallersForAllDerivedFunctions(db, func)) |         for (Use func_ref : GetUsesForAllDerived(db, func)) | ||||||
|           uses.push_back(func_ref); |           uses.push_back(func_ref); | ||||||
|         out.result = |         out.result = | ||||||
|             GetLsLocationExs(db, working_files, uses, config->xref.container, |             GetLsLocationExs(db, working_files, uses, config->xref.container, | ||||||
|  | |||||||
| @ -62,6 +62,41 @@ MAKE_REFLECT_STRUCT(Out_CqueryMemberHierarchy::Entry, | |||||||
|                     children); |                     children); | ||||||
| MAKE_REFLECT_STRUCT(Out_CqueryMemberHierarchy, jsonrpc, id, result); | 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<lsLocation> 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, | bool Expand(MessageHandler* m, | ||||||
|             Out_CqueryMemberHierarchy::Entry* entry, |             Out_CqueryMemberHierarchy::Entry* entry, | ||||||
|             bool detailed_name, |             bool detailed_name, | ||||||
| @ -98,15 +133,20 @@ bool Expand(MessageHandler* m, | |||||||
|           const QueryType::Def* def1 = m->db->types[def->alias_of->id].AnyDef(); |           const QueryType::Def* def1 = m->db->types[def->alias_of->id].AnyDef(); | ||||||
|           Out_CqueryMemberHierarchy::Entry entry1; |           Out_CqueryMemberHierarchy::Entry entry1; | ||||||
|           entry1.id = *def->alias_of; |           entry1.id = *def->alias_of; | ||||||
|           if (def1) { |           if (def1 && def1->spell) { | ||||||
|             if (def1->spell) { |             // The declaration of target type.
 | ||||||
|               if (optional<lsLocation> loc = |             if (optional<lsLocation> loc = | ||||||
|                   GetLsLocation(m->db, m->working_files, *def1->spell)) |                 GetLsLocation(m->db, m->working_files, *def1->spell)) | ||||||
|                 entry1.location = *loc; |               entry1.location = *loc; | ||||||
|             } |           } else if (def->spell) { | ||||||
|             if (detailed_name) |             // Builtin types have no declaration but the typedef declaration
 | ||||||
|               entry1.fieldName = def1->detailed_name; |             // itself is useful.
 | ||||||
|  |             if (optional<lsLocation> 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)) { |           if (Expand(m, &entry1, detailed_name, levels - 1)) { | ||||||
|             // For builtin types |name| is set.
 |             // For builtin types |name| is set.
 | ||||||
|             if (detailed_name && entry1.fieldName.empty()) |             if (detailed_name && entry1.fieldName.empty()) | ||||||
| @ -115,27 +155,7 @@ bool Expand(MessageHandler* m, | |||||||
|           } |           } | ||||||
|         } else { |         } else { | ||||||
|           EachDefinedEntity(m->db->vars, def->vars, [&](QueryVar& var) { |           EachDefinedEntity(m->db->vars, def->vars, [&](QueryVar& var) { | ||||||
|             const QueryVar::Def* def1 = var.AnyDef(); |             DoField(m, entry, var, detailed_name, levels - 1); | ||||||
|             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<lsLocation> 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)); |  | ||||||
|             } |  | ||||||
|           }); |           }); | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
| @ -148,6 +168,30 @@ bool Expand(MessageHandler* m, | |||||||
| 
 | 
 | ||||||
| struct CqueryMemberHierarchyInitialHandler | struct CqueryMemberHierarchyInitialHandler | ||||||
|     : BaseMessageHandler<Ipc_CqueryMemberHierarchyInitial> { |     : BaseMessageHandler<Ipc_CqueryMemberHierarchyInitial> { | ||||||
|  |   optional<Out_CqueryMemberHierarchy::Entry> 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<lsLocation> 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<Out_CqueryMemberHierarchy::Entry> BuildInitial(QueryTypeId root_id, |   optional<Out_CqueryMemberHierarchy::Entry> BuildInitial(QueryTypeId root_id, | ||||||
|                                                           bool detailed_name, |                                                           bool detailed_name, | ||||||
|                                                           int levels) { |                                                           int levels) { | ||||||
| @ -180,18 +224,26 @@ struct CqueryMemberHierarchyInitialHandler | |||||||
| 
 | 
 | ||||||
|     for (SymbolRef sym : |     for (SymbolRef sym : | ||||||
|          FindSymbolsAtLocation(working_file, file, params.position)) { |          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, |         out.result = BuildInitial(QueryTypeId(sym.id), params.detailedName, | ||||||
|                                   params.levels); |                                   params.levels); | ||||||
|         break; |         break; | ||||||
|       } |       case SymbolKind::Var: { | ||||||
|       if (sym.kind == SymbolKind::Var) { |  | ||||||
|         const QueryVar::Def* def = db->GetVar(sym).AnyDef(); |         const QueryVar::Def* def = db->GetVar(sym).AnyDef(); | ||||||
|         if (def && def->type) |         if (def && def->type) | ||||||
|           out.result = BuildInitial(QueryTypeId(*def->type), |           out.result = BuildInitial(QueryTypeId(*def->type), | ||||||
|                                     params.detailedName, params.levels); |                                     params.detailedName, params.levels); | ||||||
|         break; |         break; | ||||||
|       } |       } | ||||||
|  |       default: | ||||||
|  |         continue; | ||||||
|  |       } | ||||||
|  |       break; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     QueueManager::WriteStdout(IpcId::CqueryMemberHierarchyInitial, out); |     QueueManager::WriteStdout(IpcId::CqueryMemberHierarchyInitial, out); | ||||||
|  | |||||||
| @ -184,10 +184,8 @@ struct TextDocumentCodeLensHandler | |||||||
|             return *def; |             return *def; | ||||||
|           }; |           }; | ||||||
| 
 | 
 | ||||||
|           std::vector<Use> base_callers = |           std::vector<Use> base_callers = GetUsesForAllBases(db, func); | ||||||
|               GetCallersForAllBaseFunctions(db, func); |           std::vector<Use> derived_callers = GetUsesForAllDerived(db, func); | ||||||
|           std::vector<Use> derived_callers = |  | ||||||
|               GetCallersForAllDerivedFunctions(db, func); |  | ||||||
|           if (base_callers.empty() && derived_callers.empty()) { |           if (base_callers.empty() && derived_callers.empty()) { | ||||||
|             Use loc = try_ensure_spelling(use); |             Use loc = try_ensure_spelling(use); | ||||||
|             AddCodeLens("call", "calls", &common, |             AddCodeLens("call", "calls", &common, | ||||||
|  | |||||||
| @ -5,8 +5,6 @@ | |||||||
| #include <loguru.hpp> | #include <loguru.hpp> | ||||||
| 
 | 
 | ||||||
| #include <climits> | #include <climits> | ||||||
| #include <queue> |  | ||||||
| #include <stack> |  | ||||||
| #include <unordered_set> | #include <unordered_set> | ||||||
| 
 | 
 | ||||||
| namespace { | namespace { | ||||||
| @ -116,78 +114,46 @@ std::vector<Use> GetNonDefDeclarations(QueryDatabase* db, | |||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool HasCallersOnSelfOrBaseOrDerived(QueryDatabase* db, QueryFunc& root) { | std::vector<Use> GetUsesForAllBases(QueryDatabase* db, QueryFunc& root) { | ||||||
|  |   std::vector<Use> ret; | ||||||
|  |   std::vector<QueryFunc*> stack{&root}; | ||||||
|   std::unordered_set<Usr> seen; |   std::unordered_set<Usr> seen; | ||||||
|   std::stack<QueryFunc*> stack; |  | ||||||
|   seen.insert(root.usr); |   seen.insert(root.usr); | ||||||
|   stack.push(&root); |  | ||||||
|   while (!stack.empty()) { |   while (!stack.empty()) { | ||||||
|     QueryFunc& func = *stack.top(); |     QueryFunc& func = *stack.back(); | ||||||
|     stack.pop(); |     stack.pop_back(); | ||||||
|     if (!func.uses.empty()) |  | ||||||
|       return true; |  | ||||||
|     if (auto* def = func.AnyDef()) { |     if (auto* def = func.AnyDef()) { | ||||||
|       EachDefinedEntity(db->funcs, def->bases, [&](QueryFunc& func1) { |       EachDefinedEntity(db->funcs, def->bases, [&](QueryFunc& func1) { | ||||||
|         if (!seen.count(func1.usr)) { |         if (!seen.count(func1.usr)) { | ||||||
|           seen.insert(func1.usr); |           seen.insert(func1.usr); | ||||||
|           stack.push(&func1); |           stack.push_back(&func1); | ||||||
|         } |           AddRange(&ret, func1.uses); | ||||||
|       }); |  | ||||||
|       EachDefinedEntity(db->funcs, func.derived, [&](QueryFunc& func1) { |  | ||||||
|         if (!seen.count(func1.usr)) { |  | ||||||
|           seen.insert(func1.usr); |  | ||||||
|           stack.push(&func1); |  | ||||||
|         } |  | ||||||
|       }); |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|   return false; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| std::vector<Use> GetCallersForAllBaseFunctions(QueryDatabase* db, |  | ||||||
|                                                QueryFunc& root) { |  | ||||||
|   std::vector<Use> callers; |  | ||||||
|   std::unordered_set<Usr> seen; |  | ||||||
|   std::stack<QueryFunc*> 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); |  | ||||||
|         } |         } | ||||||
|       }); |       }); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   return callers; |   return ret; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| std::vector<Use> GetCallersForAllDerivedFunctions(QueryDatabase* db, | std::vector<Use> GetUsesForAllDerived(QueryDatabase* db, QueryFunc& root) { | ||||||
|                                                   QueryFunc& root) { |   std::vector<Use> ret; | ||||||
|   std::vector<Use> callers; |   std::vector<QueryFunc*> stack{&root}; | ||||||
|   std::unordered_set<Usr> seen; |   std::unordered_set<Usr> seen; | ||||||
|   std::stack<QueryFunc*> stack; |  | ||||||
|   seen.insert(root.usr); |   seen.insert(root.usr); | ||||||
|   stack.push(&root); |  | ||||||
|   while (!stack.empty()) { |   while (!stack.empty()) { | ||||||
|     QueryFunc& func = *stack.top(); |     QueryFunc& func = *stack.back(); | ||||||
|     stack.pop(); |     stack.pop_back(); | ||||||
|     AddRange(&callers, func.uses); |  | ||||||
|     EachDefinedEntity(db->funcs, func.derived, [&](QueryFunc& func1) { |     EachDefinedEntity(db->funcs, func.derived, [&](QueryFunc& func1) { | ||||||
|       if (!seen.count(func1.usr)) { |       if (!seen.count(func1.usr)) { | ||||||
|         seen.insert(func1.usr); |         seen.insert(func1.usr); | ||||||
|         stack.push(&func1); |         stack.push_back(&func1); | ||||||
|  |         AddRange(&ret, func1.uses); | ||||||
|       } |       } | ||||||
|     }); |     }); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   return callers; |   return ret; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| optional<lsPosition> GetLsPosition(WorkingFile* working_file, | optional<lsPosition> GetLsPosition(WorkingFile* working_file, | ||||||
|  | |||||||
| @ -18,11 +18,8 @@ std::vector<Use> GetDeclarations(QueryDatabase* db, const std::vector<QueryVarId | |||||||
| // Get non-defining declarations.
 | // Get non-defining declarations.
 | ||||||
| std::vector<Use> GetNonDefDeclarations(QueryDatabase* db, SymbolIdx sym); | std::vector<Use> GetNonDefDeclarations(QueryDatabase* db, SymbolIdx sym); | ||||||
| 
 | 
 | ||||||
| bool HasCallersOnSelfOrBaseOrDerived(QueryDatabase* db, QueryFunc& root); | std::vector<Use> GetUsesForAllBases(QueryDatabase* db, QueryFunc& root); | ||||||
| std::vector<Use> GetCallersForAllBaseFunctions(QueryDatabase* db, | std::vector<Use> GetUsesForAllDerived(QueryDatabase* db, QueryFunc& root); | ||||||
|                                                QueryFunc& root); |  | ||||||
| std::vector<Use> GetCallersForAllDerivedFunctions(QueryDatabase* db, |  | ||||||
|                                                   QueryFunc& root); |  | ||||||
| optional<lsPosition> GetLsPosition(WorkingFile* working_file, | optional<lsPosition> GetLsPosition(WorkingFile* working_file, | ||||||
|                                    const Position& position); |                                    const Position& position); | ||||||
| optional<lsRange> GetLsRange(WorkingFile* working_file, const Range& location); | optional<lsRange> GetLsRange(WorkingFile* working_file, const Range& location); | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user