2020-02-06 15:23:28 +00:00
|
|
|
//! `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.
|
|
|
|
|
2020-02-06 15:24:14 +00:00
|
|
|
// FIXME: this badly needs rename/rewrite (matklad, 2020-02-06).
|
|
|
|
|
2020-02-06 15:23:28 +00:00
|
|
|
use hir::{
|
2021-07-11 12:48:49 +00:00
|
|
|
Field, GenericParam, HasVisibility, Impl, Label, Local, MacroDef, Module, ModuleDef, Name,
|
|
|
|
PathResolution, Semantics, Visibility,
|
2020-02-06 15:23:28 +00:00
|
|
|
};
|
2020-08-12 16:26:51 +00:00
|
|
|
use syntax::{
|
2021-07-23 00:14:59 +00:00
|
|
|
ast::{self, AstNode},
|
2021-09-22 15:05:54 +00:00
|
|
|
match_ast, SyntaxKind, SyntaxToken,
|
2020-02-06 15:23:28 +00:00
|
|
|
};
|
|
|
|
|
2021-09-22 15:05:54 +00:00
|
|
|
use crate::{helpers::try_resolve_derive_input_at, RootDatabase};
|
2020-02-06 15:23:28 +00:00
|
|
|
|
2020-03-03 17:36:39 +00:00
|
|
|
// FIXME: a more precise name would probably be `Symbol`?
|
2021-08-28 19:37:27 +00:00
|
|
|
#[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)]
|
2020-03-03 17:36:39 +00:00
|
|
|
pub enum Definition {
|
2020-02-06 15:23:28 +00:00
|
|
|
Macro(MacroDef),
|
2020-04-25 12:23:34 +00:00
|
|
|
Field(Field),
|
2020-02-07 13:26:59 +00:00
|
|
|
ModuleDef(ModuleDef),
|
2020-12-17 11:36:15 +00:00
|
|
|
SelfType(Impl),
|
2020-02-06 15:23:28 +00:00
|
|
|
Local(Local),
|
2021-01-08 11:28:02 +00:00
|
|
|
GenericParam(GenericParam),
|
2020-12-23 16:15:01 +00:00
|
|
|
Label(Label),
|
2020-02-06 15:23:28 +00:00
|
|
|
}
|
|
|
|
|
2020-03-03 17:36:39 +00:00
|
|
|
impl Definition {
|
2021-09-22 15:05:54 +00:00
|
|
|
pub fn from_node(sema: &Semantics<RootDatabase>, token: &SyntaxToken) -> Vec<Definition> {
|
|
|
|
let node = if let Some(x) = token.parent() {
|
|
|
|
x
|
|
|
|
} else {
|
|
|
|
return vec![];
|
|
|
|
};
|
|
|
|
if token.kind() != SyntaxKind::COMMENT {
|
|
|
|
if let Some(attr) = token.ancestors().find_map(ast::Attr::cast) {
|
|
|
|
// derives
|
|
|
|
let def = try_resolve_derive_input_at(&sema, &attr, &token).map(Definition::Macro);
|
|
|
|
if let Some(def) = def {
|
|
|
|
return vec![def];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
match_ast! {
|
|
|
|
match node {
|
|
|
|
ast::Name(name) => {
|
|
|
|
let class = if let Some(x) = NameClass::classify(&sema, &name) {
|
|
|
|
x
|
|
|
|
} else {
|
|
|
|
return vec![];
|
|
|
|
};
|
|
|
|
match class {
|
|
|
|
NameClass::Definition(it) | NameClass::ConstReference(it) => vec![it],
|
|
|
|
NameClass::PatFieldShorthand { local_def, field_ref } => vec![Definition::Local(local_def), Definition::Field(field_ref)],
|
|
|
|
}
|
|
|
|
},
|
|
|
|
ast::NameRef(name_ref) => {
|
|
|
|
let class = if let Some(x) = NameRefClass::classify(sema, &name_ref) {
|
|
|
|
x
|
|
|
|
} else {
|
|
|
|
return vec![];
|
|
|
|
};
|
|
|
|
match class {
|
|
|
|
NameRefClass::Definition(def) => vec![def],
|
|
|
|
NameRefClass::FieldShorthand { local_ref, field_ref } => {
|
|
|
|
vec![Definition::Field(field_ref), Definition::Local(local_ref)]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
ast::Lifetime(lifetime) => {
|
|
|
|
(if let Some(x) = NameClass::classify_lifetime(&sema, &lifetime) {
|
|
|
|
NameClass::defined(x)
|
|
|
|
} else {
|
|
|
|
NameRefClass::classify_lifetime(&sema, &lifetime).and_then(|class| match class {
|
|
|
|
NameRefClass::Definition(it) => Some(it),
|
|
|
|
_ => None,
|
|
|
|
})
|
|
|
|
}).into_iter().collect()
|
|
|
|
},
|
|
|
|
_ => vec![],
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-19 13:32:22 +00:00
|
|
|
pub fn module(&self, db: &RootDatabase) -> Option<Module> {
|
2020-02-19 13:56:22 +00:00
|
|
|
match self {
|
2020-03-03 17:36:39 +00:00
|
|
|
Definition::Macro(it) => it.module(db),
|
2020-04-25 12:23:34 +00:00
|
|
|
Definition::Field(it) => Some(it.parent_def(db).module(db)),
|
2020-03-03 17:36:39 +00:00
|
|
|
Definition::ModuleDef(it) => it.module(db),
|
|
|
|
Definition::SelfType(it) => Some(it.module(db)),
|
|
|
|
Definition::Local(it) => Some(it.module(db)),
|
2021-01-08 11:28:02 +00:00
|
|
|
Definition::GenericParam(it) => Some(it.module(db)),
|
2020-12-23 16:15:01 +00:00
|
|
|
Definition::Label(it) => Some(it.module(db)),
|
2020-02-19 13:32:22 +00:00
|
|
|
}
|
|
|
|
}
|
2020-02-19 13:45:49 +00:00
|
|
|
|
2020-03-24 20:45:42 +00:00
|
|
|
pub fn visibility(&self, db: &RootDatabase) -> Option<Visibility> {
|
2020-02-19 13:56:22 +00:00
|
|
|
match self {
|
2020-04-25 12:23:34 +00:00
|
|
|
Definition::Field(sf) => Some(sf.visibility(db)),
|
2021-07-20 14:49:02 +00:00
|
|
|
Definition::ModuleDef(def) => Some(def.visibility(db)),
|
2021-06-22 18:22:36 +00:00
|
|
|
Definition::Macro(_)
|
|
|
|
| Definition::SelfType(_)
|
|
|
|
| Definition::Local(_)
|
|
|
|
| Definition::GenericParam(_)
|
|
|
|
| Definition::Label(_) => None,
|
2020-02-19 13:45:49 +00:00
|
|
|
}
|
|
|
|
}
|
2020-03-03 17:22:52 +00:00
|
|
|
|
|
|
|
pub fn name(&self, db: &RootDatabase) -> Option<Name> {
|
|
|
|
let name = match self {
|
2020-03-03 17:36:39 +00:00
|
|
|
Definition::Macro(it) => it.name(db)?,
|
2020-04-25 12:23:34 +00:00
|
|
|
Definition::Field(it) => it.name(db),
|
2020-03-03 17:36:39 +00:00
|
|
|
Definition::ModuleDef(def) => match def {
|
2020-03-03 17:22:52 +00:00
|
|
|
hir::ModuleDef::Module(it) => it.name(db)?,
|
|
|
|
hir::ModuleDef::Function(it) => it.name(db),
|
|
|
|
hir::ModuleDef::Adt(def) => match def {
|
|
|
|
hir::Adt::Struct(it) => it.name(db),
|
|
|
|
hir::Adt::Union(it) => it.name(db),
|
|
|
|
hir::Adt::Enum(it) => it.name(db),
|
|
|
|
},
|
2020-12-20 07:05:24 +00:00
|
|
|
hir::ModuleDef::Variant(it) => it.name(db),
|
2020-03-03 17:22:52 +00:00
|
|
|
hir::ModuleDef::Const(it) => it.name(db)?,
|
|
|
|
hir::ModuleDef::Static(it) => it.name(db)?,
|
|
|
|
hir::ModuleDef::Trait(it) => it.name(db),
|
|
|
|
hir::ModuleDef::TypeAlias(it) => it.name(db),
|
2021-03-15 08:32:06 +00:00
|
|
|
hir::ModuleDef::BuiltinType(it) => it.name(),
|
2020-03-03 17:22:52 +00:00
|
|
|
},
|
2020-03-03 17:36:39 +00:00
|
|
|
Definition::SelfType(_) => return None,
|
|
|
|
Definition::Local(it) => it.name(db)?,
|
2021-01-08 11:28:02 +00:00
|
|
|
Definition::GenericParam(it) => it.name(db),
|
2020-12-23 16:15:01 +00:00
|
|
|
Definition::Label(it) => it.name(db),
|
2020-03-03 17:22:52 +00:00
|
|
|
};
|
|
|
|
Some(name)
|
|
|
|
}
|
2020-02-19 13:32:22 +00:00
|
|
|
}
|
|
|
|
|
2021-07-11 11:39:25 +00:00
|
|
|
/// 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.
|
|
|
|
///
|
2021-07-11 12:13:42 +00:00
|
|
|
/// 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
|
2021-07-11 11:39:25 +00:00
|
|
|
/// add a [`NameClass`] enum which lists all of them!
|
|
|
|
///
|
|
|
|
/// A model special case is `None` constant in pattern.
|
2020-06-10 10:34:23 +00:00
|
|
|
#[derive(Debug)]
|
2020-02-28 14:27:52 +00:00
|
|
|
pub enum NameClass {
|
2020-03-03 17:36:39 +00:00
|
|
|
Definition(Definition),
|
2020-10-15 15:18:07 +00:00
|
|
|
/// `None` in `if let None = Some(82) {}`.
|
2021-07-11 11:39:25 +00:00
|
|
|
/// Syntactically, it is a name, but semantically it is a reference.
|
2020-03-03 17:36:39 +00:00
|
|
|
ConstReference(Definition),
|
2021-07-11 12:03:35 +00:00
|
|
|
/// `field` in `if let Foo { field } = foo`. Here, `ast::Name` both introduces
|
|
|
|
/// a definition into a local scope, and refers to an existing definition.
|
2020-10-15 14:23:55 +00:00
|
|
|
PatFieldShorthand {
|
2020-10-15 15:18:07 +00:00
|
|
|
local_def: Local,
|
2021-07-11 12:03:35 +00:00
|
|
|
field_ref: Field,
|
2020-06-08 11:46:58 +00:00
|
|
|
},
|
2020-02-28 14:27:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl NameClass {
|
2020-10-15 15:33:32 +00:00
|
|
|
/// `Definition` defined by this name.
|
2021-07-11 12:48:49 +00:00
|
|
|
pub fn defined(self) -> Option<Definition> {
|
2020-10-15 14:23:55 +00:00
|
|
|
let res = match self {
|
2020-08-08 18:14:18 +00:00
|
|
|
NameClass::Definition(it) => it,
|
|
|
|
NameClass::ConstReference(_) => return None,
|
2020-10-15 15:18:07 +00:00
|
|
|
NameClass::PatFieldShorthand { local_def, field_ref: _ } => {
|
|
|
|
Definition::Local(local_def)
|
|
|
|
}
|
2020-10-15 14:23:55 +00:00
|
|
|
};
|
|
|
|
Some(res)
|
2020-02-28 14:27:52 +00:00
|
|
|
}
|
|
|
|
|
2020-10-15 15:27:50 +00:00
|
|
|
pub fn classify(sema: &Semantics<RootDatabase>, name: &ast::Name) -> Option<NameClass> {
|
|
|
|
let _p = profile::span("classify_name");
|
2020-03-03 17:50:15 +00:00
|
|
|
|
2020-10-15 15:27:50 +00:00
|
|
|
let parent = name.syntax().parent()?;
|
2020-06-08 11:46:58 +00:00
|
|
|
|
2020-10-15 15:27:50 +00:00
|
|
|
if let Some(bind_pat) = ast::IdentPat::cast(parent.clone()) {
|
|
|
|
if let Some(def) = sema.resolve_bind_pat_to_const(&bind_pat) {
|
|
|
|
return Some(NameClass::ConstReference(Definition::ModuleDef(def)));
|
|
|
|
}
|
2020-02-28 15:36:14 +00:00
|
|
|
}
|
|
|
|
|
2020-10-15 15:27:50 +00:00
|
|
|
match_ast! {
|
|
|
|
match parent {
|
|
|
|
ast::Rename(it) => {
|
|
|
|
if let Some(use_tree) = it.syntax().parent().and_then(ast::UseTree::cast) {
|
|
|
|
let path = use_tree.path()?;
|
|
|
|
let path_segment = path.segment()?;
|
2021-07-23 00:14:59 +00:00
|
|
|
let name_ref = path_segment.name_ref()?;
|
|
|
|
let name_ref = if name_ref.self_token().is_some() {
|
|
|
|
use_tree
|
|
|
|
.syntax()
|
|
|
|
.parent()
|
|
|
|
.as_ref()
|
|
|
|
// Skip over UseTreeList
|
|
|
|
.and_then(|it| {
|
|
|
|
let use_tree = it.parent().and_then(ast::UseTree::cast)?;
|
|
|
|
let path = use_tree.path()?;
|
|
|
|
let path_segment = path.segment()?;
|
|
|
|
path_segment.name_ref()
|
|
|
|
}).unwrap_or(name_ref)
|
|
|
|
} else {
|
|
|
|
name_ref
|
|
|
|
};
|
|
|
|
let name_ref_class = NameRefClass::classify(sema, &name_ref)?;
|
2020-05-02 19:42:27 +00:00
|
|
|
|
2021-07-11 13:39:09 +00:00
|
|
|
Some(NameClass::Definition(match name_ref_class {
|
|
|
|
NameRefClass::Definition(def) => def,
|
|
|
|
NameRefClass::FieldShorthand { local_ref: _, field_ref } => {
|
|
|
|
Definition::Field(field_ref)
|
|
|
|
}
|
|
|
|
}))
|
2020-10-15 15:27:50 +00:00
|
|
|
} else {
|
|
|
|
let extern_crate = it.syntax().parent().and_then(ast::ExternCrate::cast)?;
|
2021-07-11 12:48:49 +00:00
|
|
|
let krate = sema.resolve_extern_crate(&extern_crate)?;
|
|
|
|
let root_module = krate.root_module(sema.db);
|
|
|
|
Some(NameClass::Definition(Definition::ModuleDef(root_module.into())))
|
2020-10-15 15:27:50 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
ast::IdentPat(it) => {
|
|
|
|
let local = sema.to_def(&it)?;
|
2020-06-08 11:46:58 +00:00
|
|
|
|
2020-10-15 15:27:50 +00:00
|
|
|
if let Some(record_pat_field) = it.syntax().parent().and_then(ast::RecordPatField::cast) {
|
|
|
|
if record_pat_field.name_ref().is_none() {
|
|
|
|
if let Some(field) = sema.resolve_record_pat_field(&record_pat_field) {
|
|
|
|
return Some(NameClass::PatFieldShorthand { local_def: local, field_ref: field });
|
|
|
|
}
|
2020-06-10 10:34:23 +00:00
|
|
|
}
|
2020-06-08 11:46:58 +00:00
|
|
|
}
|
2020-06-06 19:16:59 +00:00
|
|
|
|
2020-10-15 15:27:50 +00:00
|
|
|
Some(NameClass::Definition(Definition::Local(local)))
|
|
|
|
},
|
2021-01-15 20:07:38 +00:00
|
|
|
ast::SelfParam(it) => {
|
|
|
|
let def = sema.to_def(&it)?;
|
2021-03-17 00:27:56 +00:00
|
|
|
Some(NameClass::Definition(Definition::Local(def)))
|
2021-01-15 20:07:38 +00:00
|
|
|
},
|
2020-10-15 15:27:50 +00:00
|
|
|
ast::RecordField(it) => {
|
|
|
|
let field: hir::Field = sema.to_def(&it)?;
|
|
|
|
Some(NameClass::Definition(Definition::Field(field)))
|
|
|
|
},
|
|
|
|
ast::Module(it) => {
|
|
|
|
let def = sema.to_def(&it)?;
|
|
|
|
Some(NameClass::Definition(Definition::ModuleDef(def.into())))
|
|
|
|
},
|
|
|
|
ast::Struct(it) => {
|
|
|
|
let def: hir::Struct = sema.to_def(&it)?;
|
|
|
|
Some(NameClass::Definition(Definition::ModuleDef(def.into())))
|
|
|
|
},
|
|
|
|
ast::Union(it) => {
|
|
|
|
let def: hir::Union = sema.to_def(&it)?;
|
|
|
|
Some(NameClass::Definition(Definition::ModuleDef(def.into())))
|
|
|
|
},
|
|
|
|
ast::Enum(it) => {
|
|
|
|
let def: hir::Enum = sema.to_def(&it)?;
|
|
|
|
Some(NameClass::Definition(Definition::ModuleDef(def.into())))
|
|
|
|
},
|
|
|
|
ast::Trait(it) => {
|
|
|
|
let def: hir::Trait = sema.to_def(&it)?;
|
|
|
|
Some(NameClass::Definition(Definition::ModuleDef(def.into())))
|
|
|
|
},
|
|
|
|
ast::Static(it) => {
|
|
|
|
let def: hir::Static = sema.to_def(&it)?;
|
|
|
|
Some(NameClass::Definition(Definition::ModuleDef(def.into())))
|
|
|
|
},
|
|
|
|
ast::Variant(it) => {
|
2020-12-20 07:05:24 +00:00
|
|
|
let def: hir::Variant = sema.to_def(&it)?;
|
2020-10-15 15:27:50 +00:00
|
|
|
Some(NameClass::Definition(Definition::ModuleDef(def.into())))
|
|
|
|
},
|
|
|
|
ast::Fn(it) => {
|
|
|
|
let def: hir::Function = sema.to_def(&it)?;
|
|
|
|
Some(NameClass::Definition(Definition::ModuleDef(def.into())))
|
|
|
|
},
|
|
|
|
ast::Const(it) => {
|
|
|
|
let def: hir::Const = sema.to_def(&it)?;
|
|
|
|
Some(NameClass::Definition(Definition::ModuleDef(def.into())))
|
|
|
|
},
|
|
|
|
ast::TypeAlias(it) => {
|
|
|
|
let def: hir::TypeAlias = sema.to_def(&it)?;
|
|
|
|
Some(NameClass::Definition(Definition::ModuleDef(def.into())))
|
|
|
|
},
|
2021-03-27 05:48:15 +00:00
|
|
|
ast::Macro(it) => {
|
2020-10-15 15:27:50 +00:00
|
|
|
let def = sema.to_def(&it)?;
|
|
|
|
Some(NameClass::Definition(Definition::Macro(def)))
|
|
|
|
},
|
|
|
|
ast::TypeParam(it) => {
|
|
|
|
let def = sema.to_def(&it)?;
|
2021-01-08 11:28:02 +00:00
|
|
|
Some(NameClass::Definition(Definition::GenericParam(def.into())))
|
2020-10-15 15:27:50 +00:00
|
|
|
},
|
2021-01-01 09:07:01 +00:00
|
|
|
ast::ConstParam(it) => {
|
|
|
|
let def = sema.to_def(&it)?;
|
2021-01-08 11:28:02 +00:00
|
|
|
Some(NameClass::Definition(Definition::GenericParam(def.into())))
|
2021-01-01 09:07:01 +00:00
|
|
|
},
|
2020-10-15 15:27:50 +00:00
|
|
|
_ => None,
|
|
|
|
}
|
2020-02-06 15:23:28 +00:00
|
|
|
}
|
|
|
|
}
|
2020-12-16 20:35:15 +00:00
|
|
|
|
|
|
|
pub fn classify_lifetime(
|
|
|
|
sema: &Semantics<RootDatabase>,
|
|
|
|
lifetime: &ast::Lifetime,
|
|
|
|
) -> Option<NameClass> {
|
|
|
|
let _p = profile::span("classify_lifetime").detail(|| lifetime.to_string());
|
|
|
|
let parent = lifetime.syntax().parent()?;
|
|
|
|
|
|
|
|
match_ast! {
|
|
|
|
match parent {
|
|
|
|
ast::LifetimeParam(it) => {
|
|
|
|
let def = sema.to_def(&it)?;
|
2021-01-08 11:28:02 +00:00
|
|
|
Some(NameClass::Definition(Definition::GenericParam(def.into())))
|
2020-12-16 20:35:15 +00:00
|
|
|
},
|
2020-12-23 16:15:01 +00:00
|
|
|
ast::Label(it) => {
|
|
|
|
let def = sema.to_def(&it)?;
|
|
|
|
Some(NameClass::Definition(Definition::Label(def)))
|
|
|
|
},
|
2020-12-16 20:35:15 +00:00
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-02-06 15:23:28 +00:00
|
|
|
}
|
2020-03-03 17:50:15 +00:00
|
|
|
|
2021-07-11 11:39:25 +00:00
|
|
|
/// 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.
|
2020-04-18 20:05:06 +00:00
|
|
|
#[derive(Debug)]
|
2020-03-03 17:50:15 +00:00
|
|
|
pub enum NameRefClass {
|
|
|
|
Definition(Definition),
|
2021-07-11 12:03:35 +00:00
|
|
|
FieldShorthand { local_ref: Local, field_ref: Field },
|
2020-03-03 17:50:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl NameRefClass {
|
2020-10-15 15:27:50 +00:00
|
|
|
// 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<RootDatabase>,
|
|
|
|
name_ref: &ast::NameRef,
|
|
|
|
) -> Option<NameRefClass> {
|
2020-12-04 19:26:28 +00:00
|
|
|
let _p = profile::span("classify_name_ref").detail(|| name_ref.to_string());
|
2020-03-03 17:50:15 +00:00
|
|
|
|
2020-10-15 15:27:50 +00:00
|
|
|
let parent = name_ref.syntax().parent()?;
|
2020-03-03 17:50:15 +00:00
|
|
|
|
2020-10-15 15:27:50 +00:00
|
|
|
if let Some(method_call) = ast::MethodCallExpr::cast(parent.clone()) {
|
|
|
|
if let Some(func) = sema.resolve_method_call(&method_call) {
|
|
|
|
return Some(NameRefClass::Definition(Definition::ModuleDef(func.into())));
|
|
|
|
}
|
2020-03-03 17:50:15 +00:00
|
|
|
}
|
|
|
|
|
2020-10-15 15:27:50 +00:00
|
|
|
if let Some(field_expr) = ast::FieldExpr::cast(parent.clone()) {
|
|
|
|
if let Some(field) = sema.resolve_field(&field_expr) {
|
|
|
|
return Some(NameRefClass::Definition(Definition::Field(field)));
|
|
|
|
}
|
2020-03-03 17:50:15 +00:00
|
|
|
}
|
|
|
|
|
2020-10-15 15:27:50 +00:00
|
|
|
if let Some(record_field) = ast::RecordExprField::for_field_name(name_ref) {
|
2021-05-23 21:54:35 +00:00
|
|
|
if let Some((field, local, _)) = sema.resolve_record_field(&record_field) {
|
2020-10-15 15:27:50 +00:00
|
|
|
let res = match local {
|
2021-07-11 12:03:35 +00:00
|
|
|
None => NameRefClass::Definition(Definition::Field(field)),
|
2020-10-15 15:33:32 +00:00
|
|
|
Some(local) => {
|
|
|
|
NameRefClass::FieldShorthand { field_ref: field, local_ref: local }
|
|
|
|
}
|
2020-10-15 15:27:50 +00:00
|
|
|
};
|
|
|
|
return Some(res);
|
|
|
|
}
|
2020-03-03 17:50:15 +00:00
|
|
|
}
|
|
|
|
|
2020-10-15 15:27:50 +00:00
|
|
|
if let Some(record_pat_field) = ast::RecordPatField::cast(parent.clone()) {
|
|
|
|
if let Some(field) = sema.resolve_record_pat_field(&record_pat_field) {
|
|
|
|
let field = Definition::Field(field);
|
|
|
|
return Some(NameRefClass::Definition(field));
|
|
|
|
}
|
2020-04-18 20:05:06 +00:00
|
|
|
}
|
|
|
|
|
2021-03-30 00:08:33 +00:00
|
|
|
if let Some(assoc_type_arg) = ast::AssocTypeArg::cast(parent.clone()) {
|
|
|
|
if assoc_type_arg.name_ref().as_ref() == Some(name_ref) {
|
|
|
|
// `Trait<Assoc = Ty>`
|
|
|
|
// ^^^^^
|
|
|
|
let path = name_ref.syntax().ancestors().find_map(ast::Path::cast)?;
|
|
|
|
let resolved = sema.resolve_path(&path)?;
|
|
|
|
if let PathResolution::Def(ModuleDef::Trait(tr)) = resolved {
|
|
|
|
// FIXME: resolve in supertraits
|
|
|
|
if let Some(ty) = tr
|
|
|
|
.items(sema.db)
|
|
|
|
.iter()
|
|
|
|
.filter_map(|assoc| match assoc {
|
|
|
|
hir::AssocItem::TypeAlias(it) => Some(*it),
|
|
|
|
_ => None,
|
|
|
|
})
|
2021-07-21 18:52:08 +00:00
|
|
|
.find(|alias| alias.name(sema.db).to_string() == name_ref.text())
|
2021-03-30 00:08:33 +00:00
|
|
|
{
|
|
|
|
return Some(NameRefClass::Definition(Definition::ModuleDef(
|
|
|
|
ModuleDef::TypeAlias(ty),
|
|
|
|
)));
|
|
|
|
}
|
2020-10-15 15:27:50 +00:00
|
|
|
}
|
2021-03-30 00:08:33 +00:00
|
|
|
|
|
|
|
return None;
|
2020-07-17 12:58:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-09 22:25:36 +00:00
|
|
|
if let Some(path) = name_ref.syntax().ancestors().find_map(ast::Path::cast) {
|
|
|
|
if path.qualifier().is_none() {
|
|
|
|
if let Some(macro_call) = path.syntax().parent().and_then(ast::MacroCall::cast) {
|
2020-10-15 15:27:50 +00:00
|
|
|
// Only use this to resolve single-segment macro calls like `foo!()`. Multi-segment
|
2021-01-06 20:15:48 +00:00
|
|
|
// paths are handled below (allowing `log$0::info!` to resolve to the log crate).
|
2020-10-15 15:27:50 +00:00
|
|
|
if let Some(macro_def) = sema.resolve_macro_call(¯o_call) {
|
|
|
|
return Some(NameRefClass::Definition(Definition::Macro(macro_def)));
|
|
|
|
}
|
2020-07-14 15:23:33 +00:00
|
|
|
}
|
|
|
|
}
|
2021-06-30 19:29:40 +00:00
|
|
|
let top_path = path.top_path();
|
|
|
|
let is_attribute_path = top_path
|
|
|
|
.syntax()
|
|
|
|
.ancestors()
|
|
|
|
.find_map(ast::Attr::cast)
|
|
|
|
.map(|attr| attr.path().as_ref() == Some(&top_path));
|
|
|
|
return match is_attribute_path {
|
|
|
|
Some(true) => sema.resolve_path(&path).and_then(|resolved| {
|
2021-06-28 16:33:42 +00:00
|
|
|
match resolved {
|
|
|
|
// Don't wanna collide with builtin attributes here like `test` hence guard
|
2021-07-02 13:17:21 +00:00
|
|
|
// so only resolve to modules that aren't the last segment
|
|
|
|
PathResolution::Def(module @ ModuleDef::Module(_)) if path != top_path => {
|
2021-07-02 17:34:49 +00:00
|
|
|
cov_mark::hit!(name_ref_classify_attr_path_qualifier);
|
2021-06-28 16:33:42 +00:00
|
|
|
Some(NameRefClass::Definition(Definition::ModuleDef(module)))
|
2021-02-13 21:11:31 +00:00
|
|
|
}
|
2021-06-28 16:33:42 +00:00
|
|
|
PathResolution::Macro(mac) if mac.kind() == hir::MacroKind::Attr => {
|
|
|
|
Some(NameRefClass::Definition(Definition::Macro(mac)))
|
|
|
|
}
|
|
|
|
_ => None,
|
2021-02-13 21:11:31 +00:00
|
|
|
}
|
2021-06-30 19:29:40 +00:00
|
|
|
}),
|
|
|
|
Some(false) => None,
|
|
|
|
None => sema.resolve_path(&path).map(Into::into).map(NameRefClass::Definition),
|
|
|
|
};
|
2020-08-08 18:14:18 +00:00
|
|
|
}
|
|
|
|
|
2020-10-15 15:27:50 +00:00
|
|
|
let extern_crate = ast::ExternCrate::cast(parent)?;
|
2021-07-11 11:55:24 +00:00
|
|
|
let krate = sema.resolve_extern_crate(&extern_crate)?;
|
|
|
|
let root_module = krate.root_module(sema.db);
|
|
|
|
Some(NameRefClass::Definition(Definition::ModuleDef(root_module.into())))
|
2020-10-15 15:27:50 +00:00
|
|
|
}
|
2020-12-16 20:35:15 +00:00
|
|
|
|
|
|
|
pub fn classify_lifetime(
|
|
|
|
sema: &Semantics<RootDatabase>,
|
|
|
|
lifetime: &ast::Lifetime,
|
|
|
|
) -> Option<NameRefClass> {
|
|
|
|
let _p = profile::span("classify_lifetime_ref").detail(|| lifetime.to_string());
|
|
|
|
let parent = lifetime.syntax().parent()?;
|
|
|
|
match parent.kind() {
|
2020-12-23 16:15:01 +00:00
|
|
|
SyntaxKind::BREAK_EXPR | SyntaxKind::CONTINUE_EXPR => {
|
|
|
|
sema.resolve_label(lifetime).map(Definition::Label).map(NameRefClass::Definition)
|
|
|
|
}
|
2020-12-16 20:35:15 +00:00
|
|
|
SyntaxKind::LIFETIME_ARG
|
|
|
|
| SyntaxKind::SELF_PARAM
|
|
|
|
| SyntaxKind::TYPE_BOUND
|
|
|
|
| SyntaxKind::WHERE_PRED
|
|
|
|
| SyntaxKind::REF_TYPE => sema
|
|
|
|
.resolve_lifetime_param(lifetime)
|
2021-01-08 11:28:02 +00:00
|
|
|
.map(GenericParam::LifetimeParam)
|
|
|
|
.map(Definition::GenericParam)
|
2020-12-16 20:35:15 +00:00
|
|
|
.map(NameRefClass::Definition),
|
|
|
|
// lifetime bounds, as in the 'b in 'a: 'b aren't wrapped in TypeBound nodes so we gotta check
|
|
|
|
// if our lifetime is in a LifetimeParam without being the constrained lifetime
|
|
|
|
_ if ast::LifetimeParam::cast(parent).and_then(|param| param.lifetime()).as_ref()
|
|
|
|
!= Some(lifetime) =>
|
|
|
|
{
|
|
|
|
sema.resolve_lifetime_param(lifetime)
|
2021-01-08 11:28:02 +00:00
|
|
|
.map(GenericParam::LifetimeParam)
|
|
|
|
.map(Definition::GenericParam)
|
2020-12-16 20:35:15 +00:00
|
|
|
.map(NameRefClass::Definition)
|
|
|
|
}
|
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
}
|
2020-07-22 04:01:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl From<PathResolution> for Definition {
|
|
|
|
fn from(path_resolution: PathResolution) -> Self {
|
|
|
|
match path_resolution {
|
|
|
|
PathResolution::Def(def) => Definition::ModuleDef(def),
|
|
|
|
PathResolution::AssocItem(item) => {
|
|
|
|
let def = match item {
|
|
|
|
hir::AssocItem::Function(it) => it.into(),
|
|
|
|
hir::AssocItem::Const(it) => it.into(),
|
|
|
|
hir::AssocItem::TypeAlias(it) => it.into(),
|
|
|
|
};
|
|
|
|
Definition::ModuleDef(def)
|
|
|
|
}
|
|
|
|
PathResolution::Local(local) => Definition::Local(local),
|
2021-01-08 11:28:02 +00:00
|
|
|
PathResolution::TypeParam(par) => Definition::GenericParam(par.into()),
|
2020-07-22 04:01:21 +00:00
|
|
|
PathResolution::Macro(def) => Definition::Macro(def),
|
|
|
|
PathResolution::SelfType(impl_def) => Definition::SelfType(impl_def),
|
2021-01-08 11:28:02 +00:00
|
|
|
PathResolution::ConstParam(par) => Definition::GenericParam(par.into()),
|
2020-03-03 17:50:15 +00:00
|
|
|
}
|
2020-07-22 04:01:21 +00:00
|
|
|
}
|
2020-03-03 17:50:15 +00:00
|
|
|
}
|