Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .clang-format
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
BasedOnStyle: LLVM
IndentPPDirectives: AfterHash
45 changes: 27 additions & 18 deletions src/indexer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -670,14 +670,17 @@ class IndexDataConsumer : public index::IndexDataConsumer {
if (!rd->isCompleteDefinition() || rd->isDependentType() ||
rd->isInvalidDecl() || !validateRecord(rd))
offset = -1;
for (FieldDecl *fd : rd->fields()) {
int offset1 = offset < 0 ? -1 : int(offset + ctx->getFieldOffset(fd));
if (fd->getIdentifier())
type.def.vars.emplace_back(getUsr(fd), offset1);
else if (const auto *rt1 = fd->getType()->getAs<RecordType>()) {
if (const RecordDecl *rd1 = rt1->getDecl())
if (seen.insert(rd1).second)
stack.push_back({rd1, offset1});
for (Decl const *decl : rd->decls()) {
if (auto const *static_var = dyn_cast<VarDecl>(decl)) {
type.def.vars.emplace_back(getUsr(static_var), -1);
} else if (auto const *fd = dyn_cast<FieldDecl>(decl)) {
int offset1 = offset < 0 ? -1 : int(offset + ctx->getFieldOffset(fd));
if (fd->getIdentifier())
type.def.vars.emplace_back(getUsr(fd), offset1);
else if (const auto *rt1 = fd->getType()->getAs<RecordType>())
if (const RecordDecl *rd1 = rt1->getDecl())
if (seen.insert(rd1).second)
stack.push_back({rd1, offset1});
}
}
}
Expand All @@ -687,7 +690,7 @@ class IndexDataConsumer : public index::IndexDataConsumer {
IndexDataConsumer(IndexParam &param) : param(param) {}
void initialize(ASTContext &ctx) override { this->ctx = param.ctx = &ctx; }
#if LLVM_VERSION_MAJOR < 10 // llvmorg-10-init-12036-g3b9715cb219
# define handleDeclOccurrence handleDeclOccurence
# define handleDeclOccurrence handleDeclOccurence
#endif
bool handleDeclOccurrence(const Decl *d, index::SymbolRoleSet roles,
ArrayRef<index::SymbolRelation> relations,
Expand Down Expand Up @@ -785,7 +788,10 @@ class IndexDataConsumer : public index::IndexDataConsumer {
entity->def.spell = {use,
fromTokenRangeDefaulted(sm, lang, sr, fid, loc)};
entity->def.parent_kind = SymbolKind::File;
getKind(cast<Decl>(sem_dc), entity->def.parent_kind);
const Decl *dc = cast<Decl>(sem_dc);
if (Kind parent_kind = getKind(dc, entity->def.parent_kind);
parent_kind != Kind::Invalid)
entity->def.parent = {getUsr(dc), parent_kind};
} else if (is_decl) {
SourceRange sr = origD->getSourceRange();
entity->declarations.push_back(
Expand Down Expand Up @@ -863,10 +869,13 @@ class IndexDataConsumer : public index::IndexDataConsumer {
t = vd->getType();
if (is_def || is_decl) {
const Decl *dc = cast<Decl>(sem_dc);
Kind kind = getKind(dc, var->def.parent_kind);
if (kind == Kind::Func)
Kind parent_kind = getKind(dc, var->def.parent_kind);
if (parent_kind != Kind::Invalid)
var->def.parent = {getUsr(dc), parent_kind};

if (parent_kind == Kind::Func)
db->toFunc(getUsr(dc)).def.vars.push_back(usr);
else if (kind == Kind::Type && !isa<RecordDecl>(sem_dc))
else if (parent_kind == Kind::Type && !isa<RecordDecl>(sem_dc))
db->toType(getUsr(dc)).def.vars.emplace_back(usr, -1);
if (!t.isNull()) {
if (auto *bt = t->getAs<BuiltinType>()) {
Expand All @@ -885,10 +894,10 @@ class IndexDataConsumer : public index::IndexDataConsumer {
Usr usr1 = getUsr(d1, &info1);
IndexType &type1 = db->toType(usr1);
SourceLocation sl1 = d1->getLocation();
type1.def.spell = {
Use{{fromTokenRange(sm, lang, {sl1, sl1}), Role::Definition},
lid},
fromTokenRange(sm, lang, sr1)};
type1.def.spell = {Use{{fromTokenRange(sm, lang, {sl1, sl1}),
Role::Definition},
lid},
fromTokenRange(sm, lang, sr1)};
type1.def.detailed_name = intern(info1->short_name);
type1.def.short_name_size = int16_t(info1->short_name.size());
type1.def.kind = SymbolKind::TypeParameter;
Expand Down Expand Up @@ -1205,7 +1214,7 @@ class IndexFrontendAction : public ASTFrontendAction {
};
} // namespace

const int IndexFile::kMajorVersion = 21;
const int IndexFile::kMajorVersion = 22;
const int IndexFile::kMinorVersion = 0;

IndexFile::IndexFile(const std::string &path, const std::string &contents,
Expand Down
11 changes: 8 additions & 3 deletions src/indexer.hh
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ struct SymbolIdx {
}
};

REFLECT_STRUCT(SymbolIdx, usr, kind);

// |id,kind| refer to the referenced entity.
struct SymbolRef {
Range range;
Expand Down Expand Up @@ -163,14 +165,15 @@ struct FuncDef : NameMixin<FuncDef<V>> {
int16_t short_name_size = 0;
SymbolKind kind = SymbolKind::Unknown;
SymbolKind parent_kind = SymbolKind::Unknown;
SymbolIdx parent = {0, Kind::Invalid};
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will this increase memory usage?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, certainly, I haven't done measures. But I am working on another idea which doesn't introduce new things to the index and seems simpler and cleaner.

uint8_t storage = clang::SC_None;

const Usr *bases_begin() const { return bases.begin(); }
const Usr *bases_end() const { return bases.end(); }
};
REFLECT_STRUCT(FuncDef<VectorAdapter>, detailed_name, hover, comments, spell,
bases, vars, callees, qual_name_offset, short_name_offset,
short_name_size, kind, parent_kind, storage);
short_name_size, kind, parent_kind, parent, storage);

struct IndexFunc : NameMixin<IndexFunc> {
using Def = FuncDef<VectorAdapter>;
Expand Down Expand Up @@ -203,13 +206,14 @@ struct TypeDef : NameMixin<TypeDef<V>> {
int16_t short_name_size = 0;
SymbolKind kind = SymbolKind::Unknown;
SymbolKind parent_kind = SymbolKind::Unknown;
SymbolIdx parent = {0, Kind::Invalid};

const Usr *bases_begin() const { return bases.begin(); }
const Usr *bases_end() const { return bases.end(); }
};
REFLECT_STRUCT(TypeDef<VectorAdapter>, detailed_name, hover, comments, spell,
bases, funcs, types, vars, alias_of, qual_name_offset,
short_name_offset, short_name_size, kind, parent_kind);
short_name_offset, short_name_size, kind, parent_kind, parent);

struct IndexType {
using Def = TypeDef<VectorAdapter>;
Expand All @@ -236,6 +240,7 @@ struct VarDef : NameMixin<VarDef> {
int16_t short_name_size = 0;
SymbolKind kind = SymbolKind::Unknown;
SymbolKind parent_kind = SymbolKind::Unknown;
SymbolIdx parent = {0, Kind::Invalid};
// Note a variable may have instances of both |None| and |Extern|
// (declaration).
uint8_t storage = clang::SC_None;
Expand All @@ -255,7 +260,7 @@ struct VarDef : NameMixin<VarDef> {
};
REFLECT_STRUCT(VarDef, detailed_name, hover, comments, spell, type,
qual_name_offset, short_name_offset, short_name_size, kind,
parent_kind, storage);
parent_kind, parent, storage);

struct IndexVar {
using Def = VarDef;
Expand Down
67 changes: 47 additions & 20 deletions src/messages/textDocument_document.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "query.hh"

#include <algorithm>
#include <type_traits>

MAKE_HASHABLE(ccls::SymbolIdx, t.usr, t.kind);

Expand Down Expand Up @@ -166,7 +167,11 @@ void MessageHandler::textDocument_documentSymbol(JsonReader &reader,
reply(result);
} else if (g_config->client.hierarchicalDocumentSymbolSupport) {
std::unordered_map<SymbolIdx, std::unique_ptr<DocumentSymbol>> sym2ds;
std::vector<std::pair<std::vector<const void *>, DocumentSymbol *>> funcs,
std::vector<
std::pair<std::vector<const QueryFunc::Def *>, DocumentSymbol *>>
funcs;
std::vector<
std::pair<std::vector<const QueryType::Def *>, DocumentSymbol *>>
types;
for (auto [sym, refcnt] : file->symbol2refcnt) {
if (refcnt <= 0 || !sym.extent.valid())
Expand All @@ -190,56 +195,78 @@ void MessageHandler::textDocument_documentSymbol(JsonReader &reader,
}
if (!r.second)
continue;
std::vector<const void *> def_ptrs;
SymbolKind kind = SymbolKind::Unknown;
withEntity(db, sym, [&](const auto &entity) {
withEntity(db, sym, [&, sym = sym](const auto &entity) {
auto *def = entity.anyDef();
using Def = std::remove_cv_t<std::remove_reference_t<decltype(*def)>>;
if (!def)
return;
ds->name = def->name(false);
ds->detail = def->detailed_name;

std::vector<const Def *> def_ptrs;
for (auto &def : entity.def)
if (def.file_id == file_id && !ignore(&def)) {
kind = ds->kind = def.kind;
ds->kind = def.kind;
def_ptrs.push_back(&def);
}
if (def_ptrs.empty() ||
!(ds->kind == SymbolKind::Namespace || allows(sym))) {
ds.reset();
return;
}

if constexpr (std::is_same_v<Def, QueryFunc::Def>)
funcs.emplace_back(std::move(def_ptrs), ds.get());
else if constexpr (std::is_same_v<Def, QueryType::Def>)
types.emplace_back(std::move(def_ptrs), ds.get());
});
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)
for (const void *def_ptr : def_ptrs)
for (Usr usr1 : ((const QueryFunc::Def *)def_ptr)->vars) {
for (const auto *def_ptr : def_ptrs)
for (Usr usr1 : def_ptr->vars) {
auto it = sym2ds.find(SymbolIdx{usr1, Kind::Var});
if (it != sym2ds.end() && it->second)
ds->children.push_back(std::move(it->second));
}
for (auto &[def_ptrs, ds] : types)
for (const void *def_ptr : def_ptrs) {
auto *def = (const QueryType::Def *)def_ptr;
for (Usr usr1 : def->funcs) {
for (const auto *def_ptr : def_ptrs) {
for (Usr usr1 : def_ptr->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) {
for (Usr usr1 : def_ptr->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) {
for (auto [usr1, _] : def_ptr->vars) {
auto it = sym2ds.find(SymbolIdx{usr1, Kind::Var});
if (it != sym2ds.end() && it->second)
ds->children.push_back(std::move(it->second));
}
}

// put member definition in their namespace
// when definition is in separate file(cpp), we have NS -> Type -> member
// but the Type is not defined here(in .cpp), so we do NS -> member instead
for (auto &[sym, ds] : sym2ds) {
if (!ds)
continue;

SymbolKind sym_kind = getSymbolKind(db, sym);
std::optional<SymbolIdx> ns;
bool is_member = sym_kind == SymbolKind::Field ||
sym_kind == SymbolKind::Method ||
sym_kind == SymbolKind::StaticMethod;
if (is_member && (ns = getNamespace(db, sym))) {
auto it = sym2ds.find(*ns);
if (it != sym2ds.end() && it->second)
it->second->children.push_back(std::move(ds));
}
}

std::vector<std::unique_ptr<DocumentSymbol>> result;
for (auto &[_, ds] : sym2ds)
if (ds) {
Expand Down
18 changes: 18 additions & 0 deletions src/query.cc
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ QueryFunc::Def convert(const IndexFunc::Def &o) {
r.short_name_size = o.short_name_size;
r.kind = o.kind;
r.parent_kind = o.parent_kind;
r.parent = o.parent;
r.storage = o.storage;
return r;
}
Expand All @@ -111,6 +112,7 @@ QueryType::Def convert(const IndexType::Def &o) {
r.short_name_size = o.short_name_size;
r.kind = o.kind;
r.parent_kind = o.parent_kind;
r.parent = o.parent;
return r;
}

Expand Down Expand Up @@ -839,4 +841,20 @@ std::vector<SymbolRef> findSymbolsAtLocation(WorkingFile *wfile,

return symbols;
}

std::optional<SymbolIdx> getNamespace(DB *db, SymbolIdx sym) {
SymbolKind kind;
do {
withEntity(db, sym,
[&sym](auto const &entity) { sym = entity.anyDef()->parent; });
kind = getSymbolKind(db, sym);
} while (kind != SymbolKind::Namespace && kind != SymbolKind::File &&
kind != SymbolKind::Unknown);

if (kind == SymbolKind::Namespace)
return sym;
else
return std::nullopt;
}

} // namespace ccls
2 changes: 2 additions & 0 deletions src/query.hh
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,8 @@ void eachOccurrence(DB *db, SymbolIdx sym, bool include_decl, Fn &&fn) {

SymbolKind getSymbolKind(DB *db, SymbolIdx sym);

std::optional<SymbolIdx> getNamespace(DB *db, SymbolIdx sym);

template <typename C, typename Fn>
void eachDefinedFunc(DB *db, const C &usrs, Fn &&fn) {
for (Usr usr : usrs) {
Expand Down
3 changes: 3 additions & 0 deletions src/serializer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,7 @@ template <typename TVisitor> void reflect1(TVisitor &vis, IndexFunc &v) {
REFLECT_MEMBER2("callees", v.def.callees);
REFLECT_MEMBER2("kind", v.def.kind);
REFLECT_MEMBER2("parent_kind", v.def.parent_kind);
REFLECT_MEMBER2("parent", v.def.parent);
REFLECT_MEMBER2("storage", v.def.storage);

REFLECT_MEMBER2("declarations", v.declarations);
Expand Down Expand Up @@ -324,6 +325,7 @@ template <typename Vis> void reflect1(Vis &vis, IndexType &v) {
REFLECT_MEMBER2("alias_of", v.def.alias_of);
REFLECT_MEMBER2("kind", v.def.kind);
REFLECT_MEMBER2("parent_kind", v.def.parent_kind);
REFLECT_MEMBER2("parent", v.def.parent);

REFLECT_MEMBER2("declarations", v.declarations);
REFLECT_MEMBER2("derived", v.derived);
Expand All @@ -347,6 +349,7 @@ template <typename TVisitor> void reflect1(TVisitor &vis, IndexVar &v) {
REFLECT_MEMBER2("type", v.def.type);
REFLECT_MEMBER2("kind", v.def.kind);
REFLECT_MEMBER2("parent_kind", v.def.parent_kind);
REFLECT_MEMBER2("parent", v.def.parent);
REFLECT_MEMBER2("storage", v.def.storage);

REFLECT_MEMBER2("declarations", v.declarations);
Expand Down