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::CqueryCallHierarchyInitial: | ||||
|         case IpcId::CqueryCallHierarchyExpand: | ||||
|         case IpcId::CqueryCallTreeInitial: | ||||
|         case IpcId::CqueryCallTreeExpand: | ||||
|         case IpcId::CqueryInheritanceHierarchyInitial: | ||||
|         case IpcId::CqueryInheritanceHierarchyExpand: | ||||
|         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, | ||||
|                  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; | ||||
|   } | ||||
|  | ||||
| @ -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: | ||||
|  | ||||
| @ -50,8 +50,6 @@ enum class IpcId : int { | ||||
|   // Messages used in tree views.
 | ||||
|   CqueryCallHierarchyInitial, | ||||
|   CqueryCallHierarchyExpand, | ||||
|   CqueryCallTreeInitial, | ||||
|   CqueryCallTreeExpand, | ||||
|   CqueryInheritanceHierarchyInitial, | ||||
|   CqueryInheritanceHierarchyExpand, | ||||
|   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) { | ||||
|         QueryFunc& func = db->GetFunc(sym); | ||||
|         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); | ||||
|         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, | ||||
|  | ||||
| @ -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<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, | ||||
|             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 (def1 && def1->spell) { | ||||
|             // The declaration of target type.
 | ||||
|             if (optional<lsLocation> 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<lsLocation> loc = | ||||
|                     GetLsLocation(m->db, m->working_files, *def->spell)) | ||||
|               entry1.location = *loc; | ||||
|           } | ||||
|             if (detailed_name) | ||||
|           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<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)); | ||||
|             } | ||||
|             DoField(m, entry, var, detailed_name, levels - 1); | ||||
|           }); | ||||
|         } | ||||
|       } | ||||
| @ -148,6 +168,30 @@ bool Expand(MessageHandler* m, | ||||
| 
 | ||||
| struct CqueryMemberHierarchyInitialHandler | ||||
|     : 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, | ||||
|                                                           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); | ||||
|  | ||||
| @ -184,10 +184,8 @@ struct TextDocumentCodeLensHandler | ||||
|             return *def; | ||||
|           }; | ||||
| 
 | ||||
|           std::vector<Use> base_callers = | ||||
|               GetCallersForAllBaseFunctions(db, func); | ||||
|           std::vector<Use> derived_callers = | ||||
|               GetCallersForAllDerivedFunctions(db, func); | ||||
|           std::vector<Use> base_callers = GetUsesForAllBases(db, func); | ||||
|           std::vector<Use> derived_callers = GetUsesForAllDerived(db, func); | ||||
|           if (base_callers.empty() && derived_callers.empty()) { | ||||
|             Use loc = try_ensure_spelling(use); | ||||
|             AddCodeLens("call", "calls", &common, | ||||
|  | ||||
| @ -5,8 +5,6 @@ | ||||
| #include <loguru.hpp> | ||||
| 
 | ||||
| #include <climits> | ||||
| #include <queue> | ||||
| #include <stack> | ||||
| #include <unordered_set> | ||||
| 
 | ||||
| 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::stack<QueryFunc*> 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); | ||||
|           stack.push_back(&func1); | ||||
|           AddRange(&ret, func1.uses); | ||||
|         } | ||||
|       }); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   return ret; | ||||
| } | ||||
| 
 | ||||
| std::vector<Use> GetUsesForAllDerived(QueryDatabase* db, QueryFunc& root) { | ||||
|   std::vector<Use> ret; | ||||
|   std::vector<QueryFunc*> stack{&root}; | ||||
|   std::unordered_set<Usr> seen; | ||||
|   seen.insert(root.usr); | ||||
|   while (!stack.empty()) { | ||||
|     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); | ||||
|         } | ||||
|       }); | ||||
|     } | ||||
|   } | ||||
|   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; | ||||
| } | ||||
| 
 | ||||
| std::vector<Use> GetCallersForAllDerivedFunctions(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); | ||||
|     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<lsPosition> GetLsPosition(WorkingFile* working_file, | ||||
|  | ||||
| @ -18,11 +18,8 @@ std::vector<Use> GetDeclarations(QueryDatabase* db, const std::vector<QueryVarId | ||||
| // Get non-defining declarations.
 | ||||
| std::vector<Use> GetNonDefDeclarations(QueryDatabase* db, SymbolIdx sym); | ||||
| 
 | ||||
| bool HasCallersOnSelfOrBaseOrDerived(QueryDatabase* db, QueryFunc& root); | ||||
| std::vector<Use> GetCallersForAllBaseFunctions(QueryDatabase* db, | ||||
|                                                QueryFunc& root); | ||||
| std::vector<Use> GetCallersForAllDerivedFunctions(QueryDatabase* db, | ||||
|                                                   QueryFunc& root); | ||||
| std::vector<Use> GetUsesForAllBases(QueryDatabase* db, QueryFunc& root); | ||||
| std::vector<Use> GetUsesForAllDerived(QueryDatabase* db, QueryFunc& root); | ||||
| optional<lsPosition> GetLsPosition(WorkingFile* working_file, | ||||
|                                    const Position& position); | ||||
| optional<lsRange> GetLsRange(WorkingFile* working_file, const Range& location); | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user