Inline name classification reference calls

This commit is contained in:
Lukas Wirth 2021-07-11 15:39:09 +02:00
parent c65bb7f8b9
commit c41f1279a3
9 changed files with 117 additions and 80 deletions

View file

@ -112,8 +112,16 @@ pub(crate) fn external_docs(
let node = token.parent()?; let node = token.parent()?;
let definition = match_ast! { let definition = match_ast! {
match node { match node {
ast::NameRef(name_ref) => NameRefClass::classify(&sema, &name_ref).map(|d| d.referenced_field())?, ast::NameRef(name_ref) => match NameRefClass::classify(&sema, &name_ref)? {
ast::Name(name) => NameClass::classify(&sema, &name).map(|d| d.defined_or_referenced_field())?, NameRefClass::Definition(def) => def,
NameRefClass::FieldShorthand { local_ref: _, field_ref } => {
Definition::Field(field_ref)
}
},
ast::Name(name) => match NameClass::classify(&sema, &name)? {
NameClass::Definition(it) | NameClass::ConstReference(it) => it,
NameClass::PatFieldShorthand { local_def: _, field_ref } => Definition::Field(field_ref),
},
_ => return None, _ => return None,
} }
}; };

View file

@ -23,12 +23,15 @@ pub(crate) fn goto_declaration(
let parent = token.parent()?; let parent = token.parent()?;
let def = match_ast! { let def = match_ast! {
match parent { match parent {
ast::NameRef(name_ref) => { ast::NameRef(name_ref) => match NameRefClass::classify(&sema, &name_ref)? {
let name_kind = NameRefClass::classify(&sema, &name_ref)?; NameRefClass::Definition(def) => def,
name_kind.referenced_local() NameRefClass::FieldShorthand { local_ref, field_ref: _ } => {
Definition::Local(local_ref)
}
}, },
ast::Name(name) => { ast::Name(name) => match NameClass::classify(&sema, &name)? {
NameClass::classify(&sema, &name)?.defined_or_referenced_local() NameClass::Definition(it) | NameClass::ConstReference(it) => it,
NameClass::PatFieldShorthand { local_def, field_ref: _ } => Definition::Local(local_def),
}, },
_ => return None, _ => return None,
} }

View file

@ -60,11 +60,17 @@ pub(crate) fn goto_definition(
reference_definition(&sema, Either::Right(&name_ref)) reference_definition(&sema, Either::Right(&name_ref))
}, },
ast::Name(name) => { ast::Name(name) => {
let def = NameClass::classify(&sema, &name)?.defined_or_referenced_local(); let def = match NameClass::classify(&sema, &name)? {
NameClass::Definition(it) | NameClass::ConstReference(it) => it,
NameClass::PatFieldShorthand { local_def, field_ref: _ } => Definition::Local(local_def),
};
try_find_trait_item_definition(sema.db, &def).or_else(|| def.try_to_nav(sema.db)) try_find_trait_item_definition(sema.db, &def).or_else(|| def.try_to_nav(sema.db))
}, },
ast::Lifetime(lt) => if let Some(name_class) = NameClass::classify_lifetime(&sema, &lt) { ast::Lifetime(lt) => if let Some(name_class) = NameClass::classify_lifetime(&sema, &lt) {
let def = name_class.defined_or_referenced_local(); let def = match name_class {
NameClass::Definition(it) | NameClass::ConstReference(it) => it,
NameClass::PatFieldShorthand { local_def, field_ref: _ } => Definition::Local(local_def),
};
def.try_to_nav(sema.db) def.try_to_nav(sema.db)
} else { } else {
reference_definition(&sema, Either::Left(&lt)) reference_definition(&sema, Either::Left(&lt))
@ -139,7 +145,10 @@ pub(crate) fn reference_definition(
|lifetime| NameRefClass::classify_lifetime(sema, lifetime), |lifetime| NameRefClass::classify_lifetime(sema, lifetime),
|name_ref| NameRefClass::classify(sema, name_ref), |name_ref| NameRefClass::classify(sema, name_ref),
)?; )?;
let def = name_kind.referenced_local(); let def = match name_kind {
NameRefClass::Definition(def) => def,
NameRefClass::FieldShorthand { local_ref, field_ref: _ } => Definition::Local(local_ref),
};
def.try_to_nav(sema.db) def.try_to_nav(sema.db)
} }

View file

@ -28,11 +28,19 @@ pub(crate) fn goto_implementation(
let node = sema.find_node_at_offset_with_descend(&syntax, position.offset)?; let node = sema.find_node_at_offset_with_descend(&syntax, position.offset)?;
let def = match &node { let def = match &node {
ast::NameLike::Name(name) => { ast::NameLike::Name(name) => NameClass::classify(&sema, name).map(|class| match class {
NameClass::classify(&sema, name).map(|class| class.defined_or_referenced_local()) NameClass::Definition(it) | NameClass::ConstReference(it) => it,
NameClass::PatFieldShorthand { local_def, field_ref: _ } => {
Definition::Local(local_def)
} }
}),
ast::NameLike::NameRef(name_ref) => { ast::NameLike::NameRef(name_ref) => {
NameRefClass::classify(&sema, name_ref).map(|class| class.referenced_local()) NameRefClass::classify(&sema, name_ref).map(|class| match class {
NameRefClass::Definition(def) => def,
NameRefClass::FieldShorthand { local_ref, field_ref: _ } => {
Definition::Local(local_ref)
}
})
} }
ast::NameLike::Lifetime(_) => None, ast::NameLike::Lifetime(_) => None,
}?; }?;

View file

@ -96,12 +96,21 @@ pub(crate) fn hover(
match node { match node {
// we don't use NameClass::referenced_or_defined here as we do not want to resolve // we don't use NameClass::referenced_or_defined here as we do not want to resolve
// field pattern shorthands to their definition // field pattern shorthands to their definition
ast::Name(name) => NameClass::classify(&sema, &name).map(|class| class.defined_or_referenced_local()), ast::Name(name) => NameClass::classify(&sema, &name).map(|class| match class {
ast::NameRef(name_ref) => { NameClass::Definition(it) | NameClass::ConstReference(it) => it,
NameRefClass::classify(&sema, &name_ref).map(|d| d.referenced_field()) NameClass::PatFieldShorthand { local_def, field_ref: _ } => Definition::Local(local_def),
}, }),
ast::NameRef(name_ref) => NameRefClass::classify(&sema, &name_ref).map(|class| match class {
NameRefClass::Definition(def) => def,
NameRefClass::FieldShorthand { local_ref: _, field_ref } => {
Definition::Field(field_ref)
}
}),
ast::Lifetime(lifetime) => NameClass::classify_lifetime(&sema, &lifetime).map_or_else( ast::Lifetime(lifetime) => NameClass::classify_lifetime(&sema, &lifetime).map_or_else(
|| NameRefClass::classify_lifetime(&sema, &lifetime).map(|d| d.referenced_local()), || NameRefClass::classify_lifetime(&sema, &lifetime).and_then(|class| match class {
NameRefClass::Definition(it) => Some(it),
_ => None,
}),
|d| d.defined(), |d| d.defined(),
), ),
_ => { _ => {

View file

@ -58,7 +58,15 @@ pub(crate) fn find_all_refs(
let (def, is_literal_search) = let (def, is_literal_search) =
if let Some(name) = get_name_of_item_declaration(&syntax, position) { if let Some(name) = get_name_of_item_declaration(&syntax, position) {
(NameClass::classify(sema, &name)?.defined_or_referenced_field(), true) (
match NameClass::classify(sema, &name)? {
NameClass::Definition(it) | NameClass::ConstReference(it) => it,
NameClass::PatFieldShorthand { local_def: _, field_ref } => {
Definition::Field(field_ref)
}
},
true,
)
} else { } else {
(find_def(sema, &syntax, position.offset)?, false) (find_def(sema, &syntax, position.offset)?, false)
}; };
@ -116,17 +124,28 @@ pub(crate) fn find_def(
offset: TextSize, offset: TextSize,
) -> Option<Definition> { ) -> Option<Definition> {
let def = match sema.find_node_at_offset_with_descend(syntax, offset)? { let def = match sema.find_node_at_offset_with_descend(syntax, offset)? {
ast::NameLike::NameRef(name_ref) => { ast::NameLike::NameRef(name_ref) => match NameRefClass::classify(sema, &name_ref)? {
NameRefClass::classify(sema, &name_ref)?.referenced_local() NameRefClass::Definition(def) => def,
NameRefClass::FieldShorthand { local_ref, field_ref: _ } => {
Definition::Local(local_ref)
} }
ast::NameLike::Name(name) => { },
NameClass::classify(sema, &name)?.defined_or_referenced_local() ast::NameLike::Name(name) => match NameClass::classify(sema, &name)? {
NameClass::Definition(it) | NameClass::ConstReference(it) => it,
NameClass::PatFieldShorthand { local_def, field_ref: _ } => {
Definition::Local(local_def)
} }
},
ast::NameLike::Lifetime(lifetime) => NameRefClass::classify_lifetime(sema, &lifetime) ast::NameLike::Lifetime(lifetime) => NameRefClass::classify_lifetime(sema, &lifetime)
.map(|class| class.referenced_local()) .and_then(|class| match class {
NameRefClass::Definition(it) => Some(it),
_ => None,
})
.or_else(|| { .or_else(|| {
NameClass::classify_lifetime(sema, &lifetime) NameClass::classify_lifetime(sema, &lifetime).and_then(|class| match class {
.map(|class| class.defined_or_referenced_local()) NameClass::Definition(it) => Some(it),
_ => None,
})
})?, })?,
}; };
Some(def) Some(def)

View file

@ -107,13 +107,19 @@ fn find_definition(
{ {
bail!("Renaming aliases is currently unsupported") bail!("Renaming aliases is currently unsupported")
} }
ast::NameLike::Name(name) => { ast::NameLike::Name(name) => NameClass::classify(sema, &name).map(|class| match class {
NameClass::classify(sema, &name).map(|class| class.defined_or_referenced_local()) NameClass::Definition(it) | NameClass::ConstReference(it) => it,
NameClass::PatFieldShorthand { local_def, field_ref: _ } => {
Definition::Local(local_def)
} }
}),
ast::NameLike::NameRef(name_ref) => { ast::NameLike::NameRef(name_ref) => {
if let Some(def) = if let Some(def) = NameRefClass::classify(sema, &name_ref).map(|class| match class {
NameRefClass::classify(sema, &name_ref).map(|class| class.referenced_local()) NameRefClass::Definition(def) => def,
{ NameRefClass::FieldShorthand { local_ref, field_ref: _ } => {
Definition::Local(local_ref)
}
}) {
// if the name differs from the definitions name it has to be an alias // if the name differs from the definitions name it has to be an alias
if def.name(sema.db).map_or(false, |it| it.to_string() != name_ref.text()) { if def.name(sema.db).map_or(false, |it| it.to_string() != name_ref.text()) {
bail!("Renaming aliases is currently unsupported"); bail!("Renaming aliases is currently unsupported");
@ -124,10 +130,15 @@ fn find_definition(
} }
} }
ast::NameLike::Lifetime(lifetime) => NameRefClass::classify_lifetime(sema, &lifetime) ast::NameLike::Lifetime(lifetime) => NameRefClass::classify_lifetime(sema, &lifetime)
.map(|class| class.referenced_local()) .and_then(|class| match class {
NameRefClass::Definition(def) => Some(def),
_ => None,
})
.or_else(|| { .or_else(|| {
NameClass::classify_lifetime(sema, &lifetime) NameClass::classify_lifetime(sema, &lifetime).and_then(|it| match it {
.map(|it| it.defined_or_referenced_field()) NameClass::Definition(it) => Some(it),
_ => None,
})
}), }),
} }
.ok_or_else(|| format_err!("No references found at position"))?; .ok_or_else(|| format_err!("No references found at position"))?;

View file

@ -638,7 +638,12 @@ fn vars_used_in_body(ctx: &AssistContext, body: &FunctionBody) -> Vec<Local> {
body.descendants() body.descendants()
.filter_map(ast::NameRef::cast) .filter_map(ast::NameRef::cast)
.filter_map(|name_ref| NameRefClass::classify(&ctx.sema, &name_ref)) .filter_map(|name_ref| NameRefClass::classify(&ctx.sema, &name_ref))
.map(|name_kind| name_kind.referenced_local()) .map(|name_kind| match name_kind {
NameRefClass::Definition(def) => def,
NameRefClass::FieldShorthand { local_ref, field_ref: _ } => {
Definition::Local(local_ref)
}
})
.filter_map(|definition| match definition { .filter_map(|definition| match definition {
Definition::Local(local) => Some(local), Definition::Local(local) => Some(local),
_ => None, _ => None,

View file

@ -133,26 +133,6 @@ impl NameClass {
Some(res) Some(res)
} }
/// `Definition` referenced or defined by this name, in case of a shorthand this will yield the field reference.
pub fn defined_or_referenced_field(self) -> Definition {
match self {
NameClass::Definition(it) | NameClass::ConstReference(it) => it,
NameClass::PatFieldShorthand { local_def: _, field_ref } => {
Definition::Field(field_ref)
}
}
}
/// `Definition` referenced or defined by this name, in case of a shorthand this will yield the local definition.
pub fn defined_or_referenced_local(self) -> Definition {
match self {
NameClass::Definition(it) | NameClass::ConstReference(it) => it,
NameClass::PatFieldShorthand { local_def, field_ref: _ } => {
Definition::Local(local_def)
}
}
}
pub fn classify(sema: &Semantics<RootDatabase>, name: &ast::Name) -> Option<NameClass> { pub fn classify(sema: &Semantics<RootDatabase>, name: &ast::Name) -> Option<NameClass> {
let _p = profile::span("classify_name"); let _p = profile::span("classify_name");
@ -194,7 +174,12 @@ impl NameClass {
}) })
.and_then(|name_ref| NameRefClass::classify(sema, &name_ref))?; .and_then(|name_ref| NameRefClass::classify(sema, &name_ref))?;
Some(NameClass::Definition(name_ref_class.referenced_field())) Some(NameClass::Definition(match name_ref_class {
NameRefClass::Definition(def) => def,
NameRefClass::FieldShorthand { local_ref: _, field_ref } => {
Definition::Field(field_ref)
}
}))
} else { } else {
let extern_crate = it.syntax().parent().and_then(ast::ExternCrate::cast)?; let extern_crate = it.syntax().parent().and_then(ast::ExternCrate::cast)?;
let krate = sema.resolve_extern_crate(&extern_crate)?; let krate = sema.resolve_extern_crate(&extern_crate)?;
@ -316,26 +301,6 @@ pub enum NameRefClass {
} }
impl NameRefClass { impl NameRefClass {
/// `Definition`, which this name refers to with a preference for the field reference in case of a field shorthand.
pub fn referenced_field(self) -> Definition {
match self {
NameRefClass::Definition(def) => def,
NameRefClass::FieldShorthand { local_ref: _, field_ref } => {
Definition::Field(field_ref)
}
}
}
/// `Definition`, which this name refers to with a preference for the local reference in case of a field shorthand.
pub fn referenced_local(self) -> Definition {
match self {
NameRefClass::Definition(def) => def,
NameRefClass::FieldShorthand { local_ref, field_ref: _ } => {
Definition::Local(local_ref)
}
}
}
// Note: we don't have unit-tests for this rather important function. // Note: we don't have unit-tests for this rather important function.
// It is primarily exercised via goto definition tests in `ide`. // It is primarily exercised via goto definition tests in `ide`.
pub fn classify( pub fn classify(