From 90a94cbb4f72bb539787ee7dfb5130379d251507 Mon Sep 17 00:00:00 2001 From: Fangrui Song Date: Mon, 29 Oct 2018 23:49:52 -0700 Subject: [PATCH] textDocument/references workspace/symbol: add folders For textDocument/reference, base/excludeRole/role has been lifted from params.context.* to params.* --- src/message_handler.cc | 2 +- src/message_handler.hh | 3 ++ src/messages/textDocument_definition.cc | 4 +-- src/messages/textDocument_references.cc | 41 +++++++++++++++---------- src/messages/workspace.cc | 40 ++++++++++++++++-------- src/query.cc | 18 +++++++++++ src/query.hh | 1 + src/query_utils.cc | 18 ++++------- src/query_utils.hh | 2 +- 9 files changed, 84 insertions(+), 45 deletions(-) diff --git a/src/message_handler.cc b/src/message_handler.cc index 427dac75..dd04f797 100644 --- a/src/message_handler.cc +++ b/src/message_handler.cc @@ -60,7 +60,7 @@ MAKE_REFLECT_STRUCT(DidChangeWatchedFilesParam::Event, uri, type); MAKE_REFLECT_STRUCT(DidChangeWatchedFilesParam, changes); MAKE_REFLECT_STRUCT(DidChangeWorkspaceFoldersParam::Event, added, removed); MAKE_REFLECT_STRUCT(DidChangeWorkspaceFoldersParam, event); -MAKE_REFLECT_STRUCT(WorkspaceSymbolParam, query); +MAKE_REFLECT_STRUCT(WorkspaceSymbolParam, query, folders); namespace { struct CclsSemanticHighlightSymbol { diff --git a/src/message_handler.hh b/src/message_handler.hh index 8410390f..d1d81ddc 100644 --- a/src/message_handler.hh +++ b/src/message_handler.hh @@ -174,6 +174,9 @@ struct DidChangeWorkspaceFoldersParam { }; struct WorkspaceSymbolParam { std::string query; + + // ccls extensions + std::vector folders; }; // TODO llvm 8 llvm::unique_function diff --git a/src/messages/textDocument_definition.cc b/src/messages/textDocument_definition.cc index 36eb2b76..00834fc3 100644 --- a/src/messages/textDocument_definition.cc +++ b/src/messages/textDocument_definition.cc @@ -22,10 +22,10 @@ limitations under the License. namespace ccls { namespace { -std::vector GetNonDefDeclarationTargets(DB *db, SymbolRef sym) { +std::vector GetNonDefDeclarationTargets(DB *db, SymbolRef sym) { switch (sym.kind) { case SymbolKind::Var: { - std::vector ret = GetNonDefDeclarations(db, sym); + std::vector ret = GetNonDefDeclarations(db, sym); // If there is no declaration, jump to its type. if (ret.empty()) { for (auto &def : db->GetVar(sym).def) diff --git a/src/messages/textDocument_references.cc b/src/messages/textDocument_references.cc index 5ccad7ae..fca73c83 100644 --- a/src/messages/textDocument_references.cc +++ b/src/messages/textDocument_references.cc @@ -22,18 +22,23 @@ namespace ccls { namespace { struct ReferenceParam : public TextDocumentPositionParam { struct Context { - bool base = true; - // Exclude references with any |Role| bits set. - Role excludeRole = Role::None; // Include the declaration of the current symbol. bool includeDeclaration = false; - // Include references with all |Role| bits set. - Role role = Role::None; } context; + + // ccls extension + // If not empty, restrict to specified folders. + std::vector folders; + // For Type, also return references of base types. + bool base = true; + // Exclude references with any |Role| bits set. + Role excludeRole = Role::None; + // Include references with all |Role| bits set. + Role role = Role::None; }; -MAKE_REFLECT_STRUCT(ReferenceParam::Context, base, excludeRole, - includeDeclaration, role); -MAKE_REFLECT_STRUCT(ReferenceParam, textDocument, position, context); +MAKE_REFLECT_STRUCT(ReferenceParam::Context, includeDeclaration); +MAKE_REFLECT_STRUCT(ReferenceParam, textDocument, position, context, folders, + base, excludeRole, role); } // namespace void MessageHandler::textDocument_references(Reader &reader, ReplyOnce &reply) { @@ -42,10 +47,13 @@ void MessageHandler::textDocument_references(Reader &reader, ReplyOnce &reply) { QueryFile *file = FindFile(reply, param.textDocument.uri.GetPath()); if (!file) return; - std::vector result; WorkingFile *wfile = wfiles->GetFileByFilename(file->def->path); - if (!file) + if (!wfile) return; + for (auto &folder : param.folders) + EnsureEndsInSlash(folder); + std::vector file_set = db->GetFileSet(param.folders); + std::vector result; std::unordered_set seen_uses; int line = param.position.line; @@ -56,24 +64,23 @@ void MessageHandler::textDocument_references(Reader &reader, ReplyOnce &reply) { seen.insert(sym.usr); std::vector stack{sym.usr}; if (sym.kind != SymbolKind::Func) - param.context.base = false; + param.base = false; while (stack.size()) { sym.usr = stack.back(); stack.pop_back(); auto fn = [&](Use use, lsSymbolKind parent_kind) { - if (Role(use.role & param.context.role) == param.context.role && - !(use.role & param.context.excludeRole) && - seen_uses.insert(use).second) - if (auto loc = GetLsLocation(db, wfiles, use)) { + if (file_set[use.file_id] && + Role(use.role & param.role) == param.role && + !(use.role & param.excludeRole) && seen_uses.insert(use).second) + if (auto loc = GetLsLocation(db, wfiles, use)) result.push_back(*loc); - } }; WithEntity(db, sym, [&](const auto &entity) { lsSymbolKind parent_kind = lsSymbolKind::Unknown; for (auto &def : entity.def) if (def.spell) { parent_kind = GetSymbolKind(db, sym); - if (param.context.base) + if (param.base) for (Usr usr : def.GetBases()) if (!seen.count(usr)) { seen.insert(usr); diff --git a/src/messages/workspace.cc b/src/messages/workspace.cc index c1229cf4..695b2ab4 100644 --- a/src/messages/workspace.cc +++ b/src/messages/workspace.cc @@ -22,6 +22,7 @@ limitations under the License. #include "query_utils.hh" #include +#include #include #include @@ -96,23 +97,35 @@ void MessageHandler::workspace_didChangeWorkspaceFolders( namespace { // Lookup |symbol| in |db| and insert the value into |result|. bool AddSymbol( - DB *db, WorkingFiles *wfiles, SymbolIdx sym, bool use_detailed, + DB *db, WorkingFiles *wfiles, const std::vector &file_set, + SymbolIdx sym, bool use_detailed, std::vector> *result) { std::optional info = GetSymbolInfo(db, sym, true); if (!info) return false; - Use loc; - if (Maybe dr = GetDefinitionSpell(db, sym)) - loc = *dr; - else { - auto decls = GetNonDefDeclarations(db, sym); - if (decls.empty()) - return false; - loc = decls[0]; + Maybe dr; + bool in_folder = false; + WithEntity(db, sym, [&](const auto &entity) { + for (auto &def : entity.def) + if (def.spell) { + dr = def.spell; + if (!in_folder && (in_folder = file_set[def.spell->file_id])) + break; + } + }); + if (!dr) { + auto &decls = GetNonDefDeclarations(db, sym); + for (auto &dr1 : decls) { + dr = dr1; + if (!in_folder && (in_folder = file_set[dr1.file_id])) + break; + } } + if (!in_folder) + return false; - std::optional ls_location = GetLsLocation(db, wfiles, loc); + std::optional ls_location = GetLsLocation(db, wfiles, *dr); if (!ls_location) return false; info->location = *ls_location; @@ -124,7 +137,10 @@ bool AddSymbol( void MessageHandler::workspace_symbol(WorkspaceSymbolParam ¶m, ReplyOnce &reply) { std::vector result; - std::string query = param.query; + const std::string &query = param.query; + for (auto &folder : param.folders) + EnsureEndsInSlash(folder); + std::vector file_set = db->GetFileSet(param.folders); // {symbol info, matching detailed_name or short_name, index} std::vector> cands; @@ -141,7 +157,7 @@ void MessageHandler::workspace_symbol(WorkspaceSymbolParam ¶m, std::string_view detailed_name = db->GetSymbolName(sym, true); int pos = ReverseSubseqMatch(query_without_space, detailed_name, sensitive); return pos >= 0 && - AddSymbol(db, wfiles, sym, + AddSymbol(db, wfiles, file_set, sym, detailed_name.find(':', pos) != std::string::npos, &cands) && cands.size() >= g_config->workspaceSymbol.maxNum; diff --git a/src/query.cc b/src/query.cc index 25e02d48..1d134580 100644 --- a/src/query.cc +++ b/src/query.cc @@ -468,4 +468,22 @@ std::string_view DB::GetSymbolName(SymbolIdx sym, bool qualified) { } return ""; } + +std::vector DB::GetFileSet(const std::vector &folders) { + if (folders.empty()) + return std::vector(files.size(), 1); + std::vector file_set(files.size()); + for (QueryFile &file : files) + if (file.def) { + bool ok = false; + for (auto &folder : folders) + if (llvm::StringRef(file.def->path).startswith(folder)) { + ok = true; + break; + } + if (ok) + file_set[file.id] = 1; + } + return file_set; +} } // namespace ccls diff --git a/src/query.hh b/src/query.hh index a1627af5..9cf09364 100644 --- a/src/query.hh +++ b/src/query.hh @@ -181,6 +181,7 @@ struct DB { void Update(const Lid2file_id &, int file_id, std::vector> &&us); std::string_view GetSymbolName(SymbolIdx sym, bool qualified); + std::vector GetFileSet(const std::vector &folders); bool HasFunc(Usr usr) const { return func_usr.count(usr); } bool HasType(Usr usr) const { return type_usr.count(usr); } diff --git a/src/query_utils.cc b/src/query_utils.cc index fb13bbca..24d39040 100644 --- a/src/query_utils.cc +++ b/src/query_utils.cc @@ -95,25 +95,19 @@ std::vector GetVarDeclarations(DB *db, const std::vector &usrs, return ret; } -std::vector GetNonDefDeclarations(DB *db, SymbolIdx sym) { - std::vector ret; +std::vector &GetNonDefDeclarations(DB *db, SymbolIdx sym) { + static std::vector empty; switch (sym.kind) { case SymbolKind::Func: - for (auto &d : db->GetFunc(sym).declarations) - ret.push_back(d); - break; + return db->GetFunc(sym).declarations; case SymbolKind::Type: - for (auto &d : db->GetType(sym).declarations) - ret.push_back(d); - break; + return db->GetType(sym).declarations; case SymbolKind::Var: - for (auto &d : db->GetVar(sym).declarations) - ret.push_back(d); - break; + return db->GetVar(sym).declarations; default: break; } - return ret; + return empty; } std::vector GetUsesForAllBases(DB *db, QueryFunc &root) { diff --git a/src/query_utils.hh b/src/query_utils.hh index 5db3be65..0dd53fe3 100644 --- a/src/query_utils.hh +++ b/src/query_utils.hh @@ -30,7 +30,7 @@ std::vector GetTypeDeclarations(DB *, const std::vector &); std::vector GetVarDeclarations(DB *, const std::vector &, unsigned); // Get non-defining declarations. -std::vector GetNonDefDeclarations(DB *db, SymbolIdx sym); +std::vector &GetNonDefDeclarations(DB *db, SymbolIdx sym); std::vector GetUsesForAllBases(DB *db, QueryFunc &root); std::vector GetUsesForAllDerived(DB *db, QueryFunc &root);