textDocument/references workspace/symbol: add folders

For textDocument/reference, base/excludeRole/role has been lifted from params.context.* to params.*
This commit is contained in:
Fangrui Song 2018-10-29 23:49:52 -07:00
parent c4bf9c5d6a
commit c8e57ee7b3
9 changed files with 84 additions and 45 deletions

View File

@ -48,7 +48,7 @@ MAKE_REFLECT_STRUCT(DidChangeWatchedFilesParam::Event, uri, type);
MAKE_REFLECT_STRUCT(DidChangeWatchedFilesParam, changes); MAKE_REFLECT_STRUCT(DidChangeWatchedFilesParam, changes);
MAKE_REFLECT_STRUCT(DidChangeWorkspaceFoldersParam::Event, added, removed); MAKE_REFLECT_STRUCT(DidChangeWorkspaceFoldersParam::Event, added, removed);
MAKE_REFLECT_STRUCT(DidChangeWorkspaceFoldersParam, event); MAKE_REFLECT_STRUCT(DidChangeWorkspaceFoldersParam, event);
MAKE_REFLECT_STRUCT(WorkspaceSymbolParam, query); MAKE_REFLECT_STRUCT(WorkspaceSymbolParam, query, folders);
namespace { namespace {
struct CclsSemanticHighlightSymbol { struct CclsSemanticHighlightSymbol {

View File

@ -162,6 +162,9 @@ struct DidChangeWorkspaceFoldersParam {
}; };
struct WorkspaceSymbolParam { struct WorkspaceSymbolParam {
std::string query; std::string query;
// ccls extensions
std::vector<std::string> folders;
}; };
// TODO llvm 8 llvm::unique_function // TODO llvm 8 llvm::unique_function

View File

@ -10,10 +10,10 @@
namespace ccls { namespace ccls {
namespace { namespace {
std::vector<Use> GetNonDefDeclarationTargets(DB *db, SymbolRef sym) { std::vector<DeclRef> GetNonDefDeclarationTargets(DB *db, SymbolRef sym) {
switch (sym.kind) { switch (sym.kind) {
case SymbolKind::Var: { case SymbolKind::Var: {
std::vector<Use> ret = GetNonDefDeclarations(db, sym); std::vector<DeclRef> ret = GetNonDefDeclarations(db, sym);
// If there is no declaration, jump to its type. // If there is no declaration, jump to its type.
if (ret.empty()) { if (ret.empty()) {
for (auto &def : db->GetVar(sym).def) for (auto &def : db->GetVar(sym).def)

View File

@ -10,18 +10,23 @@ namespace ccls {
namespace { namespace {
struct ReferenceParam : public TextDocumentPositionParam { struct ReferenceParam : public TextDocumentPositionParam {
struct Context { struct Context {
// Include the declaration of the current symbol.
bool includeDeclaration = false;
} context;
// ccls extension
// If not empty, restrict to specified folders.
std::vector<std::string> folders;
// For Type, also return references of base types.
bool base = true; bool base = true;
// Exclude references with any |Role| bits set. // Exclude references with any |Role| bits set.
Role excludeRole = Role::None; Role excludeRole = Role::None;
// Include the declaration of the current symbol.
bool includeDeclaration = false;
// Include references with all |Role| bits set. // Include references with all |Role| bits set.
Role role = Role::None; Role role = Role::None;
} context;
}; };
MAKE_REFLECT_STRUCT(ReferenceParam::Context, base, excludeRole, MAKE_REFLECT_STRUCT(ReferenceParam::Context, includeDeclaration);
includeDeclaration, role); MAKE_REFLECT_STRUCT(ReferenceParam, textDocument, position, context, folders,
MAKE_REFLECT_STRUCT(ReferenceParam, textDocument, position, context); base, excludeRole, role);
} // namespace } // namespace
void MessageHandler::textDocument_references(Reader &reader, ReplyOnce &reply) { void MessageHandler::textDocument_references(Reader &reader, ReplyOnce &reply) {
@ -30,10 +35,13 @@ void MessageHandler::textDocument_references(Reader &reader, ReplyOnce &reply) {
QueryFile *file = FindFile(reply, param.textDocument.uri.GetPath()); QueryFile *file = FindFile(reply, param.textDocument.uri.GetPath());
if (!file) if (!file)
return; return;
std::vector<lsLocation> result;
WorkingFile *wfile = wfiles->GetFileByFilename(file->def->path); WorkingFile *wfile = wfiles->GetFileByFilename(file->def->path);
if (!file) if (!wfile)
return; return;
for (auto &folder : param.folders)
EnsureEndsInSlash(folder);
std::vector<uint8_t> file_set = db->GetFileSet(param.folders);
std::vector<lsLocation> result;
std::unordered_set<Use> seen_uses; std::unordered_set<Use> seen_uses;
int line = param.position.line; int line = param.position.line;
@ -44,24 +52,23 @@ void MessageHandler::textDocument_references(Reader &reader, ReplyOnce &reply) {
seen.insert(sym.usr); seen.insert(sym.usr);
std::vector<Usr> stack{sym.usr}; std::vector<Usr> stack{sym.usr};
if (sym.kind != SymbolKind::Func) if (sym.kind != SymbolKind::Func)
param.context.base = false; param.base = false;
while (stack.size()) { while (stack.size()) {
sym.usr = stack.back(); sym.usr = stack.back();
stack.pop_back(); stack.pop_back();
auto fn = [&](Use use, lsSymbolKind parent_kind) { auto fn = [&](Use use, lsSymbolKind parent_kind) {
if (Role(use.role & param.context.role) == param.context.role && if (file_set[use.file_id] &&
!(use.role & param.context.excludeRole) && Role(use.role & param.role) == param.role &&
seen_uses.insert(use).second) !(use.role & param.excludeRole) && seen_uses.insert(use).second)
if (auto loc = GetLsLocation(db, wfiles, use)) { if (auto loc = GetLsLocation(db, wfiles, use))
result.push_back(*loc); result.push_back(*loc);
}
}; };
WithEntity(db, sym, [&](const auto &entity) { WithEntity(db, sym, [&](const auto &entity) {
lsSymbolKind parent_kind = lsSymbolKind::Unknown; lsSymbolKind parent_kind = lsSymbolKind::Unknown;
for (auto &def : entity.def) for (auto &def : entity.def)
if (def.spell) { if (def.spell) {
parent_kind = GetSymbolKind(db, sym); parent_kind = GetSymbolKind(db, sym);
if (param.context.base) if (param.base)
for (Usr usr : def.GetBases()) for (Usr usr : def.GetBases())
if (!seen.count(usr)) { if (!seen.count(usr)) {
seen.insert(usr); seen.insert(usr);

View File

@ -10,6 +10,7 @@
#include "query_utils.hh" #include "query_utils.hh"
#include <llvm/ADT/STLExtras.h> #include <llvm/ADT/STLExtras.h>
#include <llvm/ADT/StringRef.h>
#include <algorithm> #include <algorithm>
#include <ctype.h> #include <ctype.h>
@ -84,23 +85,35 @@ void MessageHandler::workspace_didChangeWorkspaceFolders(
namespace { namespace {
// Lookup |symbol| in |db| and insert the value into |result|. // Lookup |symbol| in |db| and insert the value into |result|.
bool AddSymbol( bool AddSymbol(
DB *db, WorkingFiles *wfiles, SymbolIdx sym, bool use_detailed, DB *db, WorkingFiles *wfiles, const std::vector<uint8_t> &file_set,
SymbolIdx sym, bool use_detailed,
std::vector<std::tuple<lsSymbolInformation, int, SymbolIdx>> *result) { std::vector<std::tuple<lsSymbolInformation, int, SymbolIdx>> *result) {
std::optional<lsSymbolInformation> info = GetSymbolInfo(db, sym, true); std::optional<lsSymbolInformation> info = GetSymbolInfo(db, sym, true);
if (!info) if (!info)
return false; return false;
Use loc; Maybe<DeclRef> dr;
if (Maybe<DeclRef> dr = GetDefinitionSpell(db, sym)) bool in_folder = false;
loc = *dr; WithEntity(db, sym, [&](const auto &entity) {
else { for (auto &def : entity.def)
auto decls = GetNonDefDeclarations(db, sym); if (def.spell) {
if (decls.empty()) dr = def.spell;
return false; if (!in_folder && (in_folder = file_set[def.spell->file_id]))
loc = decls[0]; 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<lsLocation> ls_location = GetLsLocation(db, wfiles, loc); std::optional<lsLocation> ls_location = GetLsLocation(db, wfiles, *dr);
if (!ls_location) if (!ls_location)
return false; return false;
info->location = *ls_location; info->location = *ls_location;
@ -112,7 +125,10 @@ bool AddSymbol(
void MessageHandler::workspace_symbol(WorkspaceSymbolParam &param, void MessageHandler::workspace_symbol(WorkspaceSymbolParam &param,
ReplyOnce &reply) { ReplyOnce &reply) {
std::vector<lsSymbolInformation> result; std::vector<lsSymbolInformation> result;
std::string query = param.query; const std::string &query = param.query;
for (auto &folder : param.folders)
EnsureEndsInSlash(folder);
std::vector<uint8_t> file_set = db->GetFileSet(param.folders);
// {symbol info, matching detailed_name or short_name, index} // {symbol info, matching detailed_name or short_name, index}
std::vector<std::tuple<lsSymbolInformation, int, SymbolIdx>> cands; std::vector<std::tuple<lsSymbolInformation, int, SymbolIdx>> cands;
@ -129,7 +145,7 @@ void MessageHandler::workspace_symbol(WorkspaceSymbolParam &param,
std::string_view detailed_name = db->GetSymbolName(sym, true); std::string_view detailed_name = db->GetSymbolName(sym, true);
int pos = ReverseSubseqMatch(query_without_space, detailed_name, sensitive); int pos = ReverseSubseqMatch(query_without_space, detailed_name, sensitive);
return pos >= 0 && return pos >= 0 &&
AddSymbol(db, wfiles, sym, AddSymbol(db, wfiles, file_set, sym,
detailed_name.find(':', pos) != std::string::npos, detailed_name.find(':', pos) != std::string::npos,
&cands) && &cands) &&
cands.size() >= g_config->workspaceSymbol.maxNum; cands.size() >= g_config->workspaceSymbol.maxNum;

View File

@ -456,4 +456,22 @@ std::string_view DB::GetSymbolName(SymbolIdx sym, bool qualified) {
} }
return ""; return "";
} }
std::vector<uint8_t> DB::GetFileSet(const std::vector<std::string> &folders) {
if (folders.empty())
return std::vector<uint8_t>(files.size(), 1);
std::vector<uint8_t> 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 } // namespace ccls

View File

@ -170,6 +170,7 @@ struct DB {
void Update(const Lid2file_id &, int file_id, void Update(const Lid2file_id &, int file_id,
std::vector<std::pair<Usr, QueryVar::Def>> &&us); std::vector<std::pair<Usr, QueryVar::Def>> &&us);
std::string_view GetSymbolName(SymbolIdx sym, bool qualified); std::string_view GetSymbolName(SymbolIdx sym, bool qualified);
std::vector<uint8_t> GetFileSet(const std::vector<std::string> &folders);
bool HasFunc(Usr usr) const { return func_usr.count(usr); } bool HasFunc(Usr usr) const { return func_usr.count(usr); }
bool HasType(Usr usr) const { return type_usr.count(usr); } bool HasType(Usr usr) const { return type_usr.count(usr); }

View File

@ -83,25 +83,19 @@ std::vector<Use> GetVarDeclarations(DB *db, const std::vector<Usr> &usrs,
return ret; return ret;
} }
std::vector<Use> GetNonDefDeclarations(DB *db, SymbolIdx sym) { std::vector<DeclRef> &GetNonDefDeclarations(DB *db, SymbolIdx sym) {
std::vector<Use> ret; static std::vector<DeclRef> empty;
switch (sym.kind) { switch (sym.kind) {
case SymbolKind::Func: case SymbolKind::Func:
for (auto &d : db->GetFunc(sym).declarations) return db->GetFunc(sym).declarations;
ret.push_back(d);
break;
case SymbolKind::Type: case SymbolKind::Type:
for (auto &d : db->GetType(sym).declarations) return db->GetType(sym).declarations;
ret.push_back(d);
break;
case SymbolKind::Var: case SymbolKind::Var:
for (auto &d : db->GetVar(sym).declarations) return db->GetVar(sym).declarations;
ret.push_back(d);
break;
default: default:
break; break;
} }
return ret; return empty;
} }
std::vector<Use> GetUsesForAllBases(DB *db, QueryFunc &root) { std::vector<Use> GetUsesForAllBases(DB *db, QueryFunc &root) {

View File

@ -18,7 +18,7 @@ std::vector<Use> GetTypeDeclarations(DB *, const std::vector<Usr> &);
std::vector<Use> GetVarDeclarations(DB *, const std::vector<Usr> &, unsigned); std::vector<Use> GetVarDeclarations(DB *, const std::vector<Usr> &, unsigned);
// Get non-defining declarations. // Get non-defining declarations.
std::vector<Use> GetNonDefDeclarations(DB *db, SymbolIdx sym); std::vector<DeclRef> &GetNonDefDeclarations(DB *db, SymbolIdx sym);
std::vector<Use> GetUsesForAllBases(DB *db, QueryFunc &root); std::vector<Use> GetUsesForAllBases(DB *db, QueryFunc &root);
std::vector<Use> GetUsesForAllDerived(DB *db, QueryFunc &root); std::vector<Use> GetUsesForAllDerived(DB *db, QueryFunc &root);