Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/ide_db/src/defs.rs')
-rw-r--r--crates/ide_db/src/defs.rs135
1 files changed, 67 insertions, 68 deletions
diff --git a/crates/ide_db/src/defs.rs b/crates/ide_db/src/defs.rs
index 1501c4eda5..172acdbc3c 100644
--- a/crates/ide_db/src/defs.rs
+++ b/crates/ide_db/src/defs.rs
@@ -42,74 +42,6 @@ pub enum Definition {
}
impl Definition {
- pub fn from_token(
- sema: &Semantics<RootDatabase>,
- token: &SyntaxToken,
- ) -> ArrayVec<Definition, 2> {
- let parent = match token.parent() {
- Some(parent) => parent,
- None => return Default::default(),
- };
- // resolve derives if possible
- if let Some(ident) = ast::Ident::cast(token.clone()) {
- let attr = ast::TokenTree::cast(parent.clone())
- .and_then(|tt| tt.parent_meta())
- .and_then(|meta| meta.parent_attr());
- if let Some(attr) = attr {
- return sema
- .resolve_derive_ident(&attr, &ident)
- .map(Into::into)
- .into_iter()
- .collect();
- }
- }
- Self::from_node(sema, &parent)
- }
-
- pub fn from_node(sema: &Semantics<RootDatabase>, node: &SyntaxNode) -> ArrayVec<Definition, 2> {
- let mut res = ArrayVec::new();
- (|| {
- match_ast! {
- match node {
- ast::Name(name) => {
- match NameClass::classify(&sema, &name)? {
- NameClass::Definition(it) | NameClass::ConstReference(it) => res.push(it),
- NameClass::PatFieldShorthand { local_def, field_ref } => {
- res.push(Definition::Local(local_def));
- res.push(Definition::Field(field_ref));
- }
- }
- },
- ast::NameRef(name_ref) => {
- match NameRefClass::classify(sema, &name_ref)? {
- NameRefClass::Definition(it) => res.push(it),
- NameRefClass::FieldShorthand { local_ref, field_ref } => {
- res.push(Definition::Local(local_ref));
- res.push(Definition::Field(field_ref));
- }
- }
- },
- ast::Lifetime(lifetime) => {
- let def = 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,
- })
- };
- if let Some(def) = def {
- res.push(def);
- }
- },
- _ => (),
- }
- }
- Some(())
- })();
- res
- }
-
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())
}
@@ -184,6 +116,65 @@ impl Definition {
}
}
+pub enum IdentClass {
+ NameClass(NameClass),
+ NameRefClass(NameRefClass),
+}
+
+impl IdentClass {
+ pub fn classify_node(sema: &Semantics<RootDatabase>, node: &SyntaxNode) -> Option<IdentClass> {
+ 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))
+ },
+ _ => None,
+ }
+ }
+ }
+
+ pub fn classify_token(
+ sema: &Semantics<RootDatabase>,
+ token: &SyntaxToken,
+ ) -> Option<IdentClass> {
+ let parent = token.parent()?;
+ // resolve derives if possible
+ if let Some(ident) = ast::Ident::cast(token.clone()) {
+ let attr = ast::TokenTree::cast(parent.clone())
+ .and_then(|tt| tt.parent_meta())
+ .and_then(|meta| meta.parent_attr());
+ if let Some(attr) = attr {
+ return NameRefClass::classify_derive(sema, &attr, &ident)
+ .map(IdentClass::NameRefClass);
+ }
+ }
+ Self::classify_node(sema, &parent)
+ }
+
+ pub fn definitions(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 }) => {
+ 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 }) => {
+ res.push(Definition::Local(local_ref));
+ res.push(Definition::Field(field_ref));
+ }
+ }
+ 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.
@@ -465,6 +456,14 @@ impl NameRefClass {
_ => None,
}
}
+
+ pub fn classify_derive(
+ sema: &Semantics<RootDatabase>,
+ attr: &ast::Attr,
+ ident: &ast::Ident,
+ ) -> Option<NameRefClass> {
+ sema.resolve_derive_ident(&attr, &ident).map(Definition::from).map(NameRefClass::Definition)
+ }
}
impl_from!(