mirror of
				https://github.com/rust-lang/rust-analyzer.git
				synced 2025-10-30 19:49:36 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			1032 lines
		
	
	
	
		
			43 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			1032 lines
		
	
	
	
		
			43 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
| //! `NameDefinition` keeps information about the element we want to search references for.
 | |
| //! The element is represented by `NameKind`. It's located inside some `container` and
 | |
| //! has a `visibility`, which defines a search scope.
 | |
| //! Note that the reference search is possible for not all of the classified items.
 | |
| 
 | |
| // FIXME: this badly needs rename/rewrite (matklad, 2020-02-06).
 | |
| 
 | |
| use crate::RootDatabase;
 | |
| use crate::documentation::{DocsRangeMap, Documentation, HasDocs};
 | |
| use crate::famous_defs::FamousDefs;
 | |
| use arrayvec::ArrayVec;
 | |
| use either::Either;
 | |
| use hir::{
 | |
|     Adt, AsAssocItem, AsExternAssocItem, AssocItem, AttributeTemplate, BuiltinAttr, BuiltinType,
 | |
|     Const, Crate, DefWithBody, DeriveHelper, DisplayTarget, DocLinkDef, ExternAssocItem,
 | |
|     ExternCrateDecl, Field, Function, GenericDef, GenericParam, GenericSubstitution, HasContainer,
 | |
|     HasVisibility, HirDisplay, Impl, InlineAsmOperand, ItemContainer, Label, Local, Macro, Module,
 | |
|     ModuleDef, Name, PathResolution, Semantics, Static, StaticLifetime, Struct, ToolModule, Trait,
 | |
|     TupleField, TypeAlias, Variant, VariantDef, Visibility,
 | |
| };
 | |
| use span::Edition;
 | |
| use stdx::{format_to, impl_from};
 | |
| use syntax::{
 | |
|     SyntaxKind, SyntaxNode, SyntaxToken, TextSize,
 | |
|     ast::{self, AstNode},
 | |
|     match_ast,
 | |
| };
 | |
| 
 | |
| // FIXME: a more precise name would probably be `Symbol`?
 | |
| #[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)]
 | |
| pub enum Definition {
 | |
|     Macro(Macro),
 | |
|     Field(Field),
 | |
|     TupleField(TupleField),
 | |
|     Module(Module),
 | |
|     Crate(Crate),
 | |
|     Function(Function),
 | |
|     Adt(Adt),
 | |
|     Variant(Variant),
 | |
|     Const(Const),
 | |
|     Static(Static),
 | |
|     Trait(Trait),
 | |
|     TypeAlias(TypeAlias),
 | |
|     SelfType(Impl),
 | |
|     GenericParam(GenericParam),
 | |
|     Local(Local),
 | |
|     Label(Label),
 | |
|     DeriveHelper(DeriveHelper),
 | |
|     BuiltinType(BuiltinType),
 | |
|     BuiltinLifetime(StaticLifetime),
 | |
|     BuiltinAttr(BuiltinAttr),
 | |
|     ToolModule(ToolModule),
 | |
|     ExternCrateDecl(ExternCrateDecl),
 | |
|     InlineAsmRegOrRegClass(()),
 | |
|     InlineAsmOperand(InlineAsmOperand),
 | |
| }
 | |
| 
 | |
| impl Definition {
 | |
|     pub fn canonical_module_path(&self, db: &RootDatabase) -> Option<impl Iterator<Item = Module>> {
 | |
|         self.module(db).map(|it| it.path_to_root(db).into_iter().rev())
 | |
|     }
 | |
| 
 | |
|     pub fn krate(&self, db: &RootDatabase) -> Option<Crate> {
 | |
|         Some(match self {
 | |
|             Definition::Module(m) => m.krate(),
 | |
|             &Definition::Crate(it) => it,
 | |
|             _ => self.module(db)?.krate(),
 | |
|         })
 | |
|     }
 | |
| 
 | |
|     /// Returns the module this definition resides in.
 | |
|     ///
 | |
|     /// As such, for modules themselves this will return the parent module.
 | |
|     pub fn module(&self, db: &RootDatabase) -> Option<Module> {
 | |
|         let module = match self {
 | |
|             Definition::Macro(it) => it.module(db),
 | |
|             Definition::Module(it) => it.parent(db)?,
 | |
|             Definition::Crate(_) => return None,
 | |
|             Definition::Field(it) => it.parent_def(db).module(db),
 | |
|             Definition::Function(it) => it.module(db),
 | |
|             Definition::Adt(it) => it.module(db),
 | |
|             Definition::Const(it) => it.module(db),
 | |
|             Definition::Static(it) => it.module(db),
 | |
|             Definition::Trait(it) => it.module(db),
 | |
|             Definition::TypeAlias(it) => it.module(db),
 | |
|             Definition::Variant(it) => it.module(db),
 | |
|             Definition::SelfType(it) => it.module(db),
 | |
|             Definition::Local(it) => it.module(db),
 | |
|             Definition::GenericParam(it) => it.module(db),
 | |
|             Definition::Label(it) => it.module(db),
 | |
|             Definition::ExternCrateDecl(it) => it.module(db),
 | |
|             Definition::DeriveHelper(it) => it.derive().module(db),
 | |
|             Definition::InlineAsmOperand(it) => it.parent(db).module(db),
 | |
|             Definition::ToolModule(t) => t.krate().root_module(),
 | |
|             Definition::BuiltinAttr(_)
 | |
|             | Definition::BuiltinType(_)
 | |
|             | Definition::BuiltinLifetime(_)
 | |
|             | Definition::TupleField(_)
 | |
|             | Definition::InlineAsmRegOrRegClass(_) => return None,
 | |
|         };
 | |
|         Some(module)
 | |
|     }
 | |
| 
 | |
|     pub fn enclosing_definition(&self, db: &RootDatabase) -> Option<Definition> {
 | |
|         fn container_to_definition(container: ItemContainer) -> Option<Definition> {
 | |
|             match container {
 | |
|                 ItemContainer::Trait(it) => Some(it.into()),
 | |
|                 ItemContainer::Impl(it) => Some(it.into()),
 | |
|                 ItemContainer::Module(it) => Some(it.into()),
 | |
|                 ItemContainer::ExternBlock(_) | ItemContainer::Crate(_) => None,
 | |
|             }
 | |
|         }
 | |
|         match self {
 | |
|             Definition::Macro(it) => Some(it.module(db).into()),
 | |
|             Definition::Module(it) => it.parent(db).map(Definition::Module),
 | |
|             Definition::Crate(_) => None,
 | |
|             Definition::Field(it) => Some(it.parent_def(db).into()),
 | |
|             Definition::Function(it) => container_to_definition(it.container(db)),
 | |
|             Definition::Adt(it) => Some(it.module(db).into()),
 | |
|             Definition::Const(it) => container_to_definition(it.container(db)),
 | |
|             Definition::Static(it) => container_to_definition(it.container(db)),
 | |
|             Definition::Trait(it) => container_to_definition(it.container(db)),
 | |
|             Definition::TypeAlias(it) => container_to_definition(it.container(db)),
 | |
|             Definition::Variant(it) => Some(Adt::Enum(it.parent_enum(db)).into()),
 | |
|             Definition::SelfType(it) => Some(it.module(db).into()),
 | |
|             Definition::Local(it) => it.parent(db).try_into().ok(),
 | |
|             Definition::GenericParam(it) => Some(it.parent().into()),
 | |
|             Definition::Label(it) => it.parent(db).try_into().ok(),
 | |
|             Definition::ExternCrateDecl(it) => container_to_definition(it.container(db)),
 | |
|             Definition::DeriveHelper(it) => Some(it.derive().module(db).into()),
 | |
|             Definition::InlineAsmOperand(it) => it.parent(db).try_into().ok(),
 | |
|             Definition::BuiltinAttr(_)
 | |
|             | Definition::BuiltinType(_)
 | |
|             | Definition::BuiltinLifetime(_)
 | |
|             | Definition::TupleField(_)
 | |
|             | Definition::ToolModule(_)
 | |
|             | Definition::InlineAsmRegOrRegClass(_) => None,
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     pub fn visibility(&self, db: &RootDatabase) -> Option<Visibility> {
 | |
|         let vis = match self {
 | |
|             Definition::Field(sf) => sf.visibility(db),
 | |
|             Definition::Module(it) => it.visibility(db),
 | |
|             Definition::Crate(_) => return None,
 | |
|             Definition::Function(it) => it.visibility(db),
 | |
|             Definition::Adt(it) => it.visibility(db),
 | |
|             Definition::Const(it) => it.visibility(db),
 | |
|             Definition::Static(it) => it.visibility(db),
 | |
|             Definition::Trait(it) => it.visibility(db),
 | |
|             Definition::TypeAlias(it) => it.visibility(db),
 | |
|             Definition::Variant(it) => it.visibility(db),
 | |
|             Definition::ExternCrateDecl(it) => it.visibility(db),
 | |
|             Definition::Macro(it) => it.visibility(db),
 | |
|             Definition::BuiltinType(_) | Definition::TupleField(_) => Visibility::Public,
 | |
|             Definition::BuiltinAttr(_)
 | |
|             | Definition::BuiltinLifetime(_)
 | |
|             | Definition::ToolModule(_)
 | |
|             | Definition::SelfType(_)
 | |
|             | Definition::Local(_)
 | |
|             | Definition::GenericParam(_)
 | |
|             | Definition::Label(_)
 | |
|             | Definition::DeriveHelper(_)
 | |
|             | Definition::InlineAsmRegOrRegClass(_)
 | |
|             | Definition::InlineAsmOperand(_) => return None,
 | |
|         };
 | |
|         Some(vis)
 | |
|     }
 | |
| 
 | |
|     pub fn name(&self, db: &RootDatabase) -> Option<Name> {
 | |
|         let name = match self {
 | |
|             Definition::Macro(it) => it.name(db),
 | |
|             Definition::Field(it) => it.name(db),
 | |
|             Definition::Module(it) => it.name(db)?,
 | |
|             Definition::Crate(it) => {
 | |
|                 Name::new_symbol_root(it.display_name(db)?.crate_name().symbol().clone())
 | |
|             }
 | |
|             Definition::Function(it) => it.name(db),
 | |
|             Definition::Adt(it) => it.name(db),
 | |
|             Definition::Variant(it) => it.name(db),
 | |
|             Definition::Const(it) => it.name(db)?,
 | |
|             Definition::Static(it) => it.name(db),
 | |
|             Definition::Trait(it) => it.name(db),
 | |
|             Definition::TypeAlias(it) => it.name(db),
 | |
|             Definition::BuiltinType(it) => it.name(),
 | |
|             Definition::TupleField(it) => it.name(),
 | |
|             Definition::SelfType(_) => return None,
 | |
|             Definition::Local(it) => it.name(db),
 | |
|             Definition::GenericParam(it) => it.name(db),
 | |
|             Definition::Label(it) => it.name(db),
 | |
|             Definition::BuiltinLifetime(it) => it.name(),
 | |
|             Definition::BuiltinAttr(_) => return None, // FIXME
 | |
|             Definition::ToolModule(_) => return None,  // FIXME
 | |
|             Definition::DeriveHelper(it) => it.name(db),
 | |
|             Definition::ExternCrateDecl(it) => return it.alias_or_name(db),
 | |
|             Definition::InlineAsmRegOrRegClass(_) => return None,
 | |
|             Definition::InlineAsmOperand(op) => return op.name(db),
 | |
|         };
 | |
|         Some(name)
 | |
|     }
 | |
| 
 | |
|     pub fn docs(
 | |
|         &self,
 | |
|         db: &RootDatabase,
 | |
|         famous_defs: Option<&FamousDefs<'_, '_>>,
 | |
|         display_target: DisplayTarget,
 | |
|     ) -> Option<Documentation> {
 | |
|         self.docs_with_rangemap(db, famous_defs, display_target).map(|(docs, _)| docs)
 | |
|     }
 | |
| 
 | |
|     pub fn docs_with_rangemap(
 | |
|         &self,
 | |
|         db: &RootDatabase,
 | |
|         famous_defs: Option<&FamousDefs<'_, '_>>,
 | |
|         display_target: DisplayTarget,
 | |
|     ) -> Option<(Documentation, Option<DocsRangeMap>)> {
 | |
|         let docs = match self {
 | |
|             Definition::Macro(it) => it.docs_with_rangemap(db),
 | |
|             Definition::Field(it) => it.docs_with_rangemap(db),
 | |
|             Definition::Module(it) => it.docs_with_rangemap(db),
 | |
|             Definition::Crate(it) => it.docs_with_rangemap(db),
 | |
|             Definition::Function(it) => it.docs_with_rangemap(db),
 | |
|             Definition::Adt(it) => it.docs_with_rangemap(db),
 | |
|             Definition::Variant(it) => it.docs_with_rangemap(db),
 | |
|             Definition::Const(it) => it.docs_with_rangemap(db),
 | |
|             Definition::Static(it) => it.docs_with_rangemap(db),
 | |
|             Definition::Trait(it) => it.docs_with_rangemap(db),
 | |
|             Definition::TypeAlias(it) => {
 | |
|                 it.docs_with_rangemap(db).or_else(|| {
 | |
|                     // docs are missing, try to fall back to the docs of the aliased item.
 | |
|                     let adt = it.ty(db).as_adt()?;
 | |
|                     let (docs, range_map) = adt.docs_with_rangemap(db)?;
 | |
|                     let header_docs = format!(
 | |
|                         "*This is the documentation for* `{}`\n\n",
 | |
|                         adt.display(db, display_target)
 | |
|                     );
 | |
|                     let offset = TextSize::new(header_docs.len() as u32);
 | |
|                     let range_map = range_map.shift_docstring_line_range(offset);
 | |
|                     let docs = header_docs + docs.as_str();
 | |
|                     Some((Documentation::new(docs), range_map))
 | |
|                 })
 | |
|             }
 | |
|             Definition::BuiltinType(it) => {
 | |
|                 famous_defs.and_then(|fd| {
 | |
|                     // std exposes prim_{} modules with docstrings on the root to document the builtins
 | |
|                     let primitive_mod =
 | |
|                         format!("prim_{}", it.name().display(fd.0.db, display_target.edition));
 | |
|                     let doc_owner = find_std_module(fd, &primitive_mod, display_target.edition)?;
 | |
|                     doc_owner.docs_with_rangemap(fd.0.db)
 | |
|                 })
 | |
|             }
 | |
|             Definition::BuiltinLifetime(StaticLifetime) => None,
 | |
|             Definition::Local(_) => None,
 | |
|             Definition::SelfType(impl_def) => {
 | |
|                 impl_def.self_ty(db).as_adt().map(|adt| adt.docs_with_rangemap(db))?
 | |
|             }
 | |
|             Definition::GenericParam(_) => None,
 | |
|             Definition::Label(_) => None,
 | |
|             Definition::ExternCrateDecl(it) => it.docs_with_rangemap(db),
 | |
| 
 | |
|             Definition::BuiltinAttr(it) => {
 | |
|                 let name = it.name(db);
 | |
|                 let AttributeTemplate { word, list, name_value_str } = it.template(db)?;
 | |
|                 let mut docs = "Valid forms are:".to_owned();
 | |
|                 if word {
 | |
|                     format_to!(docs, "\n - #\\[{}]", name.display(db, display_target.edition));
 | |
|                 }
 | |
|                 if let Some(list) = list {
 | |
|                     format_to!(
 | |
|                         docs,
 | |
|                         "\n - #\\[{}({})]",
 | |
|                         name.display(db, display_target.edition),
 | |
|                         list
 | |
|                     );
 | |
|                 }
 | |
|                 if let Some(name_value_str) = name_value_str {
 | |
|                     format_to!(
 | |
|                         docs,
 | |
|                         "\n - #\\[{} = {}]",
 | |
|                         name.display(db, display_target.edition),
 | |
|                         name_value_str
 | |
|                     );
 | |
|                 }
 | |
| 
 | |
|                 return Some((Documentation::new(docs.replace('*', "\\*")), None));
 | |
|             }
 | |
|             Definition::ToolModule(_) => None,
 | |
|             Definition::DeriveHelper(_) => None,
 | |
|             Definition::TupleField(_) => None,
 | |
|             Definition::InlineAsmRegOrRegClass(_) | Definition::InlineAsmOperand(_) => None,
 | |
|         };
 | |
| 
 | |
|         docs.or_else(|| {
 | |
|             // docs are missing, for assoc items of trait impls try to fall back to the docs of the
 | |
|             // original item of the trait
 | |
|             let assoc = self.as_assoc_item(db)?;
 | |
|             let trait_ = assoc.implemented_trait(db)?;
 | |
|             let name = Some(assoc.name(db)?);
 | |
|             let item = trait_.items(db).into_iter().find(|it| it.name(db) == name)?;
 | |
|             item.docs_with_rangemap(db)
 | |
|         })
 | |
|         .map(|(docs, range_map)| (docs, Some(range_map)))
 | |
|     }
 | |
| 
 | |
|     pub fn label(&self, db: &RootDatabase, display_target: DisplayTarget) -> String {
 | |
|         match *self {
 | |
|             Definition::Macro(it) => it.display(db, display_target).to_string(),
 | |
|             Definition::Field(it) => it.display(db, display_target).to_string(),
 | |
|             Definition::TupleField(it) => it.display(db, display_target).to_string(),
 | |
|             Definition::Module(it) => it.display(db, display_target).to_string(),
 | |
|             Definition::Crate(it) => it.display(db, display_target).to_string(),
 | |
|             Definition::Function(it) => it.display(db, display_target).to_string(),
 | |
|             Definition::Adt(it) => it.display(db, display_target).to_string(),
 | |
|             Definition::Variant(it) => it.display(db, display_target).to_string(),
 | |
|             Definition::Const(it) => it.display(db, display_target).to_string(),
 | |
|             Definition::Static(it) => it.display(db, display_target).to_string(),
 | |
|             Definition::Trait(it) => it.display(db, display_target).to_string(),
 | |
|             Definition::TypeAlias(it) => it.display(db, display_target).to_string(),
 | |
|             Definition::BuiltinType(it) => {
 | |
|                 it.name().display(db, display_target.edition).to_string()
 | |
|             }
 | |
|             Definition::BuiltinLifetime(it) => {
 | |
|                 it.name().display(db, display_target.edition).to_string()
 | |
|             }
 | |
|             Definition::Local(it) => {
 | |
|                 let ty = it.ty(db);
 | |
|                 let ty_display = ty.display_truncated(db, None, display_target);
 | |
|                 let is_mut = if it.is_mut(db) { "mut " } else { "" };
 | |
|                 if it.is_self(db) {
 | |
|                     format!("{is_mut}self: {ty_display}")
 | |
|                 } else {
 | |
|                     let name = it.name(db);
 | |
|                     let let_kw = if it.is_param(db) { "" } else { "let " };
 | |
|                     format!(
 | |
|                         "{let_kw}{is_mut}{}: {ty_display}",
 | |
|                         name.display(db, display_target.edition)
 | |
|                     )
 | |
|                 }
 | |
|             }
 | |
|             Definition::SelfType(impl_def) => {
 | |
|                 let self_ty = &impl_def.self_ty(db);
 | |
|                 match self_ty.as_adt() {
 | |
|                     Some(it) => it.display(db, display_target).to_string(),
 | |
|                     None => self_ty.display(db, display_target).to_string(),
 | |
|                 }
 | |
|             }
 | |
|             Definition::GenericParam(it) => it.display(db, display_target).to_string(),
 | |
|             Definition::Label(it) => it.name(db).display(db, display_target.edition).to_string(),
 | |
|             Definition::ExternCrateDecl(it) => it.display(db, display_target).to_string(),
 | |
|             Definition::BuiltinAttr(it) => {
 | |
|                 format!("#[{}]", it.name(db).display(db, display_target.edition))
 | |
|             }
 | |
|             Definition::ToolModule(it) => {
 | |
|                 it.name(db).display(db, display_target.edition).to_string()
 | |
|             }
 | |
|             Definition::DeriveHelper(it) => {
 | |
|                 format!("derive_helper {}", it.name(db).display(db, display_target.edition))
 | |
|             }
 | |
|             // FIXME
 | |
|             Definition::InlineAsmRegOrRegClass(_) => "inline_asm_reg_or_reg_class".to_owned(),
 | |
|             Definition::InlineAsmOperand(_) => "inline_asm_reg_operand".to_owned(),
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| fn find_std_module(
 | |
|     famous_defs: &FamousDefs<'_, '_>,
 | |
|     name: &str,
 | |
|     edition: Edition,
 | |
| ) -> Option<hir::Module> {
 | |
|     let db = famous_defs.0.db;
 | |
|     let std_crate = famous_defs.std()?;
 | |
|     let std_root_module = std_crate.root_module();
 | |
|     std_root_module.children(db).find(|module| {
 | |
|         module.name(db).is_some_and(|module| module.display(db, edition).to_string() == name)
 | |
|     })
 | |
| }
 | |
| 
 | |
| // FIXME: IdentClass as a name no longer fits
 | |
| #[derive(Debug)]
 | |
| pub enum IdentClass<'db> {
 | |
|     NameClass(NameClass<'db>),
 | |
|     NameRefClass(NameRefClass<'db>),
 | |
|     Operator(OperatorClass),
 | |
| }
 | |
| 
 | |
| impl<'db> IdentClass<'db> {
 | |
|     pub fn classify_node(
 | |
|         sema: &Semantics<'db, RootDatabase>,
 | |
|         node: &SyntaxNode,
 | |
|     ) -> Option<IdentClass<'db>> {
 | |
|         match_ast! {
 | |
|             match node {
 | |
|                 ast::Name(name) => NameClass::classify(sema, &name).map(IdentClass::NameClass),
 | |
|                 ast::NameRef(name_ref) => NameRefClass::classify(sema, &name_ref).map(IdentClass::NameRefClass),
 | |
|                 ast::Lifetime(lifetime) => {
 | |
|                     NameClass::classify_lifetime(sema, &lifetime)
 | |
|                         .map(IdentClass::NameClass)
 | |
|                         .or_else(|| NameRefClass::classify_lifetime(sema, &lifetime).map(IdentClass::NameRefClass))
 | |
|                 },
 | |
|                 ast::RangePat(range_pat) => OperatorClass::classify_range_pat(sema, &range_pat).map(IdentClass::Operator),
 | |
|                 ast::RangeExpr(range_expr) => OperatorClass::classify_range_expr(sema, &range_expr).map(IdentClass::Operator),
 | |
|                 ast::AwaitExpr(await_expr) => OperatorClass::classify_await(sema, &await_expr).map(IdentClass::Operator),
 | |
|                 ast::BinExpr(bin_expr) => OperatorClass::classify_bin(sema, &bin_expr).map(IdentClass::Operator),
 | |
|                 ast::IndexExpr(index_expr) => OperatorClass::classify_index(sema, &index_expr).map(IdentClass::Operator),
 | |
|                 ast::PrefixExpr(prefix_expr) => OperatorClass::classify_prefix(sema, &prefix_expr).map(IdentClass::Operator),
 | |
|                 ast::TryExpr(try_expr) => OperatorClass::classify_try(sema, &try_expr).map(IdentClass::Operator),
 | |
|                 _ => None,
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     pub fn classify_token(
 | |
|         sema: &Semantics<'db, RootDatabase>,
 | |
|         token: &SyntaxToken,
 | |
|     ) -> Option<IdentClass<'db>> {
 | |
|         let parent = token.parent()?;
 | |
|         Self::classify_node(sema, &parent)
 | |
|     }
 | |
| 
 | |
|     pub fn classify_lifetime(
 | |
|         sema: &Semantics<'db, RootDatabase>,
 | |
|         lifetime: &ast::Lifetime,
 | |
|     ) -> Option<IdentClass<'db>> {
 | |
|         NameRefClass::classify_lifetime(sema, lifetime)
 | |
|             .map(IdentClass::NameRefClass)
 | |
|             .or_else(|| NameClass::classify_lifetime(sema, lifetime).map(IdentClass::NameClass))
 | |
|     }
 | |
| 
 | |
|     pub fn definitions(self) -> ArrayVec<(Definition, Option<GenericSubstitution<'db>>), 2> {
 | |
|         let mut res = ArrayVec::new();
 | |
|         match self {
 | |
|             IdentClass::NameClass(NameClass::Definition(it) | NameClass::ConstReference(it)) => {
 | |
|                 res.push((it, None))
 | |
|             }
 | |
|             IdentClass::NameClass(NameClass::PatFieldShorthand {
 | |
|                 local_def,
 | |
|                 field_ref,
 | |
|                 adt_subst,
 | |
|             }) => {
 | |
|                 res.push((Definition::Local(local_def), None));
 | |
|                 res.push((Definition::Field(field_ref), Some(adt_subst)));
 | |
|             }
 | |
|             IdentClass::NameRefClass(NameRefClass::Definition(it, subst)) => res.push((it, subst)),
 | |
|             IdentClass::NameRefClass(NameRefClass::FieldShorthand {
 | |
|                 local_ref,
 | |
|                 field_ref,
 | |
|                 adt_subst,
 | |
|             }) => {
 | |
|                 res.push((Definition::Local(local_ref), None));
 | |
|                 res.push((Definition::Field(field_ref), Some(adt_subst)));
 | |
|             }
 | |
|             IdentClass::NameRefClass(NameRefClass::ExternCrateShorthand { decl, krate }) => {
 | |
|                 res.push((Definition::ExternCrateDecl(decl), None));
 | |
|                 res.push((Definition::Crate(krate), None));
 | |
|             }
 | |
|             IdentClass::Operator(
 | |
|                 OperatorClass::Await(func)
 | |
|                 | OperatorClass::Prefix(func)
 | |
|                 | OperatorClass::Bin(func)
 | |
|                 | OperatorClass::Index(func)
 | |
|                 | OperatorClass::Try(func),
 | |
|             ) => res.push((Definition::Function(func), None)),
 | |
|             IdentClass::Operator(OperatorClass::Range(struct0)) => {
 | |
|                 res.push((Definition::Adt(Adt::Struct(struct0)), None))
 | |
|             }
 | |
|         }
 | |
|         res
 | |
|     }
 | |
| 
 | |
|     pub fn definitions_no_ops(self) -> ArrayVec<Definition, 2> {
 | |
|         let mut res = ArrayVec::new();
 | |
|         match self {
 | |
|             IdentClass::NameClass(NameClass::Definition(it) | NameClass::ConstReference(it)) => {
 | |
|                 res.push(it)
 | |
|             }
 | |
|             IdentClass::NameClass(NameClass::PatFieldShorthand {
 | |
|                 local_def,
 | |
|                 field_ref,
 | |
|                 adt_subst: _,
 | |
|             }) => {
 | |
|                 res.push(Definition::Local(local_def));
 | |
|                 res.push(Definition::Field(field_ref));
 | |
|             }
 | |
|             IdentClass::NameRefClass(NameRefClass::Definition(it, _)) => res.push(it),
 | |
|             IdentClass::NameRefClass(NameRefClass::FieldShorthand {
 | |
|                 local_ref,
 | |
|                 field_ref,
 | |
|                 adt_subst: _,
 | |
|             }) => {
 | |
|                 res.push(Definition::Local(local_ref));
 | |
|                 res.push(Definition::Field(field_ref));
 | |
|             }
 | |
|             IdentClass::NameRefClass(NameRefClass::ExternCrateShorthand { decl, krate }) => {
 | |
|                 res.push(Definition::ExternCrateDecl(decl));
 | |
|                 res.push(Definition::Crate(krate));
 | |
|             }
 | |
|             IdentClass::Operator(_) => (),
 | |
|         }
 | |
|         res
 | |
|     }
 | |
| }
 | |
| 
 | |
| /// On a first blush, a single `ast::Name` defines a single definition at some
 | |
| /// scope. That is, that, by just looking at the syntactical category, we can
 | |
| /// unambiguously define the semantic category.
 | |
| ///
 | |
| /// Sadly, that's not 100% true, there are special cases. To make sure that
 | |
| /// callers handle all the special cases correctly via exhaustive matching, we
 | |
| /// add a [`NameClass`] enum which lists all of them!
 | |
| ///
 | |
| /// A model special case is `None` constant in pattern.
 | |
| #[derive(Debug)]
 | |
| pub enum NameClass<'db> {
 | |
|     Definition(Definition),
 | |
|     /// `None` in `if let None = Some(82) {}`.
 | |
|     /// Syntactically, it is a name, but semantically it is a reference.
 | |
|     ConstReference(Definition),
 | |
|     /// `field` in `if let Foo { field } = foo`. Here, `ast::Name` both introduces
 | |
|     /// a definition into a local scope, and refers to an existing definition.
 | |
|     PatFieldShorthand {
 | |
|         local_def: Local,
 | |
|         field_ref: Field,
 | |
|         adt_subst: GenericSubstitution<'db>,
 | |
|     },
 | |
| }
 | |
| 
 | |
| impl<'db> NameClass<'db> {
 | |
|     /// `Definition` defined by this name.
 | |
|     pub fn defined(self) -> Option<Definition> {
 | |
|         let res = match self {
 | |
|             NameClass::Definition(it) => it,
 | |
|             NameClass::ConstReference(_) => return None,
 | |
|             NameClass::PatFieldShorthand { local_def, field_ref: _, adt_subst: _ } => {
 | |
|                 Definition::Local(local_def)
 | |
|             }
 | |
|         };
 | |
|         Some(res)
 | |
|     }
 | |
| 
 | |
|     pub fn classify(
 | |
|         sema: &Semantics<'db, RootDatabase>,
 | |
|         name: &ast::Name,
 | |
|     ) -> Option<NameClass<'db>> {
 | |
|         let _p = tracing::info_span!("NameClass::classify").entered();
 | |
| 
 | |
|         let parent = name.syntax().parent()?;
 | |
|         let definition = match_ast! {
 | |
|             match parent {
 | |
|                 ast::Item(it) => classify_item(sema, it)?,
 | |
|                 ast::IdentPat(it) => return classify_ident_pat(sema, it),
 | |
|                 ast::Rename(it) => classify_rename(sema, it)?,
 | |
|                 ast::SelfParam(it) => Definition::Local(sema.to_def(&it)?),
 | |
|                 ast::RecordField(it) => Definition::Field(sema.to_def(&it)?),
 | |
|                 ast::Variant(it) => Definition::Variant(sema.to_def(&it)?),
 | |
|                 ast::TypeParam(it) => Definition::GenericParam(sema.to_def(&it)?.into()),
 | |
|                 ast::ConstParam(it) => Definition::GenericParam(sema.to_def(&it)?.into()),
 | |
|                 ast::AsmOperandNamed(it) => Definition::InlineAsmOperand(sema.to_def(&it)?),
 | |
|                 _ => return None,
 | |
|             }
 | |
|         };
 | |
|         return Some(NameClass::Definition(definition));
 | |
| 
 | |
|         fn classify_item(
 | |
|             sema: &Semantics<'_, RootDatabase>,
 | |
|             item: ast::Item,
 | |
|         ) -> Option<Definition> {
 | |
|             let definition = match item {
 | |
|                 ast::Item::MacroRules(it) => {
 | |
|                     Definition::Macro(sema.to_def(&ast::Macro::MacroRules(it))?)
 | |
|                 }
 | |
|                 ast::Item::MacroDef(it) => {
 | |
|                     Definition::Macro(sema.to_def(&ast::Macro::MacroDef(it))?)
 | |
|                 }
 | |
|                 ast::Item::Const(it) => Definition::Const(sema.to_def(&it)?),
 | |
|                 ast::Item::Fn(it) => {
 | |
|                     let def = sema.to_def(&it)?;
 | |
|                     def.as_proc_macro(sema.db)
 | |
|                         .map(Definition::Macro)
 | |
|                         .unwrap_or(Definition::Function(def))
 | |
|                 }
 | |
|                 ast::Item::Module(it) => Definition::Module(sema.to_def(&it)?),
 | |
|                 ast::Item::Static(it) => Definition::Static(sema.to_def(&it)?),
 | |
|                 ast::Item::Trait(it) => Definition::Trait(sema.to_def(&it)?),
 | |
|                 ast::Item::TypeAlias(it) => Definition::TypeAlias(sema.to_def(&it)?),
 | |
|                 ast::Item::Enum(it) => Definition::Adt(hir::Adt::Enum(sema.to_def(&it)?)),
 | |
|                 ast::Item::Struct(it) => Definition::Adt(hir::Adt::Struct(sema.to_def(&it)?)),
 | |
|                 ast::Item::Union(it) => Definition::Adt(hir::Adt::Union(sema.to_def(&it)?)),
 | |
|                 ast::Item::ExternCrate(it) => Definition::ExternCrateDecl(sema.to_def(&it)?),
 | |
|                 _ => return None,
 | |
|             };
 | |
|             Some(definition)
 | |
|         }
 | |
| 
 | |
|         fn classify_ident_pat<'db>(
 | |
|             sema: &Semantics<'db, RootDatabase>,
 | |
|             ident_pat: ast::IdentPat,
 | |
|         ) -> Option<NameClass<'db>> {
 | |
|             if let Some(def) = sema.resolve_bind_pat_to_const(&ident_pat) {
 | |
|                 return Some(NameClass::ConstReference(Definition::from(def)));
 | |
|             }
 | |
| 
 | |
|             let local = sema.to_def(&ident_pat)?;
 | |
|             let pat_parent = ident_pat.syntax().parent();
 | |
|             if let Some(record_pat_field) = pat_parent.and_then(ast::RecordPatField::cast)
 | |
|                 && record_pat_field.name_ref().is_none()
 | |
|                 && let Some((field, _, adt_subst)) =
 | |
|                     sema.resolve_record_pat_field_with_subst(&record_pat_field)
 | |
|             {
 | |
|                 return Some(NameClass::PatFieldShorthand {
 | |
|                     local_def: local,
 | |
|                     field_ref: field,
 | |
|                     adt_subst,
 | |
|                 });
 | |
|             }
 | |
|             Some(NameClass::Definition(Definition::Local(local)))
 | |
|         }
 | |
| 
 | |
|         fn classify_rename(
 | |
|             sema: &Semantics<'_, RootDatabase>,
 | |
|             rename: ast::Rename,
 | |
|         ) -> Option<Definition> {
 | |
|             if let Some(use_tree) = rename.syntax().parent().and_then(ast::UseTree::cast) {
 | |
|                 let path = use_tree.path()?;
 | |
|                 sema.resolve_path(&path).map(Definition::from)
 | |
|             } else {
 | |
|                 sema.to_def(&rename.syntax().parent().and_then(ast::ExternCrate::cast)?)
 | |
|                     .map(Definition::ExternCrateDecl)
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     pub fn classify_lifetime(
 | |
|         sema: &Semantics<'db, RootDatabase>,
 | |
|         lifetime: &ast::Lifetime,
 | |
|     ) -> Option<NameClass<'db>> {
 | |
|         let _p = tracing::info_span!("NameClass::classify_lifetime", ?lifetime).entered();
 | |
|         let parent = lifetime.syntax().parent()?;
 | |
| 
 | |
|         if let Some(it) = ast::LifetimeParam::cast(parent.clone()) {
 | |
|             sema.to_def(&it).map(Into::into).map(Definition::GenericParam)
 | |
|         } else if let Some(it) = ast::Label::cast(parent) {
 | |
|             sema.to_def(&it).map(Definition::Label)
 | |
|         } else {
 | |
|             None
 | |
|         }
 | |
|         .map(NameClass::Definition)
 | |
|     }
 | |
| }
 | |
| 
 | |
| #[derive(Debug)]
 | |
| pub enum OperatorClass {
 | |
|     Range(Struct),
 | |
|     Await(Function),
 | |
|     Prefix(Function),
 | |
|     Index(Function),
 | |
|     Try(Function),
 | |
|     Bin(Function),
 | |
| }
 | |
| 
 | |
| impl OperatorClass {
 | |
|     pub fn classify_range_pat(
 | |
|         sema: &Semantics<'_, RootDatabase>,
 | |
|         range_pat: &ast::RangePat,
 | |
|     ) -> Option<OperatorClass> {
 | |
|         sema.resolve_range_pat(range_pat).map(OperatorClass::Range)
 | |
|     }
 | |
| 
 | |
|     pub fn classify_range_expr(
 | |
|         sema: &Semantics<'_, RootDatabase>,
 | |
|         range_expr: &ast::RangeExpr,
 | |
|     ) -> Option<OperatorClass> {
 | |
|         sema.resolve_range_expr(range_expr).map(OperatorClass::Range)
 | |
|     }
 | |
| 
 | |
|     pub fn classify_await(
 | |
|         sema: &Semantics<'_, RootDatabase>,
 | |
|         await_expr: &ast::AwaitExpr,
 | |
|     ) -> Option<OperatorClass> {
 | |
|         sema.resolve_await_to_poll(await_expr).map(OperatorClass::Await)
 | |
|     }
 | |
| 
 | |
|     pub fn classify_prefix(
 | |
|         sema: &Semantics<'_, RootDatabase>,
 | |
|         prefix_expr: &ast::PrefixExpr,
 | |
|     ) -> Option<OperatorClass> {
 | |
|         sema.resolve_prefix_expr(prefix_expr).map(OperatorClass::Prefix)
 | |
|     }
 | |
| 
 | |
|     pub fn classify_try(
 | |
|         sema: &Semantics<'_, RootDatabase>,
 | |
|         try_expr: &ast::TryExpr,
 | |
|     ) -> Option<OperatorClass> {
 | |
|         sema.resolve_try_expr(try_expr).map(OperatorClass::Try)
 | |
|     }
 | |
| 
 | |
|     pub fn classify_index(
 | |
|         sema: &Semantics<'_, RootDatabase>,
 | |
|         index_expr: &ast::IndexExpr,
 | |
|     ) -> Option<OperatorClass> {
 | |
|         sema.resolve_index_expr(index_expr).map(OperatorClass::Index)
 | |
|     }
 | |
| 
 | |
|     pub fn classify_bin(
 | |
|         sema: &Semantics<'_, RootDatabase>,
 | |
|         bin_expr: &ast::BinExpr,
 | |
|     ) -> Option<OperatorClass> {
 | |
|         sema.resolve_bin_expr(bin_expr).map(OperatorClass::Bin)
 | |
|     }
 | |
| }
 | |
| 
 | |
| /// This is similar to [`NameClass`], but works for [`ast::NameRef`] rather than
 | |
| /// for [`ast::Name`]. Similarly, what looks like a reference in syntax is a
 | |
| /// reference most of the time, but there are a couple of annoying exceptions.
 | |
| ///
 | |
| /// A model special case is field shorthand syntax, which uses a single
 | |
| /// reference to point to two different defs.
 | |
| #[derive(Debug)]
 | |
| pub enum NameRefClass<'db> {
 | |
|     Definition(Definition, Option<GenericSubstitution<'db>>),
 | |
|     FieldShorthand {
 | |
|         local_ref: Local,
 | |
|         field_ref: Field,
 | |
|         adt_subst: GenericSubstitution<'db>,
 | |
|     },
 | |
|     /// The specific situation where we have an extern crate decl without a rename
 | |
|     /// Here we have both a declaration and a reference.
 | |
|     /// ```rs
 | |
|     /// extern crate foo;
 | |
|     /// ```
 | |
|     ExternCrateShorthand {
 | |
|         decl: ExternCrateDecl,
 | |
|         krate: Crate,
 | |
|     },
 | |
| }
 | |
| 
 | |
| impl<'db> NameRefClass<'db> {
 | |
|     // Note: we don't have unit-tests for this rather important function.
 | |
|     // It is primarily exercised via goto definition tests in `ide`.
 | |
|     pub fn classify(
 | |
|         sema: &Semantics<'db, RootDatabase>,
 | |
|         name_ref: &ast::NameRef,
 | |
|     ) -> Option<NameRefClass<'db>> {
 | |
|         let _p = tracing::info_span!("NameRefClass::classify", ?name_ref).entered();
 | |
| 
 | |
|         let parent = name_ref.syntax().parent()?;
 | |
| 
 | |
|         if let Some(record_field) = ast::RecordExprField::for_field_name(name_ref)
 | |
|             && let Some((field, local, _, adt_subst)) =
 | |
|                 sema.resolve_record_field_with_substitution(&record_field)
 | |
|         {
 | |
|             let res = match local {
 | |
|                 None => NameRefClass::Definition(Definition::Field(field), Some(adt_subst)),
 | |
|                 Some(local) => {
 | |
|                     NameRefClass::FieldShorthand { field_ref: field, local_ref: local, adt_subst }
 | |
|                 }
 | |
|             };
 | |
|             return Some(res);
 | |
|         }
 | |
| 
 | |
|         if let Some(path) = ast::PathSegment::cast(parent.clone()).map(|it| it.parent_path()) {
 | |
|             if path.parent_path().is_none()
 | |
|                 && let Some(macro_call) = path.syntax().parent().and_then(ast::MacroCall::cast)
 | |
|             {
 | |
|                 // Only use this to resolve to macro calls for last segments as qualifiers resolve
 | |
|                 // to modules below.
 | |
|                 if let Some(macro_def) = sema.resolve_macro_call(¯o_call) {
 | |
|                     return Some(NameRefClass::Definition(Definition::Macro(macro_def), None));
 | |
|                 }
 | |
|             }
 | |
|             return sema
 | |
|                 .resolve_path_with_subst(&path)
 | |
|                 .map(|(res, subst)| NameRefClass::Definition(res.into(), subst));
 | |
|         }
 | |
| 
 | |
|         match_ast! {
 | |
|             match parent {
 | |
|                 ast::MethodCallExpr(method_call) => {
 | |
|                     sema.resolve_method_call_fallback(&method_call)
 | |
|                         .map(|(def, subst)| {
 | |
|                             match def {
 | |
|                                 Either::Left(def) => NameRefClass::Definition(def.into(), subst),
 | |
|                                 Either::Right(def) => NameRefClass::Definition(def.into(), subst),
 | |
|                             }
 | |
|                         })
 | |
|                 },
 | |
|                 ast::FieldExpr(field_expr) => {
 | |
|                     sema.resolve_field_fallback(&field_expr)
 | |
|                         .map(|(def, subst)| {
 | |
|                             match def {
 | |
|                                 Either::Left(Either::Left(def)) => NameRefClass::Definition(def.into(), subst),
 | |
|                                 Either::Left(Either::Right(def)) => NameRefClass::Definition(Definition::TupleField(def), subst),
 | |
|                                 Either::Right(def) => NameRefClass::Definition(def.into(), subst),
 | |
|                             }
 | |
|                         })
 | |
|                 },
 | |
|                 ast::RecordPatField(record_pat_field) => {
 | |
|                     sema.resolve_record_pat_field_with_subst(&record_pat_field)
 | |
|                         .map(|(field, _, subst)| NameRefClass::Definition(Definition::Field(field), Some(subst)))
 | |
|                 },
 | |
|                 ast::RecordExprField(record_expr_field) => {
 | |
|                     sema.resolve_record_field_with_substitution(&record_expr_field)
 | |
|                         .map(|(field, _, _, subst)| NameRefClass::Definition(Definition::Field(field), Some(subst)))
 | |
|                 },
 | |
|                 ast::AssocTypeArg(_) => {
 | |
|                     // `Trait<Assoc = Ty>`
 | |
|                     //        ^^^^^
 | |
|                     let containing_path = name_ref.syntax().ancestors().find_map(ast::Path::cast)?;
 | |
|                     let resolved = sema.resolve_path(&containing_path)?;
 | |
|                     if let PathResolution::Def(ModuleDef::Trait(tr)) = resolved
 | |
|                         && let Some(ty) = tr
 | |
|                             .items_with_supertraits(sema.db)
 | |
|                             .iter()
 | |
|                             .filter_map(|&assoc| match assoc {
 | |
|                                 hir::AssocItem::TypeAlias(it) => Some(it),
 | |
|                                 _ => None,
 | |
|                             })
 | |
|                             .find(|alias| alias.name(sema.db).as_str() == name_ref.text().trim_start_matches("r#"))
 | |
|                         {
 | |
|                             // No substitution, this can only occur in type position.
 | |
|                             return Some(NameRefClass::Definition(Definition::TypeAlias(ty), None));
 | |
|                         }
 | |
|                     None
 | |
|                 },
 | |
|                 ast::UseBoundGenericArgs(_) => {
 | |
|                     // No substitution, this can only occur in type position.
 | |
|                     sema.resolve_use_type_arg(name_ref)
 | |
|                         .map(GenericParam::TypeParam)
 | |
|                         .map(Definition::GenericParam)
 | |
|                         .map(|it| NameRefClass::Definition(it, None))
 | |
|                 },
 | |
|                 ast::ExternCrate(extern_crate_ast) => {
 | |
|                     let extern_crate = sema.to_def(&extern_crate_ast)?;
 | |
|                     let krate = extern_crate.resolved_crate(sema.db)?;
 | |
|                     Some(if extern_crate_ast.rename().is_some() {
 | |
|                         NameRefClass::Definition(Definition::Crate(krate), None)
 | |
|                     } else {
 | |
|                         NameRefClass::ExternCrateShorthand { krate, decl: extern_crate }
 | |
|                     })
 | |
|                 },
 | |
|                 ast::AsmRegSpec(_) => {
 | |
|                     Some(NameRefClass::Definition(Definition::InlineAsmRegOrRegClass(()), None))
 | |
|                 },
 | |
|                 ast::OffsetOfExpr(_) => {
 | |
|                     let (def, subst) = sema.resolve_offset_of_field(name_ref)?;
 | |
|                     let def = match def {
 | |
|                         Either::Left(variant) => Definition::Variant(variant),
 | |
|                         Either::Right(field) => Definition::Field(field),
 | |
|                     };
 | |
|                     Some(NameRefClass::Definition(def, Some(subst)))
 | |
|                 },
 | |
|                 _ => None
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     pub fn classify_lifetime(
 | |
|         sema: &Semantics<'db, RootDatabase>,
 | |
|         lifetime: &ast::Lifetime,
 | |
|     ) -> Option<NameRefClass<'db>> {
 | |
|         let _p = tracing::info_span!("NameRefClass::classify_lifetime", ?lifetime).entered();
 | |
|         if lifetime.text() == "'static" {
 | |
|             return Some(NameRefClass::Definition(
 | |
|                 Definition::BuiltinLifetime(StaticLifetime),
 | |
|                 None,
 | |
|             ));
 | |
|         }
 | |
|         let parent = lifetime.syntax().parent()?;
 | |
|         match parent.kind() {
 | |
|             SyntaxKind::BREAK_EXPR | SyntaxKind::CONTINUE_EXPR => sema
 | |
|                 .resolve_label(lifetime)
 | |
|                 .map(Definition::Label)
 | |
|                 .map(|it| NameRefClass::Definition(it, None)),
 | |
|             SyntaxKind::LIFETIME_ARG
 | |
|             | SyntaxKind::USE_BOUND_GENERIC_ARGS
 | |
|             | SyntaxKind::SELF_PARAM
 | |
|             | SyntaxKind::TYPE_BOUND
 | |
|             | SyntaxKind::WHERE_PRED
 | |
|             | SyntaxKind::REF_TYPE => sema
 | |
|                 .resolve_lifetime_param(lifetime)
 | |
|                 .map(GenericParam::LifetimeParam)
 | |
|                 .map(Definition::GenericParam)
 | |
|                 .map(|it| NameRefClass::Definition(it, None)),
 | |
|             _ => None,
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| impl_from!(
 | |
|     Field, Module, Function, Adt, Variant, Const, Static, Trait, TypeAlias, BuiltinType, Local,
 | |
|     GenericParam, Label, Macro, ExternCrateDecl
 | |
|     for Definition
 | |
| );
 | |
| 
 | |
| impl From<Impl> for Definition {
 | |
|     fn from(impl_: Impl) -> Self {
 | |
|         Definition::SelfType(impl_)
 | |
|     }
 | |
| }
 | |
| 
 | |
| impl From<InlineAsmOperand> for Definition {
 | |
|     fn from(value: InlineAsmOperand) -> Self {
 | |
|         Definition::InlineAsmOperand(value)
 | |
|     }
 | |
| }
 | |
| 
 | |
| impl From<Either<PathResolution, InlineAsmOperand>> for Definition {
 | |
|     fn from(value: Either<PathResolution, InlineAsmOperand>) -> Self {
 | |
|         value.either(Definition::from, Definition::from)
 | |
|     }
 | |
| }
 | |
| 
 | |
| impl AsAssocItem for Definition {
 | |
|     fn as_assoc_item(self, db: &dyn hir::db::HirDatabase) -> Option<AssocItem> {
 | |
|         match self {
 | |
|             Definition::Function(it) => it.as_assoc_item(db),
 | |
|             Definition::Const(it) => it.as_assoc_item(db),
 | |
|             Definition::TypeAlias(it) => it.as_assoc_item(db),
 | |
|             _ => None,
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| impl AsExternAssocItem for Definition {
 | |
|     fn as_extern_assoc_item(self, db: &dyn hir::db::HirDatabase) -> Option<ExternAssocItem> {
 | |
|         match self {
 | |
|             Definition::Function(it) => it.as_extern_assoc_item(db),
 | |
|             Definition::Static(it) => it.as_extern_assoc_item(db),
 | |
|             Definition::TypeAlias(it) => it.as_extern_assoc_item(db),
 | |
|             _ => None,
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| impl From<AssocItem> for Definition {
 | |
|     fn from(assoc_item: AssocItem) -> Self {
 | |
|         match assoc_item {
 | |
|             AssocItem::Function(it) => Definition::Function(it),
 | |
|             AssocItem::Const(it) => Definition::Const(it),
 | |
|             AssocItem::TypeAlias(it) => Definition::TypeAlias(it),
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| impl From<PathResolution> for Definition {
 | |
|     fn from(path_resolution: PathResolution) -> Self {
 | |
|         match path_resolution {
 | |
|             PathResolution::Def(def) => def.into(),
 | |
|             PathResolution::Local(local) => Definition::Local(local),
 | |
|             PathResolution::TypeParam(par) => Definition::GenericParam(par.into()),
 | |
|             PathResolution::ConstParam(par) => Definition::GenericParam(par.into()),
 | |
|             PathResolution::SelfType(impl_def) => Definition::SelfType(impl_def),
 | |
|             PathResolution::BuiltinAttr(attr) => Definition::BuiltinAttr(attr),
 | |
|             PathResolution::ToolModule(tool) => Definition::ToolModule(tool),
 | |
|             PathResolution::DeriveHelper(helper) => Definition::DeriveHelper(helper),
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| impl From<ModuleDef> for Definition {
 | |
|     fn from(def: ModuleDef) -> Self {
 | |
|         match def {
 | |
|             ModuleDef::Module(it) => Definition::Module(it),
 | |
|             ModuleDef::Function(it) => Definition::Function(it),
 | |
|             ModuleDef::Adt(it) => Definition::Adt(it),
 | |
|             ModuleDef::Variant(it) => Definition::Variant(it),
 | |
|             ModuleDef::Const(it) => Definition::Const(it),
 | |
|             ModuleDef::Static(it) => Definition::Static(it),
 | |
|             ModuleDef::Trait(it) => Definition::Trait(it),
 | |
|             ModuleDef::TypeAlias(it) => Definition::TypeAlias(it),
 | |
|             ModuleDef::Macro(it) => Definition::Macro(it),
 | |
|             ModuleDef::BuiltinType(it) => Definition::BuiltinType(it),
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| impl From<DocLinkDef> for Definition {
 | |
|     fn from(def: DocLinkDef) -> Self {
 | |
|         match def {
 | |
|             DocLinkDef::ModuleDef(it) => it.into(),
 | |
|             DocLinkDef::Field(it) => it.into(),
 | |
|             DocLinkDef::SelfType(it) => it.into(),
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| impl From<VariantDef> for Definition {
 | |
|     fn from(def: VariantDef) -> Self {
 | |
|         ModuleDef::from(def).into()
 | |
|     }
 | |
| }
 | |
| 
 | |
| impl TryFrom<DefWithBody> for Definition {
 | |
|     type Error = ();
 | |
|     fn try_from(def: DefWithBody) -> Result<Self, Self::Error> {
 | |
|         match def {
 | |
|             DefWithBody::Function(it) => Ok(it.into()),
 | |
|             DefWithBody::Static(it) => Ok(it.into()),
 | |
|             DefWithBody::Const(it) => Ok(it.into()),
 | |
|             DefWithBody::Variant(it) => Ok(it.into()),
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| impl From<GenericDef> for Definition {
 | |
|     fn from(def: GenericDef) -> Self {
 | |
|         match def {
 | |
|             GenericDef::Function(it) => it.into(),
 | |
|             GenericDef::Adt(it) => it.into(),
 | |
|             GenericDef::Trait(it) => it.into(),
 | |
|             GenericDef::TypeAlias(it) => it.into(),
 | |
|             GenericDef::Impl(it) => it.into(),
 | |
|             GenericDef::Const(it) => it.into(),
 | |
|             GenericDef::Static(it) => it.into(),
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| impl TryFrom<Definition> for GenericDef {
 | |
|     type Error = ();
 | |
|     fn try_from(def: Definition) -> Result<Self, Self::Error> {
 | |
|         match def {
 | |
|             Definition::Function(it) => Ok(it.into()),
 | |
|             Definition::Adt(it) => Ok(it.into()),
 | |
|             Definition::Trait(it) => Ok(it.into()),
 | |
|             Definition::TypeAlias(it) => Ok(it.into()),
 | |
|             Definition::SelfType(it) => Ok(it.into()),
 | |
|             Definition::Const(it) => Ok(it.into()),
 | |
|             _ => Err(()),
 | |
|         }
 | |
|     }
 | |
| }
 | 
