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