1use std::borrow::Cow;
9
10use crate::RootDatabase;
11use crate::documentation::{Documentation, HasDocs};
12use crate::famous_defs::FamousDefs;
13use arrayvec::ArrayVec;
14use either::Either;
15use hir::{
16 Adt, AsAssocItem, AsExternAssocItem, AssocItem, AttributeTemplate, BuiltinAttr, BuiltinType,
17 Const, Crate, DefWithBody, DeriveHelper, DisplayTarget, DocLinkDef, EnumVariant,
18 ExpressionStoreOwner, ExternAssocItem, ExternCrateDecl, Field, Function, GenericDef,
19 GenericParam, GenericSubstitution, HasContainer, HasVisibility, HirDisplay, Impl,
20 InlineAsmOperand, ItemContainer, Label, Local, Macro, Module, ModuleDef, Name, PathResolution,
21 Semantics, Static, StaticLifetime, Struct, ToolModule, Trait, TupleField, TypeAlias, Variant,
22 Visibility,
23};
24use span::Edition;
25use stdx::{format_to, impl_from};
26use syntax::{
27 SyntaxKind, SyntaxNode, SyntaxToken,
28 ast::{self, AstNode},
29 match_ast,
30};
31
32#[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)]
34pub enum Definition<'db> {
35 Macro(Macro),
36 Field(Field),
37 TupleField(TupleField<'db>),
38 Module(Module),
39 Crate(Crate),
40 Function(Function),
41 Adt(Adt),
42 EnumVariant(EnumVariant),
43 Const(Const),
44 Static(Static),
45 Trait(Trait),
46 TypeAlias(TypeAlias),
47 SelfType(Impl),
48 GenericParam(GenericParam),
49 Local(Local<'db>),
50 Label(Label),
51 DeriveHelper(DeriveHelper),
52 BuiltinType(BuiltinType),
53 BuiltinLifetime(StaticLifetime),
54 BuiltinAttr(BuiltinAttr),
55 ToolModule(ToolModule),
56 ExternCrateDecl(ExternCrateDecl),
57 InlineAsmRegOrRegClass(()),
58 InlineAsmOperand(InlineAsmOperand),
59}
60
61impl<'db> Definition<'db> {
62 pub fn canonical_module_path(&self, db: &RootDatabase) -> Option<impl Iterator<Item = Module>> {
63 self.module(db).map(|it| it.path_to_root(db).into_iter().rev())
64 }
65
66 pub fn krate(&self, db: &RootDatabase) -> Option<Crate> {
67 Some(match self {
68 Definition::Module(m) => m.krate(db),
69 &Definition::Crate(it) => it,
70 _ => self.module(db)?.krate(db),
71 })
72 }
73
74 pub fn module(&self, db: &RootDatabase) -> Option<Module> {
78 let module = match self {
79 Definition::Macro(it) => it.module(db),
80 Definition::Module(it) => it.parent(db)?,
81 Definition::Crate(_) => return None,
82 Definition::Field(it) => it.parent_def(db).module(db),
83 Definition::Function(it) => it.module(db),
84 Definition::Adt(it) => it.module(db),
85 Definition::Const(it) => it.module(db),
86 Definition::Static(it) => it.module(db),
87 Definition::Trait(it) => it.module(db),
88 Definition::TypeAlias(it) => it.module(db),
89 Definition::EnumVariant(it) => it.module(db),
90 Definition::SelfType(it) => it.module(db),
91 Definition::Local(it) => it.module(db),
92 Definition::GenericParam(it) => it.module(db),
93 Definition::Label(it) => it.module(db),
94 Definition::ExternCrateDecl(it) => it.module(db),
95 Definition::DeriveHelper(it) => it.derive().module(db),
96 Definition::InlineAsmOperand(it) => it.parent(db).module(db),
97 Definition::ToolModule(t) => t.krate().root_module(db),
98 Definition::BuiltinAttr(_)
99 | Definition::BuiltinType(_)
100 | Definition::BuiltinLifetime(_)
101 | Definition::TupleField(_)
102 | Definition::InlineAsmRegOrRegClass(_) => return None,
103 };
104 Some(module)
105 }
106
107 pub fn enclosing_definition(&self, db: &RootDatabase) -> Option<Definition<'db>> {
108 fn container_to_definition<'db>(container: ItemContainer) -> Option<Definition<'db>> {
109 match container {
110 ItemContainer::Trait(it) => Some(it.into()),
111 ItemContainer::Impl(it) => Some(it.into()),
112 ItemContainer::Module(it) => Some(it.into()),
113 ItemContainer::ExternBlock(_) | ItemContainer::Crate(_) => None,
114 }
115 }
116 match self {
117 Definition::Macro(it) => Some(it.module(db).into()),
118 Definition::Module(it) => it.parent(db).map(Definition::Module),
119 Definition::Crate(_) => None,
120 Definition::Field(it) => Some(it.parent_def(db).into()),
121 Definition::Function(it) => container_to_definition(it.container(db)),
122 Definition::Adt(it) => Some(it.module(db).into()),
123 Definition::Const(it) => container_to_definition(it.container(db)),
124 Definition::Static(it) => container_to_definition(it.container(db)),
125 Definition::Trait(it) => container_to_definition(it.container(db)),
126 Definition::TypeAlias(it) => container_to_definition(it.container(db)),
127 Definition::EnumVariant(it) => Some(Adt::Enum(it.parent_enum(db)).into()),
128 Definition::SelfType(it) => Some(it.module(db).into()),
129 Definition::Local(it) => it.parent(db).try_into().ok(),
130 Definition::GenericParam(it) => Some(it.parent().into()),
131 Definition::Label(it) => it.parent(db).try_into().ok(),
132 Definition::ExternCrateDecl(it) => container_to_definition(it.container(db)),
133 Definition::DeriveHelper(it) => Some(it.derive().module(db).into()),
134 Definition::InlineAsmOperand(it) => it.parent(db).try_into().ok(),
135 Definition::BuiltinAttr(_)
136 | Definition::BuiltinType(_)
137 | Definition::BuiltinLifetime(_)
138 | Definition::TupleField(_)
139 | Definition::ToolModule(_)
140 | Definition::InlineAsmRegOrRegClass(_) => None,
141 }
142 }
143
144 pub fn visibility(&self, db: &RootDatabase) -> Option<Visibility> {
145 let vis = match self {
146 Definition::Field(sf) => sf.visibility(db),
147 Definition::Module(it) => it.visibility(db),
148 Definition::Crate(_) => return None,
149 Definition::Function(it) => it.visibility(db),
150 Definition::Adt(it) => it.visibility(db),
151 Definition::Const(it) => it.visibility(db),
152 Definition::Static(it) => it.visibility(db),
153 Definition::Trait(it) => it.visibility(db),
154 Definition::TypeAlias(it) => it.visibility(db),
155 Definition::EnumVariant(it) => it.visibility(db),
156 Definition::ExternCrateDecl(it) => it.visibility(db),
157 Definition::Macro(it) => it.visibility(db),
158 Definition::BuiltinType(_) | Definition::TupleField(_) => Visibility::Public,
159 Definition::BuiltinAttr(_)
160 | Definition::BuiltinLifetime(_)
161 | Definition::ToolModule(_)
162 | Definition::SelfType(_)
163 | Definition::Local(_)
164 | Definition::GenericParam(_)
165 | Definition::Label(_)
166 | Definition::DeriveHelper(_)
167 | Definition::InlineAsmRegOrRegClass(_)
168 | Definition::InlineAsmOperand(_) => return None,
169 };
170 Some(vis)
171 }
172
173 pub fn name(&self, db: &RootDatabase) -> Option<Name> {
174 let name = match self {
175 Definition::Macro(it) => it.name(db),
176 Definition::Field(it) => it.name(db),
177 Definition::Module(it) => it.name(db)?,
178 Definition::Crate(it) => {
179 Name::new_symbol_root(it.display_name(db)?.crate_name().symbol().clone())
180 }
181 Definition::Function(it) => it.name(db),
182 Definition::Adt(it) => it.name(db),
183 Definition::EnumVariant(it) => it.name(db),
184 Definition::Const(it) => it.name(db)?,
185 Definition::Static(it) => it.name(db),
186 Definition::Trait(it) => it.name(db),
187 Definition::TypeAlias(it) => it.name(db),
188 Definition::BuiltinType(it) => it.name(),
189 Definition::TupleField(it) => it.name(),
190 Definition::SelfType(_) => return None,
191 Definition::Local(it) => it.name(db),
192 Definition::GenericParam(it) => it.name(db),
193 Definition::Label(it) => it.name(db),
194 Definition::BuiltinLifetime(it) => it.name(),
195 Definition::BuiltinAttr(_) => return None, Definition::ToolModule(_) => return None, Definition::DeriveHelper(it) => it.name(db),
198 Definition::ExternCrateDecl(it) => return it.alias_or_name(db),
199 Definition::InlineAsmRegOrRegClass(_) => return None,
200 Definition::InlineAsmOperand(op) => return op.name(db),
201 };
202 Some(name)
203 }
204
205 pub fn docs<'a>(
206 &self,
207 db: &'a RootDatabase,
208 famous_defs: Option<&FamousDefs<'_, '_>>,
209 display_target: DisplayTarget,
210 ) -> Option<Documentation<'a>> {
211 self.docs_with_rangemap(db, famous_defs, display_target).map(|docs| match docs {
212 Either::Left(Cow::Borrowed(docs)) => Documentation::new_borrowed(docs.docs()),
213 Either::Left(Cow::Owned(docs)) => Documentation::new_owned(docs.into_docs()),
214 Either::Right(docs) => docs,
215 })
216 }
217
218 pub fn docs_with_rangemap<'a>(
219 &self,
220 db: &'a RootDatabase,
221 famous_defs: Option<&FamousDefs<'_, '_>>,
222 display_target: DisplayTarget,
223 ) -> Option<Either<Cow<'a, hir::Docs>, Documentation<'a>>> {
224 let docs = match self {
225 Definition::Macro(it) => it.docs_with_rangemap(db),
226 Definition::Field(it) => it.docs_with_rangemap(db),
227 Definition::Module(it) => it.docs_with_rangemap(db),
228 Definition::Crate(it) => it.docs_with_rangemap(db),
229 Definition::Function(it) => it.docs_with_rangemap(db),
230 Definition::Adt(it) => it.docs_with_rangemap(db),
231 Definition::EnumVariant(it) => it.docs_with_rangemap(db),
232 Definition::Const(it) => it.docs_with_rangemap(db),
233 Definition::Static(it) => it.docs_with_rangemap(db),
234 Definition::Trait(it) => it.docs_with_rangemap(db),
235 Definition::TypeAlias(it) => {
236 it.docs_with_rangemap(db).or_else(|| {
237 let adt = it.ty(db).as_adt()?;
239 let mut docs = adt.docs_with_rangemap(db)?.into_owned();
240 let header_docs = format!(
241 "*This is the documentation for* `{}`\n\n",
242 adt.display(db, display_target)
243 );
244 docs.prepend_str(&header_docs);
245 Some(Cow::Owned(docs))
246 })
247 }
248 Definition::BuiltinType(it) => {
249 famous_defs.and_then(|fd| {
250 let primitive_mod =
252 format!("prim_{}", it.name().display(fd.0.db, display_target.edition));
253 let doc_owner = find_std_module(fd, &primitive_mod, display_target.edition)?;
254 doc_owner.docs_with_rangemap(db)
255 })
256 }
257 Definition::BuiltinLifetime(StaticLifetime) => None,
258 Definition::Local(_) => None,
259 Definition::SelfType(impl_def) => {
260 impl_def.self_ty(db).as_adt().map(|adt| adt.docs_with_rangemap(db))?
261 }
262 Definition::GenericParam(_) => None,
263 Definition::Label(_) => None,
264 Definition::ExternCrateDecl(it) => it.docs_with_rangemap(db),
265
266 Definition::BuiltinAttr(it) => {
267 let name = it.name();
268 let AttributeTemplate { word, list, name_value_str } = it.template()?;
269 let mut docs = "Valid forms are:".to_owned();
270 if word {
271 format_to!(docs, "\n - #\\[{}]", name.display(db, display_target.edition));
272 }
273 if let Some(list) = list {
274 format_to!(
275 docs,
276 "\n - #\\[{}({})]",
277 name.display(db, display_target.edition),
278 list
279 );
280 }
281 if let Some(name_value_str) = name_value_str {
282 format_to!(
283 docs,
284 "\n - #\\[{} = {}]",
285 name.display(db, display_target.edition),
286 name_value_str
287 );
288 }
289
290 return Some(Either::Right(Documentation::new_owned(docs.replace('*', "\\*"))));
291 }
292 Definition::ToolModule(_) => None,
293 Definition::DeriveHelper(_) => None,
294 Definition::TupleField(_) => None,
295 Definition::InlineAsmRegOrRegClass(_) | Definition::InlineAsmOperand(_) => None,
296 };
297
298 docs.or_else(|| {
299 let assoc = self.as_assoc_item(db)?;
302 let trait_ = assoc.implemented_trait(db)?;
303 let name = Some(assoc.name(db)?);
304 let item = trait_.items(db).into_iter().find(|it| it.name(db) == name)?;
305 item.docs_with_rangemap(db)
306 })
307 .map(Either::Left)
308 }
309
310 pub fn label(&self, db: &RootDatabase, display_target: DisplayTarget) -> String {
311 match *self {
312 Definition::Macro(it) => it.display(db, display_target).to_string(),
313 Definition::Field(it) => it.display(db, display_target).to_string(),
314 Definition::TupleField(it) => it.display(db, display_target).to_string(),
315 Definition::Module(it) => it.display(db, display_target).to_string(),
316 Definition::Crate(it) => it.display(db, display_target).to_string(),
317 Definition::Function(it) => it.display(db, display_target).to_string(),
318 Definition::Adt(it) => it.display(db, display_target).to_string(),
319 Definition::EnumVariant(it) => it.display(db, display_target).to_string(),
320 Definition::Const(it) => it.display(db, display_target).to_string(),
321 Definition::Static(it) => it.display(db, display_target).to_string(),
322 Definition::Trait(it) => it.display(db, display_target).to_string(),
323 Definition::TypeAlias(it) => it.display(db, display_target).to_string(),
324 Definition::BuiltinType(it) => {
325 it.name().display(db, display_target.edition).to_string()
326 }
327 Definition::BuiltinLifetime(it) => {
328 it.name().display(db, display_target.edition).to_string()
329 }
330 Definition::Local(it) => {
331 let ty = it.ty(db);
332 let ty_display = ty.display_truncated(db, None, display_target);
333 let is_mut = if it.is_mut(db) { "mut " } else { "" };
334 if it.is_self(db) {
335 format!("{is_mut}self: {ty_display}")
336 } else {
337 let name = it.name(db);
338 let let_kw = if it.is_param(db) { "" } else { "let " };
339 format!(
340 "{let_kw}{is_mut}{}: {ty_display}",
341 name.display(db, display_target.edition)
342 )
343 }
344 }
345 Definition::SelfType(impl_def) => {
346 let self_ty = &impl_def.self_ty(db);
347 match self_ty.as_adt() {
348 Some(it) => it.display(db, display_target).to_string(),
349 None => self_ty.display(db, display_target).to_string(),
350 }
351 }
352 Definition::GenericParam(it) => it.display(db, display_target).to_string(),
353 Definition::Label(it) => it.name(db).display(db, display_target.edition).to_string(),
354 Definition::ExternCrateDecl(it) => it.display(db, display_target).to_string(),
355 Definition::BuiltinAttr(it) => {
356 format!("#[{}]", it.name().display(db, display_target.edition))
357 }
358 Definition::ToolModule(it) => {
359 it.name(db).display(db, display_target.edition).to_string()
360 }
361 Definition::DeriveHelper(it) => {
362 format!("derive_helper {}", it.name(db).display(db, display_target.edition))
363 }
364 Definition::InlineAsmRegOrRegClass(_) => "inline_asm_reg_or_reg_class".to_owned(),
366 Definition::InlineAsmOperand(_) => "inline_asm_reg_operand".to_owned(),
367 }
368 }
369}
370
371pub fn find_std_module(
372 famous_defs: &FamousDefs<'_, '_>,
373 name: &str,
374 edition: Edition,
375) -> Option<hir::Module> {
376 let db = famous_defs.0.db;
377 let std_crate = famous_defs.std()?;
378 let std_root_module = std_crate.root_module(famous_defs.0.db);
379 std_root_module.children(db).find(|module| {
380 module.name(db).is_some_and(|module| module.display(db, edition).to_string() == name)
381 })
382}
383
384#[derive(Debug)]
386pub enum IdentClass<'db> {
387 NameClass(NameClass<'db>),
388 NameRefClass(NameRefClass<'db>),
389 Operator(OperatorClass),
390}
391
392impl<'db> IdentClass<'db> {
393 pub fn classify_node(
394 sema: &Semantics<'db, RootDatabase>,
395 node: &SyntaxNode,
396 ) -> Option<IdentClass<'db>> {
397 match_ast! {
398 match node {
399 ast::Name(name) => NameClass::classify(sema, &name).map(IdentClass::NameClass),
400 ast::NameRef(name_ref) => NameRefClass::classify(sema, &name_ref).map(IdentClass::NameRefClass),
401 ast::Lifetime(lifetime) => {
402 NameClass::classify_lifetime(sema, &lifetime)
403 .map(IdentClass::NameClass)
404 .or_else(|| NameRefClass::classify_lifetime(sema, &lifetime).map(IdentClass::NameRefClass))
405 },
406 ast::RangePat(range_pat) => OperatorClass::classify_range_pat(sema, &range_pat).map(IdentClass::Operator),
407 ast::RangeExpr(range_expr) => OperatorClass::classify_range_expr(sema, &range_expr).map(IdentClass::Operator),
408 ast::AwaitExpr(await_expr) => OperatorClass::classify_await(sema, &await_expr).map(IdentClass::Operator),
409 ast::BinExpr(bin_expr) => OperatorClass::classify_bin(sema, &bin_expr).map(IdentClass::Operator),
410 ast::IndexExpr(index_expr) => OperatorClass::classify_index(sema, &index_expr).map(IdentClass::Operator),
411 ast::PrefixExpr(prefix_expr) => OperatorClass::classify_prefix(sema, &prefix_expr).map(IdentClass::Operator),
412 ast::TryExpr(try_expr) => OperatorClass::classify_try(sema, &try_expr).map(IdentClass::Operator),
413 _ => None,
414 }
415 }
416 }
417
418 pub fn classify_token(
419 sema: &Semantics<'db, RootDatabase>,
420 token: &SyntaxToken,
421 ) -> Option<IdentClass<'db>> {
422 let parent = token.parent()?;
423 Self::classify_node(sema, &parent)
424 }
425
426 pub fn classify_lifetime(
427 sema: &Semantics<'db, RootDatabase>,
428 lifetime: &ast::Lifetime,
429 ) -> Option<IdentClass<'db>> {
430 NameRefClass::classify_lifetime(sema, lifetime)
431 .map(IdentClass::NameRefClass)
432 .or_else(|| NameClass::classify_lifetime(sema, lifetime).map(IdentClass::NameClass))
433 }
434
435 pub fn definitions(self) -> ArrayVec<(Definition<'db>, Option<GenericSubstitution<'db>>), 2> {
436 let mut res = ArrayVec::new();
437 match self {
438 IdentClass::NameClass(NameClass::Definition(it) | NameClass::ConstReference(it)) => {
439 res.push((it, None))
440 }
441 IdentClass::NameClass(NameClass::PatFieldShorthand {
442 local_def,
443 field_ref,
444 adt_subst,
445 }) => {
446 res.push((Definition::Local(local_def), None));
447 res.push((Definition::Field(field_ref), Some(adt_subst)));
448 }
449 IdentClass::NameRefClass(NameRefClass::Definition(it, subst)) => res.push((it, subst)),
450 IdentClass::NameRefClass(NameRefClass::FieldShorthand {
451 local_ref,
452 field_ref,
453 adt_subst,
454 }) => {
455 res.push((Definition::Local(local_ref), None));
456 res.push((Definition::Field(field_ref), Some(adt_subst)));
457 }
458 IdentClass::NameRefClass(NameRefClass::ExternCrateShorthand { decl, krate }) => {
459 res.push((Definition::ExternCrateDecl(decl), None));
460 res.push((Definition::Crate(krate), None));
461 }
462 IdentClass::Operator(
463 OperatorClass::Await(func)
464 | OperatorClass::Prefix(func)
465 | OperatorClass::Bin(func)
466 | OperatorClass::Index(func)
467 | OperatorClass::Try(func),
468 ) => res.push((Definition::Function(func), None)),
469 IdentClass::Operator(OperatorClass::Range(struct0)) => {
470 res.push((Definition::Adt(Adt::Struct(struct0)), None))
471 }
472 }
473 res
474 }
475
476 pub fn definitions_no_ops(self) -> ArrayVec<Definition<'db>, 2> {
477 let mut res = ArrayVec::new();
478 match self {
479 IdentClass::NameClass(NameClass::Definition(it) | NameClass::ConstReference(it)) => {
480 res.push(it)
481 }
482 IdentClass::NameClass(NameClass::PatFieldShorthand {
483 local_def,
484 field_ref,
485 adt_subst: _,
486 }) => {
487 res.push(Definition::Local(local_def));
488 res.push(Definition::Field(field_ref));
489 }
490 IdentClass::NameRefClass(NameRefClass::Definition(it, _)) => res.push(it),
491 IdentClass::NameRefClass(NameRefClass::FieldShorthand {
492 local_ref,
493 field_ref,
494 adt_subst: _,
495 }) => {
496 res.push(Definition::Local(local_ref));
497 res.push(Definition::Field(field_ref));
498 }
499 IdentClass::NameRefClass(NameRefClass::ExternCrateShorthand { decl, krate }) => {
500 res.push(Definition::ExternCrateDecl(decl));
501 res.push(Definition::Crate(krate));
502 }
503 IdentClass::Operator(_) => (),
504 }
505 res
506 }
507}
508
509#[derive(Debug)]
519pub enum NameClass<'db> {
520 Definition(Definition<'db>),
521 ConstReference(Definition<'db>),
524 PatFieldShorthand {
527 local_def: Local<'db>,
528 field_ref: Field,
529 adt_subst: GenericSubstitution<'db>,
530 },
531}
532
533impl<'db> NameClass<'db> {
534 pub fn defined(self) -> Option<Definition<'db>> {
536 let res = match self {
537 NameClass::Definition(it) => it,
538 NameClass::ConstReference(_) => return None,
539 NameClass::PatFieldShorthand { local_def, field_ref: _, adt_subst: _ } => {
540 Definition::Local(local_def)
541 }
542 };
543 Some(res)
544 }
545
546 pub fn classify(
547 sema: &Semantics<'db, RootDatabase>,
548 name: &ast::Name,
549 ) -> Option<NameClass<'db>> {
550 let _p = tracing::info_span!("NameClass::classify").entered();
551
552 let parent = name.syntax().parent()?;
553 let definition = match_ast! {
554 match parent {
555 ast::Item(it) => classify_item(sema, it)?,
556 ast::IdentPat(it) => return classify_ident_pat(sema, it),
557 ast::Rename(it) => classify_rename(sema, it)?,
558 ast::SelfParam(it) => Definition::Local(sema.to_def(&it)?),
559 ast::RecordField(it) => Definition::Field(sema.to_def(&it)?),
560 ast::Variant(it) => Definition::EnumVariant(sema.to_def(&it)?),
561 ast::TypeParam(it) => Definition::GenericParam(sema.to_def(&it)?.into()),
562 ast::ConstParam(it) => Definition::GenericParam(sema.to_def(&it)?.into()),
563 ast::AsmOperandNamed(it) => Definition::InlineAsmOperand(sema.to_def(&it)?),
564 _ => return None,
565 }
566 };
567 return Some(NameClass::Definition(definition));
568
569 fn classify_item<'db>(
570 sema: &Semantics<'db, RootDatabase>,
571 item: ast::Item,
572 ) -> Option<Definition<'db>> {
573 let definition = match item {
574 ast::Item::MacroRules(it) => {
575 Definition::Macro(sema.to_def(&ast::Macro::MacroRules(it))?)
576 }
577 ast::Item::MacroDef(it) => {
578 Definition::Macro(sema.to_def(&ast::Macro::MacroDef(it))?)
579 }
580 ast::Item::Const(it) => Definition::Const(sema.to_def(&it)?),
581 ast::Item::Fn(it) => {
582 let def = sema.to_def(&it)?;
583 def.as_proc_macro(sema.db)
584 .map(Definition::Macro)
585 .unwrap_or(Definition::Function(def))
586 }
587 ast::Item::Module(it) => Definition::Module(sema.to_def(&it)?),
588 ast::Item::Static(it) => Definition::Static(sema.to_def(&it)?),
589 ast::Item::Trait(it) => Definition::Trait(sema.to_def(&it)?),
590 ast::Item::TypeAlias(it) => Definition::TypeAlias(sema.to_def(&it)?),
591 ast::Item::Enum(it) => Definition::Adt(hir::Adt::Enum(sema.to_def(&it)?)),
592 ast::Item::Struct(it) => Definition::Adt(hir::Adt::Struct(sema.to_def(&it)?)),
593 ast::Item::Union(it) => Definition::Adt(hir::Adt::Union(sema.to_def(&it)?)),
594 ast::Item::ExternCrate(it) => Definition::ExternCrateDecl(sema.to_def(&it)?),
595 _ => return None,
596 };
597 Some(definition)
598 }
599
600 fn classify_ident_pat<'db>(
601 sema: &Semantics<'db, RootDatabase>,
602 ident_pat: ast::IdentPat,
603 ) -> Option<NameClass<'db>> {
604 if let Some(def) = sema.resolve_bind_pat_to_const(&ident_pat) {
605 return Some(NameClass::ConstReference(Definition::from(def)));
606 }
607
608 let local = sema.to_def(&ident_pat)?;
609 let pat_parent = ident_pat.syntax().parent();
610 if let Some(record_pat_field) = pat_parent.and_then(ast::RecordPatField::cast)
611 && record_pat_field.name_ref().is_none()
612 && let Some((field, _, adt_subst)) =
613 sema.resolve_record_pat_field_with_subst(&record_pat_field)
614 {
615 return Some(NameClass::PatFieldShorthand {
616 local_def: local,
617 field_ref: field,
618 adt_subst,
619 });
620 }
621 Some(NameClass::Definition(Definition::Local(local)))
622 }
623
624 fn classify_rename<'db>(
625 sema: &Semantics<'db, RootDatabase>,
626 rename: ast::Rename,
627 ) -> Option<Definition<'db>> {
628 if let Some(use_tree) = rename.syntax().parent().and_then(ast::UseTree::cast) {
629 let path = use_tree.path()?;
630 sema.resolve_path(&path).map(Definition::from)
631 } else {
632 sema.to_def(&rename.syntax().parent().and_then(ast::ExternCrate::cast)?)
633 .map(Definition::ExternCrateDecl)
634 }
635 }
636 }
637
638 pub fn classify_lifetime(
639 sema: &Semantics<'db, RootDatabase>,
640 lifetime: &ast::Lifetime,
641 ) -> Option<NameClass<'db>> {
642 let _p = tracing::info_span!("NameClass::classify_lifetime", ?lifetime).entered();
643 let parent = lifetime.syntax().parent()?;
644
645 if let Some(it) = ast::LifetimeParam::cast(parent.clone()) {
646 sema.to_def(&it).map(Into::into).map(Definition::GenericParam)
647 } else if let Some(it) = ast::Label::cast(parent) {
648 sema.to_def(&it).map(Definition::Label)
649 } else {
650 None
651 }
652 .map(NameClass::Definition)
653 }
654}
655
656#[derive(Debug)]
657pub enum OperatorClass {
658 Range(Struct),
659 Await(Function),
660 Prefix(Function),
661 Index(Function),
662 Try(Function),
663 Bin(Function),
664}
665
666impl OperatorClass {
667 pub fn classify_range_pat(
668 sema: &Semantics<'_, RootDatabase>,
669 range_pat: &ast::RangePat,
670 ) -> Option<OperatorClass> {
671 sema.resolve_range_pat(range_pat).map(OperatorClass::Range)
672 }
673
674 pub fn classify_range_expr(
675 sema: &Semantics<'_, RootDatabase>,
676 range_expr: &ast::RangeExpr,
677 ) -> Option<OperatorClass> {
678 sema.resolve_range_expr(range_expr).map(OperatorClass::Range)
679 }
680
681 pub fn classify_await(
682 sema: &Semantics<'_, RootDatabase>,
683 await_expr: &ast::AwaitExpr,
684 ) -> Option<OperatorClass> {
685 sema.resolve_await_to_poll(await_expr).map(OperatorClass::Await)
686 }
687
688 pub fn classify_prefix(
689 sema: &Semantics<'_, RootDatabase>,
690 prefix_expr: &ast::PrefixExpr,
691 ) -> Option<OperatorClass> {
692 sema.resolve_prefix_expr(prefix_expr).map(OperatorClass::Prefix)
693 }
694
695 pub fn classify_try(
696 sema: &Semantics<'_, RootDatabase>,
697 try_expr: &ast::TryExpr,
698 ) -> Option<OperatorClass> {
699 sema.resolve_try_expr(try_expr).map(OperatorClass::Try)
700 }
701
702 pub fn classify_index(
703 sema: &Semantics<'_, RootDatabase>,
704 index_expr: &ast::IndexExpr,
705 ) -> Option<OperatorClass> {
706 sema.resolve_index_expr(index_expr).map(OperatorClass::Index)
707 }
708
709 pub fn classify_bin(
710 sema: &Semantics<'_, RootDatabase>,
711 bin_expr: &ast::BinExpr,
712 ) -> Option<OperatorClass> {
713 sema.resolve_bin_expr(bin_expr).map(OperatorClass::Bin)
714 }
715}
716
717#[derive(Debug)]
724pub enum NameRefClass<'db> {
725 Definition(Definition<'db>, Option<GenericSubstitution<'db>>),
726 FieldShorthand {
727 local_ref: Local<'db>,
728 field_ref: Field,
729 adt_subst: GenericSubstitution<'db>,
730 },
731 ExternCrateShorthand {
737 decl: ExternCrateDecl,
738 krate: Crate,
739 },
740}
741
742impl<'db> NameRefClass<'db> {
743 pub fn classify(
746 sema: &Semantics<'db, RootDatabase>,
747 name_ref: &ast::NameRef,
748 ) -> Option<NameRefClass<'db>> {
749 let _p = tracing::info_span!("NameRefClass::classify", ?name_ref).entered();
750
751 let parent = name_ref.syntax().parent()?;
752
753 if let Some(record_field) = ast::RecordExprField::for_field_name(name_ref)
754 && let Some((field, local, _, adt_subst)) =
755 sema.resolve_record_field_with_substitution(&record_field)
756 {
757 let res = match local {
758 None => NameRefClass::Definition(Definition::Field(field), Some(adt_subst)),
759 Some(local) => {
760 NameRefClass::FieldShorthand { field_ref: field, local_ref: local, adt_subst }
761 }
762 };
763 return Some(res);
764 }
765
766 if let Some(path) = ast::PathSegment::cast(parent.clone()).map(|it| it.parent_path()) {
767 if path.parent_path().is_none()
768 && let Some(macro_call) = path.syntax().parent().and_then(ast::MacroCall::cast)
769 {
770 if let Some(macro_def) = sema.resolve_macro_call(¯o_call) {
773 return Some(NameRefClass::Definition(Definition::Macro(macro_def), None));
774 }
775 }
776 return sema
777 .resolve_path_with_subst(&path)
778 .map(|(res, subst)| NameRefClass::Definition(res.into(), subst));
779 }
780
781 match_ast! {
782 match parent {
783 ast::MethodCallExpr(method_call) => {
784 sema.resolve_method_call_fallback(&method_call)
785 .map(|(def, subst)| {
786 match def {
787 Either::Left(def) => NameRefClass::Definition(def.into(), subst),
788 Either::Right(def) => NameRefClass::Definition(def.into(), subst),
789 }
790 })
791 },
792 ast::FieldExpr(field_expr) => {
793 sema.resolve_field_fallback(&field_expr)
794 .map(|(def, subst)| {
795 match def {
796 Either::Left(Either::Left(def)) => NameRefClass::Definition(def.into(), subst),
797 Either::Left(Either::Right(def)) => NameRefClass::Definition(Definition::TupleField(def), subst),
798 Either::Right(def) => NameRefClass::Definition(def.into(), subst),
799 }
800 })
801 },
802 ast::RecordPatField(record_pat_field) => {
803 sema.resolve_record_pat_field_with_subst(&record_pat_field)
804 .map(|(field, _, subst)| NameRefClass::Definition(Definition::Field(field), Some(subst)))
805 },
806 ast::RecordExprField(record_expr_field) => {
807 sema.resolve_record_field_with_substitution(&record_expr_field)
808 .map(|(field, _, _, subst)| NameRefClass::Definition(Definition::Field(field), Some(subst)))
809 },
810 ast::AssocTypeArg(_) => {
811 let containing_path = name_ref.syntax().ancestors().find_map(ast::Path::cast)?;
814 let resolved = sema.resolve_path(&containing_path)?;
815 if let PathResolution::Def(ModuleDef::Trait(tr)) = resolved
816 && let Some(ty) = tr
817 .items_with_supertraits(sema.db)
818 .iter()
819 .filter_map(|&assoc| match assoc {
820 hir::AssocItem::TypeAlias(it) => Some(it),
821 _ => None,
822 })
823 .find(|alias| alias.name(sema.db).as_str() == name_ref.text().trim_start_matches("r#"))
824 {
825 return Some(NameRefClass::Definition(Definition::TypeAlias(ty), None));
827 }
828 None
829 },
830 ast::UseBoundGenericArgs(_) => {
831 sema.resolve_use_type_arg(name_ref)
833 .map(GenericParam::TypeParam)
834 .map(Definition::GenericParam)
835 .map(|it| NameRefClass::Definition(it, None))
836 },
837 ast::ExternCrate(extern_crate_ast) => {
838 let extern_crate = sema.to_def(&extern_crate_ast)?;
839 let krate = extern_crate.resolved_crate(sema.db)?;
840 Some(if extern_crate_ast.rename().is_some() {
841 NameRefClass::Definition(Definition::Crate(krate), None)
842 } else {
843 NameRefClass::ExternCrateShorthand { krate, decl: extern_crate }
844 })
845 },
846 ast::AsmRegSpec(_) => {
847 Some(NameRefClass::Definition(Definition::InlineAsmRegOrRegClass(()), None))
848 },
849 ast::OffsetOfExpr(_) => {
850 let (def, subst) = sema.resolve_offset_of_field(name_ref)?;
851 let def = match def {
852 Either::Left(variant) => Definition::EnumVariant(variant),
853 Either::Right(field) => Definition::Field(field),
854 };
855 Some(NameRefClass::Definition(def, Some(subst)))
856 },
857 _ => None
858 }
859 }
860 }
861
862 pub fn classify_lifetime(
863 sema: &Semantics<'db, RootDatabase>,
864 lifetime: &ast::Lifetime,
865 ) -> Option<NameRefClass<'db>> {
866 let _p = tracing::info_span!("NameRefClass::classify_lifetime", ?lifetime).entered();
867 if lifetime.text() == "'static" {
868 return Some(NameRefClass::Definition(
869 Definition::BuiltinLifetime(StaticLifetime),
870 None,
871 ));
872 }
873 let parent = lifetime.syntax().parent()?;
874 match parent.kind() {
875 SyntaxKind::BREAK_EXPR | SyntaxKind::CONTINUE_EXPR => sema
876 .resolve_label(lifetime)
877 .map(Definition::Label)
878 .map(|it| NameRefClass::Definition(it, None)),
879 SyntaxKind::LIFETIME_ARG
880 | SyntaxKind::USE_BOUND_GENERIC_ARGS
881 | SyntaxKind::SELF_PARAM
882 | SyntaxKind::TYPE_BOUND
883 | SyntaxKind::WHERE_PRED
884 | SyntaxKind::REF_TYPE => sema
885 .resolve_lifetime_param(lifetime)
886 .map(GenericParam::LifetimeParam)
887 .map(Definition::GenericParam)
888 .map(|it| NameRefClass::Definition(it, None)),
889 _ => None,
890 }
891 }
892}
893
894impl_from!(
895 impl<'db>
896 Field,
897 TupleField<'db>,
898 Module,
899 Function,
900 Adt,
901 EnumVariant,
902 Const,
903 Static,
904 Trait,
905 TypeAlias,
906 BuiltinType,
907 Local<'db>,
908 GenericParam,
909 Label,
910 Macro,
911 ExternCrateDecl,
912 InlineAsmOperand
913 for Definition<'db>
914);
915
916impl<'db> From<Impl> for Definition<'db> {
917 fn from(impl_: Impl) -> Self {
918 Definition::SelfType(impl_)
919 }
920}
921
922impl<'db> From<Either<PathResolution<'db>, InlineAsmOperand>> for Definition<'db> {
923 fn from(value: Either<PathResolution<'db>, InlineAsmOperand>) -> Self {
924 value.either(Definition::from, Definition::from)
925 }
926}
927
928impl AsAssocItem for Definition<'_> {
929 fn as_assoc_item(self, db: &dyn hir::db::HirDatabase) -> Option<AssocItem> {
930 match self {
931 Definition::Function(it) => it.as_assoc_item(db),
932 Definition::Const(it) => it.as_assoc_item(db),
933 Definition::TypeAlias(it) => it.as_assoc_item(db),
934 _ => None,
935 }
936 }
937}
938
939impl AsExternAssocItem for Definition<'_> {
940 fn as_extern_assoc_item(self, db: &dyn hir::db::HirDatabase) -> Option<ExternAssocItem> {
941 match self {
942 Definition::Function(it) => it.as_extern_assoc_item(db),
943 Definition::Static(it) => it.as_extern_assoc_item(db),
944 Definition::TypeAlias(it) => it.as_extern_assoc_item(db),
945 _ => None,
946 }
947 }
948}
949
950impl<'db> From<AssocItem> for Definition<'db> {
951 fn from(assoc_item: AssocItem) -> Self {
952 match assoc_item {
953 AssocItem::Function(it) => Definition::Function(it),
954 AssocItem::Const(it) => Definition::Const(it),
955 AssocItem::TypeAlias(it) => Definition::TypeAlias(it),
956 }
957 }
958}
959
960impl<'db> From<PathResolution<'db>> for Definition<'db> {
961 fn from(path_resolution: PathResolution<'db>) -> Self {
962 match path_resolution {
963 PathResolution::Def(def) => def.into(),
964 PathResolution::Local(local) => Definition::Local(local),
965 PathResolution::TypeParam(par) => Definition::GenericParam(par.into()),
966 PathResolution::ConstParam(par) => Definition::GenericParam(par.into()),
967 PathResolution::SelfType(impl_def) => Definition::SelfType(impl_def),
968 PathResolution::BuiltinAttr(attr) => Definition::BuiltinAttr(attr),
969 PathResolution::ToolModule(tool) => Definition::ToolModule(tool),
970 PathResolution::DeriveHelper(helper) => Definition::DeriveHelper(helper),
971 }
972 }
973}
974
975impl<'db> From<ModuleDef> for Definition<'db> {
976 fn from(def: ModuleDef) -> Self {
977 match def {
978 ModuleDef::Module(it) => Definition::Module(it),
979 ModuleDef::Function(it) => Definition::Function(it),
980 ModuleDef::Adt(it) => Definition::Adt(it),
981 ModuleDef::EnumVariant(it) => Definition::EnumVariant(it),
982 ModuleDef::Const(it) => Definition::Const(it),
983 ModuleDef::Static(it) => Definition::Static(it),
984 ModuleDef::Trait(it) => Definition::Trait(it),
985 ModuleDef::TypeAlias(it) => Definition::TypeAlias(it),
986 ModuleDef::Macro(it) => Definition::Macro(it),
987 ModuleDef::BuiltinType(it) => Definition::BuiltinType(it),
988 }
989 }
990}
991
992impl<'db> From<DocLinkDef> for Definition<'db> {
993 fn from(def: DocLinkDef) -> Self {
994 match def {
995 DocLinkDef::ModuleDef(it) => it.into(),
996 DocLinkDef::Field(it) => it.into(),
997 DocLinkDef::SelfType(it) => it.into(),
998 }
999 }
1000}
1001
1002impl<'db> From<Variant> for Definition<'db> {
1003 fn from(def: Variant) -> Self {
1004 ModuleDef::from(def).into()
1005 }
1006}
1007
1008impl<'db> TryFrom<DefWithBody> for Definition<'db> {
1009 type Error = ();
1010 fn try_from(def: DefWithBody) -> Result<Self, Self::Error> {
1011 match def {
1012 DefWithBody::Function(it) => Ok(it.into()),
1013 DefWithBody::Static(it) => Ok(it.into()),
1014 DefWithBody::Const(it) => Ok(it.into()),
1015 DefWithBody::EnumVariant(it) => Ok(it.into()),
1016 }
1017 }
1018}
1019
1020impl<'db> From<GenericDef> for Definition<'db> {
1021 fn from(def: GenericDef) -> Self {
1022 match def {
1023 GenericDef::Function(it) => it.into(),
1024 GenericDef::Adt(it) => it.into(),
1025 GenericDef::Trait(it) => it.into(),
1026 GenericDef::TypeAlias(it) => it.into(),
1027 GenericDef::Impl(it) => it.into(),
1028 GenericDef::Const(it) => it.into(),
1029 GenericDef::Static(it) => it.into(),
1030 }
1031 }
1032}
1033
1034impl<'db> TryFrom<ExpressionStoreOwner> for Definition<'db> {
1035 type Error = ();
1036 fn try_from(def: ExpressionStoreOwner) -> Result<Self, Self::Error> {
1037 match def {
1038 ExpressionStoreOwner::Body(def_with_body) => def_with_body.try_into(),
1039 ExpressionStoreOwner::Signature(generic_def) => Ok(generic_def.into()),
1040 ExpressionStoreOwner::VariantFields(it) => Ok(it.into()),
1041 }
1042 }
1043}
1044
1045impl TryFrom<Definition<'_>> for GenericDef {
1046 type Error = ();
1047 fn try_from(def: Definition<'_>) -> Result<Self, Self::Error> {
1048 match def {
1049 Definition::Function(it) => Ok(it.into()),
1050 Definition::Adt(it) => Ok(it.into()),
1051 Definition::Trait(it) => Ok(it.into()),
1052 Definition::TypeAlias(it) => Ok(it.into()),
1053 Definition::SelfType(it) => Ok(it.into()),
1054 Definition::Const(it) => Ok(it.into()),
1055 _ => Err(()),
1056 }
1057 }
1058}