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 {
35 Macro(Macro),
36 Field(Field),
37 TupleField(TupleField),
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),
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 Definition {
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> {
108 fn container_to_definition(container: ItemContainer) -> Option<Definition> {
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<'db>(
206 &self,
207 db: &'db RootDatabase,
208 famous_defs: Option<&FamousDefs<'_, '_>>,
209 display_target: DisplayTarget,
210 ) -> Option<Documentation<'db>> {
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<'db>(
219 &self,
220 db: &'db RootDatabase,
221 famous_defs: Option<&FamousDefs<'_, '_>>,
222 display_target: DisplayTarget,
223 ) -> Option<Either<Cow<'db, hir::Docs>, Documentation<'db>>> {
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, 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, 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),
521 ConstReference(Definition),
524 PatFieldShorthand {
527 local_def: Local,
528 field_ref: Field,
529 adt_subst: GenericSubstitution<'db>,
530 },
531}
532
533impl<'db> NameClass<'db> {
534 pub fn defined(self) -> Option<Definition> {
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(
570 sema: &Semantics<'_, RootDatabase>,
571 item: ast::Item,
572 ) -> Option<Definition> {
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(
625 sema: &Semantics<'_, RootDatabase>,
626 rename: ast::Rename,
627 ) -> Option<Definition> {
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, Option<GenericSubstitution<'db>>),
726 FieldShorthand {
727 local_ref: Local,
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 Field, Module, Function, Adt, EnumVariant, Const, Static, Trait, TypeAlias, BuiltinType, Local,
896 GenericParam, Label, Macro, ExternCrateDecl
897 for Definition
898);
899
900impl From<Impl> for Definition {
901 fn from(impl_: Impl) -> Self {
902 Definition::SelfType(impl_)
903 }
904}
905
906impl From<InlineAsmOperand> for Definition {
907 fn from(value: InlineAsmOperand) -> Self {
908 Definition::InlineAsmOperand(value)
909 }
910}
911
912impl From<Either<PathResolution, InlineAsmOperand>> for Definition {
913 fn from(value: Either<PathResolution, InlineAsmOperand>) -> Self {
914 value.either(Definition::from, Definition::from)
915 }
916}
917
918impl AsAssocItem for Definition {
919 fn as_assoc_item(self, db: &dyn hir::db::HirDatabase) -> Option<AssocItem> {
920 match self {
921 Definition::Function(it) => it.as_assoc_item(db),
922 Definition::Const(it) => it.as_assoc_item(db),
923 Definition::TypeAlias(it) => it.as_assoc_item(db),
924 _ => None,
925 }
926 }
927}
928
929impl AsExternAssocItem for Definition {
930 fn as_extern_assoc_item(self, db: &dyn hir::db::HirDatabase) -> Option<ExternAssocItem> {
931 match self {
932 Definition::Function(it) => it.as_extern_assoc_item(db),
933 Definition::Static(it) => it.as_extern_assoc_item(db),
934 Definition::TypeAlias(it) => it.as_extern_assoc_item(db),
935 _ => None,
936 }
937 }
938}
939
940impl From<AssocItem> for Definition {
941 fn from(assoc_item: AssocItem) -> Self {
942 match assoc_item {
943 AssocItem::Function(it) => Definition::Function(it),
944 AssocItem::Const(it) => Definition::Const(it),
945 AssocItem::TypeAlias(it) => Definition::TypeAlias(it),
946 }
947 }
948}
949
950impl From<PathResolution> for Definition {
951 fn from(path_resolution: PathResolution) -> Self {
952 match path_resolution {
953 PathResolution::Def(def) => def.into(),
954 PathResolution::Local(local) => Definition::Local(local),
955 PathResolution::TypeParam(par) => Definition::GenericParam(par.into()),
956 PathResolution::ConstParam(par) => Definition::GenericParam(par.into()),
957 PathResolution::SelfType(impl_def) => Definition::SelfType(impl_def),
958 PathResolution::BuiltinAttr(attr) => Definition::BuiltinAttr(attr),
959 PathResolution::ToolModule(tool) => Definition::ToolModule(tool),
960 PathResolution::DeriveHelper(helper) => Definition::DeriveHelper(helper),
961 }
962 }
963}
964
965impl From<ModuleDef> for Definition {
966 fn from(def: ModuleDef) -> Self {
967 match def {
968 ModuleDef::Module(it) => Definition::Module(it),
969 ModuleDef::Function(it) => Definition::Function(it),
970 ModuleDef::Adt(it) => Definition::Adt(it),
971 ModuleDef::EnumVariant(it) => Definition::EnumVariant(it),
972 ModuleDef::Const(it) => Definition::Const(it),
973 ModuleDef::Static(it) => Definition::Static(it),
974 ModuleDef::Trait(it) => Definition::Trait(it),
975 ModuleDef::TypeAlias(it) => Definition::TypeAlias(it),
976 ModuleDef::Macro(it) => Definition::Macro(it),
977 ModuleDef::BuiltinType(it) => Definition::BuiltinType(it),
978 }
979 }
980}
981
982impl From<DocLinkDef> for Definition {
983 fn from(def: DocLinkDef) -> Self {
984 match def {
985 DocLinkDef::ModuleDef(it) => it.into(),
986 DocLinkDef::Field(it) => it.into(),
987 DocLinkDef::SelfType(it) => it.into(),
988 }
989 }
990}
991
992impl From<Variant> for Definition {
993 fn from(def: Variant) -> Self {
994 ModuleDef::from(def).into()
995 }
996}
997
998impl TryFrom<DefWithBody> for Definition {
999 type Error = ();
1000 fn try_from(def: DefWithBody) -> Result<Self, Self::Error> {
1001 match def {
1002 DefWithBody::Function(it) => Ok(it.into()),
1003 DefWithBody::Static(it) => Ok(it.into()),
1004 DefWithBody::Const(it) => Ok(it.into()),
1005 DefWithBody::EnumVariant(it) => Ok(it.into()),
1006 }
1007 }
1008}
1009
1010impl From<GenericDef> for Definition {
1011 fn from(def: GenericDef) -> Self {
1012 match def {
1013 GenericDef::Function(it) => it.into(),
1014 GenericDef::Adt(it) => it.into(),
1015 GenericDef::Trait(it) => it.into(),
1016 GenericDef::TypeAlias(it) => it.into(),
1017 GenericDef::Impl(it) => it.into(),
1018 GenericDef::Const(it) => it.into(),
1019 GenericDef::Static(it) => it.into(),
1020 }
1021 }
1022}
1023
1024impl TryFrom<ExpressionStoreOwner> for Definition {
1025 type Error = ();
1026 fn try_from(def: ExpressionStoreOwner) -> Result<Self, Self::Error> {
1027 match def {
1028 ExpressionStoreOwner::Body(def_with_body) => def_with_body.try_into(),
1029 ExpressionStoreOwner::Signature(generic_def) => Ok(generic_def.into()),
1030 ExpressionStoreOwner::VariantFields(it) => Ok(it.into()),
1031 }
1032 }
1033}
1034
1035impl TryFrom<Definition> for GenericDef {
1036 type Error = ();
1037 fn try_from(def: Definition) -> Result<Self, Self::Error> {
1038 match def {
1039 Definition::Function(it) => Ok(it.into()),
1040 Definition::Adt(it) => Ok(it.into()),
1041 Definition::Trait(it) => Ok(it.into()),
1042 Definition::TypeAlias(it) => Ok(it.into()),
1043 Definition::SelfType(it) => Ok(it.into()),
1044 Definition::Const(it) => Ok(it.into()),
1045 _ => Err(()),
1046 }
1047 }
1048}