Skip to content

Commit 94ba2b3

Browse files
FederAndInkMaskRay
authored andcommitted
hierarchicalDocumentSymbol: use a range based method to support
out-of-line class members (#674)
1 parent c6686be commit 94ba2b3

File tree

1 file changed

+41
-85
lines changed

1 file changed

+41
-85
lines changed

src/messages/textDocument_document.cc

+41-85
Original file line numberDiff line numberDiff line change
@@ -128,16 +128,6 @@ template <> bool ignore(const QueryType::Def *def) {
128128
template <> bool ignore(const QueryVar::Def *def) {
129129
return !def || def->is_local();
130130
}
131-
132-
void uniquify(std::vector<std::unique_ptr<DocumentSymbol>> &cs) {
133-
std::sort(cs.begin(), cs.end(),
134-
[](auto &l, auto &r) { return l->range < r->range; });
135-
cs.erase(std::unique(cs.begin(), cs.end(),
136-
[](auto &l, auto &r) { return l->range == r->range; }),
137-
cs.end());
138-
for (auto &c : cs)
139-
uniquify(c->children);
140-
}
141131
} // namespace
142132

143133
void MessageHandler::textDocument_documentSymbol(JsonReader &reader,
@@ -165,89 +155,55 @@ void MessageHandler::textDocument_documentSymbol(JsonReader &reader,
165155
std::sort(result.begin(), result.end());
166156
reply(result);
167157
} else if (g_config->client.hierarchicalDocumentSymbolSupport) {
168-
std::unordered_map<SymbolIdx, std::unique_ptr<DocumentSymbol>> sym2ds;
169-
std::vector<std::pair<std::vector<const void *>, DocumentSymbol *>> funcs,
170-
types;
171-
for (auto [sym, refcnt] : file->symbol2refcnt) {
172-
if (refcnt <= 0 || !sym.extent.valid())
173-
continue;
174-
auto r = sym2ds.try_emplace(SymbolIdx{sym.usr, sym.kind});
175-
auto &ds = r.first->second;
176-
if (!ds || sym.role & Role::Definition) {
177-
if (!ds)
178-
ds = std::make_unique<DocumentSymbol>();
179-
if (auto range = getLsRange(wf, sym.range)) {
180-
ds->selectionRange = *range;
181-
ds->range = ds->selectionRange;
182-
// For a macro expansion, M(name), we may use `M` for extent and
183-
// `name` for spell, do the check as selectionRange must be a subrange
184-
// of range.
185-
if (sym.extent.valid())
186-
if (auto range1 = getLsRange(wf, sym.extent);
187-
range1 && range1->includes(*range))
188-
ds->range = *range1;
189-
}
158+
std::vector<ExtentRef> syms;
159+
syms.reserve(file->symbol2refcnt.size());
160+
for (auto [sym, refcnt] : file->symbol2refcnt)
161+
if (refcnt > 0 && sym.extent.valid())
162+
syms.push_back(sym);
163+
// If multiple ranges start at the same Position, prioritize the widest one.
164+
std::sort(syms.begin(), syms.end(),
165+
[](const ExtentRef &lhs, const ExtentRef &rhs) {
166+
return std::tie(lhs.extent.start, rhs.extent.end) <
167+
std::tie(rhs.extent.start, lhs.extent.end);
168+
});
169+
170+
std::vector<std::unique_ptr<DocumentSymbol>> res;
171+
std::vector<DocumentSymbol *> scopes;
172+
for (ExtentRef sym : syms) {
173+
auto ds = std::make_unique<DocumentSymbol>();
174+
if (auto range = getLsRange(wf, sym.range)) {
175+
ds->selectionRange = *range;
176+
ds->range = ds->selectionRange;
177+
// For a macro expansion, M(name), we may use `M` for extent and
178+
// `name` for spell, do the check as selectionRange must be a subrange
179+
// of range.
180+
if (sym.extent.valid())
181+
if (auto range1 = getLsRange(wf, sym.extent);
182+
range1 && range1->includes(*range))
183+
ds->range = *range1;
190184
}
191-
if (!r.second)
192-
continue;
193-
std::vector<const void *> def_ptrs;
194-
SymbolKind kind = SymbolKind::Unknown;
195185
withEntity(db, sym, [&](const auto &entity) {
196-
auto *def = entity.anyDef();
186+
const auto *def = entity.anyDef();
197187
if (!def)
198188
return;
199189
ds->name = def->name(false);
200190
ds->detail = def->detailed_name;
201-
for (auto &def : entity.def)
202-
if (def.file_id == file_id && !ignore(&def)) {
203-
kind = ds->kind = def.kind;
204-
def_ptrs.push_back(&def);
205-
}
191+
ds->kind = def->kind;
192+
193+
if (!ignore(def) && (ds->kind == SymbolKind::Namespace || allows(sym))) {
194+
// Drop symbols that are behind the current one.
195+
while (!scopes.empty() && scopes.back()->range.end <= ds->range.start)
196+
scopes.pop_back();
197+
auto *ds1 = ds.get();
198+
if (scopes.empty())
199+
res.push_back(std::move(ds));
200+
else
201+
scopes.back()->children.push_back(std::move(ds));
202+
scopes.push_back(ds1);
203+
}
206204
});
207-
if (def_ptrs.empty() || !(kind == SymbolKind::Namespace || allows(sym))) {
208-
ds.reset();
209-
continue;
210-
}
211-
if (sym.kind == Kind::Func)
212-
funcs.emplace_back(std::move(def_ptrs), ds.get());
213-
else if (sym.kind == Kind::Type)
214-
types.emplace_back(std::move(def_ptrs), ds.get());
215205
}
216-
217-
for (auto &[def_ptrs, ds] : funcs)
218-
for (const void *def_ptr : def_ptrs)
219-
for (Usr usr1 : ((const QueryFunc::Def *)def_ptr)->vars) {
220-
auto it = sym2ds.find(SymbolIdx{usr1, Kind::Var});
221-
if (it != sym2ds.end() && it->second)
222-
ds->children.push_back(std::move(it->second));
223-
}
224-
for (auto &[def_ptrs, ds] : types)
225-
for (const void *def_ptr : def_ptrs) {
226-
auto *def = (const QueryType::Def *)def_ptr;
227-
for (Usr usr1 : def->funcs) {
228-
auto it = sym2ds.find(SymbolIdx{usr1, Kind::Func});
229-
if (it != sym2ds.end() && it->second)
230-
ds->children.push_back(std::move(it->second));
231-
}
232-
for (Usr usr1 : def->types) {
233-
auto it = sym2ds.find(SymbolIdx{usr1, Kind::Type});
234-
if (it != sym2ds.end() && it->second)
235-
ds->children.push_back(std::move(it->second));
236-
}
237-
for (auto [usr1, _] : def->vars) {
238-
auto it = sym2ds.find(SymbolIdx{usr1, Kind::Var});
239-
if (it != sym2ds.end() && it->second)
240-
ds->children.push_back(std::move(it->second));
241-
}
242-
}
243-
std::vector<std::unique_ptr<DocumentSymbol>> result;
244-
for (auto &[_, ds] : sym2ds)
245-
if (ds) {
246-
uniquify(ds->children);
247-
result.push_back(std::move(ds));
248-
}
249-
uniquify(result);
250-
reply(result);
206+
reply(res);
251207
} else {
252208
std::vector<SymbolInformation> result;
253209
for (auto [sym, refcnt] : file->symbol2refcnt) {

0 commit comments

Comments
 (0)