Remove lossy Definition::from_token/Definition::from_node methods

This commit is contained in:
Lukas Wirth 2022-01-04 18:29:20 +01:00
parent 68bc12c3b8
commit c5a9985fc5
6 changed files with 91 additions and 92 deletions

View file

@ -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!(