From 599fee78d2a8fb51d4150ad05a60d7f145270938 Mon Sep 17 00:00:00 2001 From: hongjr03 Date: Fri, 26 Jun 2026 23:47:27 +0800 Subject: [PATCH 1/2] refactor: intern module definitions in HIR --- crates/hir/src/container.rs | 8 +- crates/hir/src/db.rs | 5 + crates/hir/src/def_id.rs | 369 +++++++++++++++++++++ crates/hir/src/file.rs | 2 +- crates/hir/src/lib.rs | 1 + crates/hir/src/semantics/pathres.rs | 67 ++++ crates/ide/src/code_lens.rs | 11 +- crates/ide/src/definitions.rs | 464 ++------------------------- crates/ide/src/document_highlight.rs | 8 +- crates/ide/src/goto_declaration.rs | 6 +- crates/ide/src/goto_definition.rs | 2 +- crates/ide/src/navigation_target.rs | 31 +- crates/ide/src/references.rs | 11 +- crates/ide/src/references/search.rs | 12 +- crates/ide/src/rename.rs | 89 ++--- crates/ide/src/render.rs | 90 +++--- crates/ide/src/semantic_index.rs | 45 +-- 17 files changed, 630 insertions(+), 591 deletions(-) create mode 100644 crates/hir/src/def_id.rs diff --git a/crates/hir/src/container.rs b/crates/hir/src/container.rs index e06a9a69..67d50589 100644 --- a/crates/hir/src/container.rs +++ b/crates/hir/src/container.rs @@ -30,7 +30,7 @@ use crate::{ }; define_enum_deriving_from! { - #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] + #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)] pub enum ContainerId { HirFileId(HirFileId), ModuleId(ModuleId), @@ -40,7 +40,7 @@ define_enum_deriving_from! { } } -#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] +#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)] pub struct InContainer { pub value: T, pub cont_id: ContainerId, @@ -60,7 +60,7 @@ impl InContainer { } } -#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] +#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)] pub struct InSubroutine { pub value: T, pub subroutine: SubroutineId, @@ -85,7 +85,7 @@ impl From> for InContainer { macro_rules! define_container_id { ($($name:ident[$id:ident : $ty:ty]),* $(,)?) => { $( - #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] + #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)] pub struct $name { pub value: T, pub $id: $ty, diff --git a/crates/hir/src/db.rs b/crates/hir/src/db.rs index ec07556b..fa2e6dc5 100644 --- a/crates/hir/src/db.rs +++ b/crates/hir/src/db.rs @@ -3,6 +3,7 @@ use triomphe::Arc; use crate::{ base_db::{salsa, source_db::SourceRootDb}, + def_id::{ModuleDef, ModuleDefId}, file::HirFileId, hir_def::{ block::{self, Block, BlockId, BlockLoc, BlockSourceMap}, @@ -45,6 +46,9 @@ pub trait InternDb: SourceRootDb { #[salsa::interned] fn intern_macro_file(&self, macro_file: MacroFileLoc) -> MacroFileId; + + #[salsa::interned] + fn intern_module_def(&self, module_def: ModuleDef) -> ModuleDefId; } impl_intern!(BuiltinDataTyId, BuiltinDataTy, intern_ty, lookup_intern_ty); @@ -58,6 +62,7 @@ impl_intern!( ); impl_intern!(MacroCallId, MacroCallLoc, intern_macro_call, lookup_intern_macro_call); impl_intern!(MacroFileId, MacroFileLoc, intern_macro_file, lookup_intern_macro_file); +impl_intern!(ModuleDefId, ModuleDef, intern_module_def, lookup_intern_module_def); #[salsa::query_group(HirDbStorage)] pub trait HirDb: InternDb { diff --git a/crates/hir/src/def_id.rs b/crates/hir/src/def_id.rs new file mode 100644 index 00000000..2d192d89 --- /dev/null +++ b/crates/hir/src/def_id.rs @@ -0,0 +1,369 @@ +use smallvec::SmallVec; +use smol_str::SmolStr; +use syntax::{ + ast::AstNode, + has_text_range::{HasTextRange, HasTextRangeIn}, +}; +use utils::{ + get::{Get, GetRef}, + impl_from, + line_index::TextRange, +}; + +use crate::{ + base_db::{intern::Lookup, salsa}, + container::{ContainerId, InContainer, InFile, InModule, InSubroutine}, + db::HirDb, + hir_def::{ + block::{BlockId, BlockLoc}, + expr::declarator::{DeclId, DeclaratorParent}, + file::{config::ConfigDeclId, library::LibraryDeclId, udp::UdpDeclId}, + module::{ + ModuleId, + generate::{GenerateBlockId, GenerateBlockLoc}, + instantiation::InstanceId, + port::NonAnsiPortId, + }, + stmt::StmtId, + subroutine::{SubroutineId, SubroutinePortId}, + typedef::TypedefId, + }, + source_map::{IsNamedSrc, IsSrc, ToAstNode}, +}; + +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum ModuleDefOrigin { + ModuleId(ModuleId), + Config(InFile), + Library(InFile), + Udp(InFile), + BlockId(BlockId), + GenerateBlockId(GenerateBlockId), + SubroutineId(SubroutineId), + SubroutinePort(InSubroutine), + + NonAnsiPort(InModule), + Decl(InContainer), + Typedef(InContainer), + Instance(InModule), + Stmt(InContainer), +} + +impl_from! { ModuleDefOrigin => + ModuleId, + Config(InFile), + Library(InFile), + Udp(InFile), + BlockId, + GenerateBlockId, + SubroutineId, + SubroutinePort(InSubroutine), + NonAnsiPort(InModule), + Decl(InContainer), + Typedef(InContainer), + Instance(InModule), + Stmt(InContainer), +} + +impl ModuleDefOrigin { + #[inline] + pub fn container_id(&self, db: &dyn HirDb) -> ContainerId { + match *self { + ModuleDefOrigin::ModuleId(InFile { file_id, .. }) => file_id.into(), + ModuleDefOrigin::Config(InFile { file_id, .. }) => file_id.into(), + ModuleDefOrigin::Library(InFile { file_id, .. }) => file_id.into(), + ModuleDefOrigin::Udp(InFile { file_id, .. }) => file_id.into(), + ModuleDefOrigin::BlockId(block_id) => block_id.lookup(db).cont_id, + ModuleDefOrigin::GenerateBlockId(generate_block_id) => { + generate_block_id.lookup(db).cont_id + } + ModuleDefOrigin::SubroutineId(subroutine_id) => subroutine_id.lookup(db).cont_id.into(), + ModuleDefOrigin::SubroutinePort(InSubroutine { subroutine, .. }) => { + ContainerId::SubroutineId(subroutine) + } + ModuleDefOrigin::NonAnsiPort(InModule { module_id, .. }) => module_id.into(), + ModuleDefOrigin::Decl(InContainer { cont_id, .. }) => cont_id, + ModuleDefOrigin::Typedef(InContainer { cont_id, .. }) => cont_id, + ModuleDefOrigin::Instance(InModule { module_id, .. }) => module_id.into(), + ModuleDefOrigin::Stmt(InContainer { cont_id, .. }) => cont_id, + } + } + + pub fn name(&self, db: &dyn HirDb) -> Option { + match *self { + ModuleDefOrigin::ModuleId(InFile { value, file_id }) => { + file_id.to_container(db).get(value).name.clone() + } + ModuleDefOrigin::Config(InFile { value, file_id }) => { + file_id.to_container(db).get(value).name.clone() + } + ModuleDefOrigin::Library(InFile { value, file_id }) => { + file_id.to_container(db).get(value).name.clone() + } + ModuleDefOrigin::Udp(InFile { value, file_id }) => { + file_id.to_container(db).get(value).name.clone() + } + ModuleDefOrigin::BlockId(block_id) => { + let BlockLoc { cont_id, src: InFile { value, file_id: _ } } = block_id.lookup(db); + let cont = cont_id.to_container(db); + value.hir(&cont, &cont_id.to_container_src_map(db))?.name.clone() + } + ModuleDefOrigin::GenerateBlockId(generate_block_id) => { + db.generate_block(generate_block_id).name.clone() + } + ModuleDefOrigin::SubroutineId(subroutine_id) => { + db.subroutine(subroutine_id).name.clone() + } + ModuleDefOrigin::SubroutinePort(InSubroutine { subroutine, value }) => { + db.subroutine(subroutine).ports.get(value.0 as usize)?.name.clone() + } + ModuleDefOrigin::NonAnsiPort(InModule { value, module_id }) => { + module_id.to_container(db).get(value).label.clone() + } + ModuleDefOrigin::Decl(InContainer { value, cont_id }) => { + cont_id.to_container(db).get(value).name.clone() + } + ModuleDefOrigin::Typedef(InContainer { value, cont_id }) => { + cont_id.to_container(db).get(value).name.clone() + } + ModuleDefOrigin::Instance(InModule { value, module_id }) => { + module_id.to_container(db).get(value).name.clone() + } + ModuleDefOrigin::Stmt(InContainer { value, cont_id }) => { + cont_id.to_container(db).get(value).label.clone() + } + } + } + + pub fn name_range(&self, db: &dyn HirDb) -> Option> { + match *self { + ModuleDefOrigin::ModuleId(InFile { value, file_id }) => { + let range = file_id.to_container_src_map(db).get(value)?.name_range()?; + Some(InFile::new(file_id, range)) + } + ModuleDefOrigin::Config(InFile { value, file_id }) => { + let range = file_id.to_container_src_map(db).get(value)?.name_range()?; + Some(InFile::new(file_id, range)) + } + ModuleDefOrigin::Library(InFile { value, file_id }) => { + let range = file_id.to_container_src_map(db).get(value)?.name_range()?; + Some(InFile::new(file_id, range)) + } + ModuleDefOrigin::Udp(InFile { value, file_id }) => { + let range = file_id.to_container_src_map(db).get(value)?.name_range()?; + Some(InFile::new(file_id, range)) + } + ModuleDefOrigin::BlockId(block_id) => { + let BlockLoc { src: InFile { value, file_id }, .. } = block_id.lookup(db); + let range = value.name_range()?; + Some(InFile::new(file_id, range)) + } + ModuleDefOrigin::GenerateBlockId(generate_block_id) => { + let GenerateBlockLoc { src: InFile { value, file_id }, .. } = + generate_block_id.lookup(db); + let range = value.name_range()?; + Some(InFile::new(file_id, range)) + } + ModuleDefOrigin::SubroutineId(subroutine_id) => { + let src = subroutine_id.lookup(db).src; + Some(InFile::new(src.file_id, src.value.name_or_full_range())) + } + ModuleDefOrigin::SubroutinePort(InSubroutine { subroutine, value }) => { + let src = subroutine.lookup(db).src; + let tree = db.parse(src.file_id); + let func = src.value.to_node(&tree)?; + let ports = func + .prototype() + .port_list() + .map(|ports| ports.ports().children().collect::>()) + .unwrap_or_default(); + let port = ports + .into_iter() + .nth(value.0 as usize) + .and_then(|port| port.as_function_port())?; + let declarator = port.declarator(); + let range = declarator.name()?.text_range_in(declarator.syntax())?; + Some(InFile::new(src.file_id, range)) + } + ModuleDefOrigin::NonAnsiPort(InModule { value, module_id }) => { + let range = module_id.to_container_src_map(db).get(value)?.name_range()?; + Some(InFile::new(module_id.file_id, range)) + } + ModuleDefOrigin::Decl(InContainer { value, cont_id }) => { + let range = cont_id.to_container_src_map(db).get(value)?.name_range()?; + Some(InFile::new(cont_id.file_id(db).into(), range)) + } + ModuleDefOrigin::Typedef(InContainer { value, cont_id }) => { + let range = cont_id.to_container_src_map(db).get(value)?.name_range()?; + Some(InFile::new(cont_id.file_id(db).into(), range)) + } + ModuleDefOrigin::Instance(InModule { value, module_id }) => { + let range = module_id.to_container_src_map(db).get(value)?.name_range()?; + Some(InFile::new(module_id.file_id, range)) + } + ModuleDefOrigin::Stmt(InContainer { value, cont_id }) => { + let range = cont_id.to_container_src_map(db).get(value)?.name_range()?; + Some(InFile::new(cont_id.file_id(db).into(), range)) + } + } + } + + pub fn range(&self, db: &dyn HirDb) -> Option> { + Some(match *self { + ModuleDefOrigin::ModuleId(InFile { value, file_id }) => { + let range = file_id.to_container_src_map(db).get(value)?.range(); + InFile::new(file_id, range) + } + ModuleDefOrigin::Config(InFile { value, file_id }) => { + let range = file_id.to_container_src_map(db).get(value)?.range(); + InFile::new(file_id, range) + } + ModuleDefOrigin::Library(InFile { value, file_id }) => { + let range = file_id.to_container_src_map(db).get(value)?.range(); + InFile::new(file_id, range) + } + ModuleDefOrigin::Udp(InFile { value, file_id }) => { + let range = file_id.to_container_src_map(db).get(value)?.range(); + InFile::new(file_id, range) + } + ModuleDefOrigin::BlockId(block_id) => { + let BlockLoc { src: InFile { value, file_id }, .. } = block_id.lookup(db); + let range = value.range(); + InFile::new(file_id, range) + } + ModuleDefOrigin::GenerateBlockId(generate_block_id) => { + let GenerateBlockLoc { src: InFile { value, file_id }, .. } = + generate_block_id.lookup(db); + let range = value.range(); + InFile::new(file_id, range) + } + ModuleDefOrigin::SubroutineId(subroutine_id) => { + let src = subroutine_id.lookup(db).src; + let range = src.value.range(); + InFile::new(src.file_id, range) + } + ModuleDefOrigin::SubroutinePort(InSubroutine { subroutine, value }) => { + let src = subroutine.lookup(db).src; + let tree = db.parse(src.file_id); + let func = src.value.to_node(&tree)?; + let ports = func.prototype().port_list()?; + let port = ports + .ports() + .children() + .nth(value.0 as usize) + .and_then(|port| port.as_function_port())?; + let range = port.syntax().text_range()?; + InFile::new(src.file_id, range) + } + ModuleDefOrigin::NonAnsiPort(InModule { value, module_id }) => { + let range = module_id.to_container_src_map(db).get(value)?.range(); + InFile::new(module_id.file_id, range) + } + ModuleDefOrigin::Decl(InContainer { value, cont_id }) => { + let range = cont_id.to_container_src_map(db).get(value)?.range(); + InFile::new(cont_id.file_id(db).into(), range) + } + ModuleDefOrigin::Typedef(InContainer { value, cont_id }) => { + let range = cont_id.to_container_src_map(db).get(value)?.range(); + InFile::new(cont_id.file_id(db).into(), range) + } + ModuleDefOrigin::Instance(InModule { value, module_id }) => { + let range = module_id.to_container_src_map(db).get(value)?.range(); + InFile::new(module_id.file_id, range) + } + ModuleDefOrigin::Stmt(InContainer { value, cont_id }) => { + let range = cont_id.to_container_src_map(db).get(value)?.range(); + InFile::new(cont_id.file_id(db).into(), range) + } + }) + } +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct ModuleDef { + origins: Box<[ModuleDefOrigin]>, +} + +impl ModuleDef { + pub fn from_origins(origins: impl IntoIterator) -> Option { + let mut origins = origins.into_iter().collect::>(); + origins.sort_unstable(); + origins.dedup(); + + (!origins.is_empty()).then(|| ModuleDef { origins: origins.into_vec().into_boxed_slice() }) + } + + pub fn origins(&self) -> &[ModuleDefOrigin] { + &self.origins + } + + fn into_origins(self) -> Box<[ModuleDefOrigin]> { + self.origins + } +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[repr(transparent)] +pub struct ModuleDefId(pub salsa::InternId); + +impl ModuleDefId { + pub fn origins(self, db: &dyn HirDb) -> Box<[ModuleDefOrigin]> { + db.lookup_intern_module_def(self).into_origins() + } + + pub fn declaration_origin(self, db: &dyn HirDb) -> Option { + let origins = self.origins(db); + if origins.iter().any(|origin| matches!(origin, ModuleDefOrigin::NonAnsiPort(_))) { + return origins.iter().copied().find(|origin| is_port_decl_origin(db, origin)).or_else( + || { + origins + .iter() + .copied() + .find(|origin| matches!(origin, ModuleDefOrigin::Decl(_))) + }, + ); + } + + origins.first().copied() + } + + pub fn def_origins(self, db: &dyn HirDb) -> SmallVec<[ModuleDefOrigin; 2]> { + let origins = self.origins(db); + if origins.iter().any(|origin| matches!(origin, ModuleDefOrigin::NonAnsiPort(_))) { + return origins + .iter() + .copied() + .filter(|origin| matches!(origin, ModuleDefOrigin::Decl(_))) + .collect(); + } + + origins.first().copied().into_iter().collect() + } + + pub fn is_port(self, db: &dyn HirDb) -> bool { + self.origins(db).iter().any(|origin| match origin { + ModuleDefOrigin::NonAnsiPort(_) => true, + ModuleDefOrigin::Decl(_) => is_port_decl_origin(db, origin), + _ => false, + }) + } + + pub fn container_id(self, db: &dyn HirDb) -> Option { + let origins = self.origins(db); + let container_id = origins.first().map(|origin| origin.container_id(db))?; + debug_assert! { + origins.iter().all(|origin| origin.container_id(db) == container_id) + }; + Some(container_id) + } +} + +fn is_port_decl_origin(db: &dyn HirDb, origin: &ModuleDefOrigin) -> bool { + let ModuleDefOrigin::Decl(decl_id) = origin else { + return false; + }; + matches!( + decl_id.cont_id.to_container(db).get(decl_id.value).parent, + DeclaratorParent::PortDeclId(_) + ) +} diff --git a/crates/hir/src/file.rs b/crates/hir/src/file.rs index 69002368..b397c755 100644 --- a/crates/hir/src/file.rs +++ b/crates/hir/src/file.rs @@ -2,7 +2,7 @@ use vfs::FileId; use crate::hir_def::macro_file::MacroFileId; -#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] +#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)] pub enum HirFileId { File(FileId), Macro(MacroFileId), diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 3fcf3243..5e85aa03 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -3,6 +3,7 @@ pub mod base_db; pub mod container; pub mod db; +pub mod def_id; pub mod display; pub mod file; pub mod has_source; diff --git a/crates/hir/src/semantics/pathres.rs b/crates/hir/src/semantics/pathres.rs index 56faf4d0..b3dd8c9c 100644 --- a/crates/hir/src/semantics/pathres.rs +++ b/crates/hir/src/semantics/pathres.rs @@ -1,3 +1,4 @@ +use smallvec::{SmallVec, smallvec}; use syntax::{SyntaxNode, SyntaxTokenWithParent}; use super::SemanticsImpl; @@ -7,6 +8,7 @@ use crate::{ InSubroutine, }, db::HirDb, + def_id::{ModuleDef, ModuleDefId, ModuleDefOrigin}, file::HirFileId, hir_def::{ Ident, @@ -93,6 +95,71 @@ pub enum PathResolution { GenerateBlock(GenerateBlockId), } +impl PathResolution { + pub fn to_def_id(self, db: &dyn HirDb) -> Option { + let module_def = ModuleDef::from_origins(self.origins())?; + Some(db.intern_module_def(module_def)) + } + + fn origins(self) -> SmallVec<[ModuleDefOrigin; 3]> { + let mut res = smallvec![]; + let mut add_source = |source| res.push(source); + + match self { + PathResolution::NonAnsiPort { label, port_decl, data_decl, module } => { + let container: ContainerId = module.into(); + if let Some(label) = label { + add_source(InModule::new(module, label).into()); + } + if let Some(port_decl) = port_decl { + add_source(InContainer::new(container, port_decl).into()); + } + if let Some(decl) = data_decl { + add_source(InContainer::new(container, decl).into()); + } + } + _ => { + if let Some(origin) = self.pick() { + add_source(origin); + } + } + }; + + res + } + + #[inline] + fn pick(self) -> Option { + match self { + PathResolution::Module(module_id) => Some(module_id.into()), + PathResolution::Config(config_id) => Some(config_id.into()), + PathResolution::Library(library_id) => Some(library_id.into()), + PathResolution::Udp(udp_id) => Some(udp_id.into()), + PathResolution::Decl(decl_id) => Some(decl_id.into()), + PathResolution::Typedef(typedef_id) => Some(typedef_id.into()), + PathResolution::Instance(instance_id) => Some(instance_id.into()), + PathResolution::Stmt(stmt_id) => Some(stmt_id.into()), + PathResolution::Block(blk_id) => Some(blk_id.into()), + PathResolution::GenerateBlock(generate_block_id) => Some(generate_block_id.into()), + PathResolution::Subroutine(subroutine_id) => Some(subroutine_id.into()), + PathResolution::SubroutinePort(port_id) => Some(port_id.into()), + PathResolution::ParamDecl(decl_id) | PathResolution::AnsiPort(decl_id) => { + Some(InContainer::new(decl_id.module_id.into(), decl_id.value).into()) + } + PathResolution::NonAnsiPort { label, port_decl, data_decl, module } => { + let container: ContainerId = module.into(); + if let Some(label) = label { + Some(InModule::new(module, label).into()) + } else if let Some(port_decl) = port_decl { + Some(InContainer::new(container, port_decl).into()) + } else { + data_decl.map(|decl| InContainer::new(container, decl).into()) + } + } + } + } +} + impl From for PathResolution { fn from(entry: UnitEntry) -> Self { use UnitEntry::*; diff --git a/crates/ide/src/code_lens.rs b/crates/ide/src/code_lens.rs index fe43c7eb..83c71f63 100644 --- a/crates/ide/src/code_lens.rs +++ b/crates/ide/src/code_lens.rs @@ -1,11 +1,12 @@ use hir::{ - db::HirDb, + db::{HirDb, InternDb}, + def_id::ModuleDefOrigin, file::HirFileId, hir_def::{ file::{FileSourceMap, HirFile}, module::ModuleId, }, - semantics::{Semantics, pathres::PathResolution}, + semantics::Semantics, source_map::IsSrc, }; use syntax::{ @@ -18,7 +19,6 @@ use vfs::FileId; use crate::{ FilePosition, FileRange, ScopeVisibility, db::root_db::RootDb, - definitions::Definition, references::{ ReferencesConfig, search::{ReferencesCtx, SearchScope}, @@ -87,7 +87,10 @@ pub(crate) fn code_lens_resolve(db: &RootDb, mut kind: CodeLensKind) -> CodeLens }; let module_id = ModuleId::new(hir_file_id, local_module_id); - let def = Definition(PathResolution::Module(module_id)); + let def = ModuleDefOrigin::ModuleId(module_id); + let def = hir::def_id::ModuleDef::from_origins([def]) + .expect("module definition should have an origin"); + let def = sema.db.intern_module_def(def); let ref_config = ReferencesConfig::new(ScopeVisibility::Public, Some(SearchScope::all(sema.db))); diff --git a/crates/ide/src/definitions.rs b/crates/ide/src/definitions.rs index 4c7fed91..5be507ce 100644 --- a/crates/ide/src/definitions.rs +++ b/crates/ide/src/definitions.rs @@ -1,40 +1,16 @@ use hir::{ - base_db::intern::Lookup, - container::{ContainerId, InContainer, InFile, InModule, InSubroutine}, - db::HirDb, + def_id::{ModuleDefId, ModuleDefOrigin}, file::HirFileId, - hir_def::{ - block::{BlockId, BlockLoc}, - expr::declarator::DeclId, - file::{config::ConfigDeclId, library::LibraryDeclId, udp::UdpDeclId}, - module::{ - ModuleId, - generate::{GenerateBlockId, GenerateBlockLoc}, - instantiation::InstanceId, - port::NonAnsiPortId, - }, - stmt::StmtId, - subroutine::{SubroutineId, SubroutinePortId}, - typedef::TypedefId, - }, semantics::{Semantics, pathres::PathResolution}, - source_map::{IsNamedSrc, IsSrc, ToAstNode}, }; -use smallvec::{SmallVec, smallvec}; -use smol_str::SmolStr; +use smallvec::SmallVec; use syntax::{ SyntaxAncestors, SyntaxToken, SyntaxTokenWithParent, ast::{self, AstNode}, has_name::HasName, - has_text_range::{HasTextRange, HasTextRangeIn}, match_ast, token::TokenKindExt, }; -use utils::{ - get::{Get, GetRef}, - impl_from, - line_index::TextRange, -}; use crate::{ db::root_db::RootDb, @@ -44,388 +20,17 @@ use crate::{ }, }; -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub enum DefinitionOrigin { - ModuleId(ModuleId), - Config(InFile), - Library(InFile), - Udp(InFile), - BlockId(BlockId), - GenerateBlockId(GenerateBlockId), - SubroutineId(SubroutineId), - SubroutinePort(InSubroutine), - - NonAnsiPort(InModule), - Decl(InContainer), - Typedef(InContainer), - Instance(InModule), - Stmt(InContainer), -} - -impl_from! { DefinitionOrigin => - ModuleId, - Config(InFile), - Library(InFile), - Udp(InFile), - BlockId, - GenerateBlockId, - SubroutineId, - SubroutinePort(InSubroutine), - NonAnsiPort(InModule), - Decl(InContainer), - Typedef(InContainer), - Instance(InModule), - Stmt(InContainer), -} - -impl DefinitionOrigin { - #[inline] - pub fn container_id(&self, db: &dyn HirDb) -> ContainerId { - match *self { - DefinitionOrigin::ModuleId(InFile { file_id, .. }) => file_id.into(), - DefinitionOrigin::Config(InFile { file_id, .. }) => file_id.into(), - DefinitionOrigin::Library(InFile { file_id, .. }) => file_id.into(), - DefinitionOrigin::Udp(InFile { file_id, .. }) => file_id.into(), - DefinitionOrigin::BlockId(block_id) => block_id.lookup(db).cont_id, - DefinitionOrigin::GenerateBlockId(generate_block_id) => { - generate_block_id.lookup(db).cont_id - } - DefinitionOrigin::SubroutineId(subroutine_id) => { - subroutine_id.lookup(db).cont_id.into() - } - DefinitionOrigin::SubroutinePort(InSubroutine { subroutine, .. }) => { - ContainerId::SubroutineId(subroutine) - } - DefinitionOrigin::NonAnsiPort(InModule { module_id, .. }) => module_id.into(), - DefinitionOrigin::Decl(InContainer { cont_id, .. }) => cont_id, - DefinitionOrigin::Typedef(InContainer { cont_id, .. }) => cont_id, - DefinitionOrigin::Instance(InModule { module_id, .. }) => module_id.into(), - DefinitionOrigin::Stmt(InContainer { cont_id, .. }) => cont_id, - } - } - - pub fn name(&self, db: &dyn HirDb) -> Option { - match *self { - DefinitionOrigin::ModuleId(InFile { value, file_id }) => { - file_id.to_container(db).get(value).name.clone() - } - DefinitionOrigin::Config(InFile { value, file_id }) => { - file_id.to_container(db).get(value).name.clone() - } - DefinitionOrigin::Library(InFile { value, file_id }) => { - file_id.to_container(db).get(value).name.clone() - } - DefinitionOrigin::Udp(InFile { value, file_id }) => { - file_id.to_container(db).get(value).name.clone() - } - DefinitionOrigin::BlockId(block_id) => { - let BlockLoc { cont_id, src: InFile { value, file_id: _ } } = block_id.lookup(db); - let cont = cont_id.to_container(db); - value.hir(&cont, &cont_id.to_container_src_map(db))?.name.clone() - } - DefinitionOrigin::GenerateBlockId(generate_block_id) => { - db.generate_block(generate_block_id).name.clone() - } - DefinitionOrigin::SubroutineId(subroutine_id) => { - db.subroutine(subroutine_id).name.clone() - } - DefinitionOrigin::SubroutinePort(InSubroutine { subroutine, value }) => { - db.subroutine(subroutine).ports.get(value.0 as usize)?.name.clone() - } - DefinitionOrigin::NonAnsiPort(InModule { value, module_id }) => { - module_id.to_container(db).get(value).label.clone() - } - DefinitionOrigin::Decl(InContainer { value, cont_id }) => { - cont_id.to_container(db).get(value).name.clone() - } - DefinitionOrigin::Typedef(InContainer { value, cont_id }) => { - cont_id.to_container(db).get(value).name.clone() - } - DefinitionOrigin::Instance(InModule { value, module_id }) => { - module_id.to_container(db).get(value).name.clone() - } - DefinitionOrigin::Stmt(InContainer { value, cont_id }) => { - cont_id.to_container(db).get(value).label.clone() - } - } - } - - pub fn name_range(&self, db: &dyn HirDb) -> Option> { - match *self { - DefinitionOrigin::ModuleId(InFile { value, file_id }) => { - let range = file_id.to_container_src_map(db).get(value)?.name_range()?; - Some(InFile::new(file_id, range)) - } - DefinitionOrigin::Config(InFile { value, file_id }) => { - let range = file_id.to_container_src_map(db).get(value)?.name_range()?; - Some(InFile::new(file_id, range)) - } - DefinitionOrigin::Library(InFile { value, file_id }) => { - let range = file_id.to_container_src_map(db).get(value)?.name_range()?; - Some(InFile::new(file_id, range)) - } - DefinitionOrigin::Udp(InFile { value, file_id }) => { - let range = file_id.to_container_src_map(db).get(value)?.name_range()?; - Some(InFile::new(file_id, range)) - } - DefinitionOrigin::BlockId(block_id) => { - let BlockLoc { src: InFile { value, file_id }, .. } = block_id.lookup(db); - let range = value.name_range()?; - Some(InFile::new(file_id, range)) - } - DefinitionOrigin::GenerateBlockId(generate_block_id) => { - let GenerateBlockLoc { src: InFile { value, file_id }, .. } = - generate_block_id.lookup(db); - let range = value.name_range()?; - Some(InFile::new(file_id, range)) - } - DefinitionOrigin::SubroutineId(subroutine_id) => { - let src = subroutine_id.lookup(db).src; - Some(InFile::new(src.file_id, src.value.name_or_full_range())) - } - DefinitionOrigin::SubroutinePort(InSubroutine { subroutine, value }) => { - let src = subroutine.lookup(db).src; - let tree = db.parse(src.file_id); - let func = src.value.to_node(&tree)?; - let ports = func - .prototype() - .port_list() - .map(|ports| ports.ports().children().collect::>()) - .unwrap_or_default(); - let port = ports - .into_iter() - .nth(value.0 as usize) - .and_then(|port| port.as_function_port())?; - let declarator = port.declarator(); - let range = declarator.name()?.text_range_in(declarator.syntax())?; - Some(InFile::new(src.file_id, range)) - } - DefinitionOrigin::NonAnsiPort(InModule { value, module_id }) => { - let range = module_id.to_container_src_map(db).get(value)?.name_range()?; - Some(InFile::new(module_id.file_id, range)) - } - DefinitionOrigin::Decl(InContainer { value, cont_id }) => { - let range = cont_id.to_container_src_map(db).get(value)?.name_range()?; - Some(InFile::new(cont_id.file_id(db).into(), range)) - } - DefinitionOrigin::Typedef(InContainer { value, cont_id }) => { - let range = cont_id.to_container_src_map(db).get(value)?.name_range()?; - Some(InFile::new(cont_id.file_id(db).into(), range)) - } - DefinitionOrigin::Instance(InModule { value, module_id }) => { - let range = module_id.to_container_src_map(db).get(value)?.name_range()?; - Some(InFile::new(module_id.file_id, range)) - } - DefinitionOrigin::Stmt(InContainer { value, cont_id }) => { - let range = cont_id.to_container_src_map(db).get(value)?.name_range()?; - Some(InFile::new(cont_id.file_id(db).into(), range)) - } - } - } - - pub fn range(&self, db: &dyn HirDb) -> Option> { - Some(match *self { - DefinitionOrigin::ModuleId(InFile { value, file_id }) => { - let range = file_id.to_container_src_map(db).get(value)?.range(); - InFile::new(file_id, range) - } - DefinitionOrigin::Config(InFile { value, file_id }) => { - let range = file_id.to_container_src_map(db).get(value)?.range(); - InFile::new(file_id, range) - } - DefinitionOrigin::Library(InFile { value, file_id }) => { - let range = file_id.to_container_src_map(db).get(value)?.range(); - InFile::new(file_id, range) - } - DefinitionOrigin::Udp(InFile { value, file_id }) => { - let range = file_id.to_container_src_map(db).get(value)?.range(); - InFile::new(file_id, range) - } - DefinitionOrigin::BlockId(block_id) => { - let BlockLoc { src: InFile { value, file_id }, .. } = block_id.lookup(db); - let range = value.range(); - InFile::new(file_id, range) - } - DefinitionOrigin::GenerateBlockId(generate_block_id) => { - let GenerateBlockLoc { src: InFile { value, file_id }, .. } = - generate_block_id.lookup(db); - let range = value.range(); - InFile::new(file_id, range) - } - DefinitionOrigin::SubroutineId(subroutine_id) => { - let src = subroutine_id.lookup(db).src; - let range = src.value.range(); - InFile::new(src.file_id, range) - } - DefinitionOrigin::SubroutinePort(InSubroutine { subroutine, value }) => { - let src = subroutine.lookup(db).src; - let tree = db.parse(src.file_id); - let func = src.value.to_node(&tree)?; - let ports = func.prototype().port_list()?; - let port = ports - .ports() - .children() - .nth(value.0 as usize) - .and_then(|port| port.as_function_port())?; - let range = port.syntax().text_range()?; - InFile::new(src.file_id, range) - } - DefinitionOrigin::NonAnsiPort(InModule { value, module_id }) => { - let range = module_id.to_container_src_map(db).get(value)?.range(); - InFile::new(module_id.file_id, range) - } - DefinitionOrigin::Decl(InContainer { value, cont_id }) => { - let range = cont_id.to_container_src_map(db).get(value)?.range(); - InFile::new(cont_id.file_id(db).into(), range) - } - DefinitionOrigin::Typedef(InContainer { value, cont_id }) => { - let range = cont_id.to_container_src_map(db).get(value)?.range(); - InFile::new(cont_id.file_id(db).into(), range) - } - DefinitionOrigin::Instance(InModule { value, module_id }) => { - let range = module_id.to_container_src_map(db).get(value)?.range(); - InFile::new(module_id.file_id, range) - } - DefinitionOrigin::Stmt(InContainer { value, cont_id }) => { - let range = cont_id.to_container_src_map(db).get(value)?.range(); - InFile::new(cont_id.file_id(db).into(), range) - } - }) - } -} - -// Definition may have multiple origins, e.g. non-ansi port -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct Definition(pub PathResolution); - -impl From for Definition { - fn from(res: PathResolution) -> Self { - Self(res) - } -} - -impl Definition { - pub fn origins(&self) -> SmallVec<[DefinitionOrigin; 3]> { - let mut res = smallvec![]; - let mut add_source = |source| res.push(source); - - match self.0 { - PathResolution::NonAnsiPort { label, port_decl, data_decl, module } => { - let container: ContainerId = module.into(); - if let Some(label) = label { - add_source(InModule::new(module, label).into()); - } - if let Some(port_decl) = port_decl { - add_source(InContainer::new(container, port_decl).into()); - } - if let Some(decl) = data_decl { - add_source(InContainer::new(container, decl).into()); - } - } - _ => { - if let Some(origin) = self.pick() { - add_source(origin); - } - } - }; - - res - } - - pub fn declaration_origins(&self) -> Option { - match self.0 { - PathResolution::NonAnsiPort { port_decl, data_decl, module, .. } => { - let container: ContainerId = module.into(); - if let Some(port_decl) = port_decl { - Some(InContainer::new(container, port_decl).into()) - } else { - data_decl.map(|decl| InContainer::new(container, decl).into()) - } - } - _ => self.pick(), - } - } - - pub fn def_origins(&self) -> SmallVec<[DefinitionOrigin; 2]> { - let mut res = SmallVec::new(); - match self.0 { - PathResolution::NonAnsiPort { port_decl, data_decl, module, .. } => { - let container: ContainerId = module.into(); - if let Some(port_decl) = port_decl { - res.push(InContainer::new(container, port_decl).into()); - } - - if let Some(decl) = data_decl { - res.push(InContainer::new(container, decl).into()); - } - } - _ => { - if let Some(origin) = self.pick() { - res.push(origin); - } - } - } - - res - } - - pub fn is_port(&self) -> bool { - matches!(self.0, PathResolution::AnsiPort(_) | PathResolution::NonAnsiPort { .. }) - } - - pub fn container_id(&self, db: &dyn HirDb) -> Option { - let container_id = - self.pick().map(|origin| origin.container_id(db)).or_else(|| match self.0 { - PathResolution::NonAnsiPort { module, .. } => Some(module.into()), - _ => None, - })?; - debug_assert! { - self.origins().into_iter().all(|source| source.container_id(db) == container_id) - }; - Some(container_id) - } - - #[inline] - fn pick(&self) -> Option { - match self.0 { - PathResolution::Module(module_id) => Some(module_id.into()), - PathResolution::Config(config_id) => Some(config_id.into()), - PathResolution::Library(library_id) => Some(library_id.into()), - PathResolution::Udp(udp_id) => Some(udp_id.into()), - PathResolution::Decl(decl_id) => Some(decl_id.into()), - PathResolution::Typedef(typedef_id) => Some(typedef_id.into()), - PathResolution::Instance(instance_id) => Some(instance_id.into()), - PathResolution::Stmt(stmt_id) => Some(stmt_id.into()), - PathResolution::Block(blk_id) => Some(blk_id.into()), - PathResolution::GenerateBlock(generate_block_id) => Some(generate_block_id.into()), - PathResolution::Subroutine(subroutine_id) => Some(subroutine_id.into()), - PathResolution::SubroutinePort(port_id) => Some(port_id.into()), - PathResolution::ParamDecl(decl_id) | PathResolution::AnsiPort(decl_id) => { - Some(InContainer::new(decl_id.module_id.into(), decl_id.value).into()) - } - PathResolution::NonAnsiPort { label, port_decl, data_decl, module } => { - let container: ContainerId = module.into(); - if let Some(label) = label { - Some(InModule::new(module, label).into()) - } else if let Some(port_decl) = port_decl { - Some(InContainer::new(container, port_decl).into()) - } else { - data_decl.map(|decl| InContainer::new(container, decl).into()) - } - } - } - } -} - #[derive(Debug, Clone, PartialEq, Eq)] pub enum DefinitionClass { - Definition(Definition), - PortConnShorthand { port: Definition, local: Definition }, - Ambiguous(Vec), + Definition(ModuleDefId), + PortConnShorthand { port: ModuleDefId, local: ModuleDefId }, + Ambiguous(Vec), } -impl_from! { DefinitionClass => - Definition, +impl From for DefinitionClass { + fn from(def: ModuleDefId) -> Self { + Self::Definition(def) + } } impl DefinitionClass { @@ -453,14 +58,14 @@ impl DefinitionClass { let res = match_ast! { parent, ast::NamedParamAssignment[it] if it.name() == Some(tok) => { resolve_named_param_assignment(sema.db, file_id.file_id(), it) - .map(Definition::from)?.into() + .and_then(|res| res.to_def_id(sema.db))?.into() }, ast::NamedPortConnection[it] if it.name() == Some(tok) => { let port = resolve_named_port_connection(sema.db, file_id.file_id(), it) - .map(Definition::from); + .and_then(|res| res.to_def_id(sema.db)); if it.open_paren().is_none() && it.close_paren().is_none() { - let local = sema.nameres_ident(file_id, tp).map(Definition::from); + let local = sema.nameres_ident(file_id, tp).and_then(|res| res.to_def_id(sema.db)); match (port, local) { (Some(port), Some(local)) => Self::PortConnShorthand { port, local }, @@ -471,20 +76,20 @@ impl DefinitionClass { port?.into() } }, - _ => Definition::from(sema.nameres_ident(file_id, tp)?).into(), + _ => sema.nameres_ident(file_id, tp)?.to_def_id(sema.db)?.into(), }; Some(res) } - pub(crate) fn origins(self) -> SmallVec<[DefinitionOrigin; 6]> { + pub(crate) fn origins(self, db: &RootDb) -> SmallVec<[ModuleDefOrigin; 6]> { match self { - DefinitionClass::Definition(definition) => definition.origins().into_iter().collect(), + DefinitionClass::Definition(definition) => definition.origins(db).into_iter().collect(), DefinitionClass::PortConnShorthand { port, local } => { - port.origins().into_iter().chain(local.origins()).collect() + port.origins(db).into_iter().chain(local.origins(db)).collect() } DefinitionClass::Ambiguous(definitions) => { - definitions.into_iter().flat_map(|definition| definition.origins()).collect() + definitions.into_iter().flat_map(|definition| definition.origins(db)).collect() } } } @@ -499,7 +104,7 @@ fn resolve_declaration_name( && module.name() == Some(tok) { let module_id = sema.module_to_def(file_id, module)?; - return Some(Definition::from(PathResolution::Module(module_id)).into()); + return Some(PathResolution::Module(module_id).to_def_id(sema.db)?.into()); } None @@ -516,7 +121,7 @@ fn resolve_member_or_scoped_name( { let expr = ast::Expression::cast(access.syntax())?; let res = sema.expr_to_def(sema.resolve_expr(file_id, expr)?)?; - return Some(Definition::from(res).into()); + return Some(res.to_def_id(sema.db)?.into()); } let scoped = SyntaxAncestors::start_from(parent).find_map(ast::ScopedName::cast)?; @@ -527,7 +132,7 @@ fn resolve_member_or_scoped_name( let expr = ast::Expression::cast(scoped.syntax())?; let res = sema.expr_to_def(sema.resolve_expr(file_id, expr)?)?; - Some(Definition::from(res).into()) + Some(res.to_def_id(sema.db)?.into()) } fn resolve_instantiation_type_name( @@ -542,13 +147,13 @@ fn resolve_instantiation_type_name( return match resolve_instantiation_target(sema.db, file_id.file_id(), instantiation) { ModuleResolution::Unique(module_id) | ModuleResolution::BestEffortProximity { selected: module_id, .. } => { - Some(Definition::from(PathResolution::Module(module_id)).into()) + Some(PathResolution::Module(module_id).to_def_id(sema.db)?.into()) } ModuleResolution::Ambiguous { candidates, .. } => Some(DefinitionClass::Ambiguous( candidates .into_iter() - .map(|module_id| Definition::from(PathResolution::Module(module_id))) - .collect(), + .map(|module_id| PathResolution::Module(module_id).to_def_id(sema.db)) + .collect::>>()?, )), ModuleResolution::Unresolved => None, }; @@ -558,7 +163,7 @@ fn resolve_instantiation_type_name( SyntaxAncestors::start_from(parent).find_map(ast::PrimitiveInstantiation::cast) && instantiation.type_() == Some(tok) { - return Some(Definition::from(sema.nameres_ident(file_id, tp)?).into()); + return Some(sema.nameres_ident(file_id, tp)?.to_def_id(sema.db)?.into()); } None @@ -579,8 +184,7 @@ mod tests { use hir::{ base_db::{change::Change, source_root::SourceRoot}, - container::InModule, - semantics::pathres::PathResolution, + def_id::ModuleDefOrigin, }; use syntax::SyntaxNodeExt; use triomphe::Arc; @@ -654,19 +258,15 @@ mod tests { panic!("expected plain definition for {name}"); }; - let (resolution, range) = match def.0 { - PathResolution::NonAnsiPort { label: Some(label), module, .. } => ( + let origins = def.origins(db); + let (resolution, range) = match origins.first().copied() { + Some(origin @ ModuleDefOrigin::NonAnsiPort(_)) => ( "NonAnsiPort", - DefinitionOrigin::NonAnsiPort(InModule::new(module, label)) - .name_range(db) - .expect("non-ANSI port label should have a name range"), - ), - PathResolution::AnsiPort(port) => ( - "AnsiPort", - DefinitionOrigin::Decl(port.into()) - .name_range(db) - .expect("ANSI port should have a name range"), + origin.name_range(db).expect("non-ANSI port label should have a name range"), ), + Some(origin @ ModuleDefOrigin::Decl(_)) => { + ("AnsiPort", origin.name_range(db).expect("ANSI port should have a name range")) + } other => panic!("unexpected definition for {name}: {other:?}"), }; let range_start = usize::from(range.value.start()); diff --git a/crates/ide/src/document_highlight.rs b/crates/ide/src/document_highlight.rs index 2dc8fb27..6c74b182 100644 --- a/crates/ide/src/document_highlight.rs +++ b/crates/ide/src/document_highlight.rs @@ -1,4 +1,4 @@ -use hir::{container::InFile, file::HirFileId, semantics::Semantics}; +use hir::{container::InFile, def_id::ModuleDefId, file::HirFileId, semantics::Semantics}; use syntax::{SyntaxTokenWithParent, TokenKind, token::TokenKindExt}; use utils::line_index::TextRange; use vfs::FileId; @@ -6,7 +6,7 @@ use vfs::FileId; use crate::{ FilePosition, ScopeVisibility, db::root_db::RootDb, - definitions::{Definition, DefinitionClass}, + definitions::DefinitionClass, references::{ self, ReferenceCategory, ReferencesConfig, search::{ReferencesCtx, SearchScope}, @@ -89,10 +89,10 @@ fn highlight_for_token( fn highlight_refs<'a>( sema: &'a Semantics<'a, RootDb>, file_id: FileId, - def: Definition, + def: ModuleDefId, DocumentHighlightConfig { scope_visibility }: DocumentHighlightConfig, ) -> Option> { - let defs = def.origins().into_iter().filter_map(|def| { + let defs = def.origins(sema.db).into_iter().filter_map(|def| { let InFile { value: range, file_id: def_file_id } = def.name_range(sema.db)?; if file_id == def_file_id.file_id() { Some(DocumentHighlight { range, category: ReferenceCategory::empty() }) diff --git a/crates/ide/src/goto_declaration.rs b/crates/ide/src/goto_declaration.rs index e30929b0..2e7a3656 100644 --- a/crates/ide/src/goto_declaration.rs +++ b/crates/ide/src/goto_declaration.rs @@ -67,15 +67,15 @@ fn render_source_declaration_target( .into_iter() .filter_map(|token| match DefinitionClass::resolve(sema, hir_file_id, token)? { DefinitionClass::Definition(definition) => { - Some(definition.declaration_origins().into_iter().collect_vec()) + Some(definition.declaration_origin(db).into_iter().collect_vec()) } DefinitionClass::PortConnShorthand { port, .. } => { - Some(port.declaration_origins().into_iter().collect_vec()) + Some(port.declaration_origin(db).into_iter().collect_vec()) } DefinitionClass::Ambiguous(definitions) => Some( definitions .into_iter() - .filter_map(|definition| definition.declaration_origins()) + .filter_map(|definition| definition.declaration_origin(db)) .collect_vec(), ), }) diff --git a/crates/ide/src/goto_definition.rs b/crates/ide/src/goto_definition.rs index 9f4d35bf..a95e2b09 100644 --- a/crates/ide/src/goto_definition.rs +++ b/crates/ide/src/goto_definition.rs @@ -91,7 +91,7 @@ fn nav_targets_for_token( ) -> Option> { handle_ctrl_flow_kw(sema, hir_file_id, token).or_else(|| { DefinitionClass::resolve(sema, hir_file_id, token)? - .origins() + .origins(db) .into_iter() .unique() .filter_map(|def| def.to_nav(db)) diff --git a/crates/ide/src/navigation_target.rs b/crates/ide/src/navigation_target.rs index 7dda6ab8..7b699343 100644 --- a/crates/ide/src/navigation_target.rs +++ b/crates/ide/src/navigation_target.rs @@ -2,6 +2,7 @@ use hir::{ base_db::intern::Lookup, container::{ContainerId, InContainer, InFile, InModule, InSubroutine}, db::HirDb, + def_id::ModuleDefOrigin, hir_def::{ block::{BlockId, BlockLoc}, declaration::Declaration, @@ -31,7 +32,7 @@ use utils::{ }; use vfs::FileId; -use crate::{SymbolKind, db::root_db::RootDb, definitions::DefinitionOrigin}; +use crate::{SymbolKind, db::root_db::RootDb}; #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct NavTarget { @@ -56,22 +57,22 @@ pub(crate) trait ToNav { fn to_nav(&self, db: &RootDb) -> Option; } -impl ToNav for DefinitionOrigin { +impl ToNav for ModuleDefOrigin { fn to_nav(&self, db: &RootDb) -> Option { match self { - DefinitionOrigin::ModuleId(module_id) => module_id.to_nav(db), - DefinitionOrigin::Config(config_id) => config_id.to_nav(db), - DefinitionOrigin::Library(library_id) => library_id.to_nav(db), - DefinitionOrigin::Udp(udp_id) => udp_id.to_nav(db), - DefinitionOrigin::BlockId(block_id) => block_id.to_nav(db), - DefinitionOrigin::GenerateBlockId(generate_block_id) => generate_block_id.to_nav(db), - DefinitionOrigin::SubroutineId(subroutine_id) => subroutine_id.to_nav(db), - DefinitionOrigin::SubroutinePort(subroutine_port_id) => subroutine_port_id.to_nav(db), - DefinitionOrigin::NonAnsiPort(nonansi_port_id) => nonansi_port_id.to_nav(db), - DefinitionOrigin::Decl(decl_id) => decl_id.to_nav(db), - DefinitionOrigin::Typedef(typedef_id) => typedef_id.to_nav(db), - DefinitionOrigin::Instance(instance_id) => instance_id.to_nav(db), - DefinitionOrigin::Stmt(stmt_id) => stmt_id.to_nav(db), + ModuleDefOrigin::ModuleId(module_id) => module_id.to_nav(db), + ModuleDefOrigin::Config(config_id) => config_id.to_nav(db), + ModuleDefOrigin::Library(library_id) => library_id.to_nav(db), + ModuleDefOrigin::Udp(udp_id) => udp_id.to_nav(db), + ModuleDefOrigin::BlockId(block_id) => block_id.to_nav(db), + ModuleDefOrigin::GenerateBlockId(generate_block_id) => generate_block_id.to_nav(db), + ModuleDefOrigin::SubroutineId(subroutine_id) => subroutine_id.to_nav(db), + ModuleDefOrigin::SubroutinePort(subroutine_port_id) => subroutine_port_id.to_nav(db), + ModuleDefOrigin::NonAnsiPort(nonansi_port_id) => nonansi_port_id.to_nav(db), + ModuleDefOrigin::Decl(decl_id) => decl_id.to_nav(db), + ModuleDefOrigin::Typedef(typedef_id) => typedef_id.to_nav(db), + ModuleDefOrigin::Instance(instance_id) => instance_id.to_nav(db), + ModuleDefOrigin::Stmt(stmt_id) => stmt_id.to_nav(db), } } } diff --git a/crates/ide/src/references.rs b/crates/ide/src/references.rs index 1d73e55c..b963e4f0 100644 --- a/crates/ide/src/references.rs +++ b/crates/ide/src/references.rs @@ -1,4 +1,4 @@ -use hir::{file::HirFileId, semantics::Semantics}; +use hir::{def_id::ModuleDefId, file::HirFileId, semantics::Semantics}; use itertools::Itertools; use nohash_hasher::IntMap; use search::{ReferencesCtx, SearchScope}; @@ -14,7 +14,7 @@ use self::preproc::render_preproc_references_target; use crate::{ FilePosition, ScopeVisibility, db::root_db::RootDb, - definitions::{Definition, DefinitionClass}, + definitions::DefinitionClass, navigation_target::{NavTarget, ToNav}, semantic_target::{SemanticTarget, TargetIntent, TargetResolution, resolve_semantic_target}, source_targets::SourceTarget, @@ -49,7 +49,7 @@ impl ReferencesConfig { Self { scope_visibility, search_scope } } - pub(crate) fn search_scope(&self, db: &RootDb, def: &Definition) -> SearchScope { + pub(crate) fn search_scope(&self, db: &RootDb, def: &ModuleDefId) -> SearchScope { SearchScope::new(db, def, self.clone()) } } @@ -178,7 +178,7 @@ pub(crate) fn handle_ctrl_flow_kw( fn search_refs<'a>( sema: &'a Semantics<'a, RootDb>, - def: Definition, + def: ModuleDefId, config: ReferencesConfig, ) -> References { let refs = ReferencesCtx::new(sema, &def, config) @@ -189,7 +189,8 @@ fn search_refs<'a>( (file_id, res) }) .collect(); - let def = def.origins().into_iter().filter_map(|def| def.to_nav(sema.db)).collect_vec().into(); + let def = + def.origins(sema.db).iter().filter_map(|def| def.to_nav(sema.db)).collect_vec().into(); References { def, refs, status: ReferencesStatus::Complete } } diff --git a/crates/ide/src/references/search.rs b/crates/ide/src/references/search.rs index d104f227..5509e50f 100644 --- a/crates/ide/src/references/search.rs +++ b/crates/ide/src/references/search.rs @@ -6,6 +6,7 @@ use hir::{ source_root::SourceRootId, }, container::{ContainerId, InFile}, + def_id::ModuleDefId, semantics::Semantics, source_map::IsSrc, }; @@ -19,7 +20,6 @@ use super::{ReferenceCategory, ReferencesConfig}; use crate::{ ScopeVisibility, db::{root_db::RootDb, workspace_symbol_index_db::source_root_semantic_index_for_root}, - definitions::Definition, semantic_index::SemanticReference, }; @@ -36,7 +36,7 @@ impl SearchScope { pub(crate) fn new( db: &RootDb, - def: &Definition, + def: &ModuleDefId, ReferencesConfig { scope_visibility, search_scope }: ReferencesConfig, ) -> Self { match scope_visibility { @@ -46,7 +46,7 @@ impl SearchScope { return search_scope.unwrap_or_default(); }; let container_id = match container_id { - ContainerId::ModuleId(InFile { file_id, .. }) if def.is_port() => { + ContainerId::ModuleId(InFile { file_id, .. }) if def.is_port(db) => { file_id.into() } cont => cont, @@ -147,7 +147,7 @@ impl SearchScope { pub(crate) struct ReferencesCtx<'a, 'b> { sema: &'a Semantics<'a, RootDb>, - def: &'b Definition, + def: &'b ModuleDefId, scope: SearchScope, } @@ -181,7 +181,7 @@ impl<'a, 'b> ReferencesCtx<'a, 'b> { pub(crate) fn new( sema: &'a Semantics<'a, RootDb>, - def: &'b Definition, + def: &'b ModuleDefId, cfg: ReferencesConfig, ) -> Self { let scope = SearchScope::new(sema.db, def, cfg); @@ -195,7 +195,7 @@ impl<'a, 'b> ReferencesCtx<'a, 'b> { for source_root_id in self.scope.source_root_ids(db) { self.sema.db.unwind_if_cancelled(); let index = source_root_semantic_index_for_root(db, source_root_id); - let Some(group) = index.references_for_definition(self.def) else { + let Some(group) = index.references_for_definition(*self.def) else { continue; }; diff --git a/crates/ide/src/rename.rs b/crates/ide/src/rename.rs index 7bee6371..6f0af8b0 100644 --- a/crates/ide/src/rename.rs +++ b/crates/ide/src/rename.rs @@ -1,4 +1,9 @@ -use hir::{base_db::source_db::SourceDb, container::InFile, semantics::Semantics}; +use hir::{ + base_db::source_db::SourceDb, + container::InFile, + def_id::{ModuleDefId, ModuleDefOrigin}, + semantics::Semantics, +}; use nohash_hasher::IntMap; use rustc_hash::FxHashMap; use smol_str::SmolStr; @@ -16,7 +21,7 @@ use vfs::FileId; use crate::{ FilePosition, ScopeVisibility, db::root_db::RootDb, - definitions::{Definition, DefinitionClass, DefinitionOrigin}, + definitions::DefinitionClass, references::{ ReferencesConfig, search::{ReferenceToken, ReferencesCtx, SearchScope}, @@ -52,7 +57,7 @@ impl RenameConfig { fn references_config( &self, db: &RootDb, - def: &Definition, + def: &ModuleDefId, file_id: FileId, ) -> RenameResult { let mut config = ReferencesConfig::new(self.scope_visibility.clone(), None); @@ -138,9 +143,9 @@ pub(crate) fn expanded_rename( let sema = Semantics::new(db); let resolved = resolve_rename_target(&sema, position)?; let targets = recursive_rename_targets(db, &sema, position.file_id, &config, resolved.targets)?; - let mut rename_targets = UniqVec::<(), DefinitionOrigin>::default(); + let mut rename_targets = UniqVec::<(), ModuleDefOrigin>::default(); for target in &targets { - rename_targets.push(target.def.origins(), ()); + rename_targets.push(target.def.origins(db), ()); } let mut source_changes = SourceChange::default(); @@ -173,7 +178,7 @@ pub(crate) fn rename_conflict_info( ) -> RenameResult { let sema = Semantics::new(db); let resolved = resolve_rename_target(&sema, position)?; - let targets: Vec = if recursive { + let targets: Vec = if recursive { recursive_rename_targets(db, &sema, position.file_id, &config, resolved.targets)? .into_iter() .map(|target| target.def) @@ -183,18 +188,18 @@ pub(crate) fn rename_conflict_info( }; let new_name = SmolStr::new(new_name); - let mut target_index = UniqVec::<(), DefinitionOrigin>::default(); + let mut target_index = UniqVec::<(), ModuleDefOrigin>::default(); for target in &targets { - target_index.push(target.origins(), ()); + target_index.push(target.origins(db), ()); } - let mut conflicts = UniqVec::::default(); - for collision in targets.iter().flat_map(|target| target.origins()).filter_map(|origin| { - sema.resolve_name(origin.container_id(db), &new_name).map(Definition::from) + let mut conflicts = UniqVec::::default(); + for collision in targets.iter().flat_map(|target| target.origins(db)).filter_map(|origin| { + sema.resolve_name(origin.container_id(db), &new_name).and_then(|res| res.to_def_id(db)) }) { - if collision.origins().iter().any(|origin| target_index.contains(origin)) { + if collision.origins(db).iter().any(|origin| target_index.contains(origin)) { continue; } - conflicts.push(collision.origins(), collision); + conflicts.push(collision.origins(db), collision); } Ok(RenameCollisionInfo { conflicts: conflicts.len() }) @@ -202,14 +207,14 @@ pub(crate) fn rename_conflict_info( struct ResolvedRenameTarget { range: TextRange, - selected_def: Definition, - targets: Vec, + selected_def: ModuleDefId, + targets: Vec, } type ReferenceSearchResult = IntMap>; struct RecursiveRenameTarget { - def: Definition, + def: ModuleDefId, refs: ReferenceSearchResult, same_name_refs: Vec, } @@ -234,19 +239,19 @@ fn resolve_rename_target( }; let (range, tokens) = target.into_parts(); let mut selected_def = None; - let mut targets = UniqVec::::default(); + let mut targets = UniqVec::::default(); for token in tokens { let token_selected = match DefinitionClass::resolve(sema, hir_file_id, token) .ok_or(RenameError::NoDefFound)? { DefinitionClass::Definition(def) => { - targets.push(def.origins(), def.clone()); + targets.push(def.origins(sema.db), def); def } DefinitionClass::PortConnShorthand { port, local } => { - targets.push(local.origins(), local.clone()); - targets.push(port.origins(), port); + targets.push(local.origins(sema.db), local); + targets.push(port.origins(sema.db), port); local } DefinitionClass::Ambiguous(_) => return Err(RenameError::NoDefFound), @@ -267,8 +272,8 @@ fn resolve_rename_target( #[derive(Debug, Clone, PartialEq, Eq)] struct SameNameConnection { - port: Definition, - local: Definition, + port: ModuleDefId, + local: ModuleDefId, collapse_range: TextRange, } @@ -284,9 +289,9 @@ fn rename_definition( sema: &Semantics<'_, RootDb>, request_file_id: FileId, config: &RenameConfig, - def: &Definition, + def: &ModuleDefId, new_name: &str, - rename_targets: Option<&UniqVec<(), DefinitionOrigin>>, + rename_targets: Option<&UniqVec<(), ModuleDefOrigin>>, ) -> RenameResult { let refs = references_for_definition(db, sema, request_file_id, config, def)?; rename_definition_with_refs(db, sema, def, new_name, rename_targets, &refs, &[]) @@ -297,7 +302,7 @@ fn references_for_definition( sema: &Semantics<'_, RootDb>, request_file_id: FileId, config: &RenameConfig, - def: &Definition, + def: &ModuleDefId, ) -> RenameResult { let refs_config = config.references_config(db, def, request_file_id)?; Ok(ReferencesCtx::new(sema, def, refs_config).search()) @@ -306,14 +311,14 @@ fn references_for_definition( fn rename_definition_with_refs( db: &RootDb, sema: &Semantics<'_, RootDb>, - def: &Definition, + def: &ModuleDefId, new_name: &str, - rename_targets: Option<&UniqVec<(), DefinitionOrigin>>, + rename_targets: Option<&UniqVec<(), ModuleDefOrigin>>, refs: &ReferenceSearchResult, same_name_refs: &[SameNameConnectionRef], ) -> RenameResult { let old_name = def - .origins() + .origins(db) .into_iter() .find_map(|origin| origin.name(db)) .ok_or(RenameError::NoRefFound)?; @@ -337,7 +342,7 @@ fn rename_definition_with_refs( .map_err(|_| RenameError::OverlappingEdits) })?; - for def in def.origins() { + for def in def.origins(db) { let Some(InFile { value: focus_range, file_id }) = def.name_range(db) else { continue; }; @@ -358,23 +363,23 @@ fn recursive_rename_targets( sema: &Semantics<'_, RootDb>, file_id: FileId, config: &RenameConfig, - initial_targets: Vec, + initial_targets: Vec, ) -> RenameResult> { - let mut targets = UniqVec::::default(); + let mut targets = UniqVec::::default(); for target in initial_targets { - targets.push(target.origins(), target); + targets.push(target.origins(db), target); } let mut resolved_targets = Vec::new(); let mut idx = 0; while idx < targets.len() { - let current = targets.get(idx).clone(); + let current = *targets.get(idx); idx += 1; let refs = references_for_definition(db, sema, file_id, config, ¤t)?; let same_name_refs = same_name_refs_collect(sema, &refs); for conn_ref in &same_name_refs { - targets.push(conn_ref.conn.port.origins(), conn_ref.conn.port.clone()); - targets.push(conn_ref.conn.local.origins(), conn_ref.conn.local.clone()); + targets.push(conn_ref.conn.port.origins(db), conn_ref.conn.port); + targets.push(conn_ref.conn.local.origins(db), conn_ref.conn.local); } resolved_targets.push(RecursiveRenameTarget { def: current, refs, same_name_refs }); } @@ -463,13 +468,13 @@ fn check_same_name_conn( let collapse_end = close_paren.text_range_in(conn.syntax())?.end(); Some(SameNameConnection { port, - local: Definition::from(sema.nameres_ident(file_id, actual_token)?), + local: sema.nameres_ident(file_id, actual_token)?.to_def_id(sema.db)?, collapse_range: TextRange::new(name_range.start(), collapse_end), }) } -fn origins_are_editable(db: &RootDb, def: &Definition, file_id: FileId) -> bool { - def.origins().into_iter().all(|origin| { +fn origins_are_editable(db: &RootDb, def: &ModuleDefId, file_id: FileId) -> bool { + def.origins(db).into_iter().all(|origin| { matches!( origin.name_range(db), Some(InFile { file_id: origin_file_id, .. }) if origin_file_id.file_id() == file_id @@ -482,23 +487,23 @@ fn edits_from_refs( sema: &Semantics<'_, RootDb>, file_id: FileId, toks: &[ReferenceToken], - def: &Definition, + def: &ModuleDefId, old_name: &str, new_name: &str, - rename_targets: Option<&UniqVec<(), DefinitionOrigin>>, + rename_targets: Option<&UniqVec<(), ModuleDefOrigin>>, same_name_refs: &[SameNameConnectionRef], ) -> (FileId, TextEdit) { let mut text_edit = TextEdit::builder(); let text = sema.db.file_text(file_id); let hir_file_id = file_id.into(); let parsed_file = sema.parse_file(file_id); - let def_origins = def.origins(); + let def_origins = def.origins(sema.db); let same_name_refs: FxHashMap<_, _> = same_name_refs .iter() .filter(|it| it.file_id == file_id) .map(|SameNameConnectionRef { range, conn, .. }| { let SameNameConnection { port, local, collapse_range } = conn; - (*range, (port.origins(), local.origins(), *collapse_range)) + (*range, (port.origins(sema.db), local.origins(sema.db), *collapse_range)) }) .collect(); diff --git a/crates/ide/src/render.rs b/crates/ide/src/render.rs index b2ce904f..854c7b5d 100644 --- a/crates/ide/src/render.rs +++ b/crates/ide/src/render.rs @@ -5,6 +5,7 @@ use hir::{ }, container::{ContainerId, ContainerParent, InContainer, InFile, InModule, InSubroutine}, db::HirDb, + def_id::{ModuleDefId, ModuleDefOrigin}, display::HirDisplay, hir_def::{ DEFAULT_NAME, @@ -35,7 +36,6 @@ use utils::get::GetRef; use crate::{ db::{line_index_db::LineIndexDb, root_db::RootDb}, - definitions::{Definition, DefinitionOrigin}, markup::{Markup, display_project_path, file_link_target, inline_code, markdown_link}, module_resolution::resolve_module_name, }; @@ -138,10 +138,10 @@ fn render_svint_as_ieee754(svint: &SVInt) -> Option { pub(crate) fn render_definition( sema: &Semantics, - def: Definition, + def: ModuleDefId, anchor_file_id: vfs::FileId, ) -> Markup { - def.def_origins().into_iter().fold(Markup::new(), |mut res, origin| { + def.def_origins(sema.db).into_iter().fold(Markup::new(), |mut res, origin| { let origin = render_def_origin(sema, &origin, anchor_file_id); if !res.is_empty() && !origin.is_empty() { @@ -155,12 +155,12 @@ pub(crate) fn render_definition( pub(crate) fn render_definition_location( sema: &Semantics, - def: Definition, + def: ModuleDefId, anchor_file_id: vfs::FileId, ) -> Markup { let db = sema.db; let mut locations = def - .def_origins() + .def_origins(db) .into_iter() .filter_map(|origin| render_def_origin_location(db, &origin, anchor_file_id)) .collect_vec(); @@ -180,7 +180,7 @@ pub(crate) fn render_definition_location( fn render_def_origin_location( db: &RootDb, - origin: &DefinitionOrigin, + origin: &ModuleDefOrigin, anchor_file_id: vfs::FileId, ) -> Option { let InFile { value: range, file_id } = origin.range(db)?; @@ -258,7 +258,7 @@ fn has_normal_path_component(path: &utils::paths::AbsPath) -> bool { fn render_def_origin( sema: &Semantics, - origin: &DefinitionOrigin, + origin: &ModuleDefOrigin, anchor_file_id: vfs::FileId, ) -> Markup { let mut res = Markup::new(); @@ -283,24 +283,24 @@ fn render_def_origin( res } -fn render_definition_title(db: &RootDb, origin: &DefinitionOrigin) -> Option { +fn render_definition_title(db: &RootDb, origin: &ModuleDefOrigin) -> Option { let name = origin.name(db)?; let kind = match origin { - DefinitionOrigin::ModuleId(_) => "Module", - DefinitionOrigin::Config(_) => "Config", - DefinitionOrigin::Library(_) => "Library", - DefinitionOrigin::Udp(_) => "Primitive", - DefinitionOrigin::BlockId(_) => "Block", - DefinitionOrigin::GenerateBlockId(_) => "Generate block", - DefinitionOrigin::SubroutineId(subroutine_id) => match db.subroutine(*subroutine_id).kind { + ModuleDefOrigin::ModuleId(_) => "Module", + ModuleDefOrigin::Config(_) => "Config", + ModuleDefOrigin::Library(_) => "Library", + ModuleDefOrigin::Udp(_) => "Primitive", + ModuleDefOrigin::BlockId(_) => "Block", + ModuleDefOrigin::GenerateBlockId(_) => "Generate block", + ModuleDefOrigin::SubroutineId(subroutine_id) => match db.subroutine(*subroutine_id).kind { SubroutineKind::Task => "Task", SubroutineKind::Function { .. } => "Function", }, - DefinitionOrigin::SubroutinePort(_) | DefinitionOrigin::NonAnsiPort(_) => "Port", - DefinitionOrigin::Decl(decl_id) => render_decl_title_kind(db, *decl_id)?, - DefinitionOrigin::Typedef(_) => "Typedef", - DefinitionOrigin::Instance(_) => "Instance", - DefinitionOrigin::Stmt(_) => "Statement", + ModuleDefOrigin::SubroutinePort(_) | ModuleDefOrigin::NonAnsiPort(_) => "Port", + ModuleDefOrigin::Decl(decl_id) => render_decl_title_kind(db, *decl_id)?, + ModuleDefOrigin::Typedef(_) => "Typedef", + ModuleDefOrigin::Instance(_) => "Instance", + ModuleDefOrigin::Stmt(_) => "Statement", }; Some(format!("{kind} {}", inline_code(name.as_str()))) @@ -326,18 +326,18 @@ fn render_decl_title_kind(db: &RootDb, decl_id: InContainer) -> Option<& }) } -fn render_signature(sema: &Semantics, origin: &DefinitionOrigin) -> Option { +fn render_signature(sema: &Semantics, origin: &ModuleDefOrigin) -> Option { let db = sema.db; match origin { - DefinitionOrigin::ModuleId(module_id) => render_module_signature(db, *module_id), - DefinitionOrigin::SubroutineId(subroutine_id) => { + ModuleDefOrigin::ModuleId(module_id) => render_module_signature(db, *module_id), + ModuleDefOrigin::SubroutineId(subroutine_id) => { render_subroutine_signature(db, *subroutine_id) } - DefinitionOrigin::SubroutinePort(port_id) => render_subroutine_port_signature(db, *port_id), - DefinitionOrigin::NonAnsiPort(port_id) => render_non_ansi_port_signature(db, *port_id), - DefinitionOrigin::Decl(decl_id) => render_decl_signature(db, *decl_id), - DefinitionOrigin::Typedef(typedef) => typedef.display_signature(db).ok(), - DefinitionOrigin::Instance(instance_id) => render_instance_signature(db, *instance_id), + ModuleDefOrigin::SubroutinePort(port_id) => render_subroutine_port_signature(db, *port_id), + ModuleDefOrigin::NonAnsiPort(port_id) => render_non_ansi_port_signature(db, *port_id), + ModuleDefOrigin::Decl(decl_id) => render_decl_signature(db, *decl_id), + ModuleDefOrigin::Typedef(typedef) => typedef.display_signature(db).ok(), + ModuleDefOrigin::Instance(instance_id) => render_instance_signature(db, *instance_id), _ => render_label_signature(db, origin), } } @@ -620,27 +620,27 @@ fn render_data_ty(db: &RootDb, container: ContainerId, ty: DataTy) -> Option Option { +fn render_label_signature(db: &RootDb, origin: &ModuleDefOrigin) -> Option { let name = origin.name(db)?; let kind = match origin { - DefinitionOrigin::Config(_) => "config", - DefinitionOrigin::Library(_) => "library", - DefinitionOrigin::Udp(_) => "primitive", - DefinitionOrigin::BlockId(_) => "block", - DefinitionOrigin::GenerateBlockId(_) => "generate", - DefinitionOrigin::Instance(_) => "instance", - DefinitionOrigin::Stmt(_) => "statement", - DefinitionOrigin::Typedef(_) => "typedef", - DefinitionOrigin::ModuleId(_) - | DefinitionOrigin::SubroutineId(_) - | DefinitionOrigin::SubroutinePort(_) - | DefinitionOrigin::NonAnsiPort(_) - | DefinitionOrigin::Decl(_) => return None, + ModuleDefOrigin::Config(_) => "config", + ModuleDefOrigin::Library(_) => "library", + ModuleDefOrigin::Udp(_) => "primitive", + ModuleDefOrigin::BlockId(_) => "block", + ModuleDefOrigin::GenerateBlockId(_) => "generate", + ModuleDefOrigin::Instance(_) => "instance", + ModuleDefOrigin::Stmt(_) => "statement", + ModuleDefOrigin::Typedef(_) => "typedef", + ModuleDefOrigin::ModuleId(_) + | ModuleDefOrigin::SubroutineId(_) + | ModuleDefOrigin::SubroutinePort(_) + | ModuleDefOrigin::NonAnsiPort(_) + | ModuleDefOrigin::Decl(_) => return None, }; Some(format!("{kind} {name}")) } -fn render_side_comments(sema: &Semantics<'_, RootDb>, origin: &DefinitionOrigin) -> Option { +fn render_side_comments(sema: &Semantics<'_, RootDb>, origin: &ModuleDefOrigin) -> Option { let db = sema.db; let InFile { value: range, file_id } = origin.range(db)?; @@ -678,7 +678,7 @@ fn render_side_comments(sema: &Semantics<'_, RootDb>, origin: &DefinitionOrigin) } } -fn render_scope_fact(sema: &Semantics, origin: &DefinitionOrigin) -> Option { +fn render_scope_fact(sema: &Semantics, origin: &ModuleDefOrigin) -> Option { // elaboration? let db = sema.db; let InFile { value: range, .. } = origin.range(db)?; @@ -714,7 +714,7 @@ fn render_scope_fact(sema: &Semantics, origin: &DefinitionOrigin) -> Opt fn render_definition_metadata( sema: &Semantics, - origin: &DefinitionOrigin, + origin: &ModuleDefOrigin, anchor_file_id: vfs::FileId, ) -> Option { let mut parts = Vec::new(); diff --git a/crates/ide/src/semantic_index.rs b/crates/ide/src/semantic_index.rs index dc2ca6fd..3e8ba205 100644 --- a/crates/ide/src/semantic_index.rs +++ b/crates/ide/src/semantic_index.rs @@ -5,6 +5,7 @@ use hir::{ }, container::InFile, db::HirDb, + def_id::{ModuleDefId, ModuleDefOrigin}, file::HirFileId, hir_def::{Ident, module::ModuleId}, scope::UnitEntry, @@ -28,22 +29,12 @@ use crate::{ source_root_semantic_index_for_root, }, }, - definitions::{Definition, DefinitionClass, DefinitionOrigin}, + definitions::DefinitionClass, module_resolution::resolve_hir_instantiation_target, references::ReferenceCategory, semantic_target::{SemanticTarget, TargetIntent, resolve_semantic_target}, }; -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub(crate) struct DefinitionKey(Box<[DefinitionOrigin]>); - -impl DefinitionKey { - pub(crate) fn from_definition(definition: &Definition) -> Option { - let origins = definition.origins(); - (!origins.is_empty()).then(|| Self(origins.into_iter().collect())) - } -} - #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct SemanticDefinitionRange { pub file_id: FileId, @@ -96,14 +87,14 @@ pub struct ModuleIndex { #[derive(Debug, Clone, PartialEq, Eq)] pub(crate) struct SemanticIndex { - references_by_definition: FxHashMap, + references_by_definition: FxHashMap, incoming_module_edges: FxHashMap>, outgoing_module_edges: FxHashMap>, } #[derive(Debug, Default)] struct SemanticIndexBuilder { - references_by_definition: FxHashMap, + references_by_definition: FxHashMap, incoming_module_edges: FxHashMap>, outgoing_module_edges: FxHashMap>, } @@ -172,7 +163,7 @@ impl ModuleIndex { impl SemanticModuleDefinition { fn new(db: &dyn HirDb, module_id: ModuleId) -> Option { - let origin = DefinitionOrigin::ModuleId(module_id); + let origin = ModuleDefOrigin::ModuleId(module_id); let name = origin.name(db)?; let InFile { file_id, value: name_range } = origin.name_range(db)?; let InFile { value: full_range, .. } = origin.range(db)?; @@ -206,10 +197,9 @@ impl SemanticIndex { pub(crate) fn references_for_definition( &self, - definition: &Definition, + definition: ModuleDefId, ) -> Option<&SemanticReferenceGroup> { - let key = DefinitionKey::from_definition(definition)?; - self.references_by_definition.get(&key) + self.references_by_definition.get(&definition) } pub(crate) fn incoming_module_edges(&self, module_id: ModuleId) -> &[ModuleCallEdge] { @@ -274,11 +264,11 @@ impl SemanticIndexBuilder { match class { DefinitionClass::Definition(definition) => { - self.collect_definition_token(db, &definition, file_id.file_id(), range, token) + self.collect_definition_token(db, definition, file_id.file_id(), range, token) } DefinitionClass::PortConnShorthand { port, local } => { - self.collect_definition_token(db, &port, file_id.file_id(), range, token); - self.collect_definition_token(db, &local, file_id.file_id(), range, token); + self.collect_definition_token(db, port, file_id.file_id(), range, token); + self.collect_definition_token(db, local, file_id.file_id(), range, token); } DefinitionClass::Ambiguous(_) => {} } @@ -287,20 +277,17 @@ impl SemanticIndexBuilder { fn collect_definition_token( &mut self, db: &RootDb, - definition: &Definition, + definition: ModuleDefId, file_id: FileId, range: TextRange, token: SyntaxTokenWithParent<'_>, ) { - let Some(key) = DefinitionKey::from_definition(definition) else { - return; - }; - let Some(name) = definition.origins().into_iter().find_map(|origin| origin.name(db)) else { + let origins = definition.origins(db); + let Some(name) = origins.iter().find_map(|origin| origin.name(db)) else { return; }; - let definition_ranges = definition - .origins() - .into_iter() + let definition_ranges = origins + .iter() .filter_map(|origin| origin.name_range(db)) .map(|InFile { file_id, value }| SemanticDefinitionRange { file_id: file_id.file_id(), @@ -312,7 +299,7 @@ impl SemanticIndexBuilder { definition_range.file_id == file_id && definition_range.range == range }); - let group = self.references_by_definition.entry(key).or_insert_with(|| { + let group = self.references_by_definition.entry(definition).or_insert_with(|| { SemanticReferenceGroupBuilder { name: name.to_string(), definition_ranges, From f178a4c332a28753f474c462887fe0d9de4cba13 Mon Sep 17 00:00:00 2001 From: hongjr03 Date: Fri, 26 Jun 2026 23:58:56 +0800 Subject: [PATCH 2/2] perf: keep module definition origins inline --- crates/hir/src/def_id.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/hir/src/def_id.rs b/crates/hir/src/def_id.rs index 2d192d89..4b6ae0a2 100644 --- a/crates/hir/src/def_id.rs +++ b/crates/hir/src/def_id.rs @@ -281,7 +281,7 @@ impl ModuleDefOrigin { #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct ModuleDef { - origins: Box<[ModuleDefOrigin]>, + origins: SmallVec<[ModuleDefOrigin; 3]>, } impl ModuleDef { @@ -290,14 +290,14 @@ impl ModuleDef { origins.sort_unstable(); origins.dedup(); - (!origins.is_empty()).then(|| ModuleDef { origins: origins.into_vec().into_boxed_slice() }) + (!origins.is_empty()).then_some(ModuleDef { origins }) } pub fn origins(&self) -> &[ModuleDefOrigin] { &self.origins } - fn into_origins(self) -> Box<[ModuleDefOrigin]> { + fn into_origins(self) -> SmallVec<[ModuleDefOrigin; 3]> { self.origins } } @@ -307,7 +307,7 @@ impl ModuleDef { pub struct ModuleDefId(pub salsa::InternId); impl ModuleDefId { - pub fn origins(self, db: &dyn HirDb) -> Box<[ModuleDefOrigin]> { + pub fn origins(self, db: &dyn HirDb) -> SmallVec<[ModuleDefOrigin; 3]> { db.lookup_intern_module_def(self).into_origins() }