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