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:
bors[bot] 2020-06-08 12:46:12 +00:00 committed by GitHub
commit 83fd0fb355
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 57 additions and 24 deletions

View file

@ -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",
);
}
}

View file

@ -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,
}
}

View file

@ -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,
}