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 26d76b75c7
commit 90a94cbb4f
9 changed files with 84 additions and 45 deletions

View File

@ -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 {

View File

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

View File

@ -22,10 +22,10 @@ limitations under the License.
namespace ccls {
namespace {
std::vector<Use> GetNonDefDeclarationTargets(DB *db, SymbolRef sym) {
std::vector<DeclRef> GetNonDefDeclarationTargets(DB *db, SymbolRef sym) {
switch (sym.kind) {
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 (ret.empty()) {
for (auto &def : db->GetVar(sym).def)

View File

@ -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<std::string> 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<lsLocation> result;
WorkingFile *wfile = wfiles->GetFileByFilename(file->def->path);
if (!file)
if (!wfile)
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;
int line = param.position.line;
@ -56,24 +64,23 @@ void MessageHandler::textDocument_references(Reader &reader, ReplyOnce &reply) {
seen.insert(sym.usr);
std::vector<Usr> 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);

View File

@ -22,6 +22,7 @@ limitations under the License.
#include "query_utils.hh"
#include <llvm/ADT/STLExtras.h>
#include <llvm/ADT/StringRef.h>
#include <algorithm>
#include <ctype.h>
@ -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<uint8_t> &file_set,
SymbolIdx sym, bool use_detailed,
std::vector<std::tuple<lsSymbolInformation, int, SymbolIdx>> *result) {
std::optional<lsSymbolInformation> info = GetSymbolInfo(db, sym, true);
if (!info)
return false;
Use loc;
if (Maybe<DeclRef> dr = GetDefinitionSpell(db, sym))
loc = *dr;
else {
auto decls = GetNonDefDeclarations(db, sym);
if (decls.empty())
return false;
loc = decls[0];
Maybe<DeclRef> 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<lsLocation> ls_location = GetLsLocation(db, wfiles, loc);
std::optional<lsLocation> 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 &param,
ReplyOnce &reply) {
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}
std::vector<std::tuple<lsSymbolInformation, int, SymbolIdx>> cands;
@ -141,7 +157,7 @@ void MessageHandler::workspace_symbol(WorkspaceSymbolParam &param,
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;

View File

@ -468,4 +468,22 @@ std::string_view DB::GetSymbolName(SymbolIdx sym, bool qualified) {
}
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

View File

@ -181,6 +181,7 @@ struct DB {
void Update(const Lid2file_id &, int file_id,
std::vector<std::pair<Usr, QueryVar::Def>> &&us);
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 HasType(Usr usr) const { return type_usr.count(usr); }

View File

@ -95,25 +95,19 @@ std::vector<Use> GetVarDeclarations(DB *db, const std::vector<Usr> &usrs,
return ret;
}
std::vector<Use> GetNonDefDeclarations(DB *db, SymbolIdx sym) {
std::vector<Use> ret;
std::vector<DeclRef> &GetNonDefDeclarations(DB *db, SymbolIdx sym) {
static std::vector<DeclRef> 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<Use> GetUsesForAllBases(DB *db, QueryFunc &root) {

View File

@ -30,7 +30,7 @@ std::vector<Use> GetTypeDeclarations(DB *, const std::vector<Usr> &);
std::vector<Use> GetVarDeclarations(DB *, const std::vector<Usr> &, unsigned);
// 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> GetUsesForAllDerived(DB *db, QueryFunc &root);