mirror of
https://github.com/rust-lang/rust-analyzer
synced 2025-01-12 13:18:47 +00:00
Merge #4775
4775: Add goto def for enum variant field r=matklad a=unexge Closes #4764. I'm not familiar with ra codebase, there might be better ways to do that 😄 Co-authored-by: unexge <unexge@gmail.com>
This commit is contained in:
commit
83fd0fb355
3 changed files with 57 additions and 24 deletions
|
@ -1,6 +1,6 @@
|
|||
use hir::Semantics;
|
||||
use ra_ide_db::{
|
||||
defs::{classify_name, classify_name_ref},
|
||||
defs::{classify_name, classify_name_ref, NameClass},
|
||||
symbol_index, RootDatabase,
|
||||
};
|
||||
use ra_syntax::{
|
||||
|
@ -39,7 +39,10 @@ pub(crate) fn goto_definition(
|
|||
reference_definition(&sema, &name_ref).to_vec()
|
||||
},
|
||||
ast::Name(name) => {
|
||||
let def = classify_name(&sema, &name)?.definition();
|
||||
let def = match classify_name(&sema, &name)? {
|
||||
NameClass::Definition(def) | NameClass::ConstReference(def) => def,
|
||||
NameClass::FieldShorthand { local: _, field } => field,
|
||||
};
|
||||
let nav = def.try_to_nav(sema.db)?;
|
||||
vec![nav]
|
||||
},
|
||||
|
@ -886,4 +889,23 @@ mod tests {
|
|||
"x",
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn goto_def_for_enum_variant_field() {
|
||||
check_goto(
|
||||
"
|
||||
//- /lib.rs
|
||||
enum Foo {
|
||||
Bar { x: i32 }
|
||||
}
|
||||
fn baz(foo: Foo) {
|
||||
match foo {
|
||||
Foo::Bar { x<|> } => x
|
||||
};
|
||||
}
|
||||
",
|
||||
"x RECORD_FIELD_DEF FileId(1) 21..27 21..22",
|
||||
"x: i32|x",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -436,6 +436,7 @@ fn highlight_element(
|
|||
highlight_name(db, def) | HighlightModifier::Definition
|
||||
}
|
||||
Some(NameClass::ConstReference(def)) => highlight_name(db, def),
|
||||
Some(NameClass::FieldShorthand { .. }) => HighlightTag::Field.into(),
|
||||
None => highlight_name_by_syntax(name) | HighlightModifier::Definition,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -82,6 +82,10 @@ pub enum NameClass {
|
|||
Definition(Definition),
|
||||
/// `None` in `if let None = Some(82) {}`
|
||||
ConstReference(Definition),
|
||||
FieldShorthand {
|
||||
local: Local,
|
||||
field: Definition,
|
||||
},
|
||||
}
|
||||
|
||||
impl NameClass {
|
||||
|
@ -89,12 +93,14 @@ impl NameClass {
|
|||
match self {
|
||||
NameClass::Definition(it) => Some(it),
|
||||
NameClass::ConstReference(_) => None,
|
||||
NameClass::FieldShorthand { local, field: _ } => Some(Definition::Local(local)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn definition(self) -> Definition {
|
||||
match self {
|
||||
NameClass::Definition(it) | NameClass::ConstReference(it) => it,
|
||||
NameClass::FieldShorthand { local: _, field } => field,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -102,18 +108,14 @@ impl NameClass {
|
|||
pub fn classify_name(sema: &Semantics<RootDatabase>, name: &ast::Name) -> Option<NameClass> {
|
||||
let _p = profile("classify_name");
|
||||
|
||||
if let Some(bind_pat) = name.syntax().parent().and_then(ast::BindPat::cast) {
|
||||
let parent = name.syntax().parent()?;
|
||||
|
||||
if let Some(bind_pat) = ast::BindPat::cast(parent.clone()) {
|
||||
if let Some(def) = sema.resolve_bind_pat_to_const(&bind_pat) {
|
||||
return Some(NameClass::ConstReference(Definition::ModuleDef(def)));
|
||||
}
|
||||
}
|
||||
|
||||
classify_name_inner(sema, name).map(NameClass::Definition)
|
||||
}
|
||||
|
||||
fn classify_name_inner(sema: &Semantics<RootDatabase>, name: &ast::Name) -> Option<Definition> {
|
||||
let parent = name.syntax().parent()?;
|
||||
|
||||
match_ast! {
|
||||
match parent {
|
||||
ast::Alias(it) => {
|
||||
|
@ -123,63 +125,71 @@ fn classify_name_inner(sema: &Semantics<RootDatabase>, name: &ast::Name) -> Opti
|
|||
let name_ref = path_segment.name_ref()?;
|
||||
let name_ref_class = classify_name_ref(sema, &name_ref)?;
|
||||
|
||||
Some(name_ref_class.definition())
|
||||
Some(NameClass::Definition(name_ref_class.definition()))
|
||||
},
|
||||
ast::BindPat(it) => {
|
||||
let local = sema.to_def(&it)?;
|
||||
Some(Definition::Local(local))
|
||||
|
||||
if let Some(record_field_pat) = it.syntax().parent().and_then(ast::RecordFieldPat::cast) {
|
||||
if let Some(field) = sema.resolve_record_field_pat(&record_field_pat) {
|
||||
let field = Definition::Field(field);
|
||||
return Some(NameClass::FieldShorthand { local, field });
|
||||
}
|
||||
}
|
||||
|
||||
Some(NameClass::Definition(Definition::Local(local)))
|
||||
},
|
||||
ast::RecordFieldDef(it) => {
|
||||
let field: hir::Field = sema.to_def(&it)?;
|
||||
Some(Definition::Field(field))
|
||||
Some(NameClass::Definition(Definition::Field(field)))
|
||||
},
|
||||
ast::Module(it) => {
|
||||
let def = sema.to_def(&it)?;
|
||||
Some(Definition::ModuleDef(def.into()))
|
||||
Some(NameClass::Definition(Definition::ModuleDef(def.into())))
|
||||
},
|
||||
ast::StructDef(it) => {
|
||||
let def: hir::Struct = sema.to_def(&it)?;
|
||||
Some(Definition::ModuleDef(def.into()))
|
||||
Some(NameClass::Definition(Definition::ModuleDef(def.into())))
|
||||
},
|
||||
ast::UnionDef(it) => {
|
||||
let def: hir::Union = sema.to_def(&it)?;
|
||||
Some(Definition::ModuleDef(def.into()))
|
||||
Some(NameClass::Definition(Definition::ModuleDef(def.into())))
|
||||
},
|
||||
ast::EnumDef(it) => {
|
||||
let def: hir::Enum = sema.to_def(&it)?;
|
||||
Some(Definition::ModuleDef(def.into()))
|
||||
Some(NameClass::Definition(Definition::ModuleDef(def.into())))
|
||||
},
|
||||
ast::TraitDef(it) => {
|
||||
let def: hir::Trait = sema.to_def(&it)?;
|
||||
Some(Definition::ModuleDef(def.into()))
|
||||
Some(NameClass::Definition(Definition::ModuleDef(def.into())))
|
||||
},
|
||||
ast::StaticDef(it) => {
|
||||
let def: hir::Static = sema.to_def(&it)?;
|
||||
Some(Definition::ModuleDef(def.into()))
|
||||
Some(NameClass::Definition(Definition::ModuleDef(def.into())))
|
||||
},
|
||||
ast::EnumVariant(it) => {
|
||||
let def: hir::EnumVariant = sema.to_def(&it)?;
|
||||
Some(Definition::ModuleDef(def.into()))
|
||||
Some(NameClass::Definition(Definition::ModuleDef(def.into())))
|
||||
},
|
||||
ast::FnDef(it) => {
|
||||
let def: hir::Function = sema.to_def(&it)?;
|
||||
Some(Definition::ModuleDef(def.into()))
|
||||
Some(NameClass::Definition(Definition::ModuleDef(def.into())))
|
||||
},
|
||||
ast::ConstDef(it) => {
|
||||
let def: hir::Const = sema.to_def(&it)?;
|
||||
Some(Definition::ModuleDef(def.into()))
|
||||
Some(NameClass::Definition(Definition::ModuleDef(def.into())))
|
||||
},
|
||||
ast::TypeAliasDef(it) => {
|
||||
let def: hir::TypeAlias = sema.to_def(&it)?;
|
||||
Some(Definition::ModuleDef(def.into()))
|
||||
Some(NameClass::Definition(Definition::ModuleDef(def.into())))
|
||||
},
|
||||
ast::MacroCall(it) => {
|
||||
let def = sema.to_def(&it)?;
|
||||
Some(Definition::Macro(def))
|
||||
Some(NameClass::Definition(Definition::Macro(def)))
|
||||
},
|
||||
ast::TypeParam(it) => {
|
||||
let def = sema.to_def(&it)?;
|
||||
Some(Definition::TypeParam(def))
|
||||
Some(NameClass::Definition(Definition::TypeParam(def)))
|
||||
},
|
||||
_ => None,
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue