diff --git a/crates/hir-def/src/item_scope.rs b/crates/hir-def/src/item_scope.rs index e96e38eceebc..8fda70214ace 100644 --- a/crates/hir-def/src/item_scope.rs +++ b/crates/hir-def/src/item_scope.rs @@ -16,10 +16,10 @@ use syntax::ast; use crate::{ db::DefDatabase, - per_ns::PerNs, + per_ns::{PerNs, PerNsRes}, visibility::{Visibility, VisibilityExplicitness}, - AdtId, BuiltinType, ConstId, ExternCrateId, FxIndexMap, HasModule, ImplId, LocalModuleId, - Lookup, MacroId, ModuleDefId, ModuleId, TraitId, UseId, + AdtId, BuiltinType, ConstId, CrateRootModuleId, ExternCrateId, FxIndexMap, HasModule, ImplId, + LocalModuleId, Lookup, MacroId, ModuleDefId, ModuleId, TraitId, UseId, }; #[derive(Debug, Default)] @@ -131,10 +131,10 @@ struct DeriveMacroInvocation { derive_call_ids: SmallVec<[Option; 1]>, } -pub(crate) static BUILTIN_SCOPE: LazyLock> = LazyLock::new(|| { +pub(crate) static BUILTIN_SCOPE: LazyLock> = LazyLock::new(|| { BuiltinType::all_builtin_types() .iter() - .map(|(name, ty)| (name.clone(), PerNs::types((*ty).into(), Visibility::Public, None))) + .map(|(name, ty)| (name.clone(), PerNsRes::types((*ty).into(), Visibility::Public, None))) .collect() }); @@ -150,7 +150,7 @@ pub(crate) enum BuiltinShadowMode { /// Legacy macros can only be accessed through special methods like `get_legacy_macros`. /// Other methods will only resolve values, types and module scoped macros only. impl ItemScope { - pub fn entries(&self) -> impl Iterator + '_ { + pub fn entries(&self) -> impl Iterator + '_ { // FIXME: shadowing self.types .keys() @@ -173,57 +173,111 @@ impl ItemScope { .dedup() } - pub fn fully_resolve_import(&self, db: &dyn DefDatabase, mut import: ImportId) -> PerNs { + pub fn fully_resolve_import( + &self, + db: &dyn DefDatabase, + import: ImportId, + ) -> PerNs { let mut res = PerNs::none(); let mut def_map; - let mut scope = self; - while let Some(&m) = scope.use_imports_macros.get(&import) { - match m { - ImportOrDef::Import(i) => { - let module_id = i.import.lookup(db).container; - def_map = module_id.def_map(db); - scope = &def_map[module_id.local_id].scope; - import = i; - } - ImportOrDef::Def(ModuleDefId::MacroId(def)) => { - res.macros = Some((def, Visibility::Public, None)); - break; + { + let mut scope = self; + let mut import = import; + while let Some(&i) = scope.use_imports_macros.get(&import) { + match i { + ImportOrDef::Import(i) => { + let module_id = i.import.lookup(db).container; + def_map = module_id.def_map(db); + scope = &def_map[module_id.local_id].scope; + import = i; + } + ImportOrDef::Def(ModuleDefId::MacroId(def)) => { + res.macros = Some(def); + break; + } + _ => break, } - _ => break, } } - let mut scope = self; - while let Some(&m) = scope.use_imports_types.get(&ImportOrExternCrate::Import(import)) { - match m { - ImportOrDef::Import(i) => { - let module_id = i.import.lookup(db).container; - def_map = module_id.def_map(db); - scope = &def_map[module_id.local_id].scope; - import = i; + { + let mut scope = self; + let mut import = import; + while let Some(&i) = scope.use_imports_types.get(&ImportOrExternCrate::Import(import)) { + match i { + ImportOrDef::Import(i) => { + let module_id = i.import.lookup(db).container; + def_map = module_id.def_map(db); + scope = &def_map[module_id.local_id].scope; + import = i; + } + ImportOrDef::Def(def) => { + res.types = Some(def); + break; + } + ImportOrDef::ExternCrate(extern_crate_id) => { + if let Some(crate_id) = db.extern_crate_decl_data(extern_crate_id).crate_id + { + res.types = Some(ModuleDefId::ModuleId( + CrateRootModuleId::from(crate_id).into(), + )); + } + break; + } } - ImportOrDef::Def(def) => { - res.types = Some((def, Visibility::Public, None)); - break; + } + } + { + let mut scope = self; + let mut import = import; + while let Some(&i) = scope.use_imports_values.get(&import) { + match i { + ImportOrDef::Import(i) => { + let module_id = i.import.lookup(db).container; + def_map = module_id.def_map(db); + scope = &def_map[module_id.local_id].scope; + import = i; + } + ImportOrDef::Def(def) => { + res.values = Some(def); + break; + } + _ => break, } - _ => break, } } - let mut scope = self; - while let Some(&m) = scope.use_imports_values.get(&import) { - match m { - ImportOrDef::Import(i) => { - let module_id = i.import.lookup(db).container; - def_map = module_id.def_map(db); - scope = &def_map[module_id.local_id].scope; - import = i; + res + } + + pub fn resolve_import(&self, import: ImportId) -> PerNs { + let mut res = PerNs::none(); + + if let Some(&i) = self.use_imports_types.get(&ImportOrExternCrate::Import(import)) { + res.types = Some(match i { + ImportOrDef::Import(i) => ImportOrDef::Import(i), + ImportOrDef::Def(def) => ImportOrDef::Def(def), + ImportOrDef::ExternCrate(extern_crate_id) => { + ImportOrDef::ExternCrate(extern_crate_id) } - ImportOrDef::Def(def) => { - res.values = Some((def, Visibility::Public, None)); - break; + }); + } + if let Some(&i) = self.use_imports_values.get(&import) { + res.values = Some(match i { + ImportOrDef::Import(i) => ImportOrDef::Import(i), + ImportOrDef::Def(def) => ImportOrDef::Def(def), + ImportOrDef::ExternCrate(extern_crate_id) => { + ImportOrDef::ExternCrate(extern_crate_id) } - _ => break, - } + }); + } + if let Some(&i) = self.use_imports_macros.get(&import) { + res.macros = Some(match i { + ImportOrDef::Import(i) => ImportOrDef::Import(i), + ImportOrDef::Def(def) => ImportOrDef::Def(def), + ImportOrDef::ExternCrate(extern_crate_id) => { + ImportOrDef::ExternCrate(extern_crate_id) + } + }); } res } @@ -274,8 +328,8 @@ impl ItemScope { } /// Get a name from current module scope, legacy macros are not included - pub(crate) fn get(&self, name: &Name) -> PerNs { - PerNs { + pub(crate) fn get(&self, name: &Name) -> PerNsRes { + PerNsRes { types: self.types.get(name).copied(), values: self.values.get(name).copied(), macros: self.macros.get(name).copied(), @@ -342,7 +396,7 @@ impl ItemScope { .chain(self.unnamed_trait_imports.keys().copied()) } - pub(crate) fn resolutions(&self) -> impl Iterator, PerNs)> + '_ { + pub(crate) fn resolutions(&self) -> impl Iterator, PerNsRes)> + '_ { self.entries().map(|(name, res)| (Some(name.clone()), res)).chain( self.unnamed_trait_imports.iter().map(|(tr, (vis, i))| { ( @@ -476,7 +530,7 @@ impl ItemScope { &mut self, glob_imports: &mut PerNsGlobImports, lookup: (LocalModuleId, Name), - def: PerNs, + def: PerNsRes, import: Option, ) -> bool { let mut changed = false; @@ -797,39 +851,39 @@ impl ItemScope { } } -impl PerNs { +impl PerNsRes { pub(crate) fn from_def( def: ModuleDefId, v: Visibility, has_constructor: bool, import: Option, - ) -> PerNs { + ) -> PerNsRes { match def { - ModuleDefId::ModuleId(_) => PerNs::types(def, v, import), + ModuleDefId::ModuleId(_) => PerNsRes::types(def, v, import), ModuleDefId::FunctionId(_) => { - PerNs::values(def, v, import.and_then(ImportOrExternCrate::into_import)) + PerNsRes::values(def, v, import.and_then(ImportOrExternCrate::into_import)) } ModuleDefId::AdtId(adt) => match adt { - AdtId::UnionId(_) => PerNs::types(def, v, import), - AdtId::EnumId(_) => PerNs::types(def, v, import), + AdtId::UnionId(_) => PerNsRes::types(def, v, import), + AdtId::EnumId(_) => PerNsRes::types(def, v, import), AdtId::StructId(_) => { if has_constructor { - PerNs::both(def, def, v, import) + PerNsRes::both(def, def, v, import) } else { - PerNs::types(def, v, import) + PerNsRes::types(def, v, import) } } }, - ModuleDefId::EnumVariantId(_) => PerNs::both(def, def, v, import), + ModuleDefId::EnumVariantId(_) => PerNsRes::both(def, def, v, import), ModuleDefId::ConstId(_) | ModuleDefId::StaticId(_) => { - PerNs::values(def, v, import.and_then(ImportOrExternCrate::into_import)) + PerNsRes::values(def, v, import.and_then(ImportOrExternCrate::into_import)) } - ModuleDefId::TraitId(_) => PerNs::types(def, v, import), - ModuleDefId::TraitAliasId(_) => PerNs::types(def, v, import), - ModuleDefId::TypeAliasId(_) => PerNs::types(def, v, import), - ModuleDefId::BuiltinType(_) => PerNs::types(def, v, import), + ModuleDefId::TraitId(_) => PerNsRes::types(def, v, import), + ModuleDefId::TraitAliasId(_) => PerNsRes::types(def, v, import), + ModuleDefId::TypeAliasId(_) => PerNsRes::types(def, v, import), + ModuleDefId::BuiltinType(_) => PerNsRes::types(def, v, import), ModuleDefId::MacroId(mac) => { - PerNs::macros(mac, v, import.and_then(ImportOrExternCrate::into_import)) + PerNsRes::macros(mac, v, import.and_then(ImportOrExternCrate::into_import)) } } } diff --git a/crates/hir-def/src/item_tree.rs b/crates/hir-def/src/item_tree.rs index b5bf2feb82a2..694ef155cfe3 100644 --- a/crates/hir-def/src/item_tree.rs +++ b/crates/hir-def/src/item_tree.rs @@ -1158,6 +1158,17 @@ pub enum ImportKind { } impl UseTree { + pub fn find(&self, idx: Idx) -> Option<&UseTree> { + if self.index == idx { + return Some(self); + } + if let UseTreeKind::Prefixed { list, .. } = &self.kind { + list.iter().find_map(|it| it.find(idx)) + } else { + None + } + } + /// Expands the `UseTree` into individually imported `ModPath`s. pub fn expand( &self, diff --git a/crates/hir-def/src/nameres.rs b/crates/hir-def/src/nameres.rs index 9bd7d38f0a64..89fe6e92df51 100644 --- a/crates/hir-def/src/nameres.rs +++ b/crates/hir-def/src/nameres.rs @@ -79,7 +79,7 @@ use crate::{ item_tree::{ItemTreeId, Mod, TreeId}, nameres::{diagnostics::DefDiagnostic, path_resolution::ResolveMode}, path::ModPath, - per_ns::PerNs, + per_ns::PerNsRes, visibility::{Visibility, VisibilityExplicitness}, AstId, BlockId, BlockLoc, CrateRootModuleId, EnumId, EnumVariantId, ExternCrateId, FunctionId, FxIndexMap, LocalModuleId, Lookup, MacroExpander, MacroId, ModuleId, ProcMacroId, UseId, @@ -603,7 +603,7 @@ impl DefMap { path: &ModPath, shadow: BuiltinShadowMode, expected_macro_subns: Option, - ) -> (PerNs, Option) { + ) -> (PerNsRes, Option) { let res = self.resolve_path_fp_with_macro( db, ResolveMode::Other, @@ -621,7 +621,7 @@ impl DefMap { original_module: LocalModuleId, path: &ModPath, shadow: BuiltinShadowMode, - ) -> (PerNs, Option) { + ) -> (PerNsRes, Option) { let res = self.resolve_path_fp_with_macro_single( db, ResolveMode::Other, diff --git a/crates/hir-def/src/nameres/collector.rs b/crates/hir-def/src/nameres/collector.rs index 98b08bcf7086..c4a46a281497 100644 --- a/crates/hir-def/src/nameres/collector.rs +++ b/crates/hir-def/src/nameres/collector.rs @@ -44,7 +44,7 @@ use crate::{ ResolveMode, }, path::{ImportAlias, ModPath, PathKind}, - per_ns::PerNs, + per_ns::PerNsRes, tt, visibility::{RawVisibility, Visibility}, AdtId, AstId, AstIdWithPath, ConstLoc, CrateRootModuleId, EnumLoc, EnumVariantLoc, @@ -112,15 +112,15 @@ enum PartialResolvedImport { /// None of any namespaces is resolved Unresolved, /// One of namespaces is resolved - Indeterminate(PerNs), + Indeterminate(PerNsRes), /// All namespaces are resolved, OR it comes from other crate - Resolved(PerNs), + Resolved(PerNsRes), } impl PartialResolvedImport { - fn namespaces(self) -> PerNs { + fn namespaces(self) -> PerNsRes { match self { - PartialResolvedImport::Unresolved => PerNs::none(), + PartialResolvedImport::Unresolved => PerNsRes::none(), PartialResolvedImport::Indeterminate(ns) | PartialResolvedImport::Resolved(ns) => ns, } } @@ -210,7 +210,7 @@ struct DefCollector<'a> { deps: FxHashMap, glob_imports: FxHashMap>, unresolved_imports: Vec, - indeterminate_imports: Vec<(ImportDirective, PerNs)>, + indeterminate_imports: Vec<(ImportDirective, PerNsRes)>, unresolved_macros: Vec, // We'd like to avoid emitting a diagnostics avalanche when some `extern crate` doesn't // resolve. When we emit diagnostics for unresolved imports, we only do so if the import @@ -634,7 +634,7 @@ impl DefCollector<'_> { self.def_map.modules[module_id].scope.declare(macro_.into()); self.update( module_id, - &[(Some(name), PerNs::macros(macro_.into(), Visibility::Public, None))], + &[(Some(name), PerNsRes::macros(macro_.into(), Visibility::Public, None))], Visibility::Public, None, ); @@ -670,7 +670,7 @@ impl DefCollector<'_> { self.def_map.modules[module_id].scope.declare(macro_.into()); self.update( module_id, - &[(Some(name), PerNs::macros(macro_.into(), Visibility::Public, None))], + &[(Some(name), PerNsRes::macros(macro_.into(), Visibility::Public, None))], vis, None, ); @@ -685,7 +685,7 @@ impl DefCollector<'_> { self.def_map.modules[module_id].scope.declare(macro_.into()); self.update( module_id, - &[(Some(name), PerNs::macros(macro_.into(), Visibility::Public, None))], + &[(Some(name), PerNsRes::macros(macro_.into(), Visibility::Public, None))], Visibility::Public, None, ); @@ -940,7 +940,7 @@ impl DefCollector<'_> { .iter() .map(|&variant| { let name = tree[variant.lookup(self.db).id.value].name.clone(); - let res = PerNs::both(variant.into(), variant.into(), vis, None); + let res = PerNsRes::both(variant.into(), variant.into(), vis, None); (Some(name), res) }) .collect::>(); @@ -961,7 +961,7 @@ impl DefCollector<'_> { &mut self, // The module for which `resolutions` have been resolve module_id: LocalModuleId, - resolutions: &[(Option, PerNs)], + resolutions: &[(Option, PerNsRes)], // Visibility this import will have vis: Visibility, import: Option, @@ -974,9 +974,9 @@ impl DefCollector<'_> { &mut self, // The module for which `resolutions` have been resolved. module_id: LocalModuleId, - resolutions: &[(Option, PerNs)], + resolutions: &[(Option, PerNsRes)], // All resolutions are imported with this visibility; the visibilities in - // the `PerNs` values are ignored and overwritten + // the `PerNsRes` values are ignored and overwritten vis: Visibility, import: Option, depth: usize, @@ -1059,7 +1059,7 @@ impl DefCollector<'_> { &mut self, module_id: LocalModuleId, name: &Name, - mut defs: PerNs, + mut defs: PerNsRes, vis: Visibility, def_import_type: Option, ) -> bool { @@ -1620,7 +1620,7 @@ impl ModCollector<'_, '_> { def_collector.def_map.modules[module_id].scope.declare(id); def_collector.update( module_id, - &[(Some(name.clone()), PerNs::from_def(id, vis, has_constructor, None))], + &[(Some(name.clone()), PerNsRes::from_def(id, vis, has_constructor, None))], vis, None, ) @@ -1725,7 +1725,7 @@ impl ModCollector<'_, '_> { module_id, &[( name.cloned(), - PerNs::types( + PerNsRes::types( resolved.into(), vis, Some(ImportOrExternCrate::ExternCrate(id)), @@ -2136,7 +2136,7 @@ impl ModCollector<'_, '_> { def_map.modules[self.module_id].scope.declare(def); self.def_collector.update( self.module_id, - &[(Some(name), PerNs::from_def(def, vis, false, None))], + &[(Some(name), PerNsRes::from_def(def, vis, false, None))], vis, None, ); diff --git a/crates/hir-def/src/nameres/path_resolution.rs b/crates/hir-def/src/nameres/path_resolution.rs index 29379d007493..f310d0f19f29 100644 --- a/crates/hir-def/src/nameres/path_resolution.rs +++ b/crates/hir-def/src/nameres/path_resolution.rs @@ -21,7 +21,7 @@ use crate::{ item_tree::FieldsShape, nameres::{sub_namespace_match, BlockInfo, BuiltinShadowMode, DefMap, MacroSubNs}, path::{ModPath, PathKind}, - per_ns::PerNs, + per_ns::PerNsRes, visibility::{RawVisibility, Visibility}, AdtId, LocalModuleId, ModuleDefId, }; @@ -40,7 +40,7 @@ pub(super) enum ReachedFixedPoint { #[derive(Debug, Clone)] pub(super) struct ResolvePathResult { - pub(super) resolved_def: PerNs, + pub(super) resolved_def: PerNsRes, pub(super) segment_index: Option, pub(super) reached_fixedpoint: ReachedFixedPoint, pub(super) from_differing_crate: bool, @@ -48,11 +48,11 @@ pub(super) struct ResolvePathResult { impl ResolvePathResult { fn empty(reached_fixedpoint: ReachedFixedPoint) -> ResolvePathResult { - ResolvePathResult::new(PerNs::none(), reached_fixedpoint, None, false) + ResolvePathResult::new(PerNsRes::none(), reached_fixedpoint, None, false) } fn new( - resolved_def: PerNs, + resolved_def: PerNsRes, reached_fixedpoint: ReachedFixedPoint, segment_index: Option, from_differing_crate: bool, @@ -61,7 +61,7 @@ impl ResolvePathResult { } } -impl PerNs { +impl PerNsRes { pub(super) fn filter_macro( mut self, db: &dyn DefDatabase, @@ -223,15 +223,15 @@ impl DefMap { PathKind::DollarCrate(krate) => { if krate == self.krate { cov_mark::hit!(macro_dollar_crate_self); - PerNs::types(self.crate_root().into(), Visibility::Public, None) + PerNsRes::types(self.crate_root().into(), Visibility::Public, None) } else { let def_map = db.crate_def_map(krate); let module = def_map.module_id(Self::ROOT); cov_mark::hit!(macro_dollar_crate_other); - PerNs::types(module.into(), Visibility::Public, None) + PerNsRes::types(module.into(), Visibility::Public, None) } } - PathKind::Crate => PerNs::types(self.crate_root().into(), Visibility::Public, None), + PathKind::Crate => PerNsRes::types(self.crate_root().into(), Visibility::Public, None), // plain import or absolute path in 2015: crate-relative with // fallback to extern prelude (with the simplification in // rust-lang/rust#57745) @@ -318,7 +318,7 @@ impl DefMap { ); } - PerNs::types(module.into(), Visibility::Public, None) + PerNsRes::types(module.into(), Visibility::Public, None) } PathKind::Abs => match self.resolve_path_abs(&mut segments, path) { Either::Left(it) => it, @@ -384,14 +384,14 @@ impl DefMap { &self, segments: &mut impl Iterator, path: &ModPath, - ) -> Either { + ) -> Either { let segment = match segments.next() { Some((_, segment)) => segment, None => return Either::Right(ReachedFixedPoint::Yes), }; if let Some(&(def, extern_crate)) = self.data.extern_prelude.get(segment) { tracing::debug!("absolute path {:?} resolved to crate {:?}", path, def); - Either::Left(PerNs::types( + Either::Left(PerNsRes::types( def.into(), Visibility::Public, extern_crate.map(ImportOrExternCrate::ExternCrate), @@ -404,7 +404,7 @@ impl DefMap { fn resolve_remaining_segments<'a>( &self, segments: impl Iterator, - mut curr_per_ns: PerNs, + mut curr_per_ns: PerNsRes, path: &ModPath, db: &dyn DefDatabase, shadow: BuiltinShadowMode, @@ -478,9 +478,9 @@ impl DefMap { let variant_data = &tree[variant.lookup(db).id.value]; (variant_data.name == *segment).then(|| match variant_data.shape { FieldsShape::Record => { - PerNs::types(variant.into(), Visibility::Public, None) + PerNsRes::types(variant.into(), Visibility::Public, None) } - FieldsShape::Tuple | FieldsShape::Unit => PerNs::both( + FieldsShape::Tuple | FieldsShape::Unit => PerNsRes::both( variant.into(), variant.into(), Visibility::Public, @@ -492,7 +492,7 @@ impl DefMap { Some(res) => res, None => { return ResolvePathResult::new( - PerNs::types(e.into(), vis, imp), + PerNsRes::types(e.into(), vis, imp), ReachedFixedPoint::Yes, Some(i), false, @@ -510,7 +510,7 @@ impl DefMap { ); return ResolvePathResult::new( - PerNs::types(s, vis, imp), + PerNsRes::types(s, vis, imp), ReachedFixedPoint::Yes, Some(i), false, @@ -532,7 +532,7 @@ impl DefMap { name: &Name, shadow: BuiltinShadowMode, expected_macro_subns: Option, - ) -> PerNs { + ) -> PerNsRes { // Resolve in: // - legacy scope of macro // - current module / scope @@ -547,14 +547,14 @@ impl DefMap { .filter(|&id| { sub_namespace_match(Some(MacroSubNs::from_id(db, id)), expected_macro_subns) }) - .map_or_else(PerNs::none, |m| PerNs::macros(m, Visibility::Public, None)); + .map_or_else(PerNsRes::none, |m| PerNsRes::macros(m, Visibility::Public, None)); let from_scope = self[module].scope.get(name).filter_macro(db, expected_macro_subns); let from_builtin = match self.block { Some(_) => { // Only resolve to builtins in the root `DefMap`. - PerNs::none() + PerNsRes::none() } - None => BUILTIN_SCOPE.get(name).copied().unwrap_or_else(PerNs::none), + None => BUILTIN_SCOPE.get(name).copied().unwrap_or_else(PerNsRes::none), }; let from_scope_or_builtin = match shadow { BuiltinShadowMode::Module => from_scope.or(from_builtin), @@ -568,14 +568,14 @@ impl DefMap { if self.block.is_some() && module == DefMap::ROOT { // Don't resolve extern prelude in pseudo-modules of blocks, because // they might been shadowed by local names. - return PerNs::none(); + return PerNsRes::none(); } self.resolve_name_in_extern_prelude(name) }; let macro_use_prelude = || self.resolve_in_macro_use_prelude(name); let prelude = || { if self.block.is_some() && module == DefMap::ROOT { - return PerNs::none(); + return PerNsRes::none(); } self.resolve_in_prelude(db, name) }; @@ -587,7 +587,7 @@ impl DefMap { .or_else(prelude) } - fn resolve_name_in_all_preludes(&self, db: &dyn DefDatabase, name: &Name) -> PerNs { + fn resolve_name_in_all_preludes(&self, db: &dyn DefDatabase, name: &Name) -> PerNsRes { // Resolve in: // - extern prelude / macro_use prelude // - std prelude @@ -598,9 +598,9 @@ impl DefMap { extern_prelude.or_else(macro_use_prelude).or_else(prelude) } - fn resolve_name_in_extern_prelude(&self, name: &Name) -> PerNs { - self.data.extern_prelude.get(name).map_or(PerNs::none(), |&(it, extern_crate)| { - PerNs::types( + fn resolve_name_in_extern_prelude(&self, name: &Name) -> PerNsRes { + self.data.extern_prelude.get(name).map_or(PerNsRes::none(), |&(it, extern_crate)| { + PerNsRes::types( it.into(), Visibility::Public, extern_crate.map(ImportOrExternCrate::ExternCrate), @@ -608,9 +608,9 @@ impl DefMap { }) } - fn resolve_in_macro_use_prelude(&self, name: &Name) -> PerNs { - self.macro_use_prelude.get(name).map_or(PerNs::none(), |&(it, _extern_crate)| { - PerNs::macros( + fn resolve_in_macro_use_prelude(&self, name: &Name) -> PerNsRes { + self.macro_use_prelude.get(name).map_or(PerNsRes::none(), |&(it, _extern_crate)| { + PerNsRes::macros( it, Visibility::Public, // FIXME? @@ -624,7 +624,7 @@ impl DefMap { db: &dyn DefDatabase, module: LocalModuleId, name: &Name, - ) -> PerNs { + ) -> PerNsRes { let from_crate_root = match self.block { Some(_) => { let def_map = self.crate_root().def_map(db); @@ -635,7 +635,7 @@ impl DefMap { let from_extern_prelude = || { if self.block.is_some() && module == DefMap::ROOT { // Don't resolve extern prelude in pseudo-module of a block. - return PerNs::none(); + return PerNsRes::none(); } self.resolve_name_in_extern_prelude(name) }; @@ -643,7 +643,7 @@ impl DefMap { from_crate_root.or_else(from_extern_prelude) } - fn resolve_in_prelude(&self, db: &dyn DefDatabase, name: &Name) -> PerNs { + fn resolve_in_prelude(&self, db: &dyn DefDatabase, name: &Name) -> PerNsRes { if let Some((prelude, _use)) = self.prelude { let keep; let def_map = if prelude.krate == self.krate { @@ -655,7 +655,7 @@ impl DefMap { }; def_map[prelude.local_id].scope.get(name) } else { - PerNs::none() + PerNsRes::none() } } } diff --git a/crates/hir-def/src/path.rs b/crates/hir-def/src/path.rs index 44e132061ad4..df8c7cacbc56 100644 --- a/crates/hir-def/src/path.rs +++ b/crates/hir-def/src/path.rs @@ -32,6 +32,13 @@ pub enum ImportAlias { } impl ImportAlias { + pub fn name(&self) -> Option { + match self { + ImportAlias::Underscore => None, + ImportAlias::Alias(name) => Some(name.clone()), + } + } + pub fn display(&self, edition: Edition) -> impl Display + '_ { ImportAliasDisplay { value: self, edition } } diff --git a/crates/hir-def/src/per_ns.rs b/crates/hir-def/src/per_ns.rs index 3f3b98c6b5b5..3f8751a5f3a9 100644 --- a/crates/hir-def/src/per_ns.rs +++ b/crates/hir-def/src/per_ns.rs @@ -28,14 +28,37 @@ bitflags! { } } +pub type PerNsRes = PerNs< + (ModuleDefId, Visibility, Option), + (ModuleDefId, Visibility, Option), + (MacroId, Visibility, Option), +>; + #[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)] -pub struct PerNs { - pub types: Option<(ModuleDefId, Visibility, Option)>, - pub values: Option<(ModuleDefId, Visibility, Option)>, - pub macros: Option<(MacroId, Visibility, Option)>, +pub struct PerNs { + pub types: Option, + pub values: Option, + pub macros: Option, } -impl PerNs { +impl PerNs { + pub fn none() -> PerNs { + PerNs { types: None, values: None, macros: None } + } + + pub fn map( + self, + types: impl FnOnce(T) -> T2, + values: impl FnOnce(V) -> V2, + macros: impl FnOnce(M) -> M2, + ) -> PerNs { + PerNs { + types: self.types.map(types), + values: self.values.map(values), + macros: self.macros.map(macros), + } + } + pub(crate) fn availability(&self) -> NsAvailability { let mut result = NsAvailability::empty(); result.set(NsAvailability::TYPES, self.types.is_some()); @@ -43,17 +66,21 @@ impl PerNs { result.set(NsAvailability::MACROS, self.macros.is_some()); result } +} - pub fn none() -> PerNs { - PerNs { types: None, values: None, macros: None } +impl PerNs { + pub fn iter(self) -> impl Iterator { + self.types.into_iter().chain(self.values).chain(self.macros) } +} - pub fn values(t: ModuleDefId, v: Visibility, i: Option) -> PerNs { - PerNs { types: None, values: Some((t, v, i)), macros: None } +impl PerNsRes { + pub fn values(t: ModuleDefId, v: Visibility, i: Option) -> PerNsRes { + PerNsRes { types: None, values: Some((t, v, i)), macros: None } } - pub fn types(t: ModuleDefId, v: Visibility, i: Option) -> PerNs { - PerNs { types: Some((t, v, i)), values: None, macros: None } + pub fn types(t: ModuleDefId, v: Visibility, i: Option) -> PerNsRes { + PerNsRes { types: Some((t, v, i)), values: None, macros: None } } pub fn both( @@ -61,16 +88,16 @@ impl PerNs { values: ModuleDefId, v: Visibility, i: Option, - ) -> PerNs { - PerNs { + ) -> PerNsRes { + PerNsRes { types: Some((types, v, i)), values: Some((values, v, i.and_then(ImportOrExternCrate::into_import))), macros: None, } } - pub fn macros(macro_: MacroId, v: Visibility, i: Option) -> PerNs { - PerNs { types: None, values: None, macros: Some((macro_, v, i)) } + pub fn macros(macro_: MacroId, v: Visibility, i: Option) -> PerNsRes { + PerNsRes { types: None, values: None, macros: Some((macro_, v, i)) } } pub fn is_none(&self) -> bool { @@ -105,32 +132,32 @@ impl PerNs { self.macros.map(|it| (it.0, it.2)) } - pub fn filter_visibility(self, mut f: impl FnMut(Visibility) -> bool) -> PerNs { - let _p = tracing::info_span!("PerNs::filter_visibility").entered(); - PerNs { + pub fn filter_visibility(self, mut f: impl FnMut(Visibility) -> bool) -> PerNsRes { + let _p = tracing::info_span!("PerNsRes::filter_visibility").entered(); + PerNsRes { types: self.types.filter(|&(_, v, _)| f(v)), values: self.values.filter(|&(_, v, _)| f(v)), macros: self.macros.filter(|&(_, v, _)| f(v)), } } - pub fn with_visibility(self, vis: Visibility) -> PerNs { - PerNs { + pub fn with_visibility(self, vis: Visibility) -> PerNsRes { + PerNsRes { types: self.types.map(|(it, _, c)| (it, vis, c)), values: self.values.map(|(it, _, c)| (it, vis, c)), macros: self.macros.map(|(it, _, import)| (it, vis, import)), } } - pub fn or(self, other: PerNs) -> PerNs { - PerNs { + pub fn or(self, other: PerNsRes) -> PerNsRes { + PerNsRes { types: self.types.or(other.types), values: self.values.or(other.values), macros: self.macros.or(other.macros), } } - pub fn or_else(self, f: impl FnOnce() -> PerNs) -> PerNs { + pub fn or_else(self, f: impl FnOnce() -> PerNsRes) -> PerNsRes { if self.is_full() { self } else { @@ -139,7 +166,6 @@ impl PerNs { } pub fn iter_items(self) -> impl Iterator)> { - let _p = tracing::info_span!("PerNs::iter_items").entered(); self.types .map(|it| (ItemInNs::Types(it.0), it.2)) .into_iter() diff --git a/crates/hir-def/src/resolver.rs b/crates/hir-def/src/resolver.rs index 316406c151f9..47154a5bb691 100644 --- a/crates/hir-def/src/resolver.rs +++ b/crates/hir-def/src/resolver.rs @@ -23,7 +23,7 @@ use crate::{ lang_item::LangItemTarget, nameres::{DefMap, MacroSubNs}, path::{ModPath, Path, PathKind}, - per_ns::PerNs, + per_ns::PerNsRes, type_ref::{LifetimeRef, TypesMap}, visibility::{RawVisibility, Visibility}, AdtId, ConstId, ConstParamId, CrateRootModuleId, DefWithBodyId, EnumId, EnumVariantId, @@ -157,7 +157,7 @@ impl Resolver { } } - pub fn resolve_module_path_in_items(&self, db: &dyn DefDatabase, path: &ModPath) -> PerNs { + pub fn resolve_module_path_in_items(&self, db: &dyn DefDatabase, path: &ModPath) -> PerNsRes { self.resolve_module_path(db, path, BuiltinShadowMode::Module) } @@ -517,7 +517,7 @@ impl Resolver { // FIXME: should we provide `self` here? // f( // Name::self_param(), - // PerNs::types(Resolution::Def { + // PerNsRes::types(Resolution::Def { // def: m.module.into(), // }), // ); @@ -757,12 +757,12 @@ impl Resolver { db: &dyn DefDatabase, path: &ModPath, shadow: BuiltinShadowMode, - ) -> PerNs { + ) -> PerNsRes { let (item_map, module) = self.item_scope(); // This method resolves `path` just like import paths, so no expected macro subns is given. let (module_res, segment_index) = item_map.resolve_path(db, module, path, shadow, None); if segment_index.is_some() { - return PerNs::none(); + return PerNsRes::none(); } module_res } @@ -965,7 +965,7 @@ impl ModuleItemMap { } } -fn to_value_ns(per_ns: PerNs) -> Option<(ValueNs, Option)> { +fn to_value_ns(per_ns: PerNsRes) -> Option<(ValueNs, Option)> { let (def, import) = per_ns.take_values_import()?; let res = match def { ModuleDefId::FunctionId(it) => ValueNs::FunctionId(it), @@ -985,7 +985,7 @@ fn to_value_ns(per_ns: PerNs) -> Option<(ValueNs, Option)> { Some((res, import)) } -fn to_type_ns(per_ns: PerNs) -> Option<(TypeNs, Option)> { +fn to_type_ns(per_ns: PerNsRes) -> Option<(TypeNs, Option)> { let (def, _, import) = per_ns.take_types_full()?; let res = match def { ModuleDefId::AdtId(it) => TypeNs::AdtId(it), @@ -1018,7 +1018,7 @@ impl ScopeNames { set.push(def) } } - fn add_per_ns(&mut self, name: &Name, def: PerNs) { + fn add_per_ns(&mut self, name: &Name, def: PerNsRes) { if let &Some((ty, _, _)) = &def.types { self.add(name, ScopeDef::ModuleDef(ty)) } diff --git a/crates/hir/src/attrs.rs b/crates/hir/src/attrs.rs index af60c233e551..40727e292b67 100644 --- a/crates/hir/src/attrs.rs +++ b/crates/hir/src/attrs.rs @@ -16,8 +16,8 @@ use span::SyntaxContextId; use crate::{ Adt, AsAssocItem, AssocItem, BuiltinType, Const, ConstParam, DocLinkDef, Enum, ExternCrateDecl, - Field, Function, GenericParam, HasCrate, Impl, LifetimeParam, Macro, Module, ModuleDef, Static, - Struct, Trait, TraitAlias, Type, TypeAlias, TypeParam, Union, Variant, VariantDef, + Field, Function, GenericParam, HasCrate, Impl, Import, LifetimeParam, Macro, Module, ModuleDef, + Static, Struct, Trait, TraitAlias, Type, TypeAlias, TypeParam, Union, Use, Variant, VariantDef, }; pub trait HasAttrs { @@ -55,6 +55,7 @@ impl_has_attrs![ (GenericParam, GenericParamId), (Impl, ImplId), (ExternCrateDecl, ExternCrateId), + (Use, UseId), ]; macro_rules! impl_has_attrs_enum { @@ -73,6 +74,16 @@ macro_rules! impl_has_attrs_enum { impl_has_attrs_enum![Struct, Union, Enum for Adt]; impl_has_attrs_enum![TypeParam, ConstParam, LifetimeParam for GenericParam]; +impl HasAttrs for Import { + fn attrs(self, db: &dyn HirDatabase) -> AttrsWithOwner { + let def = AttrDefId::UseId(self.id.import); + AttrsWithOwner::new(db.upcast(), def) + } + fn attr_id(self) -> AttrDefId { + AttrDefId::UseId(self.id.import) + } +} + impl HasAttrs for AssocItem { fn attrs(self, db: &dyn HirDatabase) -> AttrsWithOwner { match self { diff --git a/crates/hir/src/display.rs b/crates/hir/src/display.rs index 959d62d59519..d0aaf2d6e638 100644 --- a/crates/hir/src/display.rs +++ b/crates/hir/src/display.rs @@ -21,8 +21,8 @@ use itertools::Itertools; use crate::{ Adt, AsAssocItem, AssocItem, AssocItemContainer, Const, ConstParam, Enum, ExternCrateDecl, - Field, Function, GenericParam, HasCrate, HasVisibility, Impl, LifetimeParam, Macro, Module, - SelfParam, Static, Struct, Trait, TraitAlias, TupleField, TyBuilder, Type, TypeAlias, + Field, Function, GenericParam, HasCrate, HasVisibility, Impl, Import, LifetimeParam, Macro, + Module, SelfParam, Static, Struct, Trait, TraitAlias, TupleField, TyBuilder, Type, TypeAlias, TypeOrConstParam, TypeParam, Union, Variant, }; @@ -442,6 +442,32 @@ impl HirDisplay for ExternCrateDecl { } } +impl HirDisplay for Import { + fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { + use hir_def::{item_tree::ImportKind, Lookup}; + + let loc = self.id.import.lookup(f.db.upcast()); + let item_tree = loc.id.item_tree(f.db.upcast()); + let use_ = &item_tree[loc.id.value]; + write_visibility(self.module(f.db).id, self.visibility(f.db), f)?; + f.write_str("use ")?; + // FIXME: short circuit + use_.use_tree.expand(|idx, path, kind, alias| { + if idx == self.id.idx { + _ = write!(f, "{}", path.display(f.db.upcast(), f.edition())); + if let ImportKind::Glob = kind { + _ = write!(f, "*"); + } + if let Some(alias) = alias { + _ = write!(f, " as {}", alias.display(f.edition())); + } + } + }); + + Ok(()) + } +} + impl HirDisplay for GenericParam { fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { match self { diff --git a/crates/hir/src/from_id.rs b/crates/hir/src/from_id.rs index 2ad39817b2fe..0026bb744422 100644 --- a/crates/hir/src/from_id.rs +++ b/crates/hir/src/from_id.rs @@ -5,13 +5,14 @@ use hir_def::{ hir::{BindingId, LabelId}, + item_scope::ImportId, AdtId, AssocItemId, DefWithBodyId, EnumVariantId, FieldId, GenericDefId, GenericParamId, - ModuleDefId, VariantId, + ModuleDefId, UseId, VariantId, }; use crate::{ - Adt, AssocItem, BuiltinType, DefWithBody, Field, GenericDef, GenericParam, ItemInNs, Label, - Local, ModuleDef, Variant, VariantDef, + Adt, AssocItem, BuiltinType, DefWithBody, Field, GenericDef, GenericParam, Import, ItemInNs, + Label, Local, ModuleDef, Use, Variant, VariantDef, }; macro_rules! from_id { @@ -51,6 +52,33 @@ from_id![ (hir_def::ExternCrateId, crate::ExternCrateDecl), ]; +impl From for UseId { + fn from(value: Use) -> Self { + value.id + } +} +impl From for UseId { + fn from(value: Import) -> Self { + value.id.import + } +} +impl From for ImportId { + fn from(value: Import) -> Self { + value.id + } +} + +impl From for Use { + fn from(id: UseId) -> Self { + Use { id } + } +} +impl From for Import { + fn from(id: ImportId) -> Self { + Import { id } + } +} + impl From for Adt { fn from(id: AdtId) -> Self { match id { diff --git a/crates/hir/src/has_source.rs b/crates/hir/src/has_source.rs index 82c90ac30101..ee3a6639da97 100644 --- a/crates/hir/src/has_source.rs +++ b/crates/hir/src/has_source.rs @@ -14,8 +14,8 @@ use tt::TextRange; use crate::{ db::HirDatabase, Adt, Callee, Const, Enum, ExternCrateDecl, Field, FieldSource, Function, Impl, - InlineAsmOperand, Label, LifetimeParam, LocalSource, Macro, Module, Param, SelfParam, Static, - Struct, Trait, TraitAlias, TypeAlias, TypeOrConstParam, Union, Variant, + Import, InlineAsmOperand, Label, LifetimeParam, LocalSource, Macro, Module, Param, SelfParam, + Static, Struct, Trait, TraitAlias, TypeAlias, TypeOrConstParam, Union, Variant, }; pub trait HasSource { @@ -293,6 +293,15 @@ impl HasSource for ExternCrateDecl { } } +impl HasSource for Import { + type Ast = ast::UseTree; + + fn source(self, db: &dyn HirDatabase) -> Option> { + let source = self.id.import.child_source(db.upcast()); + source.map(|it| it.get(self.id.idx).cloned()).transpose() + } +} + impl HasSource for InlineAsmOperand { type Ast = ast::AsmOperandNamed; fn source(self, db: &dyn HirDatabase) -> Option> { diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 10365ba00287..e625f5edb6c1 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -46,19 +46,20 @@ use hir_def::{ data::adt::VariantData, generics::{LifetimeParamData, TypeOrConstParamData, TypeParamProvenance}, hir::{BindingAnnotation, BindingId, ExprId, ExprOrPatId, LabelId, Pat}, - item_tree::{AttrOwner, FieldParent, ItemTreeFieldId, ItemTreeNode}, + item_scope::ImportId, + item_tree::{AttrOwner, FieldParent, ItemTreeFieldId, ItemTreeNode, UseTreeKind}, lang_item::LangItemTarget, layout::{self, ReprOptions, TargetDataLayout}, nameres::{self, diagnostics::DefDiagnostic}, path::ImportAlias, - per_ns::PerNs, + per_ns::{PerNs, PerNsRes}, resolver::{HasResolver, Resolver}, type_ref::TypesSourceMap, AssocItemId, AssocItemLoc, AttrDefId, CallableDefId, ConstId, ConstParamId, CrateRootModuleId, DefWithBodyId, EnumId, EnumVariantId, ExternCrateId, FunctionId, GenericDefId, GenericParamId, HasModule, ImplId, InTypeConstId, ItemContainerId, LifetimeParamId, LocalFieldId, Lookup, MacroExpander, ModuleId, StaticId, StructId, SyntheticSyntax, TraitAliasId, TraitId, TupleId, - TypeAliasId, TypeOrConstParamId, TypeParamId, UnionId, + TypeAliasId, TypeOrConstParamId, TypeParamId, UnionId, UseId, }; use hir_expand::{ attrs::collect_attrs, proc_macro::ProcMacroKind, AstId, MacroCallKind, RenderedExpandError, @@ -2575,6 +2576,124 @@ impl HasVisibility for Function { } } +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum ImportOrDef { + Import(Import), + ExternCrate(ExternCrateDecl), + Def(ModuleDef), +} + +impl From for ImportOrDef { + fn from(import_or_def: hir_def::item_scope::ImportOrDef) -> Self { + match import_or_def { + hir_def::item_scope::ImportOrDef::Import(import) => ImportOrDef::Import(import.into()), + hir_def::item_scope::ImportOrDef::ExternCrate(extern_crate) => { + ImportOrDef::ExternCrate(extern_crate.into()) + } + hir_def::item_scope::ImportOrDef::Def(def) => ImportOrDef::Def(def.into()), + } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct Import { + pub(crate) id: ImportId, +} + +impl Import { + pub fn parent_use(self) -> Use { + Use { id: self.id.import } + } + + pub fn module(self, db: &dyn HirDatabase) -> Module { + self.id.import.module(db.upcast()).into() + } + + pub fn resolve_once( + self, + db: &dyn HirDatabase, + ) -> PerNs { + let module = self.module(db); + module.id.def_map(db.upcast())[module.id.local_id].scope.resolve_import(self.id).map( + From::from, + From::from, + From::from, + ) + } + + pub fn resolve_fully(self, db: &dyn HirDatabase) -> PerNs { + let module = self.module(db); + module.id.def_map(db.upcast())[module.id.local_id] + .scope + .fully_resolve_import(db.upcast(), self.id) + .map(From::from, From::from, |it| ModuleDefId::from(it).into()) + } + + pub fn name(self, db: &dyn HirDatabase) -> Option { + let loc = self.id.import.lookup(db.upcast()); + let item_tree = loc.id.item_tree(db.upcast()); + let use_ = &item_tree[loc.id.value]; + use_.use_tree.find(self.id.idx).and_then(|it| match it.kind() { + UseTreeKind::Single { path, .. } => path.segments().last().cloned(), + _ => None, + }) + } + + pub fn alias(self, db: &dyn HirDatabase) -> Option { + let loc = self.id.import.lookup(db.upcast()); + let item_tree = loc.id.item_tree(db.upcast()); + let use_ = &item_tree[loc.id.value]; + use_.use_tree.find(self.id.idx).and_then(|it| match it.kind() { + UseTreeKind::Single { alias, .. } => alias.clone(), + _ => None, + }) + } + + /// Returns the name under which this crate is made accessible, taking `_` into account. + pub fn alias_or_name(self, db: &dyn HirDatabase) -> Option { + let loc = self.id.import.lookup(db.upcast()); + let item_tree = loc.id.item_tree(db.upcast()); + let use_ = &item_tree[loc.id.value]; + use_.use_tree.find(self.id.idx).and_then(|it| match it.kind() { + UseTreeKind::Single { path, alias } => match alias { + Some(ImportAlias::Underscore) => None, + Some(ImportAlias::Alias(alias)) => Some(alias.clone()), + None => path.segments().last().cloned(), + }, + _ => None, + }) + } +} + +impl HasVisibility for Import { + fn visibility(&self, db: &dyn HirDatabase) -> Visibility { + let loc = self.id.import.lookup(db.upcast()); + let item_tree = loc.id.item_tree(db.upcast()); + let use_ = &item_tree[loc.id.value]; + item_tree[use_.visibility].resolve(db.upcast(), &self.id.import.resolver(db.upcast())) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct Use { + pub(crate) id: UseId, +} + +impl Use { + pub fn module(self, db: &dyn HirDatabase) -> Module { + self.id.module(db.upcast()).into() + } +} + +impl HasVisibility for Use { + fn visibility(&self, db: &dyn HirDatabase) -> Visibility { + let loc = self.id.lookup(db.upcast()); + let item_tree = loc.id.item_tree(db.upcast()); + let use_ = &item_tree[loc.id.value]; + item_tree[use_.visibility].resolve(db.upcast(), &self.id.resolver(db.upcast())) + } +} + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct ExternCrateDecl { pub(crate) id: ExternCrateId, @@ -5690,7 +5809,7 @@ pub enum ScopeDef { } impl ScopeDef { - pub fn all_items(def: PerNs) -> ArrayVec { + pub fn all_items(def: PerNsRes) -> ArrayVec { let mut items = ArrayVec::new(); match (def.take_types(), def.take_values()) { @@ -5910,6 +6029,18 @@ impl HasContainer for ExternCrateDecl { } } +impl HasContainer for Use { + fn container(&self, db: &dyn HirDatabase) -> ItemContainer { + container_id_to_hir(self.id.lookup(db.upcast()).container.into()) + } +} + +impl HasContainer for Import { + fn container(&self, db: &dyn HirDatabase) -> ItemContainer { + container_id_to_hir(self.id.import.lookup(db.upcast()).container.into()) + } +} + impl HasContainer for Module { fn container(&self, db: &dyn HirDatabase) -> ItemContainer { // FIXME: handle block expressions as modules (their parent is in a different DefMap) diff --git a/crates/hir/src/symbols.rs b/crates/hir/src/symbols.rs index f8416f86bf9f..82243e11b4ff 100644 --- a/crates/hir/src/symbols.rs +++ b/crates/hir/src/symbols.rs @@ -1,8 +1,9 @@ //! File symbol extraction. +use std::convert::identity; + use hir_def::{ db::DefDatabase, - item_scope::ItemInNs, src::{HasChildSource, HasSource}, AdtId, AssocItemId, DefWithBodyId, HasModule, ImplId, Lookup, MacroId, ModuleDefId, ModuleId, TraitId, @@ -151,8 +152,6 @@ impl<'a> SymbolCollector<'a> { } // Record renamed imports. - // FIXME: In case it imports multiple items under different namespaces we just pick one arbitrarily - // for now. for id in scope.imports() { let source = id.import.child_source(self.db.upcast()); let Some(use_tree_src) = source.value.get(id.idx) else { continue }; @@ -160,12 +159,8 @@ impl<'a> SymbolCollector<'a> { let Some(name) = rename.name() else { continue }; let res = scope.fully_resolve_import(self.db.upcast(), id); - res.iter_items().for_each(|(item, _)| { - let def = match item { - ItemInNs::Types(def) | ItemInNs::Values(def) => def, - ItemInNs::Macros(def) => ModuleDefId::from(def), - } - .into(); + res.map(identity, identity, ModuleDefId::from).iter().for_each(|def| { + let def = def.into(); let dec_loc = DeclarationLocation { hir_file_id: source.file_id, ptr: SyntaxNodePtr::new(use_tree_src.syntax()), diff --git a/crates/ide-db/src/defs.rs b/crates/ide-db/src/defs.rs index 932ca373020d..a573bfe38077 100644 --- a/crates/ide-db/src/defs.rs +++ b/crates/ide-db/src/defs.rs @@ -13,9 +13,9 @@ use either::Either; use hir::{ Adt, AsAssocItem, AsExternAssocItem, AssocItem, AttributeTemplate, BuiltinAttr, BuiltinType, Const, Crate, DefWithBody, DeriveHelper, DocLinkDef, ExternAssocItem, ExternCrateDecl, Field, - Function, GenericParam, HasVisibility, HirDisplay, Impl, InlineAsmOperand, Label, Local, Macro, - Module, ModuleDef, Name, PathResolution, Semantics, Static, StaticLifetime, Struct, ToolModule, - Trait, TraitAlias, TupleField, TypeAlias, Variant, VariantDef, Visibility, + Function, GenericParam, HasVisibility, HirDisplay, Impl, Import, InlineAsmOperand, Label, + Local, Macro, Module, ModuleDef, Name, PathResolution, Semantics, Static, StaticLifetime, + Struct, ToolModule, Trait, TraitAlias, TupleField, TypeAlias, Variant, VariantDef, Visibility, }; use span::Edition; use stdx::{format_to, impl_from}; @@ -49,6 +49,7 @@ pub enum Definition { BuiltinAttr(BuiltinAttr), ToolModule(ToolModule), ExternCrateDecl(ExternCrateDecl), + Import(Import), InlineAsmRegOrRegClass(()), InlineAsmOperand(InlineAsmOperand), } @@ -83,6 +84,7 @@ impl Definition { Definition::GenericParam(it) => it.module(db), Definition::Label(it) => it.module(db), Definition::ExternCrateDecl(it) => it.module(db), + Definition::Import(it) => it.module(db), Definition::DeriveHelper(it) => it.derive().module(db), Definition::InlineAsmOperand(it) => it.parent(db).module(db), Definition::BuiltinAttr(_) @@ -115,6 +117,7 @@ impl Definition { Definition::TypeAlias(it) => it.visibility(db), Definition::Variant(it) => it.visibility(db), Definition::ExternCrateDecl(it) => it.visibility(db), + Definition::Import(it) => it.visibility(db), Definition::BuiltinType(_) | Definition::TupleField(_) => Visibility::Public, Definition::Macro(_) => return None, Definition::BuiltinAttr(_) @@ -155,6 +158,7 @@ impl Definition { Definition::ToolModule(_) => return None, // FIXME Definition::DeriveHelper(it) => it.name(db), Definition::ExternCrateDecl(it) => return it.alias_or_name(db), + Definition::Import(it) => return it.alias_or_name(db), Definition::InlineAsmRegOrRegClass(_) => return None, Definition::InlineAsmOperand(op) => return op.name(db), }; @@ -207,6 +211,7 @@ impl Definition { Definition::GenericParam(_) => None, Definition::Label(_) => None, Definition::ExternCrateDecl(it) => it.docs(db), + Definition::Import(it) => it.docs(db), Definition::BuiltinAttr(it) => { let name = it.name(db); @@ -283,6 +288,7 @@ impl Definition { Definition::GenericParam(it) => it.display(db, edition).to_string(), Definition::Label(it) => it.name(db).display(db, edition).to_string(), Definition::ExternCrateDecl(it) => it.display(db, edition).to_string(), + Definition::Import(it) => it.display(db, edition).to_string(), Definition::BuiltinAttr(it) => format!("#[{}]", it.name(db).display(db, edition)), Definition::ToolModule(it) => it.name(db).display(db, edition).to_string(), Definition::DeriveHelper(it) => { diff --git a/crates/ide-db/src/documentation.rs b/crates/ide-db/src/documentation.rs index b52a325790b1..73673b2321a9 100644 --- a/crates/ide-db/src/documentation.rs +++ b/crates/ide-db/src/documentation.rs @@ -1,4 +1,5 @@ //! Documentation attribute related utilities. + use either::Either; use hir::{ db::{DefDatabase, HirDatabase}, @@ -178,7 +179,7 @@ macro_rules! impl_has_docs { impl_has_docs![ Variant, Field, Static, Const, Trait, TraitAlias, TypeAlias, Macro, Function, Adt, Module, - Impl, + Impl, Use, ]; macro_rules! impl_has_docs_enum { @@ -226,17 +227,59 @@ impl HasDocs for hir::AssocItem { impl HasDocs for hir::ExternCrateDecl { fn docs(self, db: &dyn HirDatabase) -> Option { - let crate_docs = - docs_from_attrs(&self.resolved_crate(db)?.root_module().attrs(db)).map(String::from); + let crate_docs = self.resolved_crate(db)?.root_module().docs(db); let decl_docs = docs_from_attrs(&self.attrs(db)).map(String::from); match (decl_docs, crate_docs) { (None, None) => None, (Some(decl_docs), None) => Some(decl_docs), - (None, Some(crate_docs)) => Some(crate_docs), + (None, Some(crate_docs)) => return Some(crate_docs), (Some(mut decl_docs), Some(crate_docs)) => { decl_docs.push('\n'); decl_docs.push('\n'); - decl_docs += &crate_docs; + decl_docs += crate_docs.as_str(); + Some(decl_docs) + } + } + .map(Documentation::new) + } + fn resolve_doc_path( + self, + db: &dyn HirDatabase, + link: &str, + ns: Option, + ) -> Option { + resolve_doc_path_on(db, self, link, ns) + } +} + +impl HasDocs for hir::Import { + fn docs(self, db: &dyn HirDatabase) -> Option { + let target_docs = self.resolve_once(db).iter().next().and_then(|it| match it { + hir::ImportOrDef::Import(it) => it.docs(db), + hir::ImportOrDef::ExternCrate(it) => it.docs(db), + hir::ImportOrDef::Def(it) => match it { + hir::ModuleDef::Module(it) => it.docs(db), + hir::ModuleDef::Function(it) => it.docs(db), + hir::ModuleDef::Adt(it) => it.docs(db), + hir::ModuleDef::Variant(it) => it.docs(db), + hir::ModuleDef::Const(it) => it.docs(db), + hir::ModuleDef::Static(it) => it.docs(db), + hir::ModuleDef::Trait(it) => it.docs(db), + hir::ModuleDef::TraitAlias(it) => it.docs(db), + hir::ModuleDef::TypeAlias(it) => it.docs(db), + hir::ModuleDef::Macro(it) => it.docs(db), + hir::ModuleDef::BuiltinType(_) => None, + }, + }); + let decl_docs = docs_from_attrs(&self.attrs(db)).map(String::from); + match (decl_docs, target_docs) { + (None, None) => None, + (Some(decl_docs), None) => Some(decl_docs), + (None, Some(target_docs)) => return Some(target_docs), + (Some(mut decl_docs), Some(target_docs)) => { + decl_docs.push('\n'); + decl_docs.push('\n'); + decl_docs += target_docs.as_str(); Some(decl_docs) } } diff --git a/crates/ide-db/src/rename.rs b/crates/ide-db/src/rename.rs index 1d1679c3ff88..d9e28dcc54e8 100644 --- a/crates/ide-db/src/rename.rs +++ b/crates/ide-db/src/rename.rs @@ -200,6 +200,20 @@ impl Definition { .and_then(syn_ctx_is_root) } } + Definition::Import(it) => { + let src = sema.source(it)?; + if let Some(rename) = src.value.rename() { + let name = rename.name()?; + src.with_value(name.syntax()) + .original_file_range_opt(sema.db) + .and_then(syn_ctx_is_root) + } else { + let name = src.value.path()?.segment()?.name_ref()?; + src.with_value(name.syntax()) + .original_file_range_opt(sema.db) + .and_then(syn_ctx_is_root) + } + } Definition::InlineAsmOperand(it) => name_range(it, sema).and_then(syn_ctx_is_root), Definition::BuiltinType(_) | Definition::BuiltinLifetime(_) diff --git a/crates/ide-db/src/test_data/test_symbol_index_collection.txt b/crates/ide-db/src/test_data/test_symbol_index_collection.txt index 9d70942199c8..f95368f5e2e2 100644 --- a/crates/ide-db/src/test_data/test_symbol_index_collection.txt +++ b/crates/ide-db/src/test_data/test_symbol_index_collection.txt @@ -877,6 +877,37 @@ }, }, [ + FileSymbol { + name: "IsThisJustATrait", + def: Trait( + Trait { + id: TraitId( + 0, + ), + }, + ), + loc: DeclarationLocation { + hir_file_id: EditionedFileId( + FileId( + 1, + ), + Edition2021, + ), + ptr: SyntaxNodePtr { + kind: USE_TREE, + range: 111..143, + }, + name_ptr: AstPtr( + SyntaxNodePtr { + kind: NAME, + range: 127..143, + }, + ), + }, + container_name: None, + is_alias: false, + is_assoc: false, + }, FileSymbol { name: "IsThisJustATrait", def: Macro( diff --git a/crates/ide/src/doc_links.rs b/crates/ide/src/doc_links.rs index ea16a11d56d0..c4c65c673c47 100644 --- a/crates/ide/src/doc_links.rs +++ b/crates/ide/src/doc_links.rs @@ -211,6 +211,7 @@ pub(crate) fn resolve_doc_path_for_def( Definition::Field(it) => it.resolve_doc_path(db, link, ns), Definition::SelfType(it) => it.resolve_doc_path(db, link, ns), Definition::ExternCrateDecl(it) => it.resolve_doc_path(db, link, ns), + Definition::Import(it) => it.resolve_doc_path(db, link, ns), Definition::BuiltinAttr(_) | Definition::BuiltinType(_) | Definition::BuiltinLifetime(_) @@ -667,6 +668,9 @@ fn filename_and_frag_for_def( Definition::ExternCrateDecl(it) => { format!("{}/index.html", it.name(db).unescaped().display(db.upcast())) } + Definition::Import(it) => { + return filename_and_frag_for_def(db, it.resolve_fully(db).iter().next()?.into()) + } Definition::Local(_) | Definition::GenericParam(_) | Definition::TupleField(_) diff --git a/crates/ide/src/moniker.rs b/crates/ide/src/moniker.rs index 14781b212969..9cb51a6db9a9 100644 --- a/crates/ide/src/moniker.rs +++ b/crates/ide/src/moniker.rs @@ -229,6 +229,9 @@ pub(crate) fn def_to_kind(db: &RootDatabase, def: Definition) -> SymbolInformati Definition::ToolModule(..) => Module, Definition::ExternCrateDecl(..) => Module, Definition::InlineAsmRegOrRegClass(..) => Module, + Definition::Import(_) => { + unreachable!() + } } } @@ -378,6 +381,9 @@ pub(crate) fn def_to_moniker( Definition::ExternCrateDecl(m) => { MonikerDescriptor { name: m.name(db).display(db, edition).to_string(), desc } } + Definition::Import(_) => { + unreachable!() + } }; description.push(name_desc); diff --git a/crates/ide/src/navigation_target.rs b/crates/ide/src/navigation_target.rs index 9259243db85d..369bbf175967 100644 --- a/crates/ide/src/navigation_target.rs +++ b/crates/ide/src/navigation_target.rs @@ -238,6 +238,7 @@ impl TryToNav for Definition { Definition::TraitAlias(it) => it.try_to_nav(db), Definition::TypeAlias(it) => it.try_to_nav(db), Definition::ExternCrateDecl(it) => it.try_to_nav(db), + Definition::Import(it) => it.try_to_nav(db), Definition::InlineAsmOperand(it) => it.try_to_nav(db), Definition::BuiltinLifetime(_) | Definition::BuiltinType(_) @@ -453,6 +454,36 @@ impl TryToNav for hir::ExternCrateDecl { } } +impl TryToNav for hir::Import { + fn try_to_nav(&self, db: &RootDatabase) -> Option> { + let src = self.source(db)?; + let name = self.alias_or_name(db).or_else(|| self.name(db))?; + let InFile { file_id, value } = src; + let focus = value.rename().map_or_else( + || value.path().and_then(|it| it.segment()).map(Either::Left), + |it| it.name().map(Either::Right), + ); + let edition = self.module(db).krate().edition(db); + + Some(orig_range_with_focus(db, file_id, value.syntax(), focus).map( + |(FileRange { file_id, range: full_range }, focus_range)| { + let mut res = NavigationTarget::from_syntax( + file_id, + name.display_no_db(edition).to_smolstr(), + focus_range, + full_range, + SymbolKind::Module, + ); + + res.docs = self.docs(db); + res.description = Some(self.display(db, edition).to_string()); + res.container_name = container_name(db, *self, edition); + res + }, + )) + } +} + impl TryToNav for hir::Field { fn try_to_nav(&self, db: &RootDatabase) -> Option> { let src = self.source(db)?; diff --git a/crates/ide/src/syntax_highlighting/highlight.rs b/crates/ide/src/syntax_highlighting/highlight.rs index 3767a3917ce7..1d7baa26f028 100644 --- a/crates/ide/src/syntax_highlighting/highlight.rs +++ b/crates/ide/src/syntax_highlighting/highlight.rs @@ -538,6 +538,9 @@ pub(super) fn highlight_def( } highlight } + Definition::Import(_) => { + unreachable!() + } Definition::Label(_) => Highlight::new(HlTag::Symbol(SymbolKind::Label)), Definition::BuiltinAttr(_) => Highlight::new(HlTag::Symbol(SymbolKind::BuiltinAttr)), Definition::ToolModule(_) => Highlight::new(HlTag::Symbol(SymbolKind::ToolModule)), diff --git a/crates/ide/src/syntax_highlighting/inject.rs b/crates/ide/src/syntax_highlighting/inject.rs index 5583f1bc8df9..10b4a05e6d16 100644 --- a/crates/ide/src/syntax_highlighting/inject.rs +++ b/crates/ide/src/syntax_highlighting/inject.rs @@ -317,6 +317,7 @@ fn module_def_to_hl_tag(def: Definition) -> HlTag { Definition::DeriveHelper(_) => SymbolKind::DeriveHelper, Definition::InlineAsmRegOrRegClass(_) => SymbolKind::InlineAsmRegOrRegClass, Definition::InlineAsmOperand(_) => SymbolKind::Local, + Definition::Import(_) => unreachable!(), }; HlTag::Symbol(symbol) }