mirror of
https://github.com/MaskRay/ccls.git
synced 2024-11-30 11:27:07 +00:00
Add kind to $ccls/member and iterate all QueryType::def
kind:2 => member functions kind:3 => nested classes / namespace members
This commit is contained in:
parent
176039fe35
commit
562207bf96
@ -7,12 +7,14 @@ ccls, which originates from [cquery](https://github.com/cquery-project/cquery),
|
|||||||
|
|
||||||
* code completion (with both signature help and snippets)
|
* code completion (with both signature help and snippets)
|
||||||
* [definition](src/messages/textDocument_definition.cc)/[references](src/messages/textDcument_references.cc), and other cross references
|
* [definition](src/messages/textDocument_definition.cc)/[references](src/messages/textDcument_references.cc), and other cross references
|
||||||
* hierarchies: [call (caller/callee) hierarchy](src/messages/ccls_callHierarchy.cc), [inheritance (base/derived) hierarchy](src/messages/ccls_inheritanceHierarchy.cc), [member hierarchy](src/messages/ccls_memberHierarchy.cc)
|
* cross reference extensions: `$ccls/call` `$ccls/inheritance` `$ccls/member` `$ccls/vars` ...
|
||||||
* [symbol rename](src/messages/text_documentRename.cc)
|
* hierarchies: [call (caller/callee) hierarchy](src/messages/ccls_call.cc), [inheritance (base/derived) hierarchy](src/messages/ccls_inheritance.cc), [member hierarchy](src/messages/ccls_member.cc)
|
||||||
|
* [symbol rename](src/messages/textDocument_rename.cc)
|
||||||
* [document symbols](src/messages/textDocument_documentSymbol.cc) and approximate search of [workspace symbol](src/messages/workspace_symbol.cc)
|
* [document symbols](src/messages/textDocument_documentSymbol.cc) and approximate search of [workspace symbol](src/messages/workspace_symbol.cc)
|
||||||
* [hover information](src/messages/textDocument_hover.cc)
|
* [hover information](src/messages/textDocument_hover.cc)
|
||||||
* diagnostics and code actions (clang FixIts)
|
* diagnostics and code actions (clang FixIts)
|
||||||
* semantic highlighting and preprocessor skipped regions
|
* semantic highlighting and preprocessor skipped regions
|
||||||
|
* semantic navigation: `$ccls/navigate`
|
||||||
|
|
||||||
It has a global view of the code base and support a lot of cross reference features, see [wiki/FAQ](../../wiki/FAQ).
|
It has a global view of the code base and support a lot of cross reference features, see [wiki/FAQ](../../wiki/FAQ).
|
||||||
It starts indexing the whole project (including subprojects if exist) parallelly when you open the first file, while the main thread can serve requests before the indexing is complete.
|
It starts indexing the whole project (including subprojects if exist) parallelly when you open the first file, while the main thread can serve requests before the indexing is complete.
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
using namespace ccls;
|
using namespace ccls;
|
||||||
|
|
||||||
#include <clang/AST/Type.h>
|
#include <clang/AST/Type.h>
|
||||||
|
#include <llvm/ADT/DenseSet.h>
|
||||||
using namespace clang;
|
using namespace clang;
|
||||||
|
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
@ -30,12 +31,15 @@ struct In_CclsMember : public RequestInMessage {
|
|||||||
|
|
||||||
bool qualified = false;
|
bool qualified = false;
|
||||||
int levels = 1;
|
int levels = 1;
|
||||||
|
// If SymbolKind::Func and the point is at a type, list member functions
|
||||||
|
// instead of member variables.
|
||||||
|
SymbolKind kind = SymbolKind::Var;
|
||||||
bool hierarchy = false;
|
bool hierarchy = false;
|
||||||
} params;
|
} params;
|
||||||
};
|
};
|
||||||
|
|
||||||
MAKE_REFLECT_STRUCT(In_CclsMember::Params, textDocument, position, id,
|
MAKE_REFLECT_STRUCT(In_CclsMember::Params, textDocument, position, id,
|
||||||
qualified, levels, hierarchy);
|
qualified, levels, kind, hierarchy);
|
||||||
MAKE_REFLECT_STRUCT(In_CclsMember, id, params);
|
MAKE_REFLECT_STRUCT(In_CclsMember, id, params);
|
||||||
REGISTER_IN_MESSAGE(In_CclsMember);
|
REGISTER_IN_MESSAGE(In_CclsMember);
|
||||||
|
|
||||||
@ -61,7 +65,7 @@ MAKE_REFLECT_STRUCT_MANDATORY_OPTIONAL(Out_CclsMember, jsonrpc, id,
|
|||||||
result);
|
result);
|
||||||
|
|
||||||
bool Expand(MessageHandler *m, Out_CclsMember::Entry *entry,
|
bool Expand(MessageHandler *m, Out_CclsMember::Entry *entry,
|
||||||
bool qualified, int levels);
|
bool qualified, int levels, SymbolKind memberKind);
|
||||||
|
|
||||||
// Add a field to |entry| which is a Func/Type.
|
// Add a field to |entry| which is a Func/Type.
|
||||||
void DoField(MessageHandler *m, Out_CclsMember::Entry *entry,
|
void DoField(MessageHandler *m, Out_CclsMember::Entry *entry,
|
||||||
@ -96,7 +100,7 @@ void DoField(MessageHandler *m, Out_CclsMember::Entry *entry,
|
|||||||
if (def1->type) {
|
if (def1->type) {
|
||||||
entry1.id = std::to_string(def1->type);
|
entry1.id = std::to_string(def1->type);
|
||||||
entry1.usr = def1->type;
|
entry1.usr = def1->type;
|
||||||
if (Expand(m, &entry1, qualified, levels))
|
if (Expand(m, &entry1, qualified, levels, SymbolKind::Var))
|
||||||
entry->children.push_back(std::move(entry1));
|
entry->children.push_back(std::move(entry1));
|
||||||
} else {
|
} else {
|
||||||
entry1.id = "0";
|
entry1.id = "0";
|
||||||
@ -107,13 +111,13 @@ void DoField(MessageHandler *m, Out_CclsMember::Entry *entry,
|
|||||||
|
|
||||||
// Expand a type node by adding members recursively to it.
|
// Expand a type node by adding members recursively to it.
|
||||||
bool Expand(MessageHandler *m, Out_CclsMember::Entry *entry,
|
bool Expand(MessageHandler *m, Out_CclsMember::Entry *entry,
|
||||||
bool qualified, int levels) {
|
bool qualified, int levels, SymbolKind memberKind) {
|
||||||
if (0 < entry->usr && entry->usr <= BuiltinType::LastKind) {
|
if (0 < entry->usr && entry->usr <= BuiltinType::LastKind) {
|
||||||
entry->name = ClangBuiltinTypeName(int(entry->usr));
|
entry->name = ClangBuiltinTypeName(int(entry->usr));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
const QueryType &type = m->db->Type(entry->usr);
|
const QueryType *type = &m->db->Type(entry->usr);
|
||||||
const QueryType::Def *def = type.AnyDef();
|
const QueryType::Def *def = type->AnyDef();
|
||||||
// builtin types have no declaration and empty |qualified|.
|
// builtin types have no declaration and empty |qualified|.
|
||||||
if (!def)
|
if (!def)
|
||||||
return false;
|
return false;
|
||||||
@ -121,51 +125,96 @@ bool Expand(MessageHandler *m, Out_CclsMember::Entry *entry,
|
|||||||
std::unordered_set<Usr> seen;
|
std::unordered_set<Usr> seen;
|
||||||
if (levels > 0) {
|
if (levels > 0) {
|
||||||
std::vector<const QueryType *> stack;
|
std::vector<const QueryType *> stack;
|
||||||
seen.insert(type.usr);
|
seen.insert(type->usr);
|
||||||
stack.push_back(&type);
|
stack.push_back(type);
|
||||||
while (stack.size()) {
|
while (stack.size()) {
|
||||||
const auto *def = stack.back()->AnyDef();
|
type = stack.back();
|
||||||
stack.pop_back();
|
stack.pop_back();
|
||||||
if (def) {
|
const auto *def = type->AnyDef();
|
||||||
for (Usr usr : def->bases) {
|
if (!def) continue;
|
||||||
auto &type1 = m->db->Type(usr);
|
for (Usr usr : def->bases) {
|
||||||
if (type1.def.size()) {
|
auto &type1 = m->db->Type(usr);
|
||||||
seen.insert(type1.usr);
|
if (type1.def.size()) {
|
||||||
stack.push_back(&type1);
|
seen.insert(type1.usr);
|
||||||
}
|
stack.push_back(&type1);
|
||||||
}
|
}
|
||||||
if (def->alias_of) {
|
}
|
||||||
const QueryType::Def *def1 = m->db->Type(def->alias_of).AnyDef();
|
if (def->alias_of) {
|
||||||
Out_CclsMember::Entry entry1;
|
const QueryType::Def *def1 = m->db->Type(def->alias_of).AnyDef();
|
||||||
entry1.id = std::to_string(def->alias_of);
|
Out_CclsMember::Entry entry1;
|
||||||
entry1.usr = def->alias_of;
|
entry1.id = std::to_string(def->alias_of);
|
||||||
if (def1 && def1->spell) {
|
entry1.usr = def->alias_of;
|
||||||
// The declaration of target type.
|
if (def1 && def1->spell) {
|
||||||
if (std::optional<lsLocation> loc =
|
// The declaration of target type.
|
||||||
|
if (std::optional<lsLocation> loc =
|
||||||
|
GetLsLocation(m->db, m->working_files, *def1->spell))
|
||||||
|
entry1.location = *loc;
|
||||||
|
} else if (def->spell) {
|
||||||
|
// Builtin types have no declaration but the typedef declaration
|
||||||
|
// itself is useful.
|
||||||
|
if (std::optional<lsLocation> loc =
|
||||||
|
GetLsLocation(m->db, m->working_files, *def->spell))
|
||||||
|
entry1.location = *loc;
|
||||||
|
}
|
||||||
|
if (def1 && qualified)
|
||||||
|
entry1.fieldName = def1->detailed_name;
|
||||||
|
if (Expand(m, &entry1, qualified, levels - 1, memberKind)) {
|
||||||
|
// For builtin types |name| is set.
|
||||||
|
if (entry1.fieldName.empty())
|
||||||
|
entry1.fieldName = std::string(entry1.name);
|
||||||
|
entry->children.push_back(std::move(entry1));
|
||||||
|
}
|
||||||
|
} else if (memberKind == SymbolKind::Func) {
|
||||||
|
llvm::DenseSet<Usr, DenseMapInfoForUsr> seen1;
|
||||||
|
for (auto &def : type->def)
|
||||||
|
for (Usr usr : def.funcs)
|
||||||
|
if (seen1.insert(usr).second) {
|
||||||
|
QueryFunc &func1 = m->db->Func(usr);
|
||||||
|
if (const QueryFunc::Def *def1 = func1.AnyDef()) {
|
||||||
|
Out_CclsMember::Entry entry1;
|
||||||
|
entry1.fieldName = def1->Name(false);
|
||||||
|
if (def1->spell) {
|
||||||
|
if (auto loc =
|
||||||
|
GetLsLocation(m->db, m->working_files, *def1->spell))
|
||||||
|
entry1.location = *loc;
|
||||||
|
} else if (func1.declarations.size()) {
|
||||||
|
if (auto loc = GetLsLocation(m->db, m->working_files,
|
||||||
|
func1.declarations[0]))
|
||||||
|
entry1.location = *loc;
|
||||||
|
}
|
||||||
|
entry->children.push_back(std::move(entry1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (memberKind == SymbolKind::Type) {
|
||||||
|
llvm::DenseSet<Usr, DenseMapInfoForUsr> seen1;
|
||||||
|
for (auto &def : type->def)
|
||||||
|
for (Usr usr : def.types)
|
||||||
|
if (seen1.insert(usr).second) {
|
||||||
|
QueryType &type1 = m->db->Type(usr);
|
||||||
|
if (const QueryType::Def *def1 = type1.AnyDef()) {
|
||||||
|
Out_CclsMember::Entry entry1;
|
||||||
|
entry1.fieldName = def1->Name(false);
|
||||||
|
if (def1->spell) {
|
||||||
|
if (auto loc =
|
||||||
GetLsLocation(m->db, m->working_files, *def1->spell))
|
GetLsLocation(m->db, m->working_files, *def1->spell))
|
||||||
entry1.location = *loc;
|
entry1.location = *loc;
|
||||||
} else if (def->spell) {
|
} else if (type1.declarations.size()) {
|
||||||
// Builtin types have no declaration but the typedef declaration
|
if (auto loc = GetLsLocation(m->db, m->working_files,
|
||||||
// itself is useful.
|
type1.declarations[0]))
|
||||||
if (std::optional<lsLocation> loc =
|
entry1.location = *loc;
|
||||||
GetLsLocation(m->db, m->working_files, *def->spell))
|
}
|
||||||
entry1.location = *loc;
|
entry->children.push_back(std::move(entry1));
|
||||||
}
|
}
|
||||||
if (def1 && qualified)
|
}
|
||||||
entry1.fieldName = def1->detailed_name;
|
} else {
|
||||||
if (Expand(m, &entry1, qualified, levels - 1)) {
|
llvm::DenseSet<Usr, DenseMapInfoForUsr> seen1;
|
||||||
// For builtin types |name| is set.
|
for (auto &def : type->def)
|
||||||
if (entry1.fieldName.empty())
|
for (auto it : def.vars)
|
||||||
entry1.fieldName = std::string(entry1.name);
|
if (seen1.insert(it.first).second) {
|
||||||
entry->children.push_back(std::move(entry1));
|
QueryVar &var = m->db->Var(it.first);
|
||||||
}
|
if (!var.def.empty())
|
||||||
} else {
|
DoField(m, entry, var, it.second, qualified, levels - 1);
|
||||||
for (auto it : def->vars) {
|
}
|
||||||
QueryVar &var = m->db->Var(it.first);
|
|
||||||
if (!var.def.empty())
|
|
||||||
DoField(m, entry, var, it.second, qualified, levels - 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
entry->numChildren = int(entry->children.size());
|
entry->numChildren = int(entry->children.size());
|
||||||
@ -179,7 +228,7 @@ struct Handler_CclsMember
|
|||||||
MethodType GetMethodType() const override { return kMethodType; }
|
MethodType GetMethodType() const override { return kMethodType; }
|
||||||
|
|
||||||
std::optional<Out_CclsMember::Entry>
|
std::optional<Out_CclsMember::Entry>
|
||||||
BuildInitial(SymbolKind kind, Usr root_usr, bool qualified, int levels) {
|
BuildInitial(SymbolKind kind, Usr root_usr, bool qualified, int levels, SymbolKind memberKind) {
|
||||||
switch (kind) {
|
switch (kind) {
|
||||||
default:
|
default:
|
||||||
return {};
|
return {};
|
||||||
@ -216,7 +265,7 @@ struct Handler_CclsMember
|
|||||||
GetLsLocation(db, working_files, *def->spell))
|
GetLsLocation(db, working_files, *def->spell))
|
||||||
entry.location = *loc;
|
entry.location = *loc;
|
||||||
}
|
}
|
||||||
Expand(this, &entry, qualified, levels);
|
Expand(this, &entry, qualified, levels, memberKind);
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -238,7 +287,7 @@ struct Handler_CclsMember
|
|||||||
entry.usr = params.usr;
|
entry.usr = params.usr;
|
||||||
// entry.name is empty as it is known by the client.
|
// entry.name is empty as it is known by the client.
|
||||||
if (db->HasType(entry.usr) &&
|
if (db->HasType(entry.usr) &&
|
||||||
Expand(this, &entry, params.qualified, params.levels))
|
Expand(this, &entry, params.qualified, params.levels, params.kind))
|
||||||
out.result = std::move(entry);
|
out.result = std::move(entry);
|
||||||
} else {
|
} else {
|
||||||
QueryFile *file;
|
QueryFile *file;
|
||||||
@ -251,14 +300,14 @@ struct Handler_CclsMember
|
|||||||
switch (sym.kind) {
|
switch (sym.kind) {
|
||||||
case SymbolKind::Func:
|
case SymbolKind::Func:
|
||||||
case SymbolKind::Type:
|
case SymbolKind::Type:
|
||||||
out.result =
|
out.result = BuildInitial(sym.kind, sym.usr, params.qualified,
|
||||||
BuildInitial(sym.kind, sym.usr, params.qualified, params.levels);
|
params.levels, params.kind);
|
||||||
break;
|
break;
|
||||||
case SymbolKind::Var: {
|
case SymbolKind::Var: {
|
||||||
const QueryVar::Def *def = db->GetVar(sym).AnyDef();
|
const QueryVar::Def *def = db->GetVar(sym).AnyDef();
|
||||||
if (def && def->type)
|
if (def && def->type)
|
||||||
out.result = BuildInitial(SymbolKind::Type, def->type,
|
out.result = BuildInitial(SymbolKind::Type, def->type,
|
||||||
params.qualified, params.levels);
|
params.qualified, params.levels, params.kind);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
Loading…
Reference in New Issue
Block a user