Add excludeRole to documentSymbol and override declaration's range/selectionRange with definition's

This commit is contained in:
Fangrui Song 2019-03-08 23:37:08 -08:00
parent 478f849ada
commit 5d27ac9f34

View File

@ -95,13 +95,15 @@ void MessageHandler::textDocument_documentLink(TextDocumentParam &param,
namespace { namespace {
struct DocumentSymbolParam : TextDocumentParam { struct DocumentSymbolParam : TextDocumentParam {
// false: outline; true: all symbols // Include sym if `!(sym.role & excludeRole)`.
bool all = false; Role excludeRole = Role((int)Role::All - (int)Role::Definition -
(int)Role::Declaration - (int)Role::Dynamic);
// If >= 0, return Range[] instead of SymbolInformation[] to reduce output. // If >= 0, return Range[] instead of SymbolInformation[] to reduce output.
int startLine = -1; int startLine = -1;
int endLine = -1; int endLine = -1;
}; };
REFLECT_STRUCT(DocumentSymbolParam, textDocument, all, startLine, endLine); REFLECT_STRUCT(DocumentSymbolParam, textDocument, excludeRole, startLine,
endLine);
struct DocumentSymbol { struct DocumentSymbol {
std::string name; std::string name;
@ -149,18 +151,22 @@ void MessageHandler::textDocument_documentSymbol(JsonReader &reader,
int file_id; int file_id;
auto [file, wf] = FindOrFail(param.textDocument.uri.GetPath(), reply, &file_id); auto [file, wf] = FindOrFail(param.textDocument.uri.GetPath(), reply, &file_id);
if (!wf) { if (!wf)
return; return;
} auto Allows = [&](SymbolRef sym) {
return !(sym.role & param.excludeRole);
};
if (param.startLine >= 0) { if (param.startLine >= 0) {
std::vector<lsRange> result; std::vector<lsRange> result;
for (auto [sym, refcnt] : file->symbol2refcnt) for (auto [sym, refcnt] : file->symbol2refcnt) {
if (refcnt > 0 && (param.all || sym.extent.Valid()) && if (refcnt <= 0 || !Allows(sym) ||
param.startLine <= sym.range.start.line && !(param.startLine <= sym.range.start.line &&
sym.range.start.line <= param.endLine) sym.range.start.line <= param.endLine))
if (auto loc = GetLsLocation(db, wfiles, sym, file_id)) continue;
result.push_back(loc->range); if (auto loc = GetLsLocation(db, wfiles, sym, file_id))
result.push_back(loc->range);
}
std::sort(result.begin(), result.end()); std::sort(result.begin(), result.end());
reply(result); reply(result);
} else if (g_config->client.hierarchicalDocumentSymbolSupport) { } else if (g_config->client.hierarchicalDocumentSymbolSupport) {
@ -171,22 +177,26 @@ void MessageHandler::textDocument_documentSymbol(JsonReader &reader,
if (refcnt <= 0 || !sym.extent.Valid()) if (refcnt <= 0 || !sym.extent.Valid())
continue; continue;
auto r = sym2ds.try_emplace(SymbolIdx{sym.usr, sym.kind}); auto r = sym2ds.try_emplace(SymbolIdx{sym.usr, sym.kind});
auto &ds = r.first->second;
if (!ds || sym.role & Role::Definition) {
if (!ds)
ds = std::make_unique<DocumentSymbol>();
if (auto range = GetLsRange(wf, sym.range)) {
ds->selectionRange = *range;
ds->range = ds->selectionRange;
// For a macro expansion, M(name), we may use `M` for extent and
// `name` for spell, do the check as selectionRange must be a subrange
// of range.
if (sym.extent.Valid())
if (auto range1 = GetLsRange(wf, sym.extent);
range1 && range1->Includes(*range))
ds->range = *range1;
}
}
if (!r.second) if (!r.second)
continue; continue;
auto &ds = r.first->second;
ds = std::make_unique<DocumentSymbol>();
if (auto range = GetLsRange(wf, sym.range)) {
ds->selectionRange = *range;
ds->range = ds->selectionRange;
// For a macro expansion, M(name), we may use `M` for extent and `name`
// for spell, do the check as selectionRange must be a subrange of
// range.
if (sym.extent.Valid())
if (auto range1 = GetLsRange(wf, sym.extent);
range1 && range1->Includes(*range))
ds->range = *range1;
}
std::vector<const void *> def_ptrs; std::vector<const void *> def_ptrs;
SymbolKind kind = SymbolKind::Unknown;
WithEntity(db, sym, [&](const auto &entity) { WithEntity(db, sym, [&](const auto &entity) {
auto *def = entity.AnyDef(); auto *def = entity.AnyDef();
if (!def) if (!def)
@ -195,20 +205,14 @@ void MessageHandler::textDocument_documentSymbol(JsonReader &reader,
ds->detail = def->detailed_name; ds->detail = def->detailed_name;
for (auto &def : entity.def) for (auto &def : entity.def)
if (def.file_id == file_id && !Ignore(&def)) { if (def.file_id == file_id && !Ignore(&def)) {
ds->kind = def.kind; kind = ds->kind = def.kind;
if (def.spell || def.kind == SymbolKind::Namespace) def_ptrs.push_back(&def);
def_ptrs.push_back(&def);
} }
}); });
if (!(param.all || sym.role & Role::Definition || if (def_ptrs.empty() || !(kind == SymbolKind::Namespace || Allows(sym))) {
ds->kind == SymbolKind::Function ||
ds->kind == SymbolKind::Method ||
ds->kind == SymbolKind::Namespace)) {
ds.reset(); ds.reset();
continue; continue;
} }
if (def_ptrs.empty())
continue;
if (sym.kind == Kind::Func) if (sym.kind == Kind::Func)
funcs.emplace_back(std::move(def_ptrs), ds.get()); funcs.emplace_back(std::move(def_ptrs), ds.get());
else if (sym.kind == Kind::Type) else if (sym.kind == Kind::Type)
@ -252,8 +256,7 @@ void MessageHandler::textDocument_documentSymbol(JsonReader &reader,
} else { } else {
std::vector<SymbolInformation> result; std::vector<SymbolInformation> result;
for (auto [sym, refcnt] : file->symbol2refcnt) { for (auto [sym, refcnt] : file->symbol2refcnt) {
if (refcnt <= 0 || !sym.extent.Valid() || if (refcnt <= 0 || !Allows(sym))
!(param.all || sym.role & Role::Definition))
continue; continue;
if (std::optional<SymbolInformation> info = if (std::optional<SymbolInformation> info =
GetSymbolInfo(db, sym, false)) { GetSymbolInfo(db, sym, false)) {