diff --git a/CMakeLists.txt b/CMakeLists.txt index 52f0f269..d3db90e0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -230,7 +230,6 @@ target_sources(ccls PRIVATE src/messages/ccls_freshen_index.cc src/messages/ccls_inheritance_hierarchy.cc src/messages/ccls_member_hierarchy.cc - src/messages/ccls_random.cc src/messages/ccls_vars.cc src/messages/exit.cc src/messages/initialize.cc diff --git a/src/indexer.h b/src/indexer.h index d79cd66e..6921a8dd 100644 --- a/src/indexer.h +++ b/src/indexer.h @@ -64,7 +64,7 @@ struct SymbolRef : Reference { : Reference{range, usr, kind, role} {} }; -// Represents an occurrence of a variable/type, |id,kind| refer to the lexical +// Represents an occurrence of a variable/type, |usr,kind| refer to the lexical // parent. struct Use : Reference { // |file| is used in Query* but not in Index* @@ -239,7 +239,10 @@ struct VarDef : NameMixin { // (declaration). StorageClass storage = StorageClass::Invalid; - bool is_local() const { return kind == lsSymbolKind::Variable; } + bool is_local() const { + return spell && spell->kind != SymbolKind::File && + storage == StorageClass::None; + } std::vector GetBases() const { return {}; } bool operator==(const VarDef& o) const { diff --git a/src/message_handler.cc b/src/message_handler.cc index cd7915e5..ab871900 100644 --- a/src/message_handler.cc +++ b/src/message_handler.cc @@ -125,7 +125,7 @@ MessageHandler::MessageHandler() { // static std::vector* MessageHandler::message_handlers = nullptr; -bool FindFileOrFail(QueryDatabase* db, +bool FindFileOrFail(DB* db, Project* project, std::optional id, const std::string& absolute_path, @@ -186,7 +186,7 @@ void EmitInactiveLines(WorkingFile* working_file, pipeline::WriteStdout(kMethodType_CclsPublishInactiveRegions, out); } -void EmitSemanticHighlighting(QueryDatabase* db, +void EmitSemanticHighlighting(DB* db, SemanticHighlightSymbolCache* semantic_cache, WorkingFile* working_file, QueryFile* file) { diff --git a/src/message_handler.h b/src/message_handler.h index d836c873..f73dc483 100644 --- a/src/message_handler.h +++ b/src/message_handler.h @@ -20,7 +20,7 @@ struct ImportManager; struct IncludeComplete; struct MultiQueueWaiter; struct Project; -struct QueryDatabase; +struct DB; struct WorkingFile; struct WorkingFiles; @@ -101,7 +101,7 @@ MAKE_REFLECT_STRUCT(Out_CclsPublishSemanticHighlighting, static type type##message_handler_instance_; struct MessageHandler { - QueryDatabase* db = nullptr; + DB* db = nullptr; MultiQueueWaiter* waiter = nullptr; Project* project = nullptr; DiagnosticsEngine* diag_engine = nullptr; @@ -134,7 +134,7 @@ struct BaseMessageHandler : MessageHandler { } }; -bool FindFileOrFail(QueryDatabase* db, +bool FindFileOrFail(DB* db, Project* project, std::optional id, const std::string& absolute_path, @@ -144,7 +144,7 @@ bool FindFileOrFail(QueryDatabase* db, void EmitInactiveLines(WorkingFile* working_file, const std::vector& inactive_regions); -void EmitSemanticHighlighting(QueryDatabase* db, +void EmitSemanticHighlighting(DB* db, SemanticHighlightSymbolCache* semantic_cache, WorkingFile* working_file, QueryFile* file); diff --git a/src/messages/ccls_base.cc b/src/messages/ccls_base.cc index fa04a498..dc29162b 100644 --- a/src/messages/ccls_base.cc +++ b/src/messages/ccls_base.cc @@ -34,13 +34,13 @@ struct Handler_CclsBase : BaseMessageHandler { FindSymbolsAtLocation(working_file, file, request->params.position)) { if (sym.kind == SymbolKind::Type) { if (const auto* def = db->GetType(sym).AnyDef()) - out.result = GetLsLocationExs( - db, working_files, GetDeclarations(db->usr2type, def->bases)); + out.result = GetLsLocationExs(db, working_files, + GetTypeDeclarations(db, def->bases)); break; } else if (sym.kind == SymbolKind::Func) { if (const auto* def = db->GetFunc(sym).AnyDef()) - out.result = GetLsLocationExs( - db, working_files, GetDeclarations(db->usr2func, def->bases)); + out.result = GetLsLocationExs(db, working_files, + GetFuncDeclarations(db, def->bases)); break; } } diff --git a/src/messages/ccls_call_hierarchy.cc b/src/messages/ccls_call_hierarchy.cc index 2911d75d..bff5ca84 100644 --- a/src/messages/ccls_call_hierarchy.cc +++ b/src/messages/ccls_call_hierarchy.cc @@ -136,7 +136,7 @@ bool Expand(MessageHandler* m, const QueryFunc& func1 = *stack.back(); stack.pop_back(); if (auto* def1 = func1.AnyDef()) { - EachDefinedEntity(m->db->usr2func, def1->bases, [&](QueryFunc& func2) { + EachDefinedFunc(m->db, def1->bases, [&](QueryFunc& func2) { if (!seen.count(func2.usr)) { seen.insert(func2.usr); stack.push_back(&func2); @@ -153,7 +153,7 @@ bool Expand(MessageHandler* m, while (stack.size()) { const QueryFunc& func1 = *stack.back(); stack.pop_back(); - EachDefinedEntity(m->db->usr2func, func1.derived, [&](QueryFunc& func2) { + EachDefinedFunc(m->db, func1.derived, [&](QueryFunc& func2) { if (!seen.count(func2.usr)) { seen.insert(func2.usr); stack.push_back(&func2); @@ -206,7 +206,7 @@ struct Handler_CclsCallHierarchy entry.id = std::to_string(params.usr); entry.usr = params.usr; entry.callType = CallType::Direct; - if (db->usr2func.count(params.usr)) + if (db->HasFunc(params.usr)) Expand(this, &entry, params.callee, params.callType, params.qualified, params.levels); out.result = std::move(entry); diff --git a/src/messages/ccls_inheritance_hierarchy.cc b/src/messages/ccls_inheritance_hierarchy.cc index c6fccaff..3d477fa6 100644 --- a/src/messages/ccls_inheritance_hierarchy.cc +++ b/src/messages/ccls_inheritance_hierarchy.cc @@ -169,8 +169,8 @@ struct Handler_CclsInheritanceHierarchy entry.id = std::to_string(params.usr); entry.usr = params.usr; entry.kind = params.kind; - if (((entry.kind == SymbolKind::Func && db->usr2func.count(entry.usr)) || - (entry.kind == SymbolKind::Type && db->usr2type.count(entry.usr))) && + if (((entry.kind == SymbolKind::Func && db->HasFunc(entry.usr)) || + (entry.kind == SymbolKind::Type && db->HasType(entry.usr))) && Expand(this, &entry, params.derived, params.qualified, params.levels)) out.result = std::move(entry); } else { diff --git a/src/messages/ccls_member_hierarchy.cc b/src/messages/ccls_member_hierarchy.cc index 6cc9b755..9fa7cd6e 100644 --- a/src/messages/ccls_member_hierarchy.cc +++ b/src/messages/ccls_member_hierarchy.cc @@ -138,7 +138,7 @@ bool Expand(MessageHandler* m, const auto* def = stack.back()->AnyDef(); stack.pop_back(); if (def) { - EachDefinedEntity(m->db->usr2type, def->bases, [&](QueryType& type1) { + EachDefinedType(m->db, def->bases, [&](QueryType& type1) { if (!seen.count(type1.usr)) { seen.insert(type1.usr); stack.push_back(&type1); @@ -171,7 +171,7 @@ bool Expand(MessageHandler* m, } } else { for (auto it : def->vars) { - QueryVar& var = m->db->usr2var[it.first]; + QueryVar& var = m->db->Var(it.first); if (!var.def.empty()) DoField(m, entry, var, it.second, qualified, levels - 1); } @@ -208,7 +208,7 @@ struct Handler_CclsMemberHierarchy GetLsLocation(db, working_files, *def->spell)) entry.location = *loc; } - EachDefinedEntity(db->usr2var, def->vars, [&](QueryVar& var) { + EachDefinedVar(db, def->vars, [&](QueryVar& var) { DoField(this, &entry, var, -1, qualified, levels - 1); }); return entry; @@ -247,7 +247,7 @@ struct Handler_CclsMemberHierarchy entry.id = std::to_string(params.usr); entry.usr = params.usr; // entry.name is empty as it is known by the client. - if (db->usr2type.count(entry.usr) && + if (db->HasType(entry.usr) && Expand(this, &entry, params.qualified, params.levels)) out.result = std::move(entry); } else { diff --git a/src/messages/ccls_random.cc b/src/messages/ccls_random.cc deleted file mode 100644 index a5fabdb2..00000000 --- a/src/messages/ccls_random.cc +++ /dev/null @@ -1,134 +0,0 @@ -#include "message_handler.h" -#include "query_utils.h" -#include "pipeline.hh" -using namespace ccls; - -#include -#include -#include - -MAKE_HASHABLE(SymbolIdx, t.usr, t.kind); - -namespace { -MethodType kMethodType = "$ccls/random"; - -struct In_CclsRandom : public RequestInMessage { - MethodType GetMethodType() const override { return kMethodType; } -}; -MAKE_REFLECT_STRUCT(In_CclsRandom, id); -REGISTER_IN_MESSAGE(In_CclsRandom); - -const double kDeclWeight = 3; -const double kDamping = 0.1; - -template -void Add(const std::unordered_map& sym2id, - std::vector>& adj, - const std::vector& collection, - int n, - double w = 1) { - for (Usr usr : collection) { - auto it = sym2id.find(SymbolIdx{usr, Q}); - if (it != sym2id.end()) - adj[it->second][n] += w; - } -} - -struct Handler_CclsRandom : BaseMessageHandler { - MethodType GetMethodType() const override { return kMethodType; } - - void Run(In_CclsRandom* request) override { - std::unordered_map sym2id; - std::vector syms; - int n = 0; - - for (auto& it : db->usr2func) - if (it.second.AnyDef()) { - syms.push_back(SymbolIdx{it.first, SymbolKind::Func}); - sym2id[syms.back()] = n++; - } - for (auto& it : db->usr2type) - if (it.second.AnyDef()) { - syms.push_back(SymbolIdx{it.first, SymbolKind::Type}); - sym2id[syms.back()] = n++; - } - for (auto& it : db->usr2var) - if (it.second.AnyDef()) { - syms.push_back(SymbolIdx{it.first, SymbolKind::Var}); - sym2id[syms.back()] = n++; - } - - std::vector> adj(n); - auto add = [&](const std::vector& uses, double w) { - for (Use use : uses) { - auto it = sym2id.find(use); - if (it != sym2id.end()) - adj[it->second][n] += w; - } - }; - n = 0; - for (auto& it : db->usr2func) - if (it.second.AnyDef()) { - add(it.second.declarations, kDeclWeight); - add(it.second.uses, 1); - Add(sym2id, adj, it.second.derived, n); - n++; - } - for (auto& it : db->usr2type) - if (const auto* def = it.second.AnyDef()) { - add(it.second.uses, 1); - Add(sym2id, adj, it.second.instances, n); - Add(sym2id, adj, def->funcs, n); - Add(sym2id, adj, def->types, n); - //Add(sym2id, adj, def->vars, n); - n++; - } - for (auto& it : db->usr2var) - if (it.second.AnyDef()) { - add(it.second.declarations, kDeclWeight); - add(it.second.uses, 1); - n++; - } - for (int i = 0; i < n; i++) { - double sum = 0; - adj[i][i] += 1; - for (auto& it : adj[i]) - sum += it.second; - for (auto& it : adj[i]) - it.second = it.second / sum * (1 - kDamping); - } - - std::vector x(n, 1), y; - for (int j = 0; j < 8; j++) { - y.assign(n, kDamping); - for (int i = 0; i < n; i++) - for (auto& it : adj[i]) - y[it.first] += x[i] * it.second; - double d = 0; - for (int i = 0; i < n; i++) - d = std::max(d, fabs(x[i] - y[i])); - if (d < 1e-5) - break; - x.swap(y); - } - - double sum = std::accumulate(x.begin(), x.end(), 0.); - Out_LocationList out; - out.id = request->id; - double roulette = rand() / (RAND_MAX + 1.0) * sum; - sum = 0; - for (int i = 0; i < n; i++) { - sum += x[i]; - if (sum >= roulette) { - if (Maybe use = GetDefinitionExtent(db, syms[i])) - if (auto ls_loc = GetLsLocationEx(db, working_files, *use, - g_config->xref.container)) - out.result.push_back(*ls_loc); - break; - } - } - pipeline::WriteStdout(kMethodType, out); - } -}; -REGISTER_MESSAGE_HANDLER(Handler_CclsRandom); -} // namespace diff --git a/src/messages/ccls_vars.cc b/src/messages/ccls_vars.cc index 31e0c779..95d8ff91 100644 --- a/src/messages/ccls_vars.cc +++ b/src/messages/ccls_vars.cc @@ -43,9 +43,9 @@ struct Handler_CclsVars : BaseMessageHandler { [[fallthrough]]; } case SymbolKind::Type: - out.result = GetLsLocationExs( - db, working_files, - GetDeclarations(db->usr2var, db->Type(usr).instances)); + out.result = + GetLsLocationExs(db, working_files, + GetVarDeclarations(db, db->Type(usr).instances)); break; } } diff --git a/src/messages/text_document_code_lens.cc b/src/messages/text_document_code_lens.cc index a5b32fb6..0691ac30 100644 --- a/src/messages/text_document_code_lens.cc +++ b/src/messages/text_document_code_lens.cc @@ -31,7 +31,7 @@ MAKE_REFLECT_STRUCT(Out_TextDocumentCodeLens, jsonrpc, id, result); struct CommonCodeLensParams { std::vector* result; - QueryDatabase* db; + DB* db; WorkingFiles* working_files; WorkingFile* working_file; }; @@ -118,10 +118,10 @@ struct Handler_TextDocumentCodeLens AddCodeLens("ref", "refs", &common, OffsetStartColumn(use, 0), type.uses, true /*force_display*/); AddCodeLens("derived", "derived", &common, OffsetStartColumn(use, 1), - GetDeclarations(db->usr2type, type.derived), + GetTypeDeclarations(db, type.derived), false /*force_display*/); AddCodeLens("var", "vars", &common, OffsetStartColumn(use, 2), - GetDeclarations(db->usr2var, type.instances), + GetVarDeclarations(db, type.instances), false /*force_display*/); break; } @@ -168,7 +168,7 @@ struct Handler_TextDocumentCodeLens AddCodeLens("derived", "derived", &common, OffsetStartColumn(use, offset++), - GetDeclarations(db->usr2func, func.derived), + GetFuncDeclarations(db, func.derived), false /*force_display*/); // "Base" @@ -196,7 +196,7 @@ struct Handler_TextDocumentCodeLens } } else { AddCodeLens("base", "base", &common, OffsetStartColumn(use, 1), - GetDeclarations(db->usr2type, def->bases), + GetTypeDeclarations(db, def->bases), false /*force_display*/); } diff --git a/src/messages/text_document_definition.cc b/src/messages/text_document_definition.cc index 80aaf9a1..b65682a5 100644 --- a/src/messages/text_document_definition.cc +++ b/src/messages/text_document_definition.cc @@ -25,7 +25,7 @@ struct Out_TextDocumentDefinition }; MAKE_REFLECT_STRUCT(Out_TextDocumentDefinition, jsonrpc, id, result); -std::vector GetNonDefDeclarationTargets(QueryDatabase* db, SymbolRef sym) { +std::vector GetNonDefDeclarationTargets(DB* db, SymbolRef sym) { switch (sym.kind) { case SymbolKind::Var: { std::vector ret = GetNonDefDeclarations(db, sym); @@ -135,18 +135,16 @@ struct Handler_TextDocumentDefinition // substring, we use the tuple to find the best match. std::tuple best_score{INT_MAX, 0, true, 0}; - int best_i = -1; - for (int i = 0; i < (int)db->symbols.size(); ++i) { - if (db->symbols[i].kind == SymbolKind::Invalid) - continue; - - std::string_view short_name = db->GetSymbolName(i, false), + SymbolIdx best_sym; + best_sym.kind = SymbolKind::Invalid; + auto fn = [&](SymbolIdx sym) { + std::string_view short_name = db->GetSymbolName(sym, false), name = short_query.size() < query.size() - ? db->GetSymbolName(i, true) + ? db->GetSymbolName(sym, true) : short_name; if (short_name != short_query) - continue; - if (Maybe use = GetDefinitionSpell(db, db->symbols[i])) { + return; + if (Maybe use = GetDefinitionSpell(db, sym)) { std::tuple score{ int(name.size() - short_query.size()), 0, use->file_id != file_id, @@ -160,12 +158,20 @@ struct Handler_TextDocumentDefinition } if (score < best_score) { best_score = score; - best_i = i; + best_sym = sym; } } - } - if (best_i != -1) { - Maybe use = GetDefinitionSpell(db, db->symbols[best_i]); + }; + for (auto& func : db->funcs) + fn({func.usr, SymbolKind::Func}); + for (auto& type : db->types) + fn({type.usr, SymbolKind::Type}); + for (auto& var : db->vars) + if (var.def.size() && !var.def[0].is_local()) + fn({var.usr, SymbolKind::Var}); + + if (best_sym.kind != SymbolKind::Invalid) { + Maybe use = GetDefinitionSpell(db, best_sym); assert(use); if (auto ls_loc = GetLsLocationEx(db, working_files, *use, g_config->xref.container)) diff --git a/src/messages/text_document_hover.cc b/src/messages/text_document_hover.cc index f3f28218..043953d3 100644 --- a/src/messages/text_document_hover.cc +++ b/src/messages/text_document_hover.cc @@ -7,7 +7,7 @@ namespace { MethodType kMethodType = "textDocument/hover"; // Find the comments for |sym|, if any. -std::optional GetComments(QueryDatabase* db, SymbolRef sym) { +std::optional GetComments(DB* db, SymbolRef sym) { std::optional ret; WithEntity(db, sym, [&](const auto& entity) { if (const auto* def = entity.AnyDef()) @@ -21,7 +21,7 @@ std::optional GetComments(QueryDatabase* db, SymbolRef sym) { } // Returns the hover or detailed name for `sym`, if any. -std::optional GetHoverOrName(QueryDatabase* db, +std::optional GetHoverOrName(DB* db, LanguageId lang, SymbolRef sym) { std::optional ret; diff --git a/src/messages/text_document_implementation.cc b/src/messages/text_document_implementation.cc index 8c10fbac..56bf2f23 100644 --- a/src/messages/text_document_implementation.cc +++ b/src/messages/text_document_implementation.cc @@ -32,13 +32,13 @@ struct Handler_TextDocumentImplementation FindSymbolsAtLocation(working_file, file, request->params.position)) { if (sym.kind == SymbolKind::Type) { QueryType& type = db->GetType(sym); - out.result = GetLsLocationExs( - db, working_files, GetDeclarations(db->usr2type, type.derived)); + out.result = GetLsLocationExs(db, working_files, + GetTypeDeclarations(db, type.derived)); break; } else if (sym.kind == SymbolKind::Func) { QueryFunc& func = db->GetFunc(sym); - out.result = GetLsLocationExs( - db, working_files, GetDeclarations(db->usr2func, func.derived)); + out.result = GetLsLocationExs(db, working_files, + GetFuncDeclarations(db, func.derived)); break; } } diff --git a/src/messages/text_document_rename.cc b/src/messages/text_document_rename.cc index 6e2844bb..096b79b9 100644 --- a/src/messages/text_document_rename.cc +++ b/src/messages/text_document_rename.cc @@ -6,7 +6,7 @@ using namespace ccls; namespace { MethodType kMethodType = "textDocument/rename"; -lsWorkspaceEdit BuildWorkspaceEdit(QueryDatabase* db, +lsWorkspaceEdit BuildWorkspaceEdit(DB* db, WorkingFiles* working_files, SymbolRef sym, const std::string& new_text) { diff --git a/src/messages/workspace_symbol.cc b/src/messages/workspace_symbol.cc index d9e88dca..2515b1fc 100644 --- a/src/messages/workspace_symbol.cc +++ b/src/messages/workspace_symbol.cc @@ -15,22 +15,21 @@ MethodType kMethodType = "workspace/symbol"; // Lookup |symbol| in |db| and insert the value into |result|. bool AddSymbol( - QueryDatabase* db, + DB* db, WorkingFiles* working_files, - int i, + SymbolIdx sym, bool use_detailed, - std::vector>* result) { - SymbolIdx symbol = db->symbols[i]; + std::vector>* result) { std::optional info = - GetSymbolInfo(db, working_files, symbol, true); + GetSymbolInfo(db, working_files, sym, true); if (!info) return false; Use loc; - if (Maybe location = GetDefinitionExtent(db, symbol)) + if (Maybe location = GetDefinitionExtent(db, sym)) loc = *location; else { - auto decls = GetNonDefDeclarations(db, symbol); + auto decls = GetNonDefDeclarations(db, sym); if (decls.empty()) return false; loc = decls[0]; @@ -40,7 +39,7 @@ bool AddSymbol( if (!ls_location) return false; info->location = *ls_location; - result->emplace_back(*info, use_detailed, i); + result->emplace_back(*info, int(use_detailed), sym); return true; } @@ -72,7 +71,7 @@ struct Handler_WorkspaceSymbol : BaseMessageHandler { std::string query = request->params.query; // {symbol info, matching detailed_name or short_name, index} - std::vector> unsorted; + std::vector> cands; bool sensitive = g_config->workspaceSymbol.caseSensitivity; // Find subsequence matches. @@ -82,47 +81,52 @@ struct Handler_WorkspaceSymbol : BaseMessageHandler { if (!isspace(c)) query_without_space += c; - for (int i = 0; i < (int)db->symbols.size(); ++i) { - std::string_view detailed_name = db->GetSymbolName(i, true); + auto Add = [&](SymbolIdx sym) { + std::string_view detailed_name = db->GetSymbolName(sym, true); int pos = ReverseSubseqMatch(query_without_space, detailed_name, sensitive); - if (pos >= 0 && - AddSymbol(db, working_files, i, - detailed_name.find(':', pos) != std::string::npos, - &unsorted) && - unsorted.size() >= g_config->workspaceSymbol.maxNum) - break; - } + return pos >= 0 && + AddSymbol(db, working_files, sym, + detailed_name.find(':', pos) != std::string::npos, + &cands) && + cands.size() >= g_config->workspaceSymbol.maxNum; + }; + for (auto& func : db->funcs) + if (Add({func.usr, SymbolKind::Func})) + goto done_add; + for (auto& type : db->types) + if (Add({type.usr, SymbolKind::Type})) + goto done_add; + for (auto& var : db->vars) + if (var.def.size() && !var.def[0].is_local() && + Add({var.usr, SymbolKind::Var})) + goto done_add; + done_add: if (g_config->workspaceSymbol.sort && query.size() <= FuzzyMatcher::kMaxPat) { // Sort results with a fuzzy matching algorithm. int longest = 0; - for (int i = 0; i < int(unsorted.size()); i++) { + for (auto& cand : cands) longest = std::max( - longest, - int(db->GetSymbolName(std::get<2>(unsorted[i]), true).size())); - } + longest, int(db->GetSymbolName(std::get<2>(cand), true).size())); FuzzyMatcher fuzzy(query, g_config->workspaceSymbol.caseSensitivity); - std::vector> permutation(unsorted.size()); - for (int i = 0; i < int(unsorted.size()); i++) { - permutation[i] = { - fuzzy.Match(db->GetSymbolName(std::get<2>(unsorted[i]), - std::get<1>(unsorted[i]))), - i}; + for (auto& cand : cands) + std::get<1>(cand) = fuzzy.Match( + db->GetSymbolName(std::get<2>(cand), std::get<1>(cand))); + std::sort(cands.begin(), cands.end(), [](const auto& l, const auto& r) { + return std::get<1>(l) > std::get<1>(r); + }); + out.result.reserve(cands.size()); + for (auto& cand: cands) { + // Discard awful candidates. + if (std::get<1>(cand) <= FuzzyMatcher::kMinScore) + break; + out.result.push_back(std::get<0>(cand)); } - std::sort(permutation.begin(), permutation.end(), - std::greater>()); - out.result.reserve(unsorted.size()); - // Discard awful candidates. - for (int i = 0; i < int(unsorted.size()) && - permutation[i].first > FuzzyMatcher::kMinScore; - i++) - out.result.push_back( - std::move(std::get<0>(unsorted[permutation[i].second]))); } else { - out.result.reserve(unsorted.size()); - for (auto& entry : unsorted) - out.result.push_back(std::get<0>(entry)); + out.result.reserve(cands.size()); + for (auto& cand : cands) + out.result.push_back(std::get<0>(cand)); } pipeline::WriteStdout(kMethodType, out); diff --git a/src/pipeline.cc b/src/pipeline.cc index 1b06cca7..d65b1db5 100644 --- a/src/pipeline.cc +++ b/src/pipeline.cc @@ -299,7 +299,7 @@ void Indexer_Main(DiagnosticsEngine* diag_engine, indexer_waiter->Wait(index_request); } -void Main_OnIndexed(QueryDatabase* db, +void Main_OnIndexed(DB* db, SemanticHighlightSymbolCache* semantic_cache, WorkingFiles* working_files, Index_OnIndexed* response) { @@ -431,7 +431,7 @@ void MainLoop() { auto global_code_complete_cache = std::make_unique(); auto non_global_code_complete_cache = std::make_unique(); auto signature_cache = std::make_unique(); - QueryDatabase db; + DB db; // Setup shared references. for (MessageHandler* handler : *MessageHandler::message_handlers) { diff --git a/src/query.cc b/src/query.cc index 256d5fa3..c221c3f8 100644 --- a/src/query.cc +++ b/src/query.cc @@ -14,7 +14,7 @@ #include #include -// Used by |HANDLE_MERGEABLE| so only |range| is needed. +// Used by |REMOVE_ADD| so only |range| is needed. MAKE_HASHABLE(Use, t.range, t.file_id); namespace { @@ -178,6 +178,7 @@ IndexUpdate IndexUpdate::CreateDelta(IndexFile* previous, r.files_def_update = BuildFileDefUpdate(std::move(*current)); + r.funcs_hint = current->usr2func.size() - previous->usr2func.size(); for (auto& it : previous->usr2func) { auto& func = it.second; if (func.def.spell) @@ -195,6 +196,7 @@ IndexUpdate IndexUpdate::CreateDelta(IndexFile* previous, r.funcs_derived[func.usr].second = std::move(func.derived); } + r.types_hint = current->usr2type.size() - previous->usr2type.size(); for (auto& it : previous->usr2type) { auto& type = it.second; if (type.def.spell) @@ -214,6 +216,7 @@ IndexUpdate IndexUpdate::CreateDelta(IndexFile* previous, r.types_instances[type.usr].second = std::move(type.instances); }; + r.vars_hint = current->usr2var.size() - previous->usr2var.size(); for (auto& it : previous->usr2var) { auto& var = it.second; if (var.def.spell) @@ -232,34 +235,14 @@ IndexUpdate IndexUpdate::CreateDelta(IndexFile* previous, return r; } -// ------------------------ -// QUERYDB THREAD FUNCTIONS -// ------------------------ - -void QueryDatabase::RemoveUsrs(SymbolKind usr_kind, - const std::vector& to_remove) { - switch (usr_kind) { - case SymbolKind::Type: { - for (Usr usr : to_remove) { - QueryType& type = usr2type[usr]; - if (type.symbol_idx >= 0) - symbols[type.symbol_idx].kind = SymbolKind::Invalid; - type.def.clear(); - } - break; - } - default: - break; - } -} - -void QueryDatabase::RemoveUsrs( - SymbolKind kind, - int file_id, - const std::vector& to_remove) { +void DB::RemoveUsrs(SymbolKind kind, + int file_id, + const std::vector& to_remove) { switch (kind) { case SymbolKind::Func: { - for (auto usr : to_remove) { + for (Usr usr : to_remove) { + // FIXME + if (!HasFunc(usr)) continue; QueryFunc& func = Func(usr); auto it = llvm::find_if(func.def, [=](const QueryFunc::Def& def) { return def.spell->file_id == file_id; @@ -269,8 +252,23 @@ void QueryDatabase::RemoveUsrs( } break; } + case SymbolKind::Type: { + for (Usr usr : to_remove) { + // FIXME + if (!HasType(usr)) continue; + QueryType& type = Type(usr); + auto it = llvm::find_if(type.def, [=](const QueryType::Def& def) { + return def.spell->file_id == file_id; + }); + if (it != type.def.end()) + type.def.erase(it); + } + break; + } case SymbolKind::Var: { - for (auto usr : to_remove) { + for (Usr usr : to_remove) { + // FIXME + if (!HasVar(usr)) continue; QueryVar& var = Var(usr); auto it = llvm::find_if(var.def, [=](const QueryVar::Def& def) { return def.spell->file_id == file_id; @@ -281,26 +279,21 @@ void QueryDatabase::RemoveUsrs( break; } default: - assert(false); break; } } -void QueryDatabase::ApplyIndexUpdate(IndexUpdate* u) { -// This function runs on the querydb thread. - -// Example types: -// storage_name => std::vector> -// merge_update => QueryType::DerivedUpdate => -// MergeableUpdate def => QueryType -// def->def_var_name => std::vector -#define HANDLE_MERGEABLE(update_var_name, def_var_name, storage_name) \ - for (auto& it : u->update_var_name) { \ - auto& entity = storage_name[it.first]; \ - AssignFileId(u->file_id, it.second.first); \ - RemoveRange(entity.def_var_name, it.second.first); \ - AssignFileId(u->file_id, it.second.second); \ - AddRange(u->file_id, entity.def_var_name, it.second.second); \ +void DB::ApplyIndexUpdate(IndexUpdate* u) { +#define REMOVE_ADD(C, F) \ + for (auto& it : u->C##s_##F) { \ + auto R = C##_usr.try_emplace({it.first}, C##_usr.size()); \ + if (R.second) \ + C##s.emplace_back().usr = it.first; \ + auto& entity = C##s[R.first->second]; \ + AssignFileId(u->file_id, it.second.first); \ + RemoveRange(entity.F, it.second.first); \ + AssignFileId(u->file_id, it.second.second); \ + AddRange(u->file_id, entity.F, it.second.second); \ } if (u->files_removed) @@ -308,101 +301,108 @@ void QueryDatabase::ApplyIndexUpdate(IndexUpdate* u) { std::nullopt; u->file_id = u->files_def_update ? Update(std::move(*u->files_def_update)) : -1; + const double grow = 1.3; + size_t t; + + if ((t = funcs.size() + u->funcs_hint) > funcs.capacity()) { + t = size_t(t * grow); + funcs.reserve(t); + func_usr.reserve(t); + } RemoveUsrs(SymbolKind::Func, u->file_id, u->funcs_removed); Update(u->file_id, std::move(u->funcs_def_update)); - HANDLE_MERGEABLE(funcs_declarations, declarations, usr2func); - HANDLE_MERGEABLE(funcs_derived, derived, usr2func); - HANDLE_MERGEABLE(funcs_uses, uses, usr2func); + REMOVE_ADD(func, declarations); + REMOVE_ADD(func, derived); + REMOVE_ADD(func, uses); - RemoveUsrs(SymbolKind::Type, u->types_removed); + if ((t = types.size() + u->types_hint) > types.capacity()) { + t = size_t(t * grow); + types.reserve(t); + type_usr.reserve(t); + } + RemoveUsrs(SymbolKind::Type, u->file_id, u->types_removed); Update(u->file_id, std::move(u->types_def_update)); - HANDLE_MERGEABLE(types_declarations, declarations, usr2type); - HANDLE_MERGEABLE(types_derived, derived, usr2type); - HANDLE_MERGEABLE(types_instances, instances, usr2type); - HANDLE_MERGEABLE(types_uses, uses, usr2type); + REMOVE_ADD(type, declarations); + REMOVE_ADD(type, derived); + REMOVE_ADD(type, instances); + REMOVE_ADD(type, uses); + if ((t = vars.size() + u->vars_hint) > vars.capacity()) { + t = size_t(t * grow); + vars.reserve(t); + var_usr.reserve(t); + } RemoveUsrs(SymbolKind::Var, u->file_id, u->vars_removed); Update(u->file_id, std::move(u->vars_def_update)); - HANDLE_MERGEABLE(vars_declarations, declarations, usr2var); - HANDLE_MERGEABLE(vars_uses, uses, usr2var); + REMOVE_ADD(var, declarations); + REMOVE_ADD(var, uses); -#undef HANDLE_MERGEABLE +#undef REMOVE_ADD } -int QueryDatabase::Update(QueryFile::DefUpdate&& u) { +int DB::Update(QueryFile::DefUpdate&& u) { int id = files.size(); auto it = name2file_id.try_emplace(LowerPathIfInsensitive(u.value.path), id); if (it.second) files.emplace_back().id = id; QueryFile& existing = files[it.first->second]; existing.def = u.value; - UpdateSymbols(&existing.symbol_idx, SymbolKind::File, it.first->second); return existing.id; } -void QueryDatabase::Update(int file_id, - std::vector>&& us) { +void DB::Update(int file_id, std::vector>&& us) { for (auto& u : us) { auto& def = u.second; assert(!def.detailed_name.empty()); AssignFileId(file_id, def.spell); AssignFileId(file_id, def.extent); AssignFileId(file_id, def.callees); - QueryFunc& existing = Func(u.first); + auto R = func_usr.try_emplace({u.first}, func_usr.size()); + if (R.second) + funcs.emplace_back(); + QueryFunc& existing = funcs[R.first->second]; existing.usr = u.first; - if (!TryReplaceDef(existing.def, std::move(def))) { + if (!TryReplaceDef(existing.def, std::move(def))) existing.def.push_back(std::move(def)); - UpdateSymbols(&existing.symbol_idx, SymbolKind::Func, u.first); - } } } -void QueryDatabase::Update(int file_id, - std::vector>&& us) { +void DB::Update(int file_id, std::vector>&& us) { for (auto& u : us) { auto& def = u.second; assert(!def.detailed_name.empty()); AssignFileId(file_id, def.spell); AssignFileId(file_id, def.extent); - QueryType& existing = Type(u.first); + auto R = type_usr.try_emplace({u.first}, type_usr.size()); + if (R.second) + types.emplace_back(); + QueryType& existing = types[R.first->second]; existing.usr = u.first; - if (!TryReplaceDef(existing.def, std::move(def))) { + if (!TryReplaceDef(existing.def, std::move(def))) existing.def.push_back(std::move(def)); - UpdateSymbols(&existing.symbol_idx, SymbolKind::Type, u.first); - } + } } -void QueryDatabase::Update(int file_id, - std::vector>&& us) { +void DB::Update(int file_id, std::vector>&& us) { for (auto& u : us) { auto& def = u.second; assert(!def.detailed_name.empty()); AssignFileId(file_id, def.spell); AssignFileId(file_id, def.extent); - QueryVar& existing = Var(u.first); + auto R = var_usr.try_emplace({u.first}, var_usr.size()); + if (R.second) + vars.emplace_back(); + QueryVar& existing = vars[R.first->second]; existing.usr = u.first; - if (!TryReplaceDef(existing.def, std::move(def))) { + if (!TryReplaceDef(existing.def, std::move(def))) existing.def.push_back(std::move(def)); - if (!existing.def.front().is_local()) - UpdateSymbols(&existing.symbol_idx, SymbolKind::Var, u.first); - } } } -void QueryDatabase::UpdateSymbols(int* symbol_idx, - SymbolKind kind, - Usr usr) { - if (*symbol_idx < 0) { - *symbol_idx = symbols.size(); - symbols.push_back(SymbolIdx{usr, kind}); - } -} - -std::string_view QueryDatabase::GetSymbolName(int symbol_idx, - bool qualified) { - Usr usr = symbols[symbol_idx].usr; - switch (symbols[symbol_idx].kind) { +std::string_view DB::GetSymbolName(SymbolIdx sym, bool qualified) { + Usr usr = sym.usr; + switch (sym.kind) { default: break; case SymbolKind::File: diff --git a/src/query.h b/src/query.h index 0186e070..d7621f1b 100644 --- a/src/query.h +++ b/src/query.h @@ -3,13 +3,14 @@ #include "indexer.h" #include "serializer.h" +#include #include struct QueryFile; struct QueryType; struct QueryFunc; struct QueryVar; -struct QueryDatabase; +struct DB; template struct WithFileContent { @@ -41,7 +42,6 @@ struct QueryFile { int id = -1; std::optional def; - int symbol_idx = -1; }; template @@ -66,7 +66,6 @@ using UsrUpdate = struct QueryFunc : QueryEntity { Usr usr; - int symbol_idx = -1; llvm::SmallVector def; std::vector declarations; std::vector uses; @@ -75,7 +74,6 @@ struct QueryFunc : QueryEntity { struct QueryType : QueryEntity { Usr usr; - int symbol_idx = -1; llvm::SmallVector def; std::vector declarations; std::vector uses; @@ -85,7 +83,6 @@ struct QueryType : QueryEntity { struct QueryVar : QueryEntity { Usr usr; - int symbol_idx = -1; llvm::SmallVector def; std::vector declarations; std::vector uses; @@ -107,6 +104,7 @@ struct IndexUpdate { std::optional files_def_update; // Function updates. + int funcs_hint; std::vector funcs_removed; std::vector> funcs_def_update; UseUpdate funcs_declarations; @@ -114,6 +112,7 @@ struct IndexUpdate { UsrUpdate funcs_derived; // Type updates. + int types_hint; std::vector types_removed; std::vector> types_def_update; UseUpdate types_declarations; @@ -122,23 +121,42 @@ struct IndexUpdate { UsrUpdate types_instances; // Variable updates. + int vars_hint; std::vector vars_removed; std::vector> vars_def_update; UseUpdate vars_declarations; UseUpdate vars_uses; }; +template +struct EntityToIndex { + using argument_type = const Q&; + llvm::DenseMap m; + unsigned operator()(const Q& entity) const { + return m[entity.usr]; + } +}; + +struct WrappedUsr { + Usr usr; +}; +template <> +struct llvm::DenseMapInfo { + static inline WrappedUsr getEmptyKey() { return {0}; } + static inline WrappedUsr getTombstoneKey() { return {~0ULL}; } + static unsigned getHashValue(WrappedUsr w) { return w.usr; } + static bool isEqual(WrappedUsr l, WrappedUsr r) { return l.usr == r.usr; } +}; + // The query database is heavily optimized for fast queries. It is stored // in-memory. -struct QueryDatabase { - // All File/Func/Type/Var symbols. - std::vector symbols; - +struct DB { std::vector files; llvm::StringMap name2file_id; - std::unordered_map usr2func; - std::unordered_map usr2type; - std::unordered_map usr2var; + llvm::DenseMap func_usr, type_usr, var_usr; + std::vector funcs; + std::vector types; + std::vector vars; // Marks the given Usrs as invalid. void RemoveUsrs(SymbolKind usr_kind, const std::vector& to_remove); @@ -149,15 +167,18 @@ struct QueryDatabase { void Update(int file_id, std::vector>&& us); void Update(int file_id, std::vector>&& us); void Update(int file_id, std::vector>&& us); - void UpdateSymbols(int* symbol_idx, SymbolKind kind, Usr usr); - std::string_view GetSymbolName(int symbol_idx, bool qualified); + std::string_view GetSymbolName(SymbolIdx sym, bool qualified); + + bool HasFunc(Usr usr) const { return func_usr.count({usr}); } + bool HasType(Usr usr) const { return type_usr.count({usr}); } + bool HasVar(Usr usr) const { return var_usr.count({usr}); } + + QueryFunc& Func(Usr usr) { return funcs[func_usr[{usr}]]; } + QueryType& Type(Usr usr) { return types[type_usr[{usr}]]; } + QueryVar& Var(Usr usr) { return vars[var_usr[{usr}]]; } QueryFile& GetFile(SymbolIdx ref) { return files[ref.usr]; } - QueryFunc& GetFunc(SymbolIdx ref) { return usr2func[ref.usr]; } - QueryType& GetType(SymbolIdx ref) { return usr2type[ref.usr]; } - QueryVar& GetVar(SymbolIdx ref) { return usr2var[ref.usr]; } - - QueryFunc& Func(Usr usr) { return usr2func[usr]; } - QueryType& Type(Usr usr) { return usr2type[usr]; } - QueryVar& Var(Usr usr) { return usr2var[usr]; } + QueryFunc& GetFunc(SymbolIdx ref) { return Func(ref.usr); } + QueryType& GetType(SymbolIdx ref) { return Type(ref.usr); } + QueryVar& GetVar(SymbolIdx ref) { return Var(ref.usr); } }; diff --git a/src/query_utils.cc b/src/query_utils.cc index 04031ded..6ffdb4af 100644 --- a/src/query_utils.cc +++ b/src/query_utils.cc @@ -14,15 +14,36 @@ int ComputeRangeSize(const Range& range) { return range.end.column - range.start.column; } +template +std::vector GetDeclarations(llvm::DenseMap& entity_usr, + std::vector& entities, + const std::vector& usrs) { + std::vector ret; + ret.reserve(usrs.size()); + for (Usr usr : usrs) { + Q& entity = entities[entity_usr[{usr}]]; + bool has_def = false; + for (auto& def : entity.def) + if (def.spell) { + ret.push_back(*def.spell); + has_def = true; + break; + } + if (!has_def && entity.declarations.size()) + ret.push_back(entity.declarations[0]); + } + return ret; +} + } // namespace -Maybe GetDefinitionSpell(QueryDatabase* db, SymbolIdx sym) { +Maybe GetDefinitionSpell(DB* db, SymbolIdx sym) { Maybe ret; EachEntityDef(db, sym, [&](const auto& def) { return !(ret = def.spell); }); return ret; } -Maybe GetDefinitionExtent(QueryDatabase* db, SymbolIdx sym) { +Maybe GetDefinitionExtent(DB* db, SymbolIdx sym) { // Used to jump to file. if (sym.kind == SymbolKind::File) return Use{{Range{{0, 0}, {0, 0}}, sym.usr, sym.kind, Role::None}, @@ -32,7 +53,17 @@ Maybe GetDefinitionExtent(QueryDatabase* db, SymbolIdx sym) { return ret; } -std::vector GetNonDefDeclarations(QueryDatabase* db, SymbolIdx sym) { +std::vector GetFuncDeclarations(DB* db, const std::vector& usrs) { + return GetDeclarations(db->func_usr, db->funcs, usrs); +} +std::vector GetTypeDeclarations(DB* db, const std::vector& usrs) { + return GetDeclarations(db->type_usr, db->types, usrs); +} +std::vector GetVarDeclarations(DB* db, const std::vector& usrs) { + return GetDeclarations(db->var_usr, db->vars, usrs); +} + +std::vector GetNonDefDeclarations(DB* db, SymbolIdx sym) { switch (sym.kind) { case SymbolKind::Func: return db->GetFunc(sym).declarations; @@ -45,7 +76,7 @@ std::vector GetNonDefDeclarations(QueryDatabase* db, SymbolIdx sym) { } } -std::vector GetUsesForAllBases(QueryDatabase* db, QueryFunc& root) { +std::vector GetUsesForAllBases(DB* db, QueryFunc& root) { std::vector ret; std::vector stack{&root}; std::unordered_set seen; @@ -54,7 +85,7 @@ std::vector GetUsesForAllBases(QueryDatabase* db, QueryFunc& root) { QueryFunc& func = *stack.back(); stack.pop_back(); if (auto* def = func.AnyDef()) { - EachDefinedEntity(db->usr2func, def->bases, [&](QueryFunc& func1) { + EachDefinedFunc(db, def->bases, [&](QueryFunc& func1) { if (!seen.count(func1.usr)) { seen.insert(func1.usr); stack.push_back(&func1); @@ -67,7 +98,7 @@ std::vector GetUsesForAllBases(QueryDatabase* db, QueryFunc& root) { return ret; } -std::vector GetUsesForAllDerived(QueryDatabase* db, QueryFunc& root) { +std::vector GetUsesForAllDerived(DB* db, QueryFunc& root) { std::vector ret; std::vector stack{&root}; std::unordered_set seen; @@ -75,7 +106,7 @@ std::vector GetUsesForAllDerived(QueryDatabase* db, QueryFunc& root) { while (!stack.empty()) { QueryFunc& func = *stack.back(); stack.pop_back(); - EachDefinedEntity(db->usr2func, func.derived, [&](QueryFunc& func1) { + EachDefinedFunc(db, func.derived, [&](QueryFunc& func1) { if (!seen.count(func1.usr)) { seen.insert(func1.usr); stack.push_back(&func1); @@ -88,7 +119,7 @@ std::vector GetUsesForAllDerived(QueryDatabase* db, QueryFunc& root) { } std::optional GetLsPosition(WorkingFile* working_file, - const Position& position) { + const Position& position) { if (!working_file) return lsPosition{position.line, position.column}; @@ -99,7 +130,8 @@ std::optional GetLsPosition(WorkingFile* working_file, return std::nullopt; } -std::optional GetLsRange(WorkingFile* working_file, const Range& location) { +std::optional GetLsRange(WorkingFile* working_file, + const Range& location) { if (!working_file) { return lsRange{lsPosition{location.start.line, location.start.column}, lsPosition{location.end.line, location.end.column}}; @@ -108,8 +140,8 @@ std::optional GetLsRange(WorkingFile* working_file, const Range& locati int start_column = location.start.column, end_column = location.end.column; std::optional start = working_file->GetBufferPosFromIndexPos( location.start.line, &start_column, false); - std::optional end = working_file->GetBufferPosFromIndexPos(location.end.line, - &end_column, true); + std::optional end = working_file->GetBufferPosFromIndexPos( + location.end.line, &end_column, true); if (!start || !end) return std::nullopt; @@ -128,9 +160,7 @@ std::optional GetLsRange(WorkingFile* working_file, const Range& locati lsPosition{*end, end_column}}; } -lsDocumentUri GetLsDocumentUri(QueryDatabase* db, - int file_id, - std::string* path) { +lsDocumentUri GetLsDocumentUri(DB* db, int file_id, std::string* path) { QueryFile& file = db->files[file_id]; if (file.def) { *path = file.def->path; @@ -141,7 +171,7 @@ lsDocumentUri GetLsDocumentUri(QueryDatabase* db, } } -lsDocumentUri GetLsDocumentUri(QueryDatabase* db, int file_id) { +lsDocumentUri GetLsDocumentUri(DB* db, int file_id) { QueryFile& file = db->files[file_id]; if (file.def) { return lsDocumentUri::FromPath(file.def->path); @@ -150,9 +180,9 @@ lsDocumentUri GetLsDocumentUri(QueryDatabase* db, int file_id) { } } -std::optional GetLsLocation(QueryDatabase* db, - WorkingFiles* working_files, - Use use) { +std::optional GetLsLocation(DB* db, + WorkingFiles* working_files, + Use use) { std::string path; lsDocumentUri uri = GetLsDocumentUri(db, use.file_id, &path); std::optional range = @@ -162,10 +192,10 @@ std::optional GetLsLocation(QueryDatabase* db, return lsLocation{uri, *range}; } -std::optional GetLsLocationEx(QueryDatabase* db, - WorkingFiles* working_files, - Use use, - bool container) { +std::optional GetLsLocationEx(DB* db, + WorkingFiles* working_files, + Use use, + bool container) { std::optional ls_loc = GetLsLocation(db, working_files, use); if (!ls_loc) return std::nullopt; @@ -181,7 +211,7 @@ std::optional GetLsLocationEx(QueryDatabase* db, return ret; } -std::vector GetLsLocationExs(QueryDatabase* db, +std::vector GetLsLocationExs(DB* db, WorkingFiles* working_files, const std::vector& uses) { std::vector ret; @@ -196,7 +226,7 @@ std::vector GetLsLocationExs(QueryDatabase* db, return ret; } -lsSymbolKind GetSymbolKind(QueryDatabase* db, SymbolIdx sym) { +lsSymbolKind GetSymbolKind(DB* db, SymbolIdx sym) { lsSymbolKind ret; if (sym.kind == SymbolKind::File) ret = lsSymbolKind::File; @@ -213,10 +243,10 @@ lsSymbolKind GetSymbolKind(QueryDatabase* db, SymbolIdx sym) { } // Returns a symbol. The symbol will have *NOT* have a location assigned. -std::optional GetSymbolInfo(QueryDatabase* db, - WorkingFiles* working_files, - SymbolIdx sym, - bool detailed_name) { +std::optional GetSymbolInfo(DB* db, + WorkingFiles* working_files, + SymbolIdx sym, + bool detailed_name) { switch (sym.kind) { case SymbolKind::Invalid: break; @@ -254,7 +284,7 @@ std::vector FindSymbolsAtLocation(WorkingFile* working_file, std::vector symbols; if (working_file) { if (auto line = working_file->GetIndexPosFromBufferPos( - ls_pos.line, &ls_pos.character, false)) { + ls_pos.line, &ls_pos.character, false)) { ls_pos.line = *line; } else { ls_pos.line = -1; diff --git a/src/query_utils.h b/src/query_utils.h index 1e65b2a3..239738cb 100644 --- a/src/query_utils.h +++ b/src/query_utils.h @@ -5,66 +5,49 @@ #include -Maybe GetDefinitionSpell(QueryDatabase* db, SymbolIdx sym); -Maybe GetDefinitionExtent(QueryDatabase* db, SymbolIdx sym); +Maybe GetDefinitionSpell(DB* db, SymbolIdx sym); +Maybe GetDefinitionExtent(DB* db, SymbolIdx sym); // Get defining declaration (if exists) or an arbitrary declaration (otherwise) // for each id. -template -std::vector GetDeclarations(std::unordered_map& usr2entity, - const std::vector& usrs) { - std::vector ret; - ret.reserve(usrs.size()); - for (Usr usr : usrs) { - Q& entity = usr2entity[usr]; - bool has_def = false; - for (auto& def : entity.def) - if (def.spell) { - ret.push_back(*def.spell); - has_def = true; - break; - } - if (!has_def && entity.declarations.size()) - ret.push_back(entity.declarations[0]); - } - return ret; -} +std::vector GetFuncDeclarations(DB*, const std::vector&); +std::vector GetTypeDeclarations(DB*, const std::vector&); +std::vector GetVarDeclarations(DB*, const std::vector&); // Get non-defining declarations. -std::vector GetNonDefDeclarations(QueryDatabase* db, SymbolIdx sym); +std::vector GetNonDefDeclarations(DB* db, SymbolIdx sym); -std::vector GetUsesForAllBases(QueryDatabase* db, QueryFunc& root); -std::vector GetUsesForAllDerived(QueryDatabase* db, QueryFunc& root); +std::vector GetUsesForAllBases(DB* db, QueryFunc& root); +std::vector GetUsesForAllDerived(DB* db, QueryFunc& root); std::optional GetLsPosition(WorkingFile* working_file, - const Position& position); -std::optional GetLsRange(WorkingFile* working_file, const Range& location); -lsDocumentUri GetLsDocumentUri(QueryDatabase* db, - int file_id, - std::string* path); -lsDocumentUri GetLsDocumentUri(QueryDatabase* db, int file_id); + const Position& position); +std::optional GetLsRange(WorkingFile* working_file, + const Range& location); +lsDocumentUri GetLsDocumentUri(DB* db, int file_id, std::string* path); +lsDocumentUri GetLsDocumentUri(DB* db, int file_id); -std::optional GetLsLocation(QueryDatabase* db, - WorkingFiles* working_files, - Use use); -std::optional GetLsLocationEx(QueryDatabase* db, - WorkingFiles* working_files, - Use use, - bool container); -std::vector GetLsLocationExs(QueryDatabase* db, +std::optional GetLsLocation(DB* db, + WorkingFiles* working_files, + Use use); +std::optional GetLsLocationEx(DB* db, + WorkingFiles* working_files, + Use use, + bool container); +std::vector GetLsLocationExs(DB* db, WorkingFiles* working_files, const std::vector& refs); // Returns a symbol. The symbol will have *NOT* have a location assigned. -std::optional GetSymbolInfo(QueryDatabase* db, - WorkingFiles* working_files, - SymbolIdx sym, - bool detailed_name); +std::optional GetSymbolInfo(DB* db, + WorkingFiles* working_files, + SymbolIdx sym, + bool detailed_name); std::vector FindSymbolsAtLocation(WorkingFile* working_file, QueryFile* file, lsPosition& ls_pos); template -void WithEntity(QueryDatabase* db, SymbolIdx sym, Fn&& fn) { +void WithEntity(DB* db, SymbolIdx sym, Fn&& fn) { switch (sym.kind) { case SymbolKind::Invalid: case SymbolKind::File: @@ -82,7 +65,7 @@ void WithEntity(QueryDatabase* db, SymbolIdx sym, Fn&& fn) { } template -void EachEntityDef(QueryDatabase* db, SymbolIdx sym, Fn&& fn) { +void EachEntityDef(DB* db, SymbolIdx sym, Fn&& fn) { WithEntity(db, sym, [&](const auto& entity) { for (auto& def : entity.def) if (!fn(def)) @@ -91,10 +74,7 @@ void EachEntityDef(QueryDatabase* db, SymbolIdx sym, Fn&& fn) { } template -void EachOccurrence(QueryDatabase* db, - SymbolIdx sym, - bool include_decl, - Fn&& fn) { +void EachOccurrence(DB* db, SymbolIdx sym, bool include_decl, Fn&& fn) { WithEntity(db, sym, [&](const auto& entity) { for (Use use : entity.uses) fn(use); @@ -108,14 +88,31 @@ void EachOccurrence(QueryDatabase* db, }); } -lsSymbolKind GetSymbolKind(QueryDatabase* db, SymbolIdx sym); +lsSymbolKind GetSymbolKind(DB* db, SymbolIdx sym); -template -void EachDefinedEntity(std::unordered_map& collection, - const std::vector& usrs, - Fn&& fn) { +template +void EachDefinedFunc(DB* db, const std::vector& usrs, Fn&& fn) { for (Usr usr : usrs) { - Q& obj = collection[usr]; + auto& obj = db->Func(usr); + if (!obj.def.empty()) + fn(obj); + } +} + + +template +void EachDefinedType(DB* db, const std::vector& usrs, Fn&& fn) { + for (Usr usr : usrs) { + auto& obj = db->Type(usr); + if (!obj.def.empty()) + fn(obj); + } +} + +template +void EachDefinedVar(DB* db, const std::vector& usrs, Fn&& fn) { + for (Usr usr : usrs) { + auto& obj = db->Var(usr); if (!obj.def.empty()) fn(obj); }