From d47869ad0fd80347456727a2a0611126378bea7a Mon Sep 17 00:00:00 2001 From: Jacob Dufault Date: Wed, 24 May 2017 17:18:04 -0700 Subject: [PATCH] Do not remove querydb defined type/func/var if the final reference is removed from a file. We still remove the defined type/func/var if it was defined in that file, though. --- src/query.cc | 69 ++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 54 insertions(+), 15 deletions(-) diff --git a/src/query.cc b/src/query.cc index 3ac732e6..a06aac15 100644 --- a/src/query.cc +++ b/src/query.cc @@ -21,8 +21,6 @@ namespace { optional ToQuery(const IdMap& id_map, const IndexType::Def& type) { if (type.detailed_name.empty()) return nullopt; - if (!type.definition_extent) - return nullopt; QueryType::DefUpdate result(type.usr); result.short_name = type.short_name; @@ -40,8 +38,6 @@ optional ToQuery(const IdMap& id_map, const IndexType::Def optional ToQuery(const IdMap& id_map, const IndexFunc::Def& func) { if (func.detailed_name.empty()) return nullopt; - if (!func.definition_extent) - return nullopt; QueryFunc::DefUpdate result(func.usr); result.short_name = func.short_name; @@ -58,8 +54,6 @@ optional ToQuery(const IdMap& id_map, const IndexFunc::Def optional ToQuery(const IdMap& id_map, const IndexVar::Def& var) { if (var.detailed_name.empty()) return nullopt; - if (!var.definition_extent) - return nullopt; QueryVar::DefUpdate result(var.usr); result.short_name = var.short_name; @@ -463,10 +457,24 @@ IndexUpdate::IndexUpdate(const IdMap& previous_id_map, const IdMap& current_id_m // File files_def_update.push_back(BuildFileDef(current_id_map, current_file)); + // **NOTE** We only remove entries if they were defined in the previous index. + // For example, if a type is included from another file it will be defined + // simply so we can attribute the usage/reference to it. If the reference goes + // away we don't want to remove the type/func/var usage. + // Types CompareGroups(previous_file.types, current_file.types, - /*onRemoved:*/[this](IndexType* def) { - types_removed.push_back(def->def.usr); + /*onRemoved:*/[this, &previous_id_map](IndexType* type) { + if (type->def.definition_spelling) + types_removed.push_back(type->def.usr); + else { + if (!type->derived.empty()) + types_derived.push_back(QueryType::DerivedUpdate(previous_id_map.ToQuery(type->id), {}, previous_id_map.ToQuery(type->derived))); + if (!type->instances.empty()) + types_instances.push_back(QueryType::InstancesUpdate(previous_id_map.ToQuery(type->id), {}, previous_id_map.ToQuery(type->instances))); + if (!type->uses.empty()) + types_uses.push_back(QueryType::UsesUpdate(previous_id_map.ToQuery(type->id), {}, previous_id_map.ToQuery(type->uses))); + } }, /*onAdded:*/[this, ¤t_id_map](IndexType* type) { optional def_update = ToQuery(current_id_map, type->def); @@ -492,8 +500,18 @@ IndexUpdate::IndexUpdate(const IdMap& previous_id_map, const IdMap& current_id_m // Functions CompareGroups(previous_file.funcs, current_file.funcs, - /*onRemoved:*/[this](IndexFunc* def) { - funcs_removed.push_back(def->def.usr); + /*onRemoved:*/[this, &previous_id_map](IndexFunc* func) { + if (func->def.definition_spelling) { + funcs_removed.push_back(func->def.usr); + } + else { + if (!func->declarations.empty()) + funcs_declarations.push_back(QueryFunc::DeclarationsUpdate(previous_id_map.ToQuery(func->id), {}, previous_id_map.ToQuery(func->declarations))); + if (!func->derived.empty()) + funcs_derived.push_back(QueryFunc::DerivedUpdate(previous_id_map.ToQuery(func->id), {}, previous_id_map.ToQuery(func->derived))); + if (!func->callers.empty()) + funcs_callers.push_back(QueryFunc::CallersUpdate(previous_id_map.ToQuery(func->id), {}, previous_id_map.ToQuery(func->callers))); + } }, /*onAdded:*/[this, ¤t_id_map](IndexFunc* func) { optional def_update = ToQuery(current_id_map, func->def); @@ -519,8 +537,14 @@ IndexUpdate::IndexUpdate(const IdMap& previous_id_map, const IdMap& current_id_m // Variables CompareGroups(previous_file.vars, current_file.vars, - /*onRemoved:*/[this](IndexVar* def) { - vars_removed.push_back(def->def.usr); + /*onRemoved:*/[this, &previous_id_map](IndexVar* var) { + if (var->def.definition_spelling) { + vars_removed.push_back(var->def.usr); + } + else { + if (!var->uses.empty()) + vars_uses.push_back(QueryVar::UsesUpdate(previous_id_map.ToQuery(var->id), {}, previous_id_map.ToQuery(var->uses))); + } }, /*onAdded:*/[this, ¤t_id_map](IndexVar* var) { optional def_update = ToQuery(current_id_map, var->def); @@ -799,9 +823,9 @@ TEST_CASE("remove defs") { IndexFile previous("foo.cc"); IndexFile current("foo.cc"); - previous.ToTypeId("usr1"); - previous.ToFuncId("usr2"); - previous.ToVarId("usr3"); + previous.Resolve(previous.ToTypeId("usr1"))->def.definition_spelling = Range(Position(1, 0)); + previous.Resolve(previous.ToFuncId("usr2"))->def.definition_spelling = Range(Position(2, 0)); + previous.Resolve(previous.ToVarId("usr3"))->def.definition_spelling = Range(Position(3, 0)); IndexUpdate update = GetDelta(previous, current); @@ -810,6 +834,21 @@ TEST_CASE("remove defs") { REQUIRE(update.vars_removed == std::vector{ "usr3" }); } +TEST_CASE("do not remove ref-only defs") { + IndexFile previous("foo.cc"); + IndexFile current("foo.cc"); + + previous.Resolve(previous.ToTypeId("usr1"))->uses.push_back(Range(Position(1, 0))); + previous.Resolve(previous.ToFuncId("usr2"))->callers.push_back(IndexFuncRef(IndexFuncId(0), Range(Position(2, 0)), false /*is_implicit*/)); + previous.Resolve(previous.ToVarId("usr3"))->uses.push_back(Range(Position(3, 0))); + + IndexUpdate update = GetDelta(previous, current); + + REQUIRE(update.types_removed == std::vector{}); + REQUIRE(update.funcs_removed == std::vector{}); + REQUIRE(update.vars_removed == std::vector{}); +} + TEST_CASE("func callers") { IndexFile previous("foo.cc"); IndexFile current("foo.cc");