Fix goto def not working when cursor was over the name of a def

We now allow goto_definition to return the named NavigationTarget if the cursor
is on the name of a definition.
This commit is contained in:
Ville Penttinen 2019-02-23 11:02:42 +02:00
parent 3d8a0982a1
commit 2a3abe2ce3
2 changed files with 126 additions and 4 deletions

View file

@ -1,7 +1,8 @@
use ra_db::{FileId, SourceDatabase};
use ra_syntax::{
AstNode, ast,
algo::find_node_at_offset,
AstNode, ast::{self, NameOwner},
algo::{find_node_at_offset, visit::{visitor, Visitor}},
SyntaxNode,
};
use test_utils::tested_by;
use hir::Resolution;
@ -114,7 +115,9 @@ fn name_definition(
file_id: FileId,
name: &ast::Name,
) -> Option<Vec<NavigationTarget>> {
if let Some(module) = name.syntax().parent().and_then(ast::Module::cast) {
let parent = name.syntax().parent()?;
if let Some(module) = ast::Module::cast(&parent) {
if module.has_semi() {
if let Some(child_module) =
hir::source_binder::module_from_declaration(db, file_id, module)
@ -124,9 +127,33 @@ fn name_definition(
}
}
}
if let Some(nav) = named_target(file_id, &parent) {
return Some(vec![nav]);
}
None
}
fn named_target(file_id: FileId, node: &SyntaxNode) -> Option<NavigationTarget> {
fn to_nav_target<N: NameOwner>(node: &N, file_id: FileId) -> Option<NavigationTarget> {
Some(NavigationTarget::from_named(file_id, node))
}
visitor()
.visit(|n: &ast::StructDef| to_nav_target(n, file_id))
.visit(|n: &ast::EnumDef| to_nav_target(n, file_id))
.visit(|n: &ast::EnumVariant| to_nav_target(n, file_id))
.visit(|n: &ast::FnDef| to_nav_target(n, file_id))
.visit(|n: &ast::TypeDef| to_nav_target(n, file_id))
.visit(|n: &ast::ConstDef| to_nav_target(n, file_id))
.visit(|n: &ast::StaticDef| to_nav_target(n, file_id))
.visit(|n: &ast::TraitDef| to_nav_target(n, file_id))
.visit(|n: &ast::NamedFieldDef| to_nav_target(n, file_id))
.visit(|n: &ast::Module| to_nav_target(n, file_id))
.accept(node)?
}
#[cfg(test)]
mod tests {
use test_utils::covers;
@ -231,4 +258,98 @@ mod tests {
"spam NAMED_FIELD_DEF FileId(1) [17; 26) [17; 21)",
);
}
#[test]
fn goto_definition_works_when_used_on_definition_name_itself() {
check_goto(
"
//- /lib.rs
struct Foo<|> { value: u32 }
",
"Foo STRUCT_DEF FileId(1) [0; 25) [7; 10)",
);
check_goto(
r#"
//- /lib.rs
struct Foo {
field<|>: string,
}
"#,
"field NAMED_FIELD_DEF FileId(1) [17; 30) [17; 22)",
);
check_goto(
"
//- /lib.rs
fn foo_test<|>() {
}
",
"foo_test FN_DEF FileId(1) [0; 17) [3; 11)",
);
check_goto(
"
//- /lib.rs
enum Foo<|> {
Variant,
}
",
"Foo ENUM_DEF FileId(1) [0; 25) [5; 8)",
);
check_goto(
"
//- /lib.rs
enum Foo {
Variant1,
Variant2<|>,
Variant3,
}
",
"Variant2 ENUM_VARIANT FileId(1) [29; 37) [29; 37)",
);
check_goto(
r#"
//- /lib.rs
static inner<|>: &str = "";
"#,
"inner STATIC_DEF FileId(1) [0; 24) [7; 12)",
);
check_goto(
r#"
//- /lib.rs
const inner<|>: &str = "";
"#,
"inner CONST_DEF FileId(1) [0; 23) [6; 11)",
);
check_goto(
r#"
//- /lib.rs
type Thing<|> = Option<()>;
"#,
"Thing TYPE_DEF FileId(1) [0; 24) [5; 10)",
);
check_goto(
r#"
//- /lib.rs
trait Foo<|> {
}
"#,
"Foo TRAIT_DEF FileId(1) [0; 13) [6; 9)",
);
check_goto(
r#"
//- /lib.rs
mod bar<|> {
}
"#,
"bar MODULE FileId(1) [0; 11) [4; 7)",
);
}
}

View file

@ -198,7 +198,8 @@ impl NavigationTarget {
buf
}
fn from_named(file_id: FileId, node: &impl ast::NameOwner) -> NavigationTarget {
/// Allows `NavigationTarget` to be created from a `NameOwner`
pub(crate) fn from_named(file_id: FileId, node: &impl ast::NameOwner) -> NavigationTarget {
let name = node.name().map(|it| it.text().clone()).unwrap_or_default();
let focus_range = node.name().map(|it| it.syntax().range());
NavigationTarget::from_syntax(file_id, name, focus_range, node.syntax())