2017-12-06 03:32:33 +00:00
|
|
|
#include "message_handler.h"
|
|
|
|
#include "query_utils.h"
|
2017-12-29 16:29:47 +00:00
|
|
|
#include "queue_manager.h"
|
2017-12-06 03:32:33 +00:00
|
|
|
|
2017-12-06 05:03:38 +00:00
|
|
|
namespace {
|
2018-03-22 04:05:25 +00:00
|
|
|
MethodType kMethodType = "$cquery/inheritanceHierarchy";
|
|
|
|
|
|
|
|
struct In_CqueryInheritanceHierarchy : public RequestMessage {
|
|
|
|
MethodType GetMethodType() const override { return kMethodType; }
|
2018-02-26 02:45:46 +00:00
|
|
|
struct Params {
|
2018-03-20 02:51:42 +00:00
|
|
|
// If id+kind are specified, expand a node; otherwise textDocument+position
|
|
|
|
// should be specified for building the root and |levels| of nodes below.
|
2018-02-26 02:45:46 +00:00
|
|
|
lsTextDocumentIdentifier textDocument;
|
|
|
|
lsPosition position;
|
2018-02-28 05:56:40 +00:00
|
|
|
|
|
|
|
Maybe<Id<void>> id;
|
|
|
|
SymbolKind kind = SymbolKind::Invalid;
|
|
|
|
|
2018-02-26 02:45:46 +00:00
|
|
|
// true: derived classes/functions; false: base classes/functions
|
|
|
|
bool derived = false;
|
|
|
|
bool detailedName = false;
|
|
|
|
int levels = 1;
|
|
|
|
};
|
|
|
|
Params params;
|
|
|
|
};
|
|
|
|
|
2018-03-22 04:05:25 +00:00
|
|
|
MAKE_REFLECT_STRUCT(In_CqueryInheritanceHierarchy::Params,
|
2018-02-26 02:45:46 +00:00
|
|
|
textDocument,
|
|
|
|
position,
|
|
|
|
id,
|
|
|
|
kind,
|
|
|
|
derived,
|
|
|
|
detailedName,
|
|
|
|
levels);
|
2018-03-22 04:05:25 +00:00
|
|
|
MAKE_REFLECT_STRUCT(In_CqueryInheritanceHierarchy, id, params);
|
|
|
|
REGISTER_IN_MESSAGE(In_CqueryInheritanceHierarchy);
|
2017-12-06 04:39:44 +00:00
|
|
|
|
2018-02-22 05:50:36 +00:00
|
|
|
struct Out_CqueryInheritanceHierarchy
|
|
|
|
: public lsOutMessage<Out_CqueryInheritanceHierarchy> {
|
2018-02-26 02:45:46 +00:00
|
|
|
struct Entry {
|
|
|
|
Id<void> id;
|
|
|
|
SymbolKind kind;
|
2018-02-11 05:36:15 +00:00
|
|
|
std::string_view name;
|
2018-02-26 02:45:46 +00:00
|
|
|
lsLocation location;
|
|
|
|
// For unexpanded nodes, this is an upper bound because some entities may be
|
|
|
|
// undefined. If it is 0, there are no members.
|
|
|
|
int numChildren;
|
|
|
|
// Empty if the |levels| limit is reached.
|
|
|
|
std::vector<Entry> children;
|
2017-12-06 04:39:44 +00:00
|
|
|
};
|
|
|
|
lsRequestId id;
|
2018-02-26 02:45:46 +00:00
|
|
|
optional<Entry> result;
|
2017-12-06 04:39:44 +00:00
|
|
|
};
|
2018-02-26 02:45:46 +00:00
|
|
|
MAKE_REFLECT_STRUCT(Out_CqueryInheritanceHierarchy::Entry,
|
|
|
|
id,
|
|
|
|
kind,
|
2017-12-06 04:39:44 +00:00
|
|
|
name,
|
|
|
|
location,
|
2018-02-26 02:45:46 +00:00
|
|
|
numChildren,
|
2017-12-06 04:39:44 +00:00
|
|
|
children);
|
2018-02-22 05:50:36 +00:00
|
|
|
MAKE_REFLECT_STRUCT(Out_CqueryInheritanceHierarchy, jsonrpc, id, result);
|
2017-12-06 04:39:44 +00:00
|
|
|
|
2018-02-26 02:45:46 +00:00
|
|
|
bool Expand(MessageHandler* m,
|
|
|
|
Out_CqueryInheritanceHierarchy::Entry* entry,
|
|
|
|
bool derived,
|
|
|
|
bool detailed_name,
|
|
|
|
int levels);
|
|
|
|
|
|
|
|
template <typename Q>
|
|
|
|
bool ExpandHelper(MessageHandler* m,
|
|
|
|
Out_CqueryInheritanceHierarchy::Entry* entry,
|
|
|
|
bool derived,
|
|
|
|
bool detailed_name,
|
|
|
|
int levels,
|
|
|
|
Q& entity) {
|
|
|
|
const auto* def = entity.AnyDef();
|
|
|
|
if (!def) {
|
|
|
|
entry->numChildren = 0;
|
|
|
|
return false;
|
2017-12-19 06:15:46 +00:00
|
|
|
}
|
2018-02-26 02:45:46 +00:00
|
|
|
if (detailed_name)
|
|
|
|
entry->name = def->DetailedName(false);
|
|
|
|
else
|
|
|
|
entry->name = def->ShortName();
|
|
|
|
if (def->spell) {
|
|
|
|
if (optional<lsLocation> loc =
|
|
|
|
GetLsLocation(m->db, m->working_files, *def->spell))
|
|
|
|
entry->location = *loc;
|
|
|
|
}
|
|
|
|
if (derived) {
|
|
|
|
if (levels > 0) {
|
|
|
|
for (auto id : entity.derived) {
|
|
|
|
Out_CqueryInheritanceHierarchy::Entry entry1;
|
|
|
|
entry1.id = id;
|
|
|
|
entry1.kind = entry->kind;
|
|
|
|
if (Expand(m, &entry1, derived, detailed_name, levels - 1))
|
|
|
|
entry->children.push_back(std::move(entry1));
|
|
|
|
}
|
|
|
|
entry->numChildren = int(entry->children.size());
|
2018-02-26 03:10:02 +00:00
|
|
|
} else
|
|
|
|
entry->numChildren = int(entity.derived.size());
|
2018-02-26 02:45:46 +00:00
|
|
|
} else {
|
|
|
|
if (levels > 0) {
|
|
|
|
for (auto id : def->bases) {
|
|
|
|
Out_CqueryInheritanceHierarchy::Entry entry1;
|
|
|
|
entry1.id = id;
|
|
|
|
entry1.kind = entry->kind;
|
|
|
|
if (Expand(m, &entry1, derived, detailed_name, levels - 1))
|
|
|
|
entry->children.push_back(std::move(entry1));
|
|
|
|
}
|
|
|
|
entry->numChildren = int(entry->children.size());
|
2018-02-26 03:10:02 +00:00
|
|
|
} else
|
|
|
|
entry->numChildren = int(def->bases.size());
|
2018-02-26 02:45:46 +00:00
|
|
|
}
|
|
|
|
return true;
|
2017-12-06 04:39:44 +00:00
|
|
|
}
|
|
|
|
|
2018-02-26 02:45:46 +00:00
|
|
|
bool Expand(MessageHandler* m,
|
|
|
|
Out_CqueryInheritanceHierarchy::Entry* entry,
|
|
|
|
bool derived,
|
|
|
|
bool detailed_name,
|
|
|
|
int levels) {
|
|
|
|
if (entry->kind == SymbolKind::Func)
|
|
|
|
return ExpandHelper(m, entry, derived, detailed_name, levels,
|
|
|
|
m->db->funcs[entry->id.id]);
|
|
|
|
else
|
|
|
|
return ExpandHelper(m, entry, derived, detailed_name, levels,
|
|
|
|
m->db->types[entry->id.id]);
|
|
|
|
}
|
2017-12-06 04:39:44 +00:00
|
|
|
|
2018-03-22 04:05:25 +00:00
|
|
|
struct Handler_CqueryInheritanceHierarchy
|
|
|
|
: BaseMessageHandler<In_CqueryInheritanceHierarchy> {
|
|
|
|
MethodType GetMethodType() const override { return kMethodType; }
|
|
|
|
|
2018-02-26 02:45:46 +00:00
|
|
|
optional<Out_CqueryInheritanceHierarchy::Entry>
|
|
|
|
BuildInitial(SymbolRef sym, bool derived, bool detailed_name, int levels) {
|
|
|
|
Out_CqueryInheritanceHierarchy::Entry entry;
|
|
|
|
entry.id = sym.id;
|
|
|
|
entry.kind = sym.kind;
|
|
|
|
Expand(this, &entry, derived, detailed_name, levels);
|
|
|
|
return entry;
|
2017-12-06 04:39:44 +00:00
|
|
|
}
|
|
|
|
|
2018-03-22 04:05:25 +00:00
|
|
|
void Run(In_CqueryInheritanceHierarchy* request) override {
|
2018-02-26 02:45:46 +00:00
|
|
|
const auto& params = request->params;
|
2018-02-22 05:50:36 +00:00
|
|
|
Out_CqueryInheritanceHierarchy out;
|
2017-12-06 03:32:33 +00:00
|
|
|
out.id = request->id;
|
|
|
|
|
2018-02-26 02:45:46 +00:00
|
|
|
if (params.id) {
|
|
|
|
Out_CqueryInheritanceHierarchy::Entry entry;
|
|
|
|
entry.id = *params.id;
|
|
|
|
entry.kind = params.kind;
|
|
|
|
if (((entry.kind == SymbolKind::Func && entry.id.id < db->funcs.size()) ||
|
|
|
|
(entry.kind == SymbolKind::Type &&
|
|
|
|
entry.id.id < db->types.size())) &&
|
|
|
|
Expand(this, &entry, params.derived, params.detailedName,
|
|
|
|
params.levels))
|
|
|
|
out.result = std::move(entry);
|
2018-02-28 05:56:40 +00:00
|
|
|
} else {
|
|
|
|
QueryFile* file;
|
|
|
|
if (!FindFileOrFail(db, project, request->id,
|
|
|
|
params.textDocument.uri.GetPath(), &file))
|
|
|
|
return;
|
|
|
|
WorkingFile* working_file =
|
|
|
|
working_files->GetFileByFilename(file->def->path);
|
|
|
|
|
2018-03-20 02:51:42 +00:00
|
|
|
for (SymbolRef sym : FindSymbolsAtLocation(working_file, file,
|
|
|
|
request->params.position)) {
|
2018-02-28 05:56:40 +00:00
|
|
|
if (sym.kind == SymbolKind::Func || sym.kind == SymbolKind::Type) {
|
|
|
|
out.result = BuildInitial(sym, params.derived, params.detailedName,
|
|
|
|
params.levels);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2018-02-26 02:45:46 +00:00
|
|
|
}
|
|
|
|
|
2018-03-22 04:05:25 +00:00
|
|
|
QueueManager::WriteStdout(kMethodType, out);
|
2017-12-06 03:32:33 +00:00
|
|
|
}
|
|
|
|
};
|
2018-03-22 04:05:25 +00:00
|
|
|
REGISTER_MESSAGE_HANDLER(Handler_CqueryInheritanceHierarchy);
|
2018-02-28 05:56:40 +00:00
|
|
|
|
2017-12-31 03:18:33 +00:00
|
|
|
} // namespace
|