Simplify query_utils

This commit is contained in:
Fangrui Song 2018-02-20 17:50:48 -08:00
parent 65ba98c3f8
commit 909c2e247a
10 changed files with 106 additions and 228 deletions

View File

@ -685,7 +685,6 @@ const int IndexFile::kMinorVersion = 0;
IndexFile::IndexFile(const std::string& path, const std::string& contents) IndexFile::IndexFile(const std::string& path, const std::string& contents)
: id_cache(path), path(path), file_contents(contents) {} : id_cache(path), path(path), file_contents(contents) {}
// TODO: Optimize for const char*?
IndexTypeId IndexFile::ToTypeId(Usr usr) { IndexTypeId IndexFile::ToTypeId(Usr usr) {
auto it = id_cache.usr_to_type_id.find(usr); auto it = id_cache.usr_to_type_id.find(usr);
if (it != id_cache.usr_to_type_id.end()) if (it != id_cache.usr_to_type_id.end())
@ -1358,7 +1357,7 @@ ClangCursor::VisitResult TemplateVisitor(ClangCursor cursor,
sem_parent, Role::Definition); sem_parent, Role::Definition);
ref_type->def.extent = ref_type->def.extent =
SetUse(db, ref_cursor.get_extent(), lex_parent, Role::None); SetUse(db, ref_cursor.get_extent(), lex_parent, Role::None);
#if CINDEX_HAVE_PRETTY #if 0&&CINDEX_HAVE_PRETTY
ref_type->def.detailed_name = param->PrettyPrintCursor(ref_cursor.cx_cursor); ref_type->def.detailed_name = param->PrettyPrintCursor(ref_cursor.cx_cursor);
#else #else
ref_type->def.detailed_name = ref_cursor.get_spell_name(); ref_type->def.detailed_name = ref_cursor.get_spell_name();
@ -1392,7 +1391,8 @@ ClangCursor::VisitResult TemplateVisitor(ClangCursor cursor,
sem_parent, Role::Definition); sem_parent, Role::Definition);
ref_type->def.extent = ref_type->def.extent =
SetUse(db, ref_cursor.get_extent(), lex_parent, Role::None); SetUse(db, ref_cursor.get_extent(), lex_parent, Role::None);
#if CINDEX_HAVE_PRETTY #if 0&&CINDEX_HAVE_PRETTY
// template<class T> void f(T t){} // weird, the name is empty
ref_type->def.detailed_name = param->PrettyPrintCursor(ref_cursor.cx_cursor); ref_type->def.detailed_name = param->PrettyPrintCursor(ref_cursor.cx_cursor);
#else #else
ref_type->def.detailed_name = ref_cursor.get_spell_name(); ref_type->def.detailed_name = ref_cursor.get_spell_name();

View File

@ -61,7 +61,7 @@ ExpandNode(QueryDatabase* db, WorkingFiles* working_files, QueryTypeId root) {
return {}; return {};
std::vector<Out_CqueryMemberHierarchy::Entry> ret; std::vector<Out_CqueryMemberHierarchy::Entry> ret;
EachWithGen(db->vars, def->vars, [&](QueryVar& var) { EachDefinedEntity(db->vars, def->vars, [&](QueryVar& var) {
const QueryVar::Def* def1 = var.AnyDef(); const QueryVar::Def* def1 = var.AnyDef();
Out_CqueryMemberHierarchy::Entry entry; Out_CqueryMemberHierarchy::Entry entry;
entry.name = def1->ShortName(); entry.name = def1->ShortName();

View File

@ -35,7 +35,7 @@ BuildParentInheritanceHierarchyForType(QueryDatabase* db,
const QueryType::Def* def = root_type.AnyDef(); const QueryType::Def* def = root_type.AnyDef();
parent_entries.reserve(def->parents.size()); parent_entries.reserve(def->parents.size());
EachWithGen(db->types, def->parents, [&](QueryType& parent_type) { EachDefinedEntity(db->types, def->parents, [&](QueryType& parent_type) {
Out_CqueryTypeHierarchyTree::TypeEntry parent_entry; Out_CqueryTypeHierarchyTree::TypeEntry parent_entry;
const QueryType::Def* def1 = parent_type.AnyDef(); const QueryType::Def* def1 = parent_type.AnyDef();
parent_entry.name = def1->detailed_name.c_str(); parent_entry.name = def1->detailed_name.c_str();
@ -74,7 +74,7 @@ BuildInheritanceHierarchyForType(QueryDatabase* db,
entry.children.push_back(base); entry.children.push_back(base);
// Add derived. // Add derived.
EachWithGen(db->types, root_type.derived, [&](QueryType& type) { EachDefinedEntity(db->types, root_type.derived, [&](QueryType& type) {
auto derived_entry = auto derived_entry =
BuildInheritanceHierarchyForType(db, working_files, type); BuildInheritanceHierarchyForType(db, working_files, type);
if (derived_entry) if (derived_entry)

View File

@ -359,7 +359,7 @@ struct TextDocumentCodeActionHandler
// Get implementation file. // Get implementation file.
Out_TextDocumentCodeAction::Command command; Out_TextDocumentCodeAction::Command command;
EachWithGen(db->funcs, def->funcs, [&](QueryFunc& func_def) { EachDefinedEntity(db->funcs, def->funcs, [&](QueryFunc& func_def) {
const QueryFunc::Def* def1 = func_def.AnyDef(); const QueryFunc::Def* def1 = func_def.AnyDef();
if (def1->extent) if (def1->extent)
return; return;

View File

@ -81,7 +81,7 @@ struct TextDocumentDefinitionHandler
// - start at spelling but end at extent for better mouse tooltip // - start at spelling but end at extent for better mouse tooltip
// - goto declaration while in definition of recursive type // - goto declaration while in definition of recursive type
std::vector<Use> uses; std::vector<Use> uses;
EachDef(db, sym, [&](const auto& def) { EachEntityDef(db, sym, [&](const auto& def) {
if (def.spell && def.extent) { if (def.spell && def.extent) {
Use spell = *def.spell; Use spell = *def.spell;
// If on a definition, clear |uses| to find declarations below. // If on a definition, clear |uses| to find declarations below.

View File

@ -39,19 +39,13 @@ struct TextDocumentDocumentHighlightHandler
for (SymbolRef sym : for (SymbolRef sym :
FindSymbolsAtLocation(working_file, file, request->params.position)) { FindSymbolsAtLocation(working_file, file, request->params.position)) {
// Found symbol. Return references to highlight. // Found symbol. Return references to highlight.
std::vector<Use> uses = GetUsesOfSymbol(db, sym, true); EachUse(db, sym, true, [&](Use use) {
out.result.reserve(uses.size());
for (Use use : uses) {
if (use.file != file_id) if (use.file != file_id)
continue; return;
if (optional<lsLocation> ls_loc =
optional<lsLocation> ls_location = GetLsLocation(db, working_files, use)) {
GetLsLocation(db, working_files, use);
if (!ls_location)
continue;
lsDocumentHighlight highlight; lsDocumentHighlight highlight;
highlight.range = ls_location->range; highlight.range = ls_loc->range;
if (use.role & Role::Write) if (use.role & Role::Write)
highlight.kind = lsDocumentHighlightKind::Write; highlight.kind = lsDocumentHighlightKind::Write;
else if (use.role & Role::Read) else if (use.role & Role::Read)
@ -61,6 +55,7 @@ struct TextDocumentDocumentHighlightHandler
highlight.role = use.role; highlight.role = use.role;
out.result.push_back(highlight); out.result.push_back(highlight);
} }
});
break; break;
} }

View File

@ -54,16 +54,13 @@ struct TextDocumentReferencesHandler
for (const SymbolRef& sym : for (const SymbolRef& sym :
FindSymbolsAtLocation(working_file, file, request->params.position)) { FindSymbolsAtLocation(working_file, file, request->params.position)) {
// Found symbol. Return references. // Found symbol. Return references.
std::vector<Use> uses = GetUsesOfSymbol( EachUse(db, sym, request->params.context.includeDeclaration,
db, sym, request->params.context.includeDeclaration); [&](Use use) {
out.result.reserve(uses.size()); if (optional<lsLocationEx> ls_loc =
for (Use use : uses) { GetLsLocationEx(db, working_files, use,
optional<lsLocationEx> ls_loc = GetLsLocationEx( config->extension.referenceContainer))
db, working_files, use, config->extension.referenceContainer);
if (ls_loc) {
out.result.push_back(*ls_loc); out.result.push_back(*ls_loc);
} });
}
break; break;
} }

View File

@ -6,15 +6,14 @@ namespace {
lsWorkspaceEdit BuildWorkspaceEdit(QueryDatabase* db, lsWorkspaceEdit BuildWorkspaceEdit(QueryDatabase* db,
WorkingFiles* working_files, WorkingFiles* working_files,
const std::vector<Use>& uses, SymbolRef sym,
const std::string& new_text) { const std::string& new_text) {
std::unordered_map<QueryFileId, lsTextDocumentEdit> path_to_edit; std::unordered_map<QueryFileId, lsTextDocumentEdit> path_to_edit;
for (Use use : uses) { EachUse(db, sym, true, [&](Use use) {
optional<lsLocation> ls_location = optional<lsLocation> ls_location = GetLsLocation(db, working_files, use);
GetLsLocation(db, working_files, use);
if (!ls_location) if (!ls_location)
continue; return;
QueryFileId file_id = use.file; QueryFileId file_id = use.file;
if (path_to_edit.find(file_id) == path_to_edit.end()) { if (path_to_edit.find(file_id) == path_to_edit.end()) {
@ -22,16 +21,14 @@ lsWorkspaceEdit BuildWorkspaceEdit(QueryDatabase* db,
QueryFile& file = db->files[file_id.id]; QueryFile& file = db->files[file_id.id];
if (!file.def) if (!file.def)
continue; return;
const std::string& path = file.def->path; const std::string& path = file.def->path;
path_to_edit[file_id].textDocument.uri = path_to_edit[file_id].textDocument.uri = lsDocumentUri::FromPath(path);
lsDocumentUri::FromPath(path);
WorkingFile* working_file = working_files->GetFileByFilename(path); WorkingFile* working_file = working_files->GetFileByFilename(path);
if (working_file) if (working_file)
path_to_edit[file_id].textDocument.version = path_to_edit[file_id].textDocument.version = working_file->version;
working_file->version;
} }
lsTextEdit edit; lsTextEdit edit;
@ -42,7 +39,7 @@ lsWorkspaceEdit BuildWorkspaceEdit(QueryDatabase* db,
auto& edits = path_to_edit[file_id].edits; auto& edits = path_to_edit[file_id].edits;
if (std::find(edits.begin(), edits.end(), edit) == edits.end()) if (std::find(edits.begin(), edits.end(), edit) == edits.end())
edits.push_back(edit); edits.push_back(edit);
} });
lsWorkspaceEdit edit; lsWorkspaceEdit edit;
for (const auto& changes : path_to_edit) for (const auto& changes : path_to_edit)
@ -98,9 +95,8 @@ struct TextDocumentRenameHandler : BaseMessageHandler<Ipc_TextDocumentRename> {
for (SymbolRef sym : for (SymbolRef sym :
FindSymbolsAtLocation(working_file, file, request->params.position)) { FindSymbolsAtLocation(working_file, file, request->params.position)) {
// Found symbol. Return references to rename. // Found symbol. Return references to rename.
out.result = BuildWorkspaceEdit(db, working_files, out.result =
GetUsesOfSymbol(db, sym, true), BuildWorkspaceEdit(db, working_files, sym, request->params.newName);
request->params.newName);
break; break;
} }

View File

@ -6,6 +6,7 @@
#include <climits> #include <climits>
#include <queue> #include <queue>
#include <unordered_set>
namespace { namespace {
@ -40,63 +41,19 @@ std::vector<Use> ToUsesHelper(std::vector<Q>& entities,
Maybe<Use> GetDefinitionSpellingOfSymbol(QueryDatabase* db, Maybe<Use> GetDefinitionSpellingOfSymbol(QueryDatabase* db,
SymbolIdx sym) { SymbolIdx sym) {
switch (sym.kind) { Maybe<Use> ret;
case SymbolKind::File: EachEntityDef(db, sym, [&](const auto& def) { return !(ret = def.spell); });
break; return ret;
case SymbolKind::Func: {
for (auto& def : db->GetFunc(sym).def)
if (def.spell)
return def.spell;
break;
}
case SymbolKind::Type: {
for (auto& def : db->GetType(sym).def)
if (def.spell)
return def.spell;
break;
}
case SymbolKind::Var: {
for (auto& def : db->GetVar(sym).def)
if (def.spell)
return def.spell;
break;
}
case SymbolKind::Invalid:
assert(false && "unexpected");
break;
}
return nullopt;
} }
Maybe<Use> GetDefinitionExtentOfSymbol(QueryDatabase* db, SymbolIdx sym) { Maybe<Use> GetDefinitionExtentOfSymbol(QueryDatabase* db, SymbolIdx sym) {
switch (sym.kind) { // Used to jump to file.
case SymbolKind::File: if (sym.kind == SymbolKind::File)
return Use(Range(Position(0, 0), Position(0, 0)), sym.id, sym.kind, return Use(Range(Position(0, 0), Position(0, 0)), sym.id, sym.kind,
Role::None, QueryFileId(sym.id)); Role::None, QueryFileId(sym.id));
case SymbolKind::Func: { Maybe<Use> ret;
for (auto& def : db->GetFunc(sym).def) EachEntityDef(db, sym, [&](const auto& def) { return !(ret = def.extent); });
if (def.extent) return ret;
return def.extent;
break;
}
case SymbolKind::Type: {
for (auto& def : db->GetType(sym).def)
if (def.extent)
return def.extent;
break;
}
case SymbolKind::Var: {
for (auto& def : db->GetVar(sym).def)
if (def.extent)
return def.extent;
break;
}
case SymbolKind::Invalid: {
assert(false && "unexpected");
break;
}
}
return nullopt;
} }
Maybe<QueryFileId> GetDeclarationFileForSymbol(QueryDatabase* db, Maybe<QueryFileId> GetDeclarationFileForSymbol(QueryDatabase* db,
@ -144,51 +101,6 @@ std::vector<Use> ToUses(QueryDatabase* db, const std::vector<QueryVarId>& ids) {
return ToUsesHelper(db->vars, ids); return ToUsesHelper(db->vars, ids);
} }
std::vector<Use> GetUsesOfSymbol(QueryDatabase* db,
SymbolIdx sym,
bool include_decl) {
switch (sym.kind) {
case SymbolKind::Type: {
QueryType& type = db->GetType(sym);
std::vector<Use> ret = type.uses;
if (include_decl) {
for (auto& def : type.def)
if (def.spell)
ret.push_back(*def.spell);
AddRange(&ret, type.declarations);
}
return ret;
}
case SymbolKind::Func: {
QueryFunc& func = db->GetFunc(sym);
std::vector<Use> ret = func.uses;
if (include_decl) {
for (auto& def : func.def)
if (def.spell)
ret.push_back(*def.spell);
AddRange(&ret, func.declarations);
}
return ret;
}
case SymbolKind::Var: {
QueryVar& var = db->GetVar(sym);
std::vector<Use> ret = var.uses;
if (include_decl) {
for (auto& def : var.def)
if (def.spell)
ret.push_back(*def.spell);
ret.insert(ret.end(), var.declarations.begin(), var.declarations.end());
}
return ret;
}
case SymbolKind::File:
case SymbolKind::Invalid: {
assert(false && "unexpected");
return {};
}
}
}
std::vector<Use> GetDeclarationsOfSymbolForGotoDefinition( std::vector<Use> GetDeclarationsOfSymbolForGotoDefinition(
QueryDatabase* db, QueryDatabase* db,
SymbolIdx sym) { SymbolIdx sym) {
@ -205,41 +117,30 @@ std::vector<Use> GetDeclarationsOfSymbolForGotoDefinition(
} }
bool HasCallersOnSelfOrBaseOrDerived(QueryDatabase* db, QueryFunc& root) { bool HasCallersOnSelfOrBaseOrDerived(QueryDatabase* db, QueryFunc& root) {
// Check self. std::unordered_set<Usr> seen;
if (!root.uses.empty())
return true;
const QueryFunc::Def* def = root.AnyDef();
// Check for base calls.
std::queue<QueryFunc*> queue; std::queue<QueryFunc*> queue;
EachWithGen<QueryFunc>(db->funcs, def->base, [&](QueryFunc& func) { seen.insert(root.usr);
queue.push(&func); queue.push(&root);
});
while (!queue.empty()) { while (!queue.empty()) {
QueryFunc& func = *queue.front(); QueryFunc& func = *queue.front();
queue.pop(); queue.pop();
if (!func.uses.empty()) if (!func.uses.empty())
return true; return true;
if (def) if (auto* def = func.AnyDef()) {
EachWithGen<QueryFunc>(db->funcs, def->base, [&](QueryFunc& func1) { EachDefinedEntity(db->funcs, def->base, [&](QueryFunc& func1) {
if (!seen.count(func1.usr)) {
seen.insert(func1.usr);
queue.push(&func1); queue.push(&func1);
}
});
EachDefinedEntity(db->funcs, func.derived, [&](QueryFunc& func1) {
if (!seen.count(func1.usr)) {
seen.insert(func1.usr);
queue.push(&func1);
}
}); });
} }
// Check for derived calls.
EachWithGen<QueryFunc>(db->funcs, root.derived, [&](QueryFunc& func1) {
queue.push(&func1);
});
while (!queue.empty()) {
QueryFunc& func = *queue.front();
queue.pop();
if (!func.uses.empty())
return true;
EachWithGen<QueryFunc>(db->funcs, func.derived, [&](QueryFunc& func1) {
queue.push(&func1);
});
} }
return false; return false;
} }
@ -251,7 +152,7 @@ std::vector<Use> GetCallersForAllBaseFunctions(QueryDatabase* db,
return callers; return callers;
std::queue<QueryFunc*> queue; std::queue<QueryFunc*> queue;
EachWithGen<QueryFunc>(db->funcs, def->base, [&](QueryFunc& func1) { EachDefinedEntity(db->funcs, def->base, [&](QueryFunc& func1) {
queue.push(&func1); queue.push(&func1);
}); });
while (!queue.empty()) { while (!queue.empty()) {
@ -260,7 +161,7 @@ std::vector<Use> GetCallersForAllBaseFunctions(QueryDatabase* db,
AddRange(&callers, func.uses); AddRange(&callers, func.uses);
if (const QueryFunc::Def* def1 = func.AnyDef()) { if (const QueryFunc::Def* def1 = func.AnyDef()) {
EachWithGen<QueryFunc>(db->funcs, def1->base, [&](QueryFunc& func1) { EachDefinedEntity(db->funcs, def1->base, [&](QueryFunc& func1) {
queue.push(&func1); queue.push(&func1);
}); });
} }
@ -274,7 +175,7 @@ std::vector<Use> GetCallersForAllDerivedFunctions(QueryDatabase* db,
std::vector<Use> callers; std::vector<Use> callers;
std::queue<QueryFunc*> queue; std::queue<QueryFunc*> queue;
EachWithGen<QueryFunc>(db->funcs, root.derived, [&](QueryFunc& func) { EachDefinedEntity(db->funcs, root.derived, [&](QueryFunc& func) {
queue.push(&func); queue.push(&func);
}); });
@ -282,7 +183,7 @@ std::vector<Use> GetCallersForAllDerivedFunctions(QueryDatabase* db,
QueryFunc& func = *queue.front(); QueryFunc& func = *queue.front();
queue.pop(); queue.pop();
EachWithGen<QueryFunc>(db->funcs, func.derived, [&](QueryFunc& func1) { EachDefinedEntity(db->funcs, func.derived, [&](QueryFunc& func1) {
queue.push(&func1); queue.push(&func1);
}); });
AddRange(&callers, func.uses); AddRange(&callers, func.uses);
@ -377,28 +278,11 @@ optional<lsLocationEx> GetLsLocationEx(QueryDatabase* db,
return nullopt; return nullopt;
lsLocationEx ret; lsLocationEx ret;
ret.lsLocation::operator=(*ls_loc); ret.lsLocation::operator=(*ls_loc);
if (extension) if (extension) {
switch (use.kind) { EachEntityDef(db, use, [&](const auto& def) {
default: ret.containerName = std::string_view(def.detailed_name);
break; return false;
case SymbolKind::Func: { });
const QueryFunc::Def* def = db->GetFunc(use).AnyDef();
if (def)
ret.containerName = std::string_view(def->detailed_name);
break;
}
case SymbolKind::Type: {
const QueryType::Def* def = db->GetType(use).AnyDef();
if (def)
ret.containerName = std::string_view(def->detailed_name);
break;
}
case SymbolKind::Var: {
const QueryVar::Def* def = db->GetVar(use).AnyDef();
if (def)
ret.containerName = std::string_view(def->detailed_name);
break;
}
} }
return ret; return ret;
} }

View File

@ -18,9 +18,6 @@ std::vector<Use> ToUses(QueryDatabase* db,
std::vector<Use> ToUses(QueryDatabase* db, std::vector<Use> ToUses(QueryDatabase* db,
const std::vector<QueryVarId>& ids); const std::vector<QueryVarId>& ids);
std::vector<Use> GetUsesOfSymbol(QueryDatabase* db,
SymbolIdx sym,
bool include_decl);
std::vector<Use> GetDeclarationsOfSymbolForGotoDefinition( std::vector<Use> GetDeclarationsOfSymbolForGotoDefinition(
QueryDatabase* db, QueryDatabase* db,
SymbolIdx sym); SymbolIdx sym);
@ -64,43 +61,52 @@ void EmitDiagnostics(WorkingFiles* working_files,
std::vector<lsDiagnostic> diagnostics); std::vector<lsDiagnostic> diagnostics);
template <typename Fn> template <typename Fn>
void EachDef(QueryDatabase* db, SymbolIdx sym, Fn fn) { void WithEntity(QueryDatabase* db, SymbolIdx sym, Fn&& fn) {
switch (sym.kind) { switch (sym.kind) {
case SymbolKind::Invalid: case SymbolKind::Invalid:
case SymbolKind::File: case SymbolKind::File:
break; break;
case SymbolKind::Func: case SymbolKind::Func:
for (auto& def : db->GetFunc(sym).def) fn(db->GetFunc(sym));
if (!fn(def))
break;
break; break;
case SymbolKind::Type: case SymbolKind::Type:
for (auto& def : db->GetType(sym).def) fn(db->GetType(sym));
if (!fn(def))
break;
break; break;
case SymbolKind::Var: case SymbolKind::Var:
for (auto& def : db->GetVar(sym).def) fn(db->GetVar(sym));
break;
}
}
template <typename Fn>
void EachEntityDef(QueryDatabase* db, SymbolIdx sym, Fn&& fn) {
WithEntity(db, sym, [&](const auto& entity) {
for (auto& def : entity.def)
if (!fn(def)) if (!fn(def))
break; break;
break; });
} }
template <typename Fn>
void EachUse(QueryDatabase* db, SymbolIdx sym, bool include_decl, Fn&& fn) {
WithEntity(db, sym, [&](const auto& entity) {
for (Use use : entity.uses)
fn(use);
if (include_decl) {
for (auto& def : entity.def)
if (def.spell)
fn(*def.spell);
for (Use use : entity.declarations)
fn(use);
}
});
} }
template <typename Q, typename Fn> template <typename Q, typename Fn>
void EachWithGen(std::vector<Q>& collection, Id<Q> x, Fn fn) { void EachDefinedEntity(std::vector<Q>& collection, const std::vector<Id<Q>>& ids, Fn&& fn) {
Q& obj = collection[x.id];
// FIXME Deprecate optional<Def> def
// if (obj.gen == x.gen && obj.def)
if (obj.AnyDef())
fn(obj);
}
template <typename Q, typename Fn>
void EachWithGen(std::vector<Q>& collection, const std::vector<Id<Q>>& ids, Fn fn) {
for (Id<Q> x : ids) { for (Id<Q> x : ids) {
Q& obj = collection[x.id]; Q& obj = collection[x.id];
if (obj.AnyDef()) if (!obj.def.empty())
fn(obj); fn(obj);
} }
} }