1 //! Maps *syntax* of various definitions to their semantic ids. 2 //! 3 //! This is a very interesting module, and, in some sense, can be considered the 4 //! heart of the IDE parts of rust-analyzer. 5 //! 6 //! This module solves the following problem: 7 //! 8 //! Given a piece of syntax, find the corresponding semantic definition (def). 9 //! 10 //! This problem is a part of more-or-less every IDE feature implemented. Every 11 //! IDE functionality (like goto to definition), conceptually starts with a 12 //! specific cursor position in a file. Starting with this text offset, we first 13 //! figure out what syntactic construct are we at: is this a pattern, an 14 //! expression, an item definition. 15 //! 16 //! Knowing only the syntax gives us relatively little info. For example, 17 //! looking at the syntax of the function we can realize that it is a part of an 18 //! `impl` block, but we won't be able to tell what trait function the current 19 //! function overrides, and whether it does that correctly. For that, we need to 20 //! go from [`ast::Fn`] to [`crate::Function`], and that's exactly what this 21 //! module does. 22 //! 23 //! As syntax trees are values and don't know their place of origin/identity, 24 //! this module also requires [`InFile`] wrappers to understand which specific 25 //! real or macro-expanded file the tree comes from. 26 //! 27 //! The actual algorithm to resolve syntax to def is curious in two aspects: 28 //! 29 //! * It is recursive 30 //! * It uses the inverse algorithm (what is the syntax for this def?) 31 //! 32 //! Specifically, the algorithm goes like this: 33 //! 34 //! 1. Find the syntactic container for the syntax. For example, field's 35 //! container is the struct, and structs container is a module. 36 //! 2. Recursively get the def corresponding to container. 37 //! 3. Ask the container def for all child defs. These child defs contain 38 //! the answer and answer's siblings. 39 //! 4. For each child def, ask for it's source. 40 //! 5. The child def whose source is the syntax node we've started with 41 //! is the answer. 42 //! 43 //! It's interesting that both Roslyn and Kotlin contain very similar code 44 //! shape. 45 //! 46 //! Let's take a look at Roslyn: 47 //! 48 //! <https://github.com/dotnet/roslyn/blob/36a0c338d6621cc5fe34b79d414074a95a6a489c/src/Compilers/CSharp/Portable/Compilation/SyntaxTreeSemanticModel.cs#L1403-L1429> 49 //! <https://sourceroslyn.io/#Microsoft.CodeAnalysis.CSharp/Compilation/SyntaxTreeSemanticModel.cs,1403> 50 //! 51 //! The `GetDeclaredType` takes `Syntax` as input, and returns `Symbol` as 52 //! output. First, it retrieves a `Symbol` for parent `Syntax`: 53 //! 54 //! * <https://sourceroslyn.io/#Microsoft.CodeAnalysis.CSharp/Compilation/SyntaxTreeSemanticModel.cs,1423> 55 //! 56 //! Then, it iterates parent symbol's children, looking for one which has the 57 //! same text span as the original node: 58 //! 59 //! <https://sourceroslyn.io/#Microsoft.CodeAnalysis.CSharp/Compilation/SyntaxTreeSemanticModel.cs,1786> 60 //! 61 //! Now, let's look at Kotlin: 62 //! 63 //! <https://github.com/JetBrains/kotlin/blob/a288b8b00e4754a1872b164999c6d3f3b8c8994a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/FirModuleResolveStateImpl.kt#L93-L125> 64 //! 65 //! This function starts with a syntax node (`KtExpression` is syntax, like all 66 //! `Kt` nodes), and returns a def. It uses 67 //! `getNonLocalContainingOrThisDeclaration` to get syntactic container for a 68 //! current node. Then, `findSourceNonLocalFirDeclaration` gets `Fir` for this 69 //! parent. Finally, `findElementIn` function traverses `Fir` children to find 70 //! one with the same source we originally started with. 71 //! 72 //! One question is left though -- where does the recursion stops? This happens 73 //! when we get to the file syntax node, which doesn't have a syntactic parent. 74 //! In that case, we loop through all the crates that might contain this file 75 //! and look for a module whose source is the given file. 76 //! 77 //! Note that the logic in this module is somewhat fundamentally imprecise -- 78 //! due to conditional compilation and `#[path]` attributes, there's no 79 //! injective mapping from syntax nodes to defs. This is not an edge case -- 80 //! more or less every item in a `lib.rs` is a part of two distinct crates: a 81 //! library with `--cfg test` and a library without. 82 //! 83 //! At the moment, we don't really handle this well and return the first answer 84 //! that works. Ideally, we should first let the caller to pick a specific 85 //! active crate for a given position, and then provide an API to resolve all 86 //! syntax nodes against this specific crate. 87 88 use base_db::FileId; 89 use hir_def::{ 90 child_by_source::ChildBySource, 91 dyn_map::{ 92 keys::{self, Key}, 93 DynMap, 94 }, 95 hir::{BindingId, LabelId}, 96 AdtId, ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId, FieldId, FunctionId, 97 GenericDefId, GenericParamId, ImplId, LifetimeParamId, MacroId, ModuleId, StaticId, StructId, 98 TraitAliasId, TraitId, TypeAliasId, TypeParamId, UnionId, VariantId, 99 }; 100 use hir_expand::{attrs::AttrId, name::AsName, HirFileId, MacroCallId}; 101 use rustc_hash::FxHashMap; 102 use smallvec::SmallVec; 103 use stdx::{impl_from, never}; 104 use syntax::{ 105 ast::{self, HasName}, 106 AstNode, SyntaxNode, 107 }; 108 109 use crate::{db::HirDatabase, InFile}; 110 111 pub(super) type SourceToDefCache = FxHashMap<(ChildContainer, HirFileId), DynMap>; 112 113 pub(super) struct SourceToDefCtx<'a, 'b> { 114 pub(super) db: &'b dyn HirDatabase, 115 pub(super) cache: &'a mut SourceToDefCache, 116 } 117 118 impl SourceToDefCtx<'_, '_> { file_to_def(&self, file: FileId) -> SmallVec<[ModuleId; 1]>119 pub(super) fn file_to_def(&self, file: FileId) -> SmallVec<[ModuleId; 1]> { 120 let _p = profile::span("SourceBinder::to_module_def"); 121 let mut mods = SmallVec::new(); 122 for &crate_id in self.db.relevant_crates(file).iter() { 123 // FIXME: inner items 124 let crate_def_map = self.db.crate_def_map(crate_id); 125 mods.extend( 126 crate_def_map 127 .modules_for_file(file) 128 .map(|local_id| crate_def_map.module_id(local_id)), 129 ) 130 } 131 mods 132 } 133 module_to_def(&self, src: InFile<ast::Module>) -> Option<ModuleId>134 pub(super) fn module_to_def(&self, src: InFile<ast::Module>) -> Option<ModuleId> { 135 let _p = profile::span("module_to_def"); 136 let parent_declaration = src 137 .syntax() 138 .ancestors_with_macros_skip_attr_item(self.db.upcast()) 139 .find_map(|it| it.map(ast::Module::cast).transpose()); 140 141 let parent_module = match parent_declaration { 142 Some(parent_declaration) => self.module_to_def(parent_declaration), 143 None => { 144 let file_id = src.file_id.original_file(self.db.upcast()); 145 self.file_to_def(file_id).get(0).copied() 146 } 147 }?; 148 149 let child_name = src.value.name()?.as_name(); 150 let def_map = parent_module.def_map(self.db.upcast()); 151 let &child_id = def_map[parent_module.local_id].children.get(&child_name)?; 152 Some(def_map.module_id(child_id)) 153 } 154 source_file_to_def(&self, src: InFile<ast::SourceFile>) -> Option<ModuleId>155 pub(super) fn source_file_to_def(&self, src: InFile<ast::SourceFile>) -> Option<ModuleId> { 156 let _p = profile::span("source_file_to_def"); 157 let file_id = src.file_id.original_file(self.db.upcast()); 158 self.file_to_def(file_id).get(0).copied() 159 } 160 trait_to_def(&mut self, src: InFile<ast::Trait>) -> Option<TraitId>161 pub(super) fn trait_to_def(&mut self, src: InFile<ast::Trait>) -> Option<TraitId> { 162 self.to_def(src, keys::TRAIT) 163 } trait_alias_to_def( &mut self, src: InFile<ast::TraitAlias>, ) -> Option<TraitAliasId>164 pub(super) fn trait_alias_to_def( 165 &mut self, 166 src: InFile<ast::TraitAlias>, 167 ) -> Option<TraitAliasId> { 168 self.to_def(src, keys::TRAIT_ALIAS) 169 } impl_to_def(&mut self, src: InFile<ast::Impl>) -> Option<ImplId>170 pub(super) fn impl_to_def(&mut self, src: InFile<ast::Impl>) -> Option<ImplId> { 171 self.to_def(src, keys::IMPL) 172 } fn_to_def(&mut self, src: InFile<ast::Fn>) -> Option<FunctionId>173 pub(super) fn fn_to_def(&mut self, src: InFile<ast::Fn>) -> Option<FunctionId> { 174 self.to_def(src, keys::FUNCTION) 175 } struct_to_def(&mut self, src: InFile<ast::Struct>) -> Option<StructId>176 pub(super) fn struct_to_def(&mut self, src: InFile<ast::Struct>) -> Option<StructId> { 177 self.to_def(src, keys::STRUCT) 178 } enum_to_def(&mut self, src: InFile<ast::Enum>) -> Option<EnumId>179 pub(super) fn enum_to_def(&mut self, src: InFile<ast::Enum>) -> Option<EnumId> { 180 self.to_def(src, keys::ENUM) 181 } union_to_def(&mut self, src: InFile<ast::Union>) -> Option<UnionId>182 pub(super) fn union_to_def(&mut self, src: InFile<ast::Union>) -> Option<UnionId> { 183 self.to_def(src, keys::UNION) 184 } static_to_def(&mut self, src: InFile<ast::Static>) -> Option<StaticId>185 pub(super) fn static_to_def(&mut self, src: InFile<ast::Static>) -> Option<StaticId> { 186 self.to_def(src, keys::STATIC) 187 } const_to_def(&mut self, src: InFile<ast::Const>) -> Option<ConstId>188 pub(super) fn const_to_def(&mut self, src: InFile<ast::Const>) -> Option<ConstId> { 189 self.to_def(src, keys::CONST) 190 } type_alias_to_def(&mut self, src: InFile<ast::TypeAlias>) -> Option<TypeAliasId>191 pub(super) fn type_alias_to_def(&mut self, src: InFile<ast::TypeAlias>) -> Option<TypeAliasId> { 192 self.to_def(src, keys::TYPE_ALIAS) 193 } record_field_to_def(&mut self, src: InFile<ast::RecordField>) -> Option<FieldId>194 pub(super) fn record_field_to_def(&mut self, src: InFile<ast::RecordField>) -> Option<FieldId> { 195 self.to_def(src, keys::RECORD_FIELD) 196 } tuple_field_to_def(&mut self, src: InFile<ast::TupleField>) -> Option<FieldId>197 pub(super) fn tuple_field_to_def(&mut self, src: InFile<ast::TupleField>) -> Option<FieldId> { 198 self.to_def(src, keys::TUPLE_FIELD) 199 } enum_variant_to_def( &mut self, src: InFile<ast::Variant>, ) -> Option<EnumVariantId>200 pub(super) fn enum_variant_to_def( 201 &mut self, 202 src: InFile<ast::Variant>, 203 ) -> Option<EnumVariantId> { 204 self.to_def(src, keys::VARIANT) 205 } 206 pub(super) fn adt_to_def( 207 &mut self, 208 InFile { file_id, value }: InFile<ast::Adt>, 209 ) -> Option<AdtId> { 210 match value { 211 ast::Adt::Enum(it) => self.enum_to_def(InFile::new(file_id, it)).map(AdtId::EnumId), 212 ast::Adt::Struct(it) => { 213 self.struct_to_def(InFile::new(file_id, it)).map(AdtId::StructId) 214 } 215 ast::Adt::Union(it) => self.union_to_def(InFile::new(file_id, it)).map(AdtId::UnionId), 216 } 217 } bind_pat_to_def( &mut self, src: InFile<ast::IdentPat>, ) -> Option<(DefWithBodyId, BindingId)>218 pub(super) fn bind_pat_to_def( 219 &mut self, 220 src: InFile<ast::IdentPat>, 221 ) -> Option<(DefWithBodyId, BindingId)> { 222 let container = self.find_pat_or_label_container(src.syntax())?; 223 let (body, source_map) = self.db.body_with_source_map(container); 224 let src = src.map(ast::Pat::from); 225 let pat_id = source_map.node_pat(src.as_ref())?; 226 // the pattern could resolve to a constant, verify that that is not the case 227 if let crate::Pat::Bind { id, .. } = body[pat_id] { 228 Some((container, id)) 229 } else { 230 None 231 } 232 } self_param_to_def( &mut self, src: InFile<ast::SelfParam>, ) -> Option<(DefWithBodyId, BindingId)>233 pub(super) fn self_param_to_def( 234 &mut self, 235 src: InFile<ast::SelfParam>, 236 ) -> Option<(DefWithBodyId, BindingId)> { 237 let container = self.find_pat_or_label_container(src.syntax())?; 238 let (body, source_map) = self.db.body_with_source_map(container); 239 let pat_id = source_map.node_self_param(src.as_ref())?; 240 if let crate::Pat::Bind { id, .. } = body[pat_id] { 241 Some((container, id)) 242 } else { 243 never!(); 244 None 245 } 246 } label_to_def( &mut self, src: InFile<ast::Label>, ) -> Option<(DefWithBodyId, LabelId)>247 pub(super) fn label_to_def( 248 &mut self, 249 src: InFile<ast::Label>, 250 ) -> Option<(DefWithBodyId, LabelId)> { 251 let container = self.find_pat_or_label_container(src.syntax())?; 252 let (_body, source_map) = self.db.body_with_source_map(container); 253 let label_id = source_map.node_label(src.as_ref())?; 254 Some((container, label_id)) 255 } 256 item_to_macro_call(&mut self, src: InFile<ast::Item>) -> Option<MacroCallId>257 pub(super) fn item_to_macro_call(&mut self, src: InFile<ast::Item>) -> Option<MacroCallId> { 258 let map = self.dyn_map(src.as_ref())?; 259 map[keys::ATTR_MACRO_CALL].get(&src.value).copied() 260 } 261 262 /// (AttrId, derive attribute call id, derive call ids) attr_to_derive_macro_call( &mut self, item: InFile<&ast::Adt>, src: InFile<ast::Attr>, ) -> Option<(AttrId, MacroCallId, &[Option<MacroCallId>])>263 pub(super) fn attr_to_derive_macro_call( 264 &mut self, 265 item: InFile<&ast::Adt>, 266 src: InFile<ast::Attr>, 267 ) -> Option<(AttrId, MacroCallId, &[Option<MacroCallId>])> { 268 let map = self.dyn_map(item)?; 269 map[keys::DERIVE_MACRO_CALL] 270 .get(&src.value) 271 .map(|&(attr_id, call_id, ref ids)| (attr_id, call_id, &**ids)) 272 } 273 has_derives(&mut self, adt: InFile<&ast::Adt>) -> bool274 pub(super) fn has_derives(&mut self, adt: InFile<&ast::Adt>) -> bool { 275 self.dyn_map(adt).as_ref().map_or(false, |map| !map[keys::DERIVE_MACRO_CALL].is_empty()) 276 } 277 to_def<Ast: AstNode + 'static, ID: Copy + 'static>( &mut self, src: InFile<Ast>, key: Key<Ast, ID>, ) -> Option<ID>278 fn to_def<Ast: AstNode + 'static, ID: Copy + 'static>( 279 &mut self, 280 src: InFile<Ast>, 281 key: Key<Ast, ID>, 282 ) -> Option<ID> { 283 self.dyn_map(src.as_ref())?[key].get(&src.value).copied() 284 } 285 dyn_map<Ast: AstNode + 'static>(&mut self, src: InFile<&Ast>) -> Option<&DynMap>286 fn dyn_map<Ast: AstNode + 'static>(&mut self, src: InFile<&Ast>) -> Option<&DynMap> { 287 let container = self.find_container(src.map(|it| it.syntax()))?; 288 Some(self.cache_for(container, src.file_id)) 289 } 290 cache_for(&mut self, container: ChildContainer, file_id: HirFileId) -> &DynMap291 fn cache_for(&mut self, container: ChildContainer, file_id: HirFileId) -> &DynMap { 292 let db = self.db; 293 self.cache 294 .entry((container, file_id)) 295 .or_insert_with(|| container.child_by_source(db, file_id)) 296 } 297 type_param_to_def(&mut self, src: InFile<ast::TypeParam>) -> Option<TypeParamId>298 pub(super) fn type_param_to_def(&mut self, src: InFile<ast::TypeParam>) -> Option<TypeParamId> { 299 let container: ChildContainer = self.find_generic_param_container(src.syntax())?.into(); 300 let dyn_map = self.cache_for(container, src.file_id); 301 dyn_map[keys::TYPE_PARAM].get(&src.value).copied().map(|x| TypeParamId::from_unchecked(x)) 302 } 303 lifetime_param_to_def( &mut self, src: InFile<ast::LifetimeParam>, ) -> Option<LifetimeParamId>304 pub(super) fn lifetime_param_to_def( 305 &mut self, 306 src: InFile<ast::LifetimeParam>, 307 ) -> Option<LifetimeParamId> { 308 let container: ChildContainer = self.find_generic_param_container(src.syntax())?.into(); 309 let dyn_map = self.cache_for(container, src.file_id); 310 dyn_map[keys::LIFETIME_PARAM].get(&src.value).copied() 311 } 312 const_param_to_def( &mut self, src: InFile<ast::ConstParam>, ) -> Option<ConstParamId>313 pub(super) fn const_param_to_def( 314 &mut self, 315 src: InFile<ast::ConstParam>, 316 ) -> Option<ConstParamId> { 317 let container: ChildContainer = self.find_generic_param_container(src.syntax())?.into(); 318 let dyn_map = self.cache_for(container, src.file_id); 319 dyn_map[keys::CONST_PARAM].get(&src.value).copied().map(|x| ConstParamId::from_unchecked(x)) 320 } 321 322 pub(super) fn generic_param_to_def( 323 &mut self, 324 InFile { file_id, value }: InFile<ast::GenericParam>, 325 ) -> Option<GenericParamId> { 326 match value { 327 ast::GenericParam::ConstParam(it) => { 328 self.const_param_to_def(InFile::new(file_id, it)).map(GenericParamId::ConstParamId) 329 } 330 ast::GenericParam::LifetimeParam(it) => self 331 .lifetime_param_to_def(InFile::new(file_id, it)) 332 .map(GenericParamId::LifetimeParamId), 333 ast::GenericParam::TypeParam(it) => { 334 self.type_param_to_def(InFile::new(file_id, it)).map(GenericParamId::TypeParamId) 335 } 336 } 337 } 338 macro_to_def(&mut self, src: InFile<ast::Macro>) -> Option<MacroId>339 pub(super) fn macro_to_def(&mut self, src: InFile<ast::Macro>) -> Option<MacroId> { 340 self.dyn_map(src.as_ref()).and_then(|it| match &src.value { 341 ast::Macro::MacroRules(value) => { 342 it[keys::MACRO_RULES].get(value).copied().map(MacroId::from) 343 } 344 ast::Macro::MacroDef(value) => it[keys::MACRO2].get(value).copied().map(MacroId::from), 345 }) 346 } 347 proc_macro_to_def(&mut self, src: InFile<ast::Fn>) -> Option<MacroId>348 pub(super) fn proc_macro_to_def(&mut self, src: InFile<ast::Fn>) -> Option<MacroId> { 349 self.dyn_map(src.as_ref()) 350 .and_then(|it| it[keys::PROC_MACRO].get(&src.value).copied().map(MacroId::from)) 351 } 352 find_container(&mut self, src: InFile<&SyntaxNode>) -> Option<ChildContainer>353 pub(super) fn find_container(&mut self, src: InFile<&SyntaxNode>) -> Option<ChildContainer> { 354 for container in src.ancestors_with_macros_skip_attr_item(self.db.upcast()) { 355 if let Some(res) = self.container_to_def(container) { 356 return Some(res); 357 } 358 } 359 360 let def = self.file_to_def(src.file_id.original_file(self.db.upcast())).get(0).copied()?; 361 Some(def.into()) 362 } 363 container_to_def(&mut self, container: InFile<SyntaxNode>) -> Option<ChildContainer>364 fn container_to_def(&mut self, container: InFile<SyntaxNode>) -> Option<ChildContainer> { 365 let cont = if let Some(item) = ast::Item::cast(container.value.clone()) { 366 match item { 367 ast::Item::Module(it) => self.module_to_def(container.with_value(it))?.into(), 368 ast::Item::Trait(it) => self.trait_to_def(container.with_value(it))?.into(), 369 ast::Item::TraitAlias(it) => { 370 self.trait_alias_to_def(container.with_value(it))?.into() 371 } 372 ast::Item::Impl(it) => self.impl_to_def(container.with_value(it))?.into(), 373 ast::Item::Enum(it) => self.enum_to_def(container.with_value(it))?.into(), 374 ast::Item::TypeAlias(it) => { 375 self.type_alias_to_def(container.with_value(it))?.into() 376 } 377 ast::Item::Struct(it) => { 378 let def = self.struct_to_def(container.with_value(it))?; 379 VariantId::from(def).into() 380 } 381 ast::Item::Union(it) => { 382 let def = self.union_to_def(container.with_value(it))?; 383 VariantId::from(def).into() 384 } 385 ast::Item::Fn(it) => { 386 let def = self.fn_to_def(container.with_value(it))?; 387 DefWithBodyId::from(def).into() 388 } 389 ast::Item::Static(it) => { 390 let def = self.static_to_def(container.with_value(it))?; 391 DefWithBodyId::from(def).into() 392 } 393 ast::Item::Const(it) => { 394 let def = self.const_to_def(container.with_value(it))?; 395 DefWithBodyId::from(def).into() 396 } 397 _ => return None, 398 } 399 } else { 400 let it = ast::Variant::cast(container.value)?; 401 let def = self.enum_variant_to_def(InFile::new(container.file_id, it))?; 402 DefWithBodyId::from(def).into() 403 }; 404 Some(cont) 405 } 406 find_generic_param_container(&mut self, src: InFile<&SyntaxNode>) -> Option<GenericDefId>407 fn find_generic_param_container(&mut self, src: InFile<&SyntaxNode>) -> Option<GenericDefId> { 408 let ancestors = src.ancestors_with_macros_skip_attr_item(self.db.upcast()); 409 for InFile { file_id, value } in ancestors { 410 let item = match ast::Item::cast(value) { 411 Some(it) => it, 412 None => continue, 413 }; 414 let res: GenericDefId = match item { 415 ast::Item::Fn(it) => self.fn_to_def(InFile::new(file_id, it))?.into(), 416 ast::Item::Struct(it) => self.struct_to_def(InFile::new(file_id, it))?.into(), 417 ast::Item::Enum(it) => self.enum_to_def(InFile::new(file_id, it))?.into(), 418 ast::Item::Trait(it) => self.trait_to_def(InFile::new(file_id, it))?.into(), 419 ast::Item::TraitAlias(it) => { 420 self.trait_alias_to_def(InFile::new(file_id, it))?.into() 421 } 422 ast::Item::TypeAlias(it) => { 423 self.type_alias_to_def(InFile::new(file_id, it))?.into() 424 } 425 ast::Item::Impl(it) => self.impl_to_def(InFile::new(file_id, it))?.into(), 426 _ => continue, 427 }; 428 return Some(res); 429 } 430 None 431 } 432 find_pat_or_label_container(&mut self, src: InFile<&SyntaxNode>) -> Option<DefWithBodyId>433 fn find_pat_or_label_container(&mut self, src: InFile<&SyntaxNode>) -> Option<DefWithBodyId> { 434 let ancestors = src.ancestors_with_macros_skip_attr_item(self.db.upcast()); 435 for InFile { file_id, value } in ancestors { 436 let item = match ast::Item::cast(value) { 437 Some(it) => it, 438 None => continue, 439 }; 440 let res: DefWithBodyId = match item { 441 ast::Item::Const(it) => self.const_to_def(InFile::new(file_id, it))?.into(), 442 ast::Item::Static(it) => self.static_to_def(InFile::new(file_id, it))?.into(), 443 ast::Item::Fn(it) => self.fn_to_def(InFile::new(file_id, it))?.into(), 444 _ => continue, 445 }; 446 return Some(res); 447 } 448 None 449 } 450 } 451 452 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] 453 pub(crate) enum ChildContainer { 454 DefWithBodyId(DefWithBodyId), 455 ModuleId(ModuleId), 456 TraitId(TraitId), 457 TraitAliasId(TraitAliasId), 458 ImplId(ImplId), 459 EnumId(EnumId), 460 VariantId(VariantId), 461 TypeAliasId(TypeAliasId), 462 /// XXX: this might be the same def as, for example an `EnumId`. However, 463 /// here the children are generic parameters, and not, eg enum variants. 464 GenericDefId(GenericDefId), 465 } 466 impl_from! { 467 DefWithBodyId, 468 ModuleId, 469 TraitId, 470 TraitAliasId, 471 ImplId, 472 EnumId, 473 VariantId, 474 TypeAliasId, 475 GenericDefId 476 for ChildContainer 477 } 478 479 impl ChildContainer { child_by_source(self, db: &dyn HirDatabase, file_id: HirFileId) -> DynMap480 fn child_by_source(self, db: &dyn HirDatabase, file_id: HirFileId) -> DynMap { 481 let db = db.upcast(); 482 match self { 483 ChildContainer::DefWithBodyId(it) => it.child_by_source(db, file_id), 484 ChildContainer::ModuleId(it) => it.child_by_source(db, file_id), 485 ChildContainer::TraitId(it) => it.child_by_source(db, file_id), 486 ChildContainer::TraitAliasId(_) => DynMap::default(), 487 ChildContainer::ImplId(it) => it.child_by_source(db, file_id), 488 ChildContainer::EnumId(it) => it.child_by_source(db, file_id), 489 ChildContainer::VariantId(it) => it.child_by_source(db, file_id), 490 ChildContainer::TypeAliasId(_) => DynMap::default(), 491 ChildContainer::GenericDefId(it) => it.child_by_source(db, file_id), 492 } 493 } 494 } 495