1 //! `NameDefinition` keeps information about the element we want to search references for.
2 //! The element is represented by `NameKind`. It's located inside some `container` and
3 //! has a `visibility`, which defines a search scope.
4 //! Note that the reference search is possible for not all of the classified items.
6 // FIXME: this badly needs rename/rewrite (matklad, 2020-02-06).
9 Field, HasVisibility, ImplDef, Local, MacroDef, Module, ModuleDef, Name, PathResolution,
10 Semantics, TypeParam, Visibility,
18 use crate::RootDatabase;
20 // FIXME: a more precise name would probably be `Symbol`?
21 #[derive(Debug, PartialEq, Eq, Copy, Clone)]
32 pub fn module(&self, db: &RootDatabase) -> Option<Module> {
34 Definition::Macro(it) => it.module(db),
35 Definition::Field(it) => Some(it.parent_def(db).module(db)),
36 Definition::ModuleDef(it) => it.module(db),
37 Definition::SelfType(it) => Some(it.module(db)),
38 Definition::Local(it) => Some(it.module(db)),
39 Definition::TypeParam(it) => Some(it.module(db)),
43 pub fn visibility(&self, db: &RootDatabase) -> Option<Visibility> {
45 Definition::Macro(_) => None,
46 Definition::Field(sf) => Some(sf.visibility(db)),
47 Definition::ModuleDef(def) => def.definition_visibility(db),
48 Definition::SelfType(_) => None,
49 Definition::Local(_) => None,
50 Definition::TypeParam(_) => None,
54 pub fn name(&self, db: &RootDatabase) -> Option<Name> {
55 let name = match self {
56 Definition::Macro(it) => it.name(db)?,
57 Definition::Field(it) => it.name(db),
58 Definition::ModuleDef(def) => match def {
59 hir::ModuleDef::Module(it) => it.name(db)?,
60 hir::ModuleDef::Function(it) => it.name(db),
61 hir::ModuleDef::Adt(def) => match def {
62 hir::Adt::Struct(it) => it.name(db),
63 hir::Adt::Union(it) => it.name(db),
64 hir::Adt::Enum(it) => it.name(db),
66 hir::ModuleDef::EnumVariant(it) => it.name(db),
67 hir::ModuleDef::Const(it) => it.name(db)?,
68 hir::ModuleDef::Static(it) => it.name(db)?,
69 hir::ModuleDef::Trait(it) => it.name(db),
70 hir::ModuleDef::TypeAlias(it) => it.name(db),
71 hir::ModuleDef::BuiltinType(_) => return None,
73 Definition::SelfType(_) => return None,
74 Definition::Local(it) => it.name(db)?,
75 Definition::TypeParam(it) => it.name(db),
82 Definition(Definition),
83 /// `None` in `if let None = Some(82) {}`
84 ConstReference(Definition),
92 pub fn into_definition(self) -> Option<Definition> {
94 NameClass::Definition(it) => Some(it),
95 NameClass::ConstReference(_) => None,
96 NameClass::FieldShorthand { local, field: _ } => Some(Definition::Local(local)),
100 pub fn definition(self) -> Definition {
102 NameClass::Definition(it) | NameClass::ConstReference(it) => it,
103 NameClass::FieldShorthand { local: _, field } => field,
108 pub fn classify_name(sema: &Semantics<RootDatabase>, name: &ast::Name) -> Option<NameClass> {
109 let _p = profile("classify_name");
111 let parent = name.syntax().parent()?;
113 if let Some(bind_pat) = ast::BindPat::cast(parent.clone()) {
114 if let Some(def) = sema.resolve_bind_pat_to_const(&bind_pat) {
115 return Some(NameClass::ConstReference(Definition::ModuleDef(def)));
122 let use_tree = it.syntax().parent().and_then(ast::UseTree::cast)?;
123 let path = use_tree.path()?;
124 let path_segment = path.segment()?;
125 let name_ref = path_segment.name_ref()?;
126 let name_ref_class = classify_name_ref(sema, &name_ref)?;
128 Some(NameClass::Definition(name_ref_class.definition()))
130 ast::BindPat(it) => {
131 let local = sema.to_def(&it)?;
133 if let Some(record_field_pat) = it.syntax().parent().and_then(ast::RecordFieldPat::cast) {
134 if let Some(field) = sema.resolve_record_field_pat(&record_field_pat) {
135 let field = Definition::Field(field);
136 return Some(NameClass::FieldShorthand { local, field });
140 Some(NameClass::Definition(Definition::Local(local)))
142 ast::RecordFieldDef(it) => {
143 let field: hir::Field = sema.to_def(&it)?;
144 Some(NameClass::Definition(Definition::Field(field)))
147 let def = sema.to_def(&it)?;
148 Some(NameClass::Definition(Definition::ModuleDef(def.into())))
150 ast::StructDef(it) => {
151 let def: hir::Struct = sema.to_def(&it)?;
152 Some(NameClass::Definition(Definition::ModuleDef(def.into())))
154 ast::UnionDef(it) => {
155 let def: hir::Union = sema.to_def(&it)?;
156 Some(NameClass::Definition(Definition::ModuleDef(def.into())))
158 ast::EnumDef(it) => {
159 let def: hir::Enum = sema.to_def(&it)?;
160 Some(NameClass::Definition(Definition::ModuleDef(def.into())))
162 ast::TraitDef(it) => {
163 let def: hir::Trait = sema.to_def(&it)?;
164 Some(NameClass::Definition(Definition::ModuleDef(def.into())))
166 ast::StaticDef(it) => {
167 let def: hir::Static = sema.to_def(&it)?;
168 Some(NameClass::Definition(Definition::ModuleDef(def.into())))
170 ast::EnumVariant(it) => {
171 let def: hir::EnumVariant = sema.to_def(&it)?;
172 Some(NameClass::Definition(Definition::ModuleDef(def.into())))
175 let def: hir::Function = sema.to_def(&it)?;
176 Some(NameClass::Definition(Definition::ModuleDef(def.into())))
178 ast::ConstDef(it) => {
179 let def: hir::Const = sema.to_def(&it)?;
180 Some(NameClass::Definition(Definition::ModuleDef(def.into())))
182 ast::TypeAliasDef(it) => {
183 let def: hir::TypeAlias = sema.to_def(&it)?;
184 Some(NameClass::Definition(Definition::ModuleDef(def.into())))
186 ast::MacroCall(it) => {
187 let def = sema.to_def(&it)?;
188 Some(NameClass::Definition(Definition::Macro(def)))
190 ast::TypeParam(it) => {
191 let def = sema.to_def(&it)?;
192 Some(NameClass::Definition(Definition::TypeParam(def)))
200 pub enum NameRefClass {
201 Definition(Definition),
202 FieldShorthand { local: Local, field: Definition },
206 pub fn definition(self) -> Definition {
208 NameRefClass::Definition(def) => def,
209 NameRefClass::FieldShorthand { local, field: _ } => Definition::Local(local),
214 // Note: we don't have unit-tests for this rather important function.
215 // It is primarily exercised via goto definition tests in `ra_ide`.
216 pub fn classify_name_ref(
217 sema: &Semantics<RootDatabase>,
218 name_ref: &ast::NameRef,
219 ) -> Option<NameRefClass> {
220 let _p = profile("classify_name_ref");
222 let parent = name_ref.syntax().parent()?;
224 if let Some(method_call) = ast::MethodCallExpr::cast(parent.clone()) {
225 if let Some(func) = sema.resolve_method_call(&method_call) {
226 return Some(NameRefClass::Definition(Definition::ModuleDef(func.into())));
230 if let Some(field_expr) = ast::FieldExpr::cast(parent.clone()) {
231 if let Some(field) = sema.resolve_field(&field_expr) {
232 return Some(NameRefClass::Definition(Definition::Field(field)));
236 if let Some(record_field) = ast::RecordField::for_field_name(name_ref) {
237 if let Some((field, local)) = sema.resolve_record_field(&record_field) {
238 let field = Definition::Field(field);
239 let res = match local {
240 None => NameRefClass::Definition(field),
241 Some(local) => NameRefClass::FieldShorthand { field, local },
247 if let Some(record_field_pat) = ast::RecordFieldPat::cast(parent.clone()) {
248 if let Some(field) = sema.resolve_record_field_pat(&record_field_pat) {
249 let field = Definition::Field(field);
250 return Some(NameRefClass::Definition(field));
254 if let Some(macro_call) = parent.ancestors().find_map(ast::MacroCall::cast) {
255 if let Some(macro_def) = sema.resolve_macro_call(¯o_call) {
256 return Some(NameRefClass::Definition(Definition::Macro(macro_def)));
260 let path = name_ref.syntax().ancestors().find_map(ast::Path::cast)?;
261 let resolved = sema.resolve_path(&path)?;
262 let res = match resolved {
263 PathResolution::Def(def) => Definition::ModuleDef(def),
264 PathResolution::AssocItem(item) => {
265 let def = match item {
266 hir::AssocItem::Function(it) => it.into(),
267 hir::AssocItem::Const(it) => it.into(),
268 hir::AssocItem::TypeAlias(it) => it.into(),
270 Definition::ModuleDef(def)
272 PathResolution::Local(local) => Definition::Local(local),
273 PathResolution::TypeParam(par) => Definition::TypeParam(par),
274 PathResolution::Macro(def) => Definition::Macro(def),
275 PathResolution::SelfType(impl_def) => Definition::SelfType(impl_def),
277 Some(NameRefClass::Definition(res))