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, GenericParam, HasVisibility, Impl, Label, Local, MacroDef, Module, ModuleDef, Name,
10 PathResolution, Semantics, Visibility,
13 ast::{self, AstNode, PathSegmentKind},
14 match_ast, SyntaxKind, SyntaxNode,
17 use crate::RootDatabase;
19 // FIXME: a more precise name would probably be `Symbol`?
20 #[derive(Debug, PartialEq, Eq, Copy, Clone)]
27 GenericParam(GenericParam),
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::GenericParam(it) => Some(it.module(db)),
40 Definition::Label(it) => Some(it.module(db)),
44 pub fn visibility(&self, db: &RootDatabase) -> Option<Visibility> {
46 Definition::Field(sf) => Some(sf.visibility(db)),
47 Definition::ModuleDef(def) => match def {
48 ModuleDef::Module(it) => {
49 // FIXME: should work like other cases here.
50 let parent = it.parent(db)?;
51 parent.visibility_of(db, def)
53 ModuleDef::Function(it) => Some(it.visibility(db)),
54 ModuleDef::Adt(it) => Some(it.visibility(db)),
55 ModuleDef::Const(it) => Some(it.visibility(db)),
56 ModuleDef::Static(it) => Some(it.visibility(db)),
57 ModuleDef::Trait(it) => Some(it.visibility(db)),
58 ModuleDef::TypeAlias(it) => Some(it.visibility(db)),
59 // NB: Variants don't have their own visibility, and just inherit
60 // one from the parent. Not sure if that's the right thing to do.
61 ModuleDef::Variant(it) => Some(it.parent_enum(db).visibility(db)),
62 ModuleDef::BuiltinType(_) => None,
65 | Definition::SelfType(_)
66 | Definition::Local(_)
67 | Definition::GenericParam(_)
68 | Definition::Label(_) => None,
72 pub fn name(&self, db: &RootDatabase) -> Option<Name> {
73 let name = match self {
74 Definition::Macro(it) => it.name(db)?,
75 Definition::Field(it) => it.name(db),
76 Definition::ModuleDef(def) => match def {
77 hir::ModuleDef::Module(it) => it.name(db)?,
78 hir::ModuleDef::Function(it) => it.name(db),
79 hir::ModuleDef::Adt(def) => match def {
80 hir::Adt::Struct(it) => it.name(db),
81 hir::Adt::Union(it) => it.name(db),
82 hir::Adt::Enum(it) => it.name(db),
84 hir::ModuleDef::Variant(it) => it.name(db),
85 hir::ModuleDef::Const(it) => it.name(db)?,
86 hir::ModuleDef::Static(it) => it.name(db)?,
87 hir::ModuleDef::Trait(it) => it.name(db),
88 hir::ModuleDef::TypeAlias(it) => it.name(db),
89 hir::ModuleDef::BuiltinType(it) => it.name(),
91 Definition::SelfType(_) => return None,
92 Definition::Local(it) => it.name(db)?,
93 Definition::GenericParam(it) => it.name(db),
94 Definition::Label(it) => it.name(db),
100 /// On a first blush, a single `ast::Name` defines a single definition at some
101 /// scope. That is, that, by just looking at the syntactical category, we can
102 /// unambiguously define the semantic category.
104 /// Sadly, that's not 100% true, there are special cases. To make sure that
105 /// callers handle all the special cases correctly via exhaustive matching, we
106 /// add a [`NameClass`] enum which lists all of them!
108 /// A model special case is `None` constant in pattern.
111 Definition(Definition),
112 /// `None` in `if let None = Some(82) {}`.
113 /// Syntactically, it is a name, but semantically it is a reference.
114 ConstReference(Definition),
115 /// `field` in `if let Foo { field } = foo`. Here, `ast::Name` both introduces
116 /// a definition into a local scope, and refers to an existing definition.
124 /// `Definition` defined by this name.
125 pub fn defined(self) -> Option<Definition> {
126 let res = match self {
127 NameClass::Definition(it) => it,
128 NameClass::ConstReference(_) => return None,
129 NameClass::PatFieldShorthand { local_def, field_ref: _ } => {
130 Definition::Local(local_def)
136 /// `Definition` referenced or defined by this name, in case of a shorthand this will yield the field reference.
137 pub fn defined_or_referenced_field(self) -> Definition {
139 NameClass::Definition(it) | NameClass::ConstReference(it) => it,
140 NameClass::PatFieldShorthand { local_def: _, field_ref } => {
141 Definition::Field(field_ref)
146 /// `Definition` referenced or defined by this name, in case of a shorthand this will yield the local definition.
147 pub fn defined_or_referenced_local(self) -> Definition {
149 NameClass::Definition(it) | NameClass::ConstReference(it) => it,
150 NameClass::PatFieldShorthand { local_def, field_ref: _ } => {
151 Definition::Local(local_def)
156 pub fn classify(sema: &Semantics<RootDatabase>, name: &ast::Name) -> Option<NameClass> {
157 let _p = profile::span("classify_name");
159 let parent = name.syntax().parent()?;
161 if let Some(bind_pat) = ast::IdentPat::cast(parent.clone()) {
162 if let Some(def) = sema.resolve_bind_pat_to_const(&bind_pat) {
163 return Some(NameClass::ConstReference(Definition::ModuleDef(def)));
170 if let Some(use_tree) = it.syntax().parent().and_then(ast::UseTree::cast) {
171 let path = use_tree.path()?;
172 let path_segment = path.segment()?;
173 let name_ref_class = path_segment
177 // The rename might be from a `self` token, so fallback to the name higher
179 PathSegmentKind::SelfKw => {
180 let use_tree = use_tree
184 // Skip over UseTreeList
185 .and_then(SyntaxNode::parent)
186 .and_then(ast::UseTree::cast)?;
187 let path = use_tree.path()?;
188 let path_segment = path.segment()?;
189 path_segment.name_ref()
191 PathSegmentKind::Name(name_ref) => Some(name_ref),
195 .and_then(|name_ref| NameRefClass::classify(sema, &name_ref))?;
197 Some(NameClass::Definition(name_ref_class.referenced_field()))
199 let extern_crate = it.syntax().parent().and_then(ast::ExternCrate::cast)?;
200 let krate = sema.resolve_extern_crate(&extern_crate)?;
201 let root_module = krate.root_module(sema.db);
202 Some(NameClass::Definition(Definition::ModuleDef(root_module.into())))
205 ast::IdentPat(it) => {
206 let local = sema.to_def(&it)?;
208 if let Some(record_pat_field) = it.syntax().parent().and_then(ast::RecordPatField::cast) {
209 if record_pat_field.name_ref().is_none() {
210 if let Some(field) = sema.resolve_record_pat_field(&record_pat_field) {
211 return Some(NameClass::PatFieldShorthand { local_def: local, field_ref: field });
216 Some(NameClass::Definition(Definition::Local(local)))
218 ast::SelfParam(it) => {
219 let def = sema.to_def(&it)?;
220 Some(NameClass::Definition(Definition::Local(def)))
222 ast::RecordField(it) => {
223 let field: hir::Field = sema.to_def(&it)?;
224 Some(NameClass::Definition(Definition::Field(field)))
227 let def = sema.to_def(&it)?;
228 Some(NameClass::Definition(Definition::ModuleDef(def.into())))
231 let def: hir::Struct = sema.to_def(&it)?;
232 Some(NameClass::Definition(Definition::ModuleDef(def.into())))
235 let def: hir::Union = sema.to_def(&it)?;
236 Some(NameClass::Definition(Definition::ModuleDef(def.into())))
239 let def: hir::Enum = sema.to_def(&it)?;
240 Some(NameClass::Definition(Definition::ModuleDef(def.into())))
243 let def: hir::Trait = sema.to_def(&it)?;
244 Some(NameClass::Definition(Definition::ModuleDef(def.into())))
247 let def: hir::Static = sema.to_def(&it)?;
248 Some(NameClass::Definition(Definition::ModuleDef(def.into())))
250 ast::Variant(it) => {
251 let def: hir::Variant = sema.to_def(&it)?;
252 Some(NameClass::Definition(Definition::ModuleDef(def.into())))
255 let def: hir::Function = sema.to_def(&it)?;
256 Some(NameClass::Definition(Definition::ModuleDef(def.into())))
259 let def: hir::Const = sema.to_def(&it)?;
260 Some(NameClass::Definition(Definition::ModuleDef(def.into())))
262 ast::TypeAlias(it) => {
263 let def: hir::TypeAlias = sema.to_def(&it)?;
264 Some(NameClass::Definition(Definition::ModuleDef(def.into())))
267 let def = sema.to_def(&it)?;
268 Some(NameClass::Definition(Definition::Macro(def)))
270 ast::TypeParam(it) => {
271 let def = sema.to_def(&it)?;
272 Some(NameClass::Definition(Definition::GenericParam(def.into())))
274 ast::ConstParam(it) => {
275 let def = sema.to_def(&it)?;
276 Some(NameClass::Definition(Definition::GenericParam(def.into())))
283 pub fn classify_lifetime(
284 sema: &Semantics<RootDatabase>,
285 lifetime: &ast::Lifetime,
286 ) -> Option<NameClass> {
287 let _p = profile::span("classify_lifetime").detail(|| lifetime.to_string());
288 let parent = lifetime.syntax().parent()?;
292 ast::LifetimeParam(it) => {
293 let def = sema.to_def(&it)?;
294 Some(NameClass::Definition(Definition::GenericParam(def.into())))
297 let def = sema.to_def(&it)?;
298 Some(NameClass::Definition(Definition::Label(def)))
306 /// This is similar to [`NameClass`], but works for [`ast::NameRef`] rather than
307 /// for [`ast::Name`]. Similarly, what looks like a reference in syntax is a
308 /// reference most of the time, but there are a couple of annoying exceptions.
310 /// A model special case is field shorthand syntax, which uses a single
311 /// reference to point to two different defs.
313 pub enum NameRefClass {
314 Definition(Definition),
315 FieldShorthand { local_ref: Local, field_ref: Field },
319 /// `Definition`, which this name refers to with a preference for the field reference in case of a field shorthand.
320 pub fn referenced_field(self) -> Definition {
322 NameRefClass::Definition(def) => def,
323 NameRefClass::FieldShorthand { local_ref: _, field_ref } => {
324 Definition::Field(field_ref)
329 /// `Definition`, which this name refers to with a preference for the local reference in case of a field shorthand.
330 pub fn referenced_local(self) -> Definition {
332 NameRefClass::Definition(def) => def,
333 NameRefClass::FieldShorthand { local_ref, field_ref: _ } => {
334 Definition::Local(local_ref)
339 // Note: we don't have unit-tests for this rather important function.
340 // It is primarily exercised via goto definition tests in `ide`.
342 sema: &Semantics<RootDatabase>,
343 name_ref: &ast::NameRef,
344 ) -> Option<NameRefClass> {
345 let _p = profile::span("classify_name_ref").detail(|| name_ref.to_string());
347 let parent = name_ref.syntax().parent()?;
349 if let Some(method_call) = ast::MethodCallExpr::cast(parent.clone()) {
350 if let Some(func) = sema.resolve_method_call(&method_call) {
351 return Some(NameRefClass::Definition(Definition::ModuleDef(func.into())));
355 if let Some(field_expr) = ast::FieldExpr::cast(parent.clone()) {
356 if let Some(field) = sema.resolve_field(&field_expr) {
357 return Some(NameRefClass::Definition(Definition::Field(field)));
361 if let Some(record_field) = ast::RecordExprField::for_field_name(name_ref) {
362 if let Some((field, local, _)) = sema.resolve_record_field(&record_field) {
363 let res = match local {
364 None => NameRefClass::Definition(Definition::Field(field)),
366 NameRefClass::FieldShorthand { field_ref: field, local_ref: local }
373 if let Some(record_pat_field) = ast::RecordPatField::cast(parent.clone()) {
374 if let Some(field) = sema.resolve_record_pat_field(&record_pat_field) {
375 let field = Definition::Field(field);
376 return Some(NameRefClass::Definition(field));
380 if let Some(assoc_type_arg) = ast::AssocTypeArg::cast(parent.clone()) {
381 if assoc_type_arg.name_ref().as_ref() == Some(name_ref) {
382 // `Trait<Assoc = Ty>`
384 let path = name_ref.syntax().ancestors().find_map(ast::Path::cast)?;
385 let resolved = sema.resolve_path(&path)?;
386 if let PathResolution::Def(ModuleDef::Trait(tr)) = resolved {
387 // FIXME: resolve in supertraits
391 .filter_map(|assoc| match assoc {
392 hir::AssocItem::TypeAlias(it) => Some(*it),
395 .find(|alias| &alias.name(sema.db).to_string() == &name_ref.text())
397 return Some(NameRefClass::Definition(Definition::ModuleDef(
398 ModuleDef::TypeAlias(ty),
407 if let Some(path) = name_ref.syntax().ancestors().find_map(ast::Path::cast) {
408 if path.qualifier().is_none() {
409 if let Some(macro_call) = path.syntax().parent().and_then(ast::MacroCall::cast) {
410 // Only use this to resolve single-segment macro calls like `foo!()`. Multi-segment
411 // paths are handled below (allowing `log$0::info!` to resolve to the log crate).
412 if let Some(macro_def) = sema.resolve_macro_call(¯o_call) {
413 return Some(NameRefClass::Definition(Definition::Macro(macro_def)));
417 let top_path = path.top_path();
418 let is_attribute_path = top_path
421 .find_map(ast::Attr::cast)
422 .map(|attr| attr.path().as_ref() == Some(&top_path));
423 return match is_attribute_path {
424 Some(true) => sema.resolve_path(&path).and_then(|resolved| {
426 // Don't wanna collide with builtin attributes here like `test` hence guard
427 // so only resolve to modules that aren't the last segment
428 PathResolution::Def(module @ ModuleDef::Module(_)) if path != top_path => {
429 cov_mark::hit!(name_ref_classify_attr_path_qualifier);
430 Some(NameRefClass::Definition(Definition::ModuleDef(module)))
432 PathResolution::Macro(mac) if mac.kind() == hir::MacroKind::Attr => {
433 Some(NameRefClass::Definition(Definition::Macro(mac)))
439 None => sema.resolve_path(&path).map(Into::into).map(NameRefClass::Definition),
443 let extern_crate = ast::ExternCrate::cast(parent)?;
444 let krate = sema.resolve_extern_crate(&extern_crate)?;
445 let root_module = krate.root_module(sema.db);
446 Some(NameRefClass::Definition(Definition::ModuleDef(root_module.into())))
449 pub fn classify_lifetime(
450 sema: &Semantics<RootDatabase>,
451 lifetime: &ast::Lifetime,
452 ) -> Option<NameRefClass> {
453 let _p = profile::span("classify_lifetime_ref").detail(|| lifetime.to_string());
454 let parent = lifetime.syntax().parent()?;
455 match parent.kind() {
456 SyntaxKind::BREAK_EXPR | SyntaxKind::CONTINUE_EXPR => {
457 sema.resolve_label(lifetime).map(Definition::Label).map(NameRefClass::Definition)
459 SyntaxKind::LIFETIME_ARG
460 | SyntaxKind::SELF_PARAM
461 | SyntaxKind::TYPE_BOUND
462 | SyntaxKind::WHERE_PRED
463 | SyntaxKind::REF_TYPE => sema
464 .resolve_lifetime_param(lifetime)
465 .map(GenericParam::LifetimeParam)
466 .map(Definition::GenericParam)
467 .map(NameRefClass::Definition),
468 // lifetime bounds, as in the 'b in 'a: 'b aren't wrapped in TypeBound nodes so we gotta check
469 // if our lifetime is in a LifetimeParam without being the constrained lifetime
470 _ if ast::LifetimeParam::cast(parent).and_then(|param| param.lifetime()).as_ref()
473 sema.resolve_lifetime_param(lifetime)
474 .map(GenericParam::LifetimeParam)
475 .map(Definition::GenericParam)
476 .map(NameRefClass::Definition)
483 impl From<PathResolution> for Definition {
484 fn from(path_resolution: PathResolution) -> Self {
485 match path_resolution {
486 PathResolution::Def(def) => Definition::ModuleDef(def),
487 PathResolution::AssocItem(item) => {
488 let def = match item {
489 hir::AssocItem::Function(it) => it.into(),
490 hir::AssocItem::Const(it) => it.into(),
491 hir::AssocItem::TypeAlias(it) => it.into(),
493 Definition::ModuleDef(def)
495 PathResolution::Local(local) => Definition::Local(local),
496 PathResolution::TypeParam(par) => Definition::GenericParam(par.into()),
497 PathResolution::Macro(def) => Definition::Macro(def),
498 PathResolution::SelfType(impl_def) => Definition::SelfType(impl_def),
499 PathResolution::ConstParam(par) => Definition::GenericParam(par.into()),