mirror of
https://github.com/MaskRay/ccls.git
synced 2025-02-18 06:31:15 +00:00
Support listing local variables in memberHierarchy and better handling of locations for typedef; remove cquery_call_tree.cc
This commit is contained in:
parent
60c0267432
commit
214eded2cb
@ -344,8 +344,6 @@ void LaunchStdinLoop(Config* config,
|
|||||||
case IpcId::CqueryFreshenIndex:
|
case IpcId::CqueryFreshenIndex:
|
||||||
case IpcId::CqueryCallHierarchyInitial:
|
case IpcId::CqueryCallHierarchyInitial:
|
||||||
case IpcId::CqueryCallHierarchyExpand:
|
case IpcId::CqueryCallHierarchyExpand:
|
||||||
case IpcId::CqueryCallTreeInitial:
|
|
||||||
case IpcId::CqueryCallTreeExpand:
|
|
||||||
case IpcId::CqueryInheritanceHierarchyInitial:
|
case IpcId::CqueryInheritanceHierarchyInitial:
|
||||||
case IpcId::CqueryInheritanceHierarchyExpand:
|
case IpcId::CqueryInheritanceHierarchyExpand:
|
||||||
case IpcId::CqueryMemberHierarchyInitial:
|
case IpcId::CqueryMemberHierarchyInitial:
|
||||||
|
@ -499,6 +499,21 @@ Use SetUse(IndexFile* db, Range range, ClangCursor parent, Role role) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char* GetAnonName(CXCursorKind kind) {
|
||||||
|
switch (kind) {
|
||||||
|
case CXCursor_ClassDecl:
|
||||||
|
return "(anon class)";
|
||||||
|
case CXCursor_EnumDecl:
|
||||||
|
return "(anon enum)";
|
||||||
|
case CXCursor_StructDecl:
|
||||||
|
return "(anon struct)";
|
||||||
|
case CXCursor_UnionDecl:
|
||||||
|
return "(anon union)";
|
||||||
|
default:
|
||||||
|
return "(anon)";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void SetTypeName(IndexType* type,
|
void SetTypeName(IndexType* type,
|
||||||
const ClangCursor& cursor,
|
const ClangCursor& cursor,
|
||||||
const CXIdxContainerInfo* container,
|
const CXIdxContainerInfo* container,
|
||||||
@ -508,7 +523,7 @@ void SetTypeName(IndexType* type,
|
|||||||
// |name| can be null in an anonymous struct (see
|
// |name| can be null in an anonymous struct (see
|
||||||
// tests/types/anonymous_struct.cc).
|
// tests/types/anonymous_struct.cc).
|
||||||
if (!name)
|
if (!name)
|
||||||
name = "(anon)";
|
name = GetAnonName(cursor.get_kind());
|
||||||
if (!container)
|
if (!container)
|
||||||
parent.cursor = cursor.get_semantic_parent().cx_cursor;
|
parent.cursor = cursor.get_semantic_parent().cx_cursor;
|
||||||
// Investigate why clang_getCursorPrettyPrinted gives `struct A {}` `namespace
|
// Investigate why clang_getCursorPrettyPrinted gives `struct A {}` `namespace
|
||||||
@ -1443,23 +1458,7 @@ std::string NamespaceHelper::QualifiedName(const CXIdxContainerInfo* container,
|
|||||||
if (name.size())
|
if (name.size())
|
||||||
qualifier += name;
|
qualifier += name;
|
||||||
else
|
else
|
||||||
switch (namespaces[i].get_kind()) {
|
qualifier += GetAnonName(namespaces[i].get_kind());
|
||||||
case CXCursor_ClassDecl:
|
|
||||||
qualifier += "(anon class)";
|
|
||||||
break;
|
|
||||||
case CXCursor_EnumDecl:
|
|
||||||
qualifier += "(anon enum)";
|
|
||||||
break;
|
|
||||||
case CXCursor_StructDecl:
|
|
||||||
qualifier += "(anon struct)";
|
|
||||||
break;
|
|
||||||
case CXCursor_UnionDecl:
|
|
||||||
qualifier += "(anon union)";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
qualifier += "(anon)";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
qualifier += "::";
|
qualifier += "::";
|
||||||
container_cursor_to_qualified_name[namespaces[i]] = qualifier;
|
container_cursor_to_qualified_name[namespaces[i]] = qualifier;
|
||||||
}
|
}
|
||||||
|
@ -74,10 +74,6 @@ const char* IpcIdToString(IpcId id) {
|
|||||||
return "$cquery/callHierarchyInitial";
|
return "$cquery/callHierarchyInitial";
|
||||||
case IpcId::CqueryCallHierarchyExpand:
|
case IpcId::CqueryCallHierarchyExpand:
|
||||||
return "$cquery/callHierarchyExpand";
|
return "$cquery/callHierarchyExpand";
|
||||||
case IpcId::CqueryCallTreeInitial:
|
|
||||||
return "$cquery/callTreeInitial";
|
|
||||||
case IpcId::CqueryCallTreeExpand:
|
|
||||||
return "$cquery/callTreeExpand";
|
|
||||||
case IpcId::CqueryInheritanceHierarchyInitial:
|
case IpcId::CqueryInheritanceHierarchyInitial:
|
||||||
return "$cquery/inheritanceHierarchyInitial";
|
return "$cquery/inheritanceHierarchyInitial";
|
||||||
case IpcId::CqueryInheritanceHierarchyExpand:
|
case IpcId::CqueryInheritanceHierarchyExpand:
|
||||||
|
@ -50,8 +50,6 @@ enum class IpcId : int {
|
|||||||
// Messages used in tree views.
|
// Messages used in tree views.
|
||||||
CqueryCallHierarchyInitial,
|
CqueryCallHierarchyInitial,
|
||||||
CqueryCallHierarchyExpand,
|
CqueryCallHierarchyExpand,
|
||||||
CqueryCallTreeInitial,
|
|
||||||
CqueryCallTreeExpand,
|
|
||||||
CqueryInheritanceHierarchyInitial,
|
CqueryInheritanceHierarchyInitial,
|
||||||
CqueryInheritanceHierarchyExpand,
|
CqueryInheritanceHierarchyExpand,
|
||||||
CqueryMemberHierarchyInitial,
|
CqueryMemberHierarchyInitial,
|
||||||
|
@ -1,198 +0,0 @@
|
|||||||
#include "message_handler.h"
|
|
||||||
#include "query_utils.h"
|
|
||||||
#include "queue_manager.h"
|
|
||||||
|
|
||||||
#include <loguru.hpp>
|
|
||||||
|
|
||||||
// FIXME Interop with VSCode, change std::string usr to Usr (uint64_t)
|
|
||||||
namespace {
|
|
||||||
struct Ipc_CqueryCallTreeInitial
|
|
||||||
: public RequestMessage<Ipc_CqueryCallTreeInitial> {
|
|
||||||
const static IpcId kIpcId = IpcId::CqueryCallTreeInitial;
|
|
||||||
lsTextDocumentPositionParams params;
|
|
||||||
};
|
|
||||||
MAKE_REFLECT_STRUCT(Ipc_CqueryCallTreeInitial, id, params);
|
|
||||||
REGISTER_IPC_MESSAGE(Ipc_CqueryCallTreeInitial);
|
|
||||||
|
|
||||||
struct Ipc_CqueryCallTreeExpand
|
|
||||||
: public RequestMessage<Ipc_CqueryCallTreeExpand> {
|
|
||||||
const static IpcId kIpcId = IpcId::CqueryCallTreeExpand;
|
|
||||||
struct Params {
|
|
||||||
std::string usr;
|
|
||||||
};
|
|
||||||
Params params;
|
|
||||||
};
|
|
||||||
MAKE_REFLECT_STRUCT(Ipc_CqueryCallTreeExpand::Params, usr);
|
|
||||||
MAKE_REFLECT_STRUCT(Ipc_CqueryCallTreeExpand, id, params);
|
|
||||||
REGISTER_IPC_MESSAGE(Ipc_CqueryCallTreeExpand);
|
|
||||||
|
|
||||||
struct Out_CqueryCallTree : public lsOutMessage<Out_CqueryCallTree> {
|
|
||||||
enum class CallType { Direct = 0, Base = 1, Derived = 2 };
|
|
||||||
struct CallEntry {
|
|
||||||
std::string_view name;
|
|
||||||
std::string usr;
|
|
||||||
lsLocation location;
|
|
||||||
bool hasCallers = true;
|
|
||||||
CallType callType = CallType::Direct;
|
|
||||||
};
|
|
||||||
|
|
||||||
lsRequestId id;
|
|
||||||
std::vector<CallEntry> result;
|
|
||||||
};
|
|
||||||
MAKE_REFLECT_TYPE_PROXY(Out_CqueryCallTree::CallType);
|
|
||||||
MAKE_REFLECT_STRUCT(Out_CqueryCallTree::CallEntry,
|
|
||||||
name,
|
|
||||||
usr,
|
|
||||||
location,
|
|
||||||
hasCallers,
|
|
||||||
callType);
|
|
||||||
MAKE_REFLECT_STRUCT(Out_CqueryCallTree, jsonrpc, id, result);
|
|
||||||
|
|
||||||
std::vector<Out_CqueryCallTree::CallEntry> BuildInitialCallTree(
|
|
||||||
QueryDatabase* db,
|
|
||||||
WorkingFiles* working_files,
|
|
||||||
QueryFuncId root) {
|
|
||||||
QueryFunc& root_func = db->funcs[root.id];
|
|
||||||
const QueryFunc::Def* def = root_func.AnyDef();
|
|
||||||
if (!def || !def->spell)
|
|
||||||
return {};
|
|
||||||
optional<lsLocation> def_loc = GetLsLocation(db, working_files, *def->spell);
|
|
||||||
if (!def_loc)
|
|
||||||
return {};
|
|
||||||
|
|
||||||
Out_CqueryCallTree::CallEntry entry;
|
|
||||||
entry.name = def->ShortName();
|
|
||||||
entry.usr = std::to_string(root_func.usr);
|
|
||||||
entry.location = *def_loc;
|
|
||||||
entry.hasCallers = HasCallersOnSelfOrBaseOrDerived(db, root_func);
|
|
||||||
std::vector<Out_CqueryCallTree::CallEntry> result;
|
|
||||||
result.push_back(entry);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<Out_CqueryCallTree::CallEntry> BuildExpandCallTree(
|
|
||||||
QueryDatabase* db,
|
|
||||||
WorkingFiles* working_files,
|
|
||||||
QueryFuncId root) {
|
|
||||||
QueryFunc& root_func = db->funcs[root.id];
|
|
||||||
const QueryFunc::Def* root_func_def = root_func.AnyDef();
|
|
||||||
if (!root_func_def)
|
|
||||||
return {};
|
|
||||||
|
|
||||||
std::vector<Out_CqueryCallTree::CallEntry> result;
|
|
||||||
|
|
||||||
auto handle_caller = [&](Use caller, Out_CqueryCallTree::CallType call_type) {
|
|
||||||
optional<lsLocation> call_location =
|
|
||||||
GetLsLocation(db, working_files, caller);
|
|
||||||
if (!call_location)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// TODO: REMOVE |seen_locations| once we fix the querydb update bugs
|
|
||||||
// TODO: REMOVE |seen_locations| once we fix the querydb update bugs
|
|
||||||
// TODO: REMOVE |seen_locations| once we fix the querydb update bugs
|
|
||||||
// TODO: REMOVE |seen_locations| once we fix the querydb update bugs
|
|
||||||
// TODO: REMOVE |seen_locations| once we fix the querydb update bugs
|
|
||||||
// TODO: REMOVE |seen_locations| once we fix the querydb update bugs
|
|
||||||
// TODO: REMOVE |seen_locations| once we fix the querydb update bugs
|
|
||||||
// TODO: REMOVE |seen_locations| once we fix the querydb update bugs
|
|
||||||
// TODO: REMOVE |seen_locations| once we fix the querydb update bugs
|
|
||||||
// TODO: REMOVE |seen_locations| once we fix the querydb update bugs
|
|
||||||
// TODO: REMOVE |seen_locations| once we fix the querydb update bugs
|
|
||||||
// TODO: REMOVE |seen_locations| once we fix the querydb update bugs
|
|
||||||
// TODO: basically, querydb gets duplicate references inserted into it.
|
|
||||||
// if (!seen_locations.insert(caller.loc).second) {
|
|
||||||
// LOG_S(ERROR) << "!!!! FIXME DUPLICATE REFERENCE IN QUERYDB" <<
|
|
||||||
// std::endl; return;
|
|
||||||
//}
|
|
||||||
|
|
||||||
if (caller.kind == SymbolKind::Func) {
|
|
||||||
QueryFunc& call_func = db->GetFunc(caller);
|
|
||||||
const QueryFunc::Def* def = call_func.AnyDef();
|
|
||||||
if (!def)
|
|
||||||
return;
|
|
||||||
|
|
||||||
Out_CqueryCallTree::CallEntry call_entry;
|
|
||||||
call_entry.name = def->ShortName();
|
|
||||||
call_entry.usr = std::to_string(call_func.usr);
|
|
||||||
call_entry.location = *call_location;
|
|
||||||
call_entry.hasCallers = HasCallersOnSelfOrBaseOrDerived(db, call_func);
|
|
||||||
call_entry.callType = call_type;
|
|
||||||
result.push_back(call_entry);
|
|
||||||
} else {
|
|
||||||
// TODO: See if we can do a better job here. Need more information from
|
|
||||||
// the indexer.
|
|
||||||
Out_CqueryCallTree::CallEntry call_entry;
|
|
||||||
call_entry.name = "Likely Constructor";
|
|
||||||
call_entry.usr = "no_usr";
|
|
||||||
call_entry.location = *call_location;
|
|
||||||
call_entry.hasCallers = false;
|
|
||||||
call_entry.callType = call_type;
|
|
||||||
result.push_back(call_entry);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
std::vector<Use> base_callers = GetCallersForAllBaseFunctions(db, root_func);
|
|
||||||
std::vector<Use> derived_callers =
|
|
||||||
GetCallersForAllDerivedFunctions(db, root_func);
|
|
||||||
result.reserve(root_func.uses.size() + base_callers.size() +
|
|
||||||
derived_callers.size());
|
|
||||||
|
|
||||||
for (Use caller : root_func.uses)
|
|
||||||
handle_caller(caller, Out_CqueryCallTree::CallType::Direct);
|
|
||||||
for (Use caller : base_callers)
|
|
||||||
if (caller.kind == SymbolKind::Func && caller.id != Id<void>(root)) {
|
|
||||||
// Do not show calls to the base function coming from this function.
|
|
||||||
handle_caller(caller, Out_CqueryCallTree::CallType::Base);
|
|
||||||
}
|
|
||||||
for (Use caller : derived_callers)
|
|
||||||
handle_caller(caller, Out_CqueryCallTree::CallType::Derived);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct CqueryCallTreeInitialHandler
|
|
||||||
: BaseMessageHandler<Ipc_CqueryCallTreeInitial> {
|
|
||||||
void Run(Ipc_CqueryCallTreeInitial* request) override {
|
|
||||||
QueryFile* file;
|
|
||||||
if (!FindFileOrFail(db, project, request->id,
|
|
||||||
request->params.textDocument.uri.GetPath(), &file)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
WorkingFile* working_file =
|
|
||||||
working_files->GetFileByFilename(file->def->path);
|
|
||||||
|
|
||||||
Out_CqueryCallTree out;
|
|
||||||
out.id = request->id;
|
|
||||||
|
|
||||||
for (SymbolRef sym :
|
|
||||||
FindSymbolsAtLocation(working_file, file, request->params.position)) {
|
|
||||||
if (sym.kind == SymbolKind::Func) {
|
|
||||||
out.result =
|
|
||||||
BuildInitialCallTree(db, working_files, QueryFuncId(sym.id));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QueueManager::WriteStdout(IpcId::CqueryCallTreeInitial, out);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
REGISTER_MESSAGE_HANDLER(CqueryCallTreeInitialHandler);
|
|
||||||
|
|
||||||
struct CqueryCallTreeExpandHandler
|
|
||||||
: BaseMessageHandler<Ipc_CqueryCallTreeExpand> {
|
|
||||||
void Run(Ipc_CqueryCallTreeExpand* request) override {
|
|
||||||
Out_CqueryCallTree out;
|
|
||||||
out.id = request->id;
|
|
||||||
|
|
||||||
// FIXME
|
|
||||||
Maybe<QueryFuncId> func_id =
|
|
||||||
db->GetQueryFuncIdFromUsr(std::stoull(request->params.usr));
|
|
||||||
if (func_id)
|
|
||||||
out.result = BuildExpandCallTree(db, working_files, *func_id);
|
|
||||||
|
|
||||||
QueueManager::WriteStdout(IpcId::CqueryCallTreeExpand, out);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
REGISTER_MESSAGE_HANDLER(CqueryCallTreeExpandHandler);
|
|
||||||
} // namespace
|
|
@ -28,9 +28,9 @@ struct CqueryCallersHandler : BaseMessageHandler<Ipc_CqueryCallers> {
|
|||||||
if (sym.kind == SymbolKind::Func) {
|
if (sym.kind == SymbolKind::Func) {
|
||||||
QueryFunc& func = db->GetFunc(sym);
|
QueryFunc& func = db->GetFunc(sym);
|
||||||
std::vector<Use> uses = func.uses;
|
std::vector<Use> uses = func.uses;
|
||||||
for (Use func_ref : GetCallersForAllBaseFunctions(db, func))
|
for (Use func_ref : GetUsesForAllBases(db, func))
|
||||||
uses.push_back(func_ref);
|
uses.push_back(func_ref);
|
||||||
for (Use func_ref : GetCallersForAllDerivedFunctions(db, func))
|
for (Use func_ref : GetUsesForAllDerived(db, func))
|
||||||
uses.push_back(func_ref);
|
uses.push_back(func_ref);
|
||||||
out.result =
|
out.result =
|
||||||
GetLsLocationExs(db, working_files, uses, config->xref.container,
|
GetLsLocationExs(db, working_files, uses, config->xref.container,
|
||||||
|
@ -62,6 +62,41 @@ MAKE_REFLECT_STRUCT(Out_CqueryMemberHierarchy::Entry,
|
|||||||
children);
|
children);
|
||||||
MAKE_REFLECT_STRUCT(Out_CqueryMemberHierarchy, jsonrpc, id, result);
|
MAKE_REFLECT_STRUCT(Out_CqueryMemberHierarchy, jsonrpc, id, result);
|
||||||
|
|
||||||
|
bool Expand(MessageHandler* m,
|
||||||
|
Out_CqueryMemberHierarchy::Entry* entry,
|
||||||
|
bool detailed_name,
|
||||||
|
int levels);
|
||||||
|
|
||||||
|
// Add a field to |entry| which is a Func/Type.
|
||||||
|
void DoField(MessageHandler* m,
|
||||||
|
Out_CqueryMemberHierarchy::Entry* entry,
|
||||||
|
const QueryVar& var,
|
||||||
|
bool detailed_name,
|
||||||
|
int levels) {
|
||||||
|
const QueryVar::Def* def1 = var.AnyDef();
|
||||||
|
if (!def1)
|
||||||
|
return;
|
||||||
|
Out_CqueryMemberHierarchy::Entry entry1;
|
||||||
|
if (detailed_name)
|
||||||
|
entry1.fieldName = def1->DetailedName(false);
|
||||||
|
else
|
||||||
|
entry1.fieldName = std::string(def1->ShortName());
|
||||||
|
if (def1->spell) {
|
||||||
|
if (optional<lsLocation> loc =
|
||||||
|
GetLsLocation(m->db, m->working_files, *def1->spell))
|
||||||
|
entry1.location = *loc;
|
||||||
|
}
|
||||||
|
if (def1->type) {
|
||||||
|
entry1.id = *def1->type;
|
||||||
|
if (Expand(m, &entry1, detailed_name, levels))
|
||||||
|
entry->children.push_back(std::move(entry1));
|
||||||
|
} else {
|
||||||
|
entry1.id = QueryTypeId();
|
||||||
|
entry->children.push_back(std::move(entry1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Expand a type node by adding members recursively to it.
|
||||||
bool Expand(MessageHandler* m,
|
bool Expand(MessageHandler* m,
|
||||||
Out_CqueryMemberHierarchy::Entry* entry,
|
Out_CqueryMemberHierarchy::Entry* entry,
|
||||||
bool detailed_name,
|
bool detailed_name,
|
||||||
@ -98,15 +133,20 @@ bool Expand(MessageHandler* m,
|
|||||||
const QueryType::Def* def1 = m->db->types[def->alias_of->id].AnyDef();
|
const QueryType::Def* def1 = m->db->types[def->alias_of->id].AnyDef();
|
||||||
Out_CqueryMemberHierarchy::Entry entry1;
|
Out_CqueryMemberHierarchy::Entry entry1;
|
||||||
entry1.id = *def->alias_of;
|
entry1.id = *def->alias_of;
|
||||||
if (def1) {
|
if (def1 && def1->spell) {
|
||||||
if (def1->spell) {
|
// The declaration of target type.
|
||||||
if (optional<lsLocation> loc =
|
if (optional<lsLocation> 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) {
|
||||||
|
// Builtin types have no declaration but the typedef declaration
|
||||||
|
// itself is useful.
|
||||||
|
if (optional<lsLocation> loc =
|
||||||
|
GetLsLocation(m->db, m->working_files, *def->spell))
|
||||||
|
entry1.location = *loc;
|
||||||
}
|
}
|
||||||
if (detailed_name)
|
if (def1 && detailed_name)
|
||||||
entry1.fieldName = def1->detailed_name;
|
entry1.fieldName = def1->detailed_name;
|
||||||
}
|
|
||||||
if (Expand(m, &entry1, detailed_name, levels - 1)) {
|
if (Expand(m, &entry1, detailed_name, levels - 1)) {
|
||||||
// For builtin types |name| is set.
|
// For builtin types |name| is set.
|
||||||
if (detailed_name && entry1.fieldName.empty())
|
if (detailed_name && entry1.fieldName.empty())
|
||||||
@ -115,27 +155,7 @@ bool Expand(MessageHandler* m,
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
EachDefinedEntity(m->db->vars, def->vars, [&](QueryVar& var) {
|
EachDefinedEntity(m->db->vars, def->vars, [&](QueryVar& var) {
|
||||||
const QueryVar::Def* def1 = var.AnyDef();
|
DoField(m, entry, var, detailed_name, levels - 1);
|
||||||
if (!def1)
|
|
||||||
return;
|
|
||||||
Out_CqueryMemberHierarchy::Entry entry1;
|
|
||||||
if (detailed_name)
|
|
||||||
entry1.fieldName = def1->DetailedName(false);
|
|
||||||
else
|
|
||||||
entry1.fieldName = std::string(def1->ShortName());
|
|
||||||
if (def1->spell) {
|
|
||||||
if (optional<lsLocation> loc =
|
|
||||||
GetLsLocation(m->db, m->working_files, *def1->spell))
|
|
||||||
entry1.location = *loc;
|
|
||||||
}
|
|
||||||
if (def1->type) {
|
|
||||||
entry1.id = *def1->type;
|
|
||||||
if (Expand(m, &entry1, detailed_name, levels - 1))
|
|
||||||
entry->children.push_back(std::move(entry1));
|
|
||||||
} else {
|
|
||||||
entry1.id = QueryTypeId();
|
|
||||||
entry->children.push_back(std::move(entry1));
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -148,6 +168,30 @@ bool Expand(MessageHandler* m,
|
|||||||
|
|
||||||
struct CqueryMemberHierarchyInitialHandler
|
struct CqueryMemberHierarchyInitialHandler
|
||||||
: BaseMessageHandler<Ipc_CqueryMemberHierarchyInitial> {
|
: BaseMessageHandler<Ipc_CqueryMemberHierarchyInitial> {
|
||||||
|
optional<Out_CqueryMemberHierarchy::Entry> BuildInitial(QueryFuncId root_id,
|
||||||
|
bool detailed_name,
|
||||||
|
int levels) {
|
||||||
|
const auto* def = db->funcs[root_id.id].AnyDef();
|
||||||
|
if (!def)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
Out_CqueryMemberHierarchy::Entry entry;
|
||||||
|
// Not type, |id| is invalid.
|
||||||
|
if (detailed_name)
|
||||||
|
entry.name = def->DetailedName(false);
|
||||||
|
else
|
||||||
|
entry.name = std::string(def->ShortName());
|
||||||
|
if (def->spell) {
|
||||||
|
if (optional<lsLocation> loc =
|
||||||
|
GetLsLocation(db, working_files, *def->spell))
|
||||||
|
entry.location = *loc;
|
||||||
|
}
|
||||||
|
EachDefinedEntity(db->vars, def->vars, [&](QueryVar& var) {
|
||||||
|
DoField(this, &entry, var, detailed_name, levels - 1);
|
||||||
|
});
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
|
||||||
optional<Out_CqueryMemberHierarchy::Entry> BuildInitial(QueryTypeId root_id,
|
optional<Out_CqueryMemberHierarchy::Entry> BuildInitial(QueryTypeId root_id,
|
||||||
bool detailed_name,
|
bool detailed_name,
|
||||||
int levels) {
|
int levels) {
|
||||||
@ -180,18 +224,26 @@ struct CqueryMemberHierarchyInitialHandler
|
|||||||
|
|
||||||
for (SymbolRef sym :
|
for (SymbolRef sym :
|
||||||
FindSymbolsAtLocation(working_file, file, params.position)) {
|
FindSymbolsAtLocation(working_file, file, params.position)) {
|
||||||
if (sym.kind == SymbolKind::Type) {
|
switch (sym.kind) {
|
||||||
|
case SymbolKind::Func:
|
||||||
|
out.result = BuildInitial(QueryFuncId(sym.id), params.detailedName,
|
||||||
|
params.levels);
|
||||||
|
break;
|
||||||
|
case SymbolKind::Type:
|
||||||
out.result = BuildInitial(QueryTypeId(sym.id), params.detailedName,
|
out.result = BuildInitial(QueryTypeId(sym.id), params.detailedName,
|
||||||
params.levels);
|
params.levels);
|
||||||
break;
|
break;
|
||||||
}
|
case SymbolKind::Var: {
|
||||||
if (sym.kind == 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(QueryTypeId(*def->type),
|
out.result = BuildInitial(QueryTypeId(*def->type),
|
||||||
params.detailedName, params.levels);
|
params.detailedName, params.levels);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
default:
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
QueueManager::WriteStdout(IpcId::CqueryMemberHierarchyInitial, out);
|
QueueManager::WriteStdout(IpcId::CqueryMemberHierarchyInitial, out);
|
||||||
|
@ -184,10 +184,8 @@ struct TextDocumentCodeLensHandler
|
|||||||
return *def;
|
return *def;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::vector<Use> base_callers =
|
std::vector<Use> base_callers = GetUsesForAllBases(db, func);
|
||||||
GetCallersForAllBaseFunctions(db, func);
|
std::vector<Use> derived_callers = GetUsesForAllDerived(db, func);
|
||||||
std::vector<Use> derived_callers =
|
|
||||||
GetCallersForAllDerivedFunctions(db, func);
|
|
||||||
if (base_callers.empty() && derived_callers.empty()) {
|
if (base_callers.empty() && derived_callers.empty()) {
|
||||||
Use loc = try_ensure_spelling(use);
|
Use loc = try_ensure_spelling(use);
|
||||||
AddCodeLens("call", "calls", &common,
|
AddCodeLens("call", "calls", &common,
|
||||||
|
@ -5,8 +5,6 @@
|
|||||||
#include <loguru.hpp>
|
#include <loguru.hpp>
|
||||||
|
|
||||||
#include <climits>
|
#include <climits>
|
||||||
#include <queue>
|
|
||||||
#include <stack>
|
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
@ -116,78 +114,46 @@ std::vector<Use> GetNonDefDeclarations(QueryDatabase* db,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HasCallersOnSelfOrBaseOrDerived(QueryDatabase* db, QueryFunc& root) {
|
std::vector<Use> GetUsesForAllBases(QueryDatabase* db, QueryFunc& root) {
|
||||||
|
std::vector<Use> ret;
|
||||||
|
std::vector<QueryFunc*> stack{&root};
|
||||||
std::unordered_set<Usr> seen;
|
std::unordered_set<Usr> seen;
|
||||||
std::stack<QueryFunc*> stack;
|
|
||||||
seen.insert(root.usr);
|
seen.insert(root.usr);
|
||||||
stack.push(&root);
|
|
||||||
while (!stack.empty()) {
|
while (!stack.empty()) {
|
||||||
QueryFunc& func = *stack.top();
|
QueryFunc& func = *stack.back();
|
||||||
stack.pop();
|
stack.pop_back();
|
||||||
if (!func.uses.empty())
|
|
||||||
return true;
|
|
||||||
if (auto* def = func.AnyDef()) {
|
if (auto* def = func.AnyDef()) {
|
||||||
EachDefinedEntity(db->funcs, def->bases, [&](QueryFunc& func1) {
|
EachDefinedEntity(db->funcs, def->bases, [&](QueryFunc& func1) {
|
||||||
if (!seen.count(func1.usr)) {
|
if (!seen.count(func1.usr)) {
|
||||||
seen.insert(func1.usr);
|
seen.insert(func1.usr);
|
||||||
stack.push(&func1);
|
stack.push_back(&func1);
|
||||||
|
AddRange(&ret, func1.uses);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Use> GetUsesForAllDerived(QueryDatabase* db, QueryFunc& root) {
|
||||||
|
std::vector<Use> ret;
|
||||||
|
std::vector<QueryFunc*> stack{&root};
|
||||||
|
std::unordered_set<Usr> seen;
|
||||||
|
seen.insert(root.usr);
|
||||||
|
while (!stack.empty()) {
|
||||||
|
QueryFunc& func = *stack.back();
|
||||||
|
stack.pop_back();
|
||||||
EachDefinedEntity(db->funcs, func.derived, [&](QueryFunc& func1) {
|
EachDefinedEntity(db->funcs, func.derived, [&](QueryFunc& func1) {
|
||||||
if (!seen.count(func1.usr)) {
|
if (!seen.count(func1.usr)) {
|
||||||
seen.insert(func1.usr);
|
seen.insert(func1.usr);
|
||||||
stack.push(&func1);
|
stack.push_back(&func1);
|
||||||
}
|
AddRange(&ret, func1.uses);
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<Use> GetCallersForAllBaseFunctions(QueryDatabase* db,
|
|
||||||
QueryFunc& root) {
|
|
||||||
std::vector<Use> callers;
|
|
||||||
std::unordered_set<Usr> seen;
|
|
||||||
std::stack<QueryFunc*> stack;
|
|
||||||
seen.insert(root.usr);
|
|
||||||
stack.push(&root);
|
|
||||||
while (!stack.empty()) {
|
|
||||||
QueryFunc& func = *stack.top();
|
|
||||||
stack.pop();
|
|
||||||
AddRange(&callers, func.uses);
|
|
||||||
if (auto* def = func.AnyDef()) {
|
|
||||||
EachDefinedEntity(db->funcs, def->bases, [&](QueryFunc& func1) {
|
|
||||||
if (!seen.count(func1.usr)) {
|
|
||||||
seen.insert(func1.usr);
|
|
||||||
stack.push(&func1);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return callers;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<Use> GetCallersForAllDerivedFunctions(QueryDatabase* db,
|
|
||||||
QueryFunc& root) {
|
|
||||||
std::vector<Use> callers;
|
|
||||||
std::unordered_set<Usr> seen;
|
|
||||||
std::stack<QueryFunc*> stack;
|
|
||||||
seen.insert(root.usr);
|
|
||||||
stack.push(&root);
|
|
||||||
while (!stack.empty()) {
|
|
||||||
QueryFunc& func = *stack.top();
|
|
||||||
stack.pop();
|
|
||||||
AddRange(&callers, func.uses);
|
|
||||||
EachDefinedEntity(db->funcs, func.derived, [&](QueryFunc& func1) {
|
|
||||||
if (!seen.count(func1.usr)) {
|
|
||||||
seen.insert(func1.usr);
|
|
||||||
stack.push(&func1);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return callers;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
optional<lsPosition> GetLsPosition(WorkingFile* working_file,
|
optional<lsPosition> GetLsPosition(WorkingFile* working_file,
|
||||||
|
@ -18,11 +18,8 @@ std::vector<Use> GetDeclarations(QueryDatabase* db, const std::vector<QueryVarId
|
|||||||
// Get non-defining declarations.
|
// Get non-defining declarations.
|
||||||
std::vector<Use> GetNonDefDeclarations(QueryDatabase* db, SymbolIdx sym);
|
std::vector<Use> GetNonDefDeclarations(QueryDatabase* db, SymbolIdx sym);
|
||||||
|
|
||||||
bool HasCallersOnSelfOrBaseOrDerived(QueryDatabase* db, QueryFunc& root);
|
std::vector<Use> GetUsesForAllBases(QueryDatabase* db, QueryFunc& root);
|
||||||
std::vector<Use> GetCallersForAllBaseFunctions(QueryDatabase* db,
|
std::vector<Use> GetUsesForAllDerived(QueryDatabase* db, QueryFunc& root);
|
||||||
QueryFunc& root);
|
|
||||||
std::vector<Use> GetCallersForAllDerivedFunctions(QueryDatabase* db,
|
|
||||||
QueryFunc& root);
|
|
||||||
optional<lsPosition> GetLsPosition(WorkingFile* working_file,
|
optional<lsPosition> GetLsPosition(WorkingFile* working_file,
|
||||||
const Position& position);
|
const Position& position);
|
||||||
optional<lsRange> GetLsRange(WorkingFile* working_file, const Range& location);
|
optional<lsRange> GetLsRange(WorkingFile* working_file, const Range& location);
|
||||||
|
Loading…
Reference in New Issue
Block a user