• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! `NameDefinition` keeps information about the element we want to search references for.
2 //! The element is represented by `NameKind`. It's located inside some `container` and
3 //! has a `visibility`, which defines a search scope.
4 //! Note that the reference search is possible for not all of the classified items.
5 
6 // FIXME: this badly needs rename/rewrite (matklad, 2020-02-06).
7 
8 use arrayvec::ArrayVec;
9 use hir::{
10     Adt, AsAssocItem, AssocItem, BuiltinAttr, BuiltinType, Const, Crate, DeriveHelper, Field,
11     Function, GenericParam, HasVisibility, Impl, Label, Local, Macro, Module, ModuleDef, Name,
12     PathResolution, Semantics, Static, ToolModule, Trait, TraitAlias, TypeAlias, Variant,
13     Visibility,
14 };
15 use stdx::impl_from;
16 use syntax::{
17     ast::{self, AstNode},
18     match_ast, SyntaxKind, SyntaxNode, SyntaxToken,
19 };
20 
21 use crate::RootDatabase;
22 
23 // FIXME: a more precise name would probably be `Symbol`?
24 #[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)]
25 pub enum Definition {
26     Macro(Macro),
27     Field(Field),
28     Module(Module),
29     Function(Function),
30     Adt(Adt),
31     Variant(Variant),
32     Const(Const),
33     Static(Static),
34     Trait(Trait),
35     TraitAlias(TraitAlias),
36     TypeAlias(TypeAlias),
37     BuiltinType(BuiltinType),
38     SelfType(Impl),
39     GenericParam(GenericParam),
40     Local(Local),
41     Label(Label),
42     DeriveHelper(DeriveHelper),
43     BuiltinAttr(BuiltinAttr),
44     ToolModule(ToolModule),
45 }
46 
47 impl Definition {
canonical_module_path(&self, db: &RootDatabase) -> Option<impl Iterator<Item = Module>>48     pub fn canonical_module_path(&self, db: &RootDatabase) -> Option<impl Iterator<Item = Module>> {
49         self.module(db).map(|it| it.path_to_root(db).into_iter().rev())
50     }
51 
krate(&self, db: &RootDatabase) -> Option<Crate>52     pub fn krate(&self, db: &RootDatabase) -> Option<Crate> {
53         Some(match self {
54             Definition::Module(m) => m.krate(),
55             _ => self.module(db)?.krate(),
56         })
57     }
58 
module(&self, db: &RootDatabase) -> Option<Module>59     pub fn module(&self, db: &RootDatabase) -> Option<Module> {
60         let module = match self {
61             Definition::Macro(it) => it.module(db),
62             Definition::Module(it) => it.parent(db)?,
63             Definition::Field(it) => it.parent_def(db).module(db),
64             Definition::Function(it) => it.module(db),
65             Definition::Adt(it) => it.module(db),
66             Definition::Const(it) => it.module(db),
67             Definition::Static(it) => it.module(db),
68             Definition::Trait(it) => it.module(db),
69             Definition::TraitAlias(it) => it.module(db),
70             Definition::TypeAlias(it) => it.module(db),
71             Definition::Variant(it) => it.module(db),
72             Definition::SelfType(it) => it.module(db),
73             Definition::Local(it) => it.module(db),
74             Definition::GenericParam(it) => it.module(db),
75             Definition::Label(it) => it.module(db),
76             Definition::DeriveHelper(it) => it.derive().module(db),
77             Definition::BuiltinAttr(_) | Definition::BuiltinType(_) | Definition::ToolModule(_) => {
78                 return None
79             }
80         };
81         Some(module)
82     }
83 
visibility(&self, db: &RootDatabase) -> Option<Visibility>84     pub fn visibility(&self, db: &RootDatabase) -> Option<Visibility> {
85         let vis = match self {
86             Definition::Field(sf) => sf.visibility(db),
87             Definition::Module(it) => it.visibility(db),
88             Definition::Function(it) => it.visibility(db),
89             Definition::Adt(it) => it.visibility(db),
90             Definition::Const(it) => it.visibility(db),
91             Definition::Static(it) => it.visibility(db),
92             Definition::Trait(it) => it.visibility(db),
93             Definition::TraitAlias(it) => it.visibility(db),
94             Definition::TypeAlias(it) => it.visibility(db),
95             Definition::Variant(it) => it.visibility(db),
96             Definition::BuiltinType(_) => Visibility::Public,
97             Definition::Macro(_) => return None,
98             Definition::BuiltinAttr(_)
99             | Definition::ToolModule(_)
100             | Definition::SelfType(_)
101             | Definition::Local(_)
102             | Definition::GenericParam(_)
103             | Definition::Label(_)
104             | Definition::DeriveHelper(_) => return None,
105         };
106         Some(vis)
107     }
108 
name(&self, db: &RootDatabase) -> Option<Name>109     pub fn name(&self, db: &RootDatabase) -> Option<Name> {
110         let name = match self {
111             Definition::Macro(it) => it.name(db),
112             Definition::Field(it) => it.name(db),
113             Definition::Module(it) => it.name(db)?,
114             Definition::Function(it) => it.name(db),
115             Definition::Adt(it) => it.name(db),
116             Definition::Variant(it) => it.name(db),
117             Definition::Const(it) => it.name(db)?,
118             Definition::Static(it) => it.name(db),
119             Definition::Trait(it) => it.name(db),
120             Definition::TraitAlias(it) => it.name(db),
121             Definition::TypeAlias(it) => it.name(db),
122             Definition::BuiltinType(it) => it.name(),
123             Definition::SelfType(_) => return None,
124             Definition::Local(it) => it.name(db),
125             Definition::GenericParam(it) => it.name(db),
126             Definition::Label(it) => it.name(db),
127             Definition::BuiltinAttr(_) => return None, // FIXME
128             Definition::ToolModule(_) => return None,  // FIXME
129             Definition::DeriveHelper(it) => it.name(db),
130         };
131         Some(name)
132     }
133 }
134 
135 // FIXME: IdentClass as a name no longer fits
136 #[derive(Debug)]
137 pub enum IdentClass {
138     NameClass(NameClass),
139     NameRefClass(NameRefClass),
140     Operator(OperatorClass),
141 }
142 
143 impl IdentClass {
classify_node( sema: &Semantics<'_, RootDatabase>, node: &SyntaxNode, ) -> Option<IdentClass>144     pub fn classify_node(
145         sema: &Semantics<'_, RootDatabase>,
146         node: &SyntaxNode,
147     ) -> Option<IdentClass> {
148         match_ast! {
149             match node {
150                 ast::Name(name) => NameClass::classify(sema, &name).map(IdentClass::NameClass),
151                 ast::NameRef(name_ref) => NameRefClass::classify(sema, &name_ref).map(IdentClass::NameRefClass),
152                 ast::Lifetime(lifetime) => {
153                     NameClass::classify_lifetime(sema, &lifetime)
154                         .map(IdentClass::NameClass)
155                         .or_else(|| NameRefClass::classify_lifetime(sema, &lifetime).map(IdentClass::NameRefClass))
156                 },
157                 ast::AwaitExpr(await_expr) => OperatorClass::classify_await(sema, &await_expr).map(IdentClass::Operator),
158                 ast::BinExpr(bin_expr) => OperatorClass::classify_bin(sema, &bin_expr).map(IdentClass::Operator),
159                 ast::IndexExpr(index_expr) => OperatorClass::classify_index(sema, &index_expr).map(IdentClass::Operator),
160                 ast::PrefixExpr(prefix_expr) => OperatorClass::classify_prefix(sema,&prefix_expr).map(IdentClass::Operator),
161                 ast::TryExpr(try_expr) => OperatorClass::classify_try(sema,&try_expr).map(IdentClass::Operator),
162                 _ => None,
163             }
164         }
165     }
166 
classify_token( sema: &Semantics<'_, RootDatabase>, token: &SyntaxToken, ) -> Option<IdentClass>167     pub fn classify_token(
168         sema: &Semantics<'_, RootDatabase>,
169         token: &SyntaxToken,
170     ) -> Option<IdentClass> {
171         let parent = token.parent()?;
172         Self::classify_node(sema, &parent)
173     }
174 
classify_lifetime( sema: &Semantics<'_, RootDatabase>, lifetime: &ast::Lifetime, ) -> Option<IdentClass>175     pub fn classify_lifetime(
176         sema: &Semantics<'_, RootDatabase>,
177         lifetime: &ast::Lifetime,
178     ) -> Option<IdentClass> {
179         NameRefClass::classify_lifetime(sema, lifetime)
180             .map(IdentClass::NameRefClass)
181             .or_else(|| NameClass::classify_lifetime(sema, lifetime).map(IdentClass::NameClass))
182     }
183 
definitions(self) -> ArrayVec<Definition, 2>184     pub fn definitions(self) -> ArrayVec<Definition, 2> {
185         let mut res = ArrayVec::new();
186         match self {
187             IdentClass::NameClass(NameClass::Definition(it) | NameClass::ConstReference(it)) => {
188                 res.push(it)
189             }
190             IdentClass::NameClass(NameClass::PatFieldShorthand { local_def, field_ref }) => {
191                 res.push(Definition::Local(local_def));
192                 res.push(Definition::Field(field_ref));
193             }
194             IdentClass::NameRefClass(NameRefClass::Definition(it)) => res.push(it),
195             IdentClass::NameRefClass(NameRefClass::FieldShorthand { local_ref, field_ref }) => {
196                 res.push(Definition::Local(local_ref));
197                 res.push(Definition::Field(field_ref));
198             }
199             IdentClass::Operator(
200                 OperatorClass::Await(func)
201                 | OperatorClass::Prefix(func)
202                 | OperatorClass::Bin(func)
203                 | OperatorClass::Index(func)
204                 | OperatorClass::Try(func),
205             ) => res.push(Definition::Function(func)),
206         }
207         res
208     }
209 
definitions_no_ops(self) -> ArrayVec<Definition, 2>210     pub fn definitions_no_ops(self) -> ArrayVec<Definition, 2> {
211         let mut res = ArrayVec::new();
212         match self {
213             IdentClass::NameClass(NameClass::Definition(it) | NameClass::ConstReference(it)) => {
214                 res.push(it)
215             }
216             IdentClass::NameClass(NameClass::PatFieldShorthand { local_def, field_ref }) => {
217                 res.push(Definition::Local(local_def));
218                 res.push(Definition::Field(field_ref));
219             }
220             IdentClass::NameRefClass(NameRefClass::Definition(it)) => res.push(it),
221             IdentClass::NameRefClass(NameRefClass::FieldShorthand { local_ref, field_ref }) => {
222                 res.push(Definition::Local(local_ref));
223                 res.push(Definition::Field(field_ref));
224             }
225             IdentClass::Operator(_) => (),
226         }
227         res
228     }
229 }
230 
231 /// On a first blush, a single `ast::Name` defines a single definition at some
232 /// scope. That is, that, by just looking at the syntactical category, we can
233 /// unambiguously define the semantic category.
234 ///
235 /// Sadly, that's not 100% true, there are special cases. To make sure that
236 /// callers handle all the special cases correctly via exhaustive matching, we
237 /// add a [`NameClass`] enum which lists all of them!
238 ///
239 /// A model special case is `None` constant in pattern.
240 #[derive(Debug)]
241 pub enum NameClass {
242     Definition(Definition),
243     /// `None` in `if let None = Some(82) {}`.
244     /// Syntactically, it is a name, but semantically it is a reference.
245     ConstReference(Definition),
246     /// `field` in `if let Foo { field } = foo`. Here, `ast::Name` both introduces
247     /// a definition into a local scope, and refers to an existing definition.
248     PatFieldShorthand {
249         local_def: Local,
250         field_ref: Field,
251     },
252 }
253 
254 impl NameClass {
255     /// `Definition` defined by this name.
defined(self) -> Option<Definition>256     pub fn defined(self) -> Option<Definition> {
257         let res = match self {
258             NameClass::Definition(it) => it,
259             NameClass::ConstReference(_) => return None,
260             NameClass::PatFieldShorthand { local_def, field_ref: _ } => {
261                 Definition::Local(local_def)
262             }
263         };
264         Some(res)
265     }
266 
classify(sema: &Semantics<'_, RootDatabase>, name: &ast::Name) -> Option<NameClass>267     pub fn classify(sema: &Semantics<'_, RootDatabase>, name: &ast::Name) -> Option<NameClass> {
268         let _p = profile::span("classify_name");
269 
270         let parent = name.syntax().parent()?;
271 
272         let definition = match_ast! {
273             match parent {
274                 ast::Item(it) => classify_item(sema, it)?,
275                 ast::IdentPat(it) => return classify_ident_pat(sema, it),
276                 ast::Rename(it) => classify_rename(sema, it)?,
277                 ast::SelfParam(it) => Definition::Local(sema.to_def(&it)?),
278                 ast::RecordField(it) => Definition::Field(sema.to_def(&it)?),
279                 ast::Variant(it) => Definition::Variant(sema.to_def(&it)?),
280                 ast::TypeParam(it) => Definition::GenericParam(sema.to_def(&it)?.into()),
281                 ast::ConstParam(it) => Definition::GenericParam(sema.to_def(&it)?.into()),
282                 _ => return None,
283             }
284         };
285         return Some(NameClass::Definition(definition));
286 
287         fn classify_item(
288             sema: &Semantics<'_, RootDatabase>,
289             item: ast::Item,
290         ) -> Option<Definition> {
291             let definition = match item {
292                 ast::Item::MacroRules(it) => {
293                     Definition::Macro(sema.to_def(&ast::Macro::MacroRules(it))?)
294                 }
295                 ast::Item::MacroDef(it) => {
296                     Definition::Macro(sema.to_def(&ast::Macro::MacroDef(it))?)
297                 }
298                 ast::Item::Const(it) => Definition::Const(sema.to_def(&it)?),
299                 ast::Item::Fn(it) => {
300                     let def = sema.to_def(&it)?;
301                     def.as_proc_macro(sema.db)
302                         .map(Definition::Macro)
303                         .unwrap_or(Definition::Function(def))
304                 }
305                 ast::Item::Module(it) => Definition::Module(sema.to_def(&it)?),
306                 ast::Item::Static(it) => Definition::Static(sema.to_def(&it)?),
307                 ast::Item::Trait(it) => Definition::Trait(sema.to_def(&it)?),
308                 ast::Item::TraitAlias(it) => Definition::TraitAlias(sema.to_def(&it)?),
309                 ast::Item::TypeAlias(it) => Definition::TypeAlias(sema.to_def(&it)?),
310                 ast::Item::Enum(it) => Definition::Adt(hir::Adt::Enum(sema.to_def(&it)?)),
311                 ast::Item::Struct(it) => Definition::Adt(hir::Adt::Struct(sema.to_def(&it)?)),
312                 ast::Item::Union(it) => Definition::Adt(hir::Adt::Union(sema.to_def(&it)?)),
313                 _ => return None,
314             };
315             Some(definition)
316         }
317 
318         fn classify_ident_pat(
319             sema: &Semantics<'_, RootDatabase>,
320             ident_pat: ast::IdentPat,
321         ) -> Option<NameClass> {
322             if let Some(def) = sema.resolve_bind_pat_to_const(&ident_pat) {
323                 return Some(NameClass::ConstReference(Definition::from(def)));
324             }
325 
326             let local = sema.to_def(&ident_pat)?;
327             let pat_parent = ident_pat.syntax().parent();
328             if let Some(record_pat_field) = pat_parent.and_then(ast::RecordPatField::cast) {
329                 if record_pat_field.name_ref().is_none() {
330                     if let Some((field, _)) = sema.resolve_record_pat_field(&record_pat_field) {
331                         return Some(NameClass::PatFieldShorthand {
332                             local_def: local,
333                             field_ref: field,
334                         });
335                     }
336                 }
337             }
338             Some(NameClass::Definition(Definition::Local(local)))
339         }
340 
341         fn classify_rename(
342             sema: &Semantics<'_, RootDatabase>,
343             rename: ast::Rename,
344         ) -> Option<Definition> {
345             if let Some(use_tree) = rename.syntax().parent().and_then(ast::UseTree::cast) {
346                 let path = use_tree.path()?;
347                 sema.resolve_path(&path).map(Definition::from)
348             } else {
349                 let extern_crate = rename.syntax().parent().and_then(ast::ExternCrate::cast)?;
350                 let krate = sema.resolve_extern_crate(&extern_crate)?;
351                 let root_module = krate.root_module(sema.db);
352                 Some(Definition::Module(root_module))
353             }
354         }
355     }
356 
classify_lifetime( sema: &Semantics<'_, RootDatabase>, lifetime: &ast::Lifetime, ) -> Option<NameClass>357     pub fn classify_lifetime(
358         sema: &Semantics<'_, RootDatabase>,
359         lifetime: &ast::Lifetime,
360     ) -> Option<NameClass> {
361         let _p = profile::span("classify_lifetime").detail(|| lifetime.to_string());
362         let parent = lifetime.syntax().parent()?;
363 
364         if let Some(it) = ast::LifetimeParam::cast(parent.clone()) {
365             sema.to_def(&it).map(Into::into).map(Definition::GenericParam)
366         } else if let Some(it) = ast::Label::cast(parent) {
367             sema.to_def(&it).map(Definition::Label)
368         } else {
369             None
370         }
371         .map(NameClass::Definition)
372     }
373 }
374 
375 #[derive(Debug)]
376 pub enum OperatorClass {
377     Await(Function),
378     Prefix(Function),
379     Index(Function),
380     Try(Function),
381     Bin(Function),
382 }
383 
384 impl OperatorClass {
classify_await( sema: &Semantics<'_, RootDatabase>, await_expr: &ast::AwaitExpr, ) -> Option<OperatorClass>385     pub fn classify_await(
386         sema: &Semantics<'_, RootDatabase>,
387         await_expr: &ast::AwaitExpr,
388     ) -> Option<OperatorClass> {
389         sema.resolve_await_to_poll(await_expr).map(OperatorClass::Await)
390     }
391 
classify_prefix( sema: &Semantics<'_, RootDatabase>, prefix_expr: &ast::PrefixExpr, ) -> Option<OperatorClass>392     pub fn classify_prefix(
393         sema: &Semantics<'_, RootDatabase>,
394         prefix_expr: &ast::PrefixExpr,
395     ) -> Option<OperatorClass> {
396         sema.resolve_prefix_expr(prefix_expr).map(OperatorClass::Prefix)
397     }
398 
classify_try( sema: &Semantics<'_, RootDatabase>, try_expr: &ast::TryExpr, ) -> Option<OperatorClass>399     pub fn classify_try(
400         sema: &Semantics<'_, RootDatabase>,
401         try_expr: &ast::TryExpr,
402     ) -> Option<OperatorClass> {
403         sema.resolve_try_expr(try_expr).map(OperatorClass::Try)
404     }
405 
classify_index( sema: &Semantics<'_, RootDatabase>, index_expr: &ast::IndexExpr, ) -> Option<OperatorClass>406     pub fn classify_index(
407         sema: &Semantics<'_, RootDatabase>,
408         index_expr: &ast::IndexExpr,
409     ) -> Option<OperatorClass> {
410         sema.resolve_index_expr(index_expr).map(OperatorClass::Index)
411     }
412 
classify_bin( sema: &Semantics<'_, RootDatabase>, bin_expr: &ast::BinExpr, ) -> Option<OperatorClass>413     pub fn classify_bin(
414         sema: &Semantics<'_, RootDatabase>,
415         bin_expr: &ast::BinExpr,
416     ) -> Option<OperatorClass> {
417         sema.resolve_bin_expr(bin_expr).map(OperatorClass::Bin)
418     }
419 }
420 
421 /// This is similar to [`NameClass`], but works for [`ast::NameRef`] rather than
422 /// for [`ast::Name`]. Similarly, what looks like a reference in syntax is a
423 /// reference most of the time, but there are a couple of annoying exceptions.
424 ///
425 /// A model special case is field shorthand syntax, which uses a single
426 /// reference to point to two different defs.
427 #[derive(Debug)]
428 pub enum NameRefClass {
429     Definition(Definition),
430     FieldShorthand { local_ref: Local, field_ref: Field },
431 }
432 
433 impl NameRefClass {
434     // Note: we don't have unit-tests for this rather important function.
435     // It is primarily exercised via goto definition tests in `ide`.
classify( sema: &Semantics<'_, RootDatabase>, name_ref: &ast::NameRef, ) -> Option<NameRefClass>436     pub fn classify(
437         sema: &Semantics<'_, RootDatabase>,
438         name_ref: &ast::NameRef,
439     ) -> Option<NameRefClass> {
440         let _p = profile::span("classify_name_ref").detail(|| name_ref.to_string());
441 
442         let parent = name_ref.syntax().parent()?;
443 
444         if let Some(record_field) = ast::RecordExprField::for_field_name(name_ref) {
445             if let Some((field, local, _)) = sema.resolve_record_field(&record_field) {
446                 let res = match local {
447                     None => NameRefClass::Definition(Definition::Field(field)),
448                     Some(local) => {
449                         NameRefClass::FieldShorthand { field_ref: field, local_ref: local }
450                     }
451                 };
452                 return Some(res);
453             }
454         }
455 
456         if let Some(path) = ast::PathSegment::cast(parent.clone()).map(|it| it.parent_path()) {
457             if path.parent_path().is_none() {
458                 if let Some(macro_call) = path.syntax().parent().and_then(ast::MacroCall::cast) {
459                     // Only use this to resolve to macro calls for last segments as qualifiers resolve
460                     // to modules below.
461                     if let Some(macro_def) = sema.resolve_macro_call(&macro_call) {
462                         return Some(NameRefClass::Definition(Definition::Macro(macro_def)));
463                     }
464                 }
465             }
466             return sema.resolve_path(&path).map(Into::into).map(NameRefClass::Definition);
467         }
468 
469         match_ast! {
470             match parent {
471                 ast::MethodCallExpr(method_call) => {
472                     sema.resolve_method_call_field_fallback(&method_call)
473                         .map(|it| {
474                             it.map_left(Definition::Function)
475                                 .map_right(Definition::Field)
476                                 .either(NameRefClass::Definition, NameRefClass::Definition)
477                         })
478                 },
479                 ast::FieldExpr(field_expr) => {
480                     sema.resolve_field(&field_expr)
481                         .map(Definition::Field)
482                         .map(NameRefClass::Definition)
483                 },
484                 ast::RecordPatField(record_pat_field) => {
485                     sema.resolve_record_pat_field(&record_pat_field)
486                         .map(|(field, ..)|field)
487                         .map(Definition::Field)
488                         .map(NameRefClass::Definition)
489                 },
490                 ast::RecordExprField(record_expr_field) => {
491                     sema.resolve_record_field(&record_expr_field)
492                         .map(|(field, ..)|field)
493                         .map(Definition::Field)
494                         .map(NameRefClass::Definition)
495                 },
496                 ast::AssocTypeArg(_) => {
497                     // `Trait<Assoc = Ty>`
498                     //        ^^^^^
499                     let containing_path = name_ref.syntax().ancestors().find_map(ast::Path::cast)?;
500                     let resolved = sema.resolve_path(&containing_path)?;
501                     if let PathResolution::Def(ModuleDef::Trait(tr)) = resolved {
502                         if let Some(ty) = tr
503                             .items_with_supertraits(sema.db)
504                             .iter()
505                             .filter_map(|&assoc| match assoc {
506                                 hir::AssocItem::TypeAlias(it) => Some(it),
507                                 _ => None,
508                             })
509                             .find(|alias| alias.name(sema.db).to_smol_str() == name_ref.text().as_str())
510                         {
511                             return Some(NameRefClass::Definition(Definition::TypeAlias(ty)));
512                         }
513                     }
514                     None
515                 },
516                 ast::ExternCrate(extern_crate) => {
517                     let krate = sema.resolve_extern_crate(&extern_crate)?;
518                     let root_module = krate.root_module(sema.db);
519                     Some(NameRefClass::Definition(Definition::Module(root_module)))
520                 },
521                 _ => None
522             }
523         }
524     }
525 
classify_lifetime( sema: &Semantics<'_, RootDatabase>, lifetime: &ast::Lifetime, ) -> Option<NameRefClass>526     pub fn classify_lifetime(
527         sema: &Semantics<'_, RootDatabase>,
528         lifetime: &ast::Lifetime,
529     ) -> Option<NameRefClass> {
530         let _p = profile::span("classify_lifetime_ref").detail(|| lifetime.to_string());
531         let parent = lifetime.syntax().parent()?;
532         match parent.kind() {
533             SyntaxKind::BREAK_EXPR | SyntaxKind::CONTINUE_EXPR => {
534                 sema.resolve_label(lifetime).map(Definition::Label).map(NameRefClass::Definition)
535             }
536             SyntaxKind::LIFETIME_ARG
537             | SyntaxKind::SELF_PARAM
538             | SyntaxKind::TYPE_BOUND
539             | SyntaxKind::WHERE_PRED
540             | SyntaxKind::REF_TYPE => sema
541                 .resolve_lifetime_param(lifetime)
542                 .map(GenericParam::LifetimeParam)
543                 .map(Definition::GenericParam)
544                 .map(NameRefClass::Definition),
545             // lifetime bounds, as in the 'b in 'a: 'b aren't wrapped in TypeBound nodes so we gotta check
546             // if our lifetime is in a LifetimeParam without being the constrained lifetime
547             _ if ast::LifetimeParam::cast(parent).and_then(|param| param.lifetime()).as_ref()
548                 != Some(lifetime) =>
549             {
550                 sema.resolve_lifetime_param(lifetime)
551                     .map(GenericParam::LifetimeParam)
552                     .map(Definition::GenericParam)
553                     .map(NameRefClass::Definition)
554             }
555             _ => None,
556         }
557     }
558 }
559 
560 impl_from!(
561     Field, Module, Function, Adt, Variant, Const, Static, Trait, TraitAlias, TypeAlias, BuiltinType, Local,
562     GenericParam, Label, Macro
563     for Definition
564 );
565 
566 impl From<Impl> for Definition {
from(impl_: Impl) -> Self567     fn from(impl_: Impl) -> Self {
568         Definition::SelfType(impl_)
569     }
570 }
571 
572 impl AsAssocItem for Definition {
as_assoc_item(self, db: &dyn hir::db::HirDatabase) -> Option<AssocItem>573     fn as_assoc_item(self, db: &dyn hir::db::HirDatabase) -> Option<AssocItem> {
574         match self {
575             Definition::Function(it) => it.as_assoc_item(db),
576             Definition::Const(it) => it.as_assoc_item(db),
577             Definition::TypeAlias(it) => it.as_assoc_item(db),
578             _ => None,
579         }
580     }
581 }
582 
583 impl From<AssocItem> for Definition {
from(assoc_item: AssocItem) -> Self584     fn from(assoc_item: AssocItem) -> Self {
585         match assoc_item {
586             AssocItem::Function(it) => Definition::Function(it),
587             AssocItem::Const(it) => Definition::Const(it),
588             AssocItem::TypeAlias(it) => Definition::TypeAlias(it),
589         }
590     }
591 }
592 
593 impl From<PathResolution> for Definition {
from(path_resolution: PathResolution) -> Self594     fn from(path_resolution: PathResolution) -> Self {
595         match path_resolution {
596             PathResolution::Def(def) => def.into(),
597             PathResolution::Local(local) => Definition::Local(local),
598             PathResolution::TypeParam(par) => Definition::GenericParam(par.into()),
599             PathResolution::ConstParam(par) => Definition::GenericParam(par.into()),
600             PathResolution::SelfType(impl_def) => Definition::SelfType(impl_def),
601             PathResolution::BuiltinAttr(attr) => Definition::BuiltinAttr(attr),
602             PathResolution::ToolModule(tool) => Definition::ToolModule(tool),
603             PathResolution::DeriveHelper(helper) => Definition::DeriveHelper(helper),
604         }
605     }
606 }
607 
608 impl From<ModuleDef> for Definition {
from(def: ModuleDef) -> Self609     fn from(def: ModuleDef) -> Self {
610         match def {
611             ModuleDef::Module(it) => Definition::Module(it),
612             ModuleDef::Function(it) => Definition::Function(it),
613             ModuleDef::Adt(it) => Definition::Adt(it),
614             ModuleDef::Variant(it) => Definition::Variant(it),
615             ModuleDef::Const(it) => Definition::Const(it),
616             ModuleDef::Static(it) => Definition::Static(it),
617             ModuleDef::Trait(it) => Definition::Trait(it),
618             ModuleDef::TraitAlias(it) => Definition::TraitAlias(it),
619             ModuleDef::TypeAlias(it) => Definition::TypeAlias(it),
620             ModuleDef::Macro(it) => Definition::Macro(it),
621             ModuleDef::BuiltinType(it) => Definition::BuiltinType(it),
622         }
623     }
624 }
625