diff --git a/src/indexer.cc b/src/indexer.cc index 61c78342..19eeacc6 100644 --- a/src/indexer.cc +++ b/src/indexer.cc @@ -39,6 +39,23 @@ void AddFuncUse(std::vector* result, Use ref) { result->push_back(ref); } +// TODO How to check if a reference to type is a declaration? +// This currently also includes constructors/destructors. +// It seems declarations in functions are not indexed. +bool IsDeclContext(CXIdxEntityKind kind) { + switch (kind) { + case CXIdxEntity_CXXClass: + case CXIdxEntity_CXXNamespace: + case CXIdxEntity_ObjCCategory: + case CXIdxEntity_ObjCClass: + case CXIdxEntity_ObjCProtocol: + case CXIdxEntity_Struct: + return true; + default: + return false; + } +} + bool IsScopeSemanticContainer(CXCursorKind kind) { switch (kind) { case CXCursor_Namespace: @@ -1820,7 +1837,8 @@ void OnIndexDeclaration(CXClientData client_data, const CXIdxDeclInfo* decl) { } } } else - UniqueAddUse(db, type->uses, spell, fromContainer(decl->lexicalContainer)); + UniqueAddUse(db, type->declarations, spell, + fromContainer(decl->lexicalContainer)); switch (decl->entityInfo->templateKind) { default: @@ -2152,7 +2170,10 @@ void OnIndexReference(CXClientData client_data, const CXIdxEntityRefInfo* ref) { // Foo f; // } // - UniqueAddUseSpell(db, ref_type->uses, ref->cursor); + if (!ref->parentEntity || IsDeclContext(ref->parentEntity->kind)) + UniqueAddUseSpell(db, ref_type->declarations, ref->cursor); + else + UniqueAddUseSpell(db, ref_type->uses, ref->cursor); break; } diff --git a/src/indexer.h b/src/indexer.h index 7427ad65..a0fc4ed9 100644 --- a/src/indexer.h +++ b/src/indexer.h @@ -231,6 +231,7 @@ struct IndexType { IndexTypeId id; Def def; + std::vector declarations; // Immediate derived types. std::vector derived; diff --git a/src/messages/text_document_definition.cc b/src/messages/text_document_definition.cc index eafedccd..38f6b46a 100644 --- a/src/messages/text_document_definition.cc +++ b/src/messages/text_document_definition.cc @@ -37,11 +37,15 @@ std::vector GetGotoDefinitionTargets(QueryDatabase* db, case SymbolKind::Var: { std::vector ret = GetDeclarationsOfSymbolForGotoDefinition(db, sym); - QueryVar::Def* def = db->GetVar(sym).AnyDef(); - if (def && def->type) { - std::vector types = GetDeclarationsOfSymbolForGotoDefinition( - db, SymbolIdx{*def->type, SymbolKind::Type}); - ret.insert(ret.end(), types.begin(), types.end()); + if (ret.empty()) { + for (auto& def : db->GetVar(sym).def) + if (def.type) { + if (Maybe use = GetDefinitionSpellingOfSymbol( + db, SymbolIdx{*def.type, SymbolKind::Type})) { + ret.push_back(*use); + break; + } + } } return ret; } diff --git a/src/query.cc b/src/query.cc index 3167bd19..42753ce9 100644 --- a/src/query.cc +++ b/src/query.cc @@ -247,6 +247,10 @@ QueryFile::DefUpdate BuildFileDefUpdate(const IdMap& id_map, const IndexFile& in add_all_symbols(*type.def.spell, id, SymbolKind::Type); if (type.def.extent) add_outline(*type.def.extent, id, SymbolKind::Type); + for (Use decl : type.declarations) { + add_all_symbols(decl, id, SymbolKind::Type); + add_outline(decl, id, SymbolKind::Type); + } for (Use use : type.uses) add_all_symbols(use, id, SymbolKind::Type); } @@ -523,6 +527,10 @@ IndexUpdate::IndexUpdate(const IdMap& previous_id_map, [this, &previous_id_map](IndexType* type) { if (type->def.spell) types_removed.push_back(type->usr); + if (!type->declarations.empty()) + types_declarations.push_back(QueryType::DeclarationsUpdate( + previous_id_map.ToQuery(type->id), {}, + previous_id_map.ToQuery(type->declarations))); if (!type->derived.empty()) types_derived.push_back(QueryType::DerivedUpdate( previous_id_map.ToQuery(type->id), {}, @@ -543,6 +551,10 @@ IndexUpdate::IndexUpdate(const IdMap& previous_id_map, if (def_update) types_def_update.push_back( QueryType::DefUpdate(type->usr, std::move(*def_update))); + if (!type->declarations.empty()) + types_declarations.push_back(QueryType::DeclarationsUpdate( + current_id_map.ToQuery(type->id), + current_id_map.ToQuery(type->declarations))); if (!type->derived.empty()) types_derived.push_back( QueryType::DerivedUpdate(current_id_map.ToQuery(type->id), @@ -570,6 +582,7 @@ IndexUpdate::IndexUpdate(const IdMap& previous_id_map, current->usr, std::move(*current_remapped_def))); } + PROCESS_UPDATE_DIFF(QueryTypeId, types_declarations, declarations, Use); PROCESS_UPDATE_DIFF(QueryTypeId, types_derived, derived, QueryTypeId); PROCESS_UPDATE_DIFF(QueryTypeId, types_instances, instances, QueryVarId); @@ -820,6 +833,7 @@ void QueryDatabase::ApplyIndexUpdate(IndexUpdate* update) { RemoveUsrs(SymbolKind::Type, update->types_removed); ImportOrUpdate(std::move(update->types_def_update)); + HANDLE_MERGEABLE(types_declarations, declarations, types); HANDLE_MERGEABLE(types_derived, derived, types); HANDLE_MERGEABLE(types_instances, instances, types); HANDLE_MERGEABLE(types_uses, uses, types); diff --git a/src/query.h b/src/query.h index f9819bb8..5d72e92d 100644 --- a/src/query.h +++ b/src/query.h @@ -136,6 +136,7 @@ MAKE_REFLECT_STRUCT(QueryFile::Def, struct QueryType { using Def = TypeDefDefinitionData; using DefUpdate = WithUsr; + using DeclarationsUpdate = MergeableUpdate; using DerivedUpdate = MergeableUpdate; using InstancesUpdate = MergeableUpdate; using UsesUpdate = MergeableUpdate; @@ -143,6 +144,7 @@ struct QueryType { Usr usr; Maybe> symbol_idx; std::forward_list def; + std::vector declarations; std::vector derived; std::vector instances; std::vector uses; @@ -228,6 +230,7 @@ struct IndexUpdate { // Type updates. std::vector types_removed; std::vector types_def_update; + std::vector types_declarations; std::vector types_derived; std::vector types_instances; std::vector types_uses; diff --git a/src/query_utils.cc b/src/query_utils.cc index 592a4ec3..8c0c2c0d 100644 --- a/src/query_utils.cc +++ b/src/query_utils.cc @@ -16,6 +16,26 @@ int ComputeRangeSize(const Range& range) { return range.end.column - range.start.column; } +template +std::vector ToUsesHelper(std::vector& entities, + const std::vector>& ids) { + std::vector ret; + ret.reserve(ids.size()); + for (auto id : ids) { + Q& entity = entities[id.id]; + bool has_def = false; + for (auto& def : entity.def) + if (def.spell) { + ret.push_back(*def.spell); + has_def = true; + break; + } + if (!has_def && entity.declarations.size()) + ret.push_back(entity.declarations[0]); + } + return ret; +} + } // namespace Maybe GetDefinitionSpellingOfSymbol(QueryDatabase* db, @@ -112,54 +132,16 @@ Maybe GetDeclarationFileForSymbol(QueryDatabase* db, std::vector ToUses(QueryDatabase* db, const std::vector& ids) { - std::vector ret; - ret.reserve(ids.size()); - for (auto id : ids) { - QueryFunc& func = db->funcs[id.id]; - bool has_def = false; - for (auto& def : func.def) - if (def.spell) { - ret.push_back(*def.spell); - has_def = true; - break; - } - if (!has_def && func.declarations.size()) - ret.push_back(func.declarations[0]); - } - return ret; + return ToUsesHelper(db->funcs, ids); } std::vector ToUses(QueryDatabase* db, const std::vector& ids) { - std::vector ret; - ret.reserve(ids.size()); - for (auto id : ids) { - QueryType& type = db->types[id.id]; - for (auto& def : type.def) - if (def.spell) { - ret.push_back(*def.spell); - break; - } - } - return ret; + return ToUsesHelper(db->types, ids); } std::vector ToUses(QueryDatabase* db, const std::vector& ids) { - std::vector ret; - ret.reserve(ids.size()); - for (auto id : ids) { - QueryVar& var = db->vars[id.id]; - bool has_def = false; - for (auto& def : var.def) - if (def.spell) { - ret.push_back(*def.spell); - has_def = true; - break; - } - if (!has_def && var.declarations.size()) - ret.push_back(var.declarations[0]); - } - return ret; + return ToUsesHelper(db->vars, ids); } std::vector GetUsesOfSymbol(QueryDatabase* db, @@ -173,6 +155,7 @@ std::vector GetUsesOfSymbol(QueryDatabase* db, for (auto& def : type.def) if (def.spell) ret.push_back(*def.spell); + AddRange(&ret, type.declarations); } return ret; } @@ -210,27 +193,15 @@ std::vector GetDeclarationsOfSymbolForGotoDefinition( QueryDatabase* db, SymbolIdx sym) { switch (sym.kind) { - case SymbolKind::Type: { - // Returning the definition spelling of a type is a hack (and is why the - // function has the postfix `ForGotoDefintion`, but it lets the user - // jump to the start of a type if clicking goto-definition on the same - // type from within the type definition. - if (const auto* def = db->GetType(sym).AnyDef()) { - Maybe spell = def->spell; - if (spell) - return {*spell}; - } - break; - } case SymbolKind::Func: return db->GetFunc(sym).declarations; + case SymbolKind::Type: + return db->GetType(sym).declarations; case SymbolKind::Var: return db->GetVar(sym).declarations; default: - break; + return {}; } - - return {}; } bool HasCallersOnSelfOrBaseOrDerived(QueryDatabase* db, QueryFunc& root) { diff --git a/src/serializer.cc b/src/serializer.cc index 29f9324c..1f77c3c2 100644 --- a/src/serializer.cc +++ b/src/serializer.cc @@ -215,6 +215,7 @@ void Reflect(TVisitor& visitor, IndexType& value) { ReflectShortName(visitor, value.def); REFLECT_MEMBER2("kind", value.def.kind); ReflectHoverAndComments(visitor, value.def); + REFLECT_MEMBER2("declarations", value.declarations); REFLECT_MEMBER2("spell", value.def.spell); REFLECT_MEMBER2("extent", value.def.extent); REFLECT_MEMBER2("alias_of", value.def.alias_of);