mirror of
https://github.com/MaskRay/ccls.git
synced 2024-11-24 16:45:07 +00:00
hierarchicalDocumentSymbol: use a range based method to support
out-of-line class members (#674)
This commit is contained in:
parent
c6686be382
commit
c018bce9af
@ -128,16 +128,6 @@ template <> bool ignore(const QueryType::Def *def) {
|
|||||||
template <> bool ignore(const QueryVar::Def *def) {
|
template <> bool ignore(const QueryVar::Def *def) {
|
||||||
return !def || def->is_local();
|
return !def || def->is_local();
|
||||||
}
|
}
|
||||||
|
|
||||||
void uniquify(std::vector<std::unique_ptr<DocumentSymbol>> &cs) {
|
|
||||||
std::sort(cs.begin(), cs.end(),
|
|
||||||
[](auto &l, auto &r) { return l->range < r->range; });
|
|
||||||
cs.erase(std::unique(cs.begin(), cs.end(),
|
|
||||||
[](auto &l, auto &r) { return l->range == r->range; }),
|
|
||||||
cs.end());
|
|
||||||
for (auto &c : cs)
|
|
||||||
uniquify(c->children);
|
|
||||||
}
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
void MessageHandler::textDocument_documentSymbol(JsonReader &reader,
|
void MessageHandler::textDocument_documentSymbol(JsonReader &reader,
|
||||||
@ -165,89 +155,58 @@ void MessageHandler::textDocument_documentSymbol(JsonReader &reader,
|
|||||||
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) {
|
||||||
std::unordered_map<SymbolIdx, std::unique_ptr<DocumentSymbol>> sym2ds;
|
std::vector<ExtentRef> syms;
|
||||||
std::vector<std::pair<std::vector<const void *>, DocumentSymbol *>> funcs,
|
syms.reserve(file->symbol2refcnt.size());
|
||||||
types;
|
for (auto [sym, refcnt] : file->symbol2refcnt)
|
||||||
for (auto [sym, refcnt] : file->symbol2refcnt) {
|
if (refcnt > 0 && sym.extent.valid())
|
||||||
if (refcnt <= 0 || !sym.extent.valid())
|
syms.push_back(sym);
|
||||||
continue;
|
// Global variables `int i, j, k;` have the same extent.start. Sort them by
|
||||||
auto r = sym2ds.try_emplace(SymbolIdx{sym.usr, sym.kind});
|
// range.start instead. In case of a tie, prioritize the widest ExtentRef.
|
||||||
auto &ds = r.first->second;
|
std::sort(syms.begin(), syms.end(),
|
||||||
if (!ds || sym.role & Role::Definition) {
|
[](const ExtentRef &lhs, const ExtentRef &rhs) {
|
||||||
if (!ds)
|
return std::tie(lhs.range.start, rhs.extent.end) <
|
||||||
ds = std::make_unique<DocumentSymbol>();
|
std::tie(rhs.range.start, lhs.extent.end);
|
||||||
if (auto range = getLsRange(wf, sym.range)) {
|
});
|
||||||
ds->selectionRange = *range;
|
|
||||||
ds->range = ds->selectionRange;
|
std::vector<std::unique_ptr<DocumentSymbol>> res;
|
||||||
// For a macro expansion, M(name), we may use `M` for extent and
|
std::vector<DocumentSymbol *> scopes;
|
||||||
// `name` for spell, do the check as selectionRange must be a subrange
|
for (ExtentRef sym : syms) {
|
||||||
// of range.
|
auto ds = std::make_unique<DocumentSymbol>();
|
||||||
if (sym.extent.valid())
|
if (auto range = getLsRange(wf, sym.range)) {
|
||||||
if (auto range1 = getLsRange(wf, sym.extent);
|
ds->selectionRange = *range;
|
||||||
range1 && range1->includes(*range))
|
ds->range = ds->selectionRange;
|
||||||
ds->range = *range1;
|
// 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)
|
|
||||||
continue;
|
|
||||||
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();
|
const auto *def = entity.anyDef();
|
||||||
if (!def)
|
if (!def)
|
||||||
return;
|
return;
|
||||||
ds->name = def->name(false);
|
ds->name = def->name(false);
|
||||||
ds->detail = def->detailed_name;
|
ds->detail = def->detailed_name;
|
||||||
for (auto &def : entity.def)
|
ds->kind = def->kind;
|
||||||
if (def.file_id == file_id && !ignore(&def)) {
|
|
||||||
kind = ds->kind = def.kind;
|
|
||||||
def_ptrs.push_back(&def);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (def_ptrs.empty() || !(kind == SymbolKind::Namespace || allows(sym))) {
|
|
||||||
ds.reset();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (sym.kind == Kind::Func)
|
|
||||||
funcs.emplace_back(std::move(def_ptrs), ds.get());
|
|
||||||
else if (sym.kind == Kind::Type)
|
|
||||||
types.emplace_back(std::move(def_ptrs), ds.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto &[def_ptrs, ds] : funcs)
|
if (!ignore(def) && (ds->kind == SymbolKind::Namespace || allows(sym))) {
|
||||||
for (const void *def_ptr : def_ptrs)
|
// Drop scopes which are before selectionRange.start. In
|
||||||
for (Usr usr1 : ((const QueryFunc::Def *)def_ptr)->vars) {
|
// `int i, j, k;`, the scope of i will be ended by j.
|
||||||
auto it = sym2ds.find(SymbolIdx{usr1, Kind::Var});
|
while (!scopes.empty() &&
|
||||||
if (it != sym2ds.end() && it->second)
|
scopes.back()->range.end <= ds->selectionRange.start)
|
||||||
ds->children.push_back(std::move(it->second));
|
scopes.pop_back();
|
||||||
|
auto *ds1 = ds.get();
|
||||||
|
if (scopes.empty())
|
||||||
|
res.push_back(std::move(ds));
|
||||||
|
else
|
||||||
|
scopes.back()->children.push_back(std::move(ds));
|
||||||
|
scopes.push_back(ds1);
|
||||||
}
|
}
|
||||||
for (auto &[def_ptrs, ds] : types)
|
});
|
||||||
for (const void *def_ptr : def_ptrs) {
|
}
|
||||||
auto *def = (const QueryType::Def *)def_ptr;
|
reply(res);
|
||||||
for (Usr usr1 : def->funcs) {
|
|
||||||
auto it = sym2ds.find(SymbolIdx{usr1, Kind::Func});
|
|
||||||
if (it != sym2ds.end() && it->second)
|
|
||||||
ds->children.push_back(std::move(it->second));
|
|
||||||
}
|
|
||||||
for (Usr usr1 : def->types) {
|
|
||||||
auto it = sym2ds.find(SymbolIdx{usr1, Kind::Type});
|
|
||||||
if (it != sym2ds.end() && it->second)
|
|
||||||
ds->children.push_back(std::move(it->second));
|
|
||||||
}
|
|
||||||
for (auto [usr1, _] : def->vars) {
|
|
||||||
auto it = sym2ds.find(SymbolIdx{usr1, Kind::Var});
|
|
||||||
if (it != sym2ds.end() && it->second)
|
|
||||||
ds->children.push_back(std::move(it->second));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
std::vector<std::unique_ptr<DocumentSymbol>> result;
|
|
||||||
for (auto &[_, ds] : sym2ds)
|
|
||||||
if (ds) {
|
|
||||||
uniquify(ds->children);
|
|
||||||
result.push_back(std::move(ds));
|
|
||||||
}
|
|
||||||
uniquify(result);
|
|
||||||
reply(result);
|
|
||||||
} else {
|
} else {
|
||||||
std::vector<SymbolInformation> result;
|
std::vector<SymbolInformation> result;
|
||||||
for (auto [sym, refcnt] : file->symbol2refcnt) {
|
for (auto [sym, refcnt] : file->symbol2refcnt) {
|
||||||
|
Loading…
Reference in New Issue
Block a user