From be84a112a75f4e9acac76c497d714aba8d465ed2 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sat, 5 Jan 2019 20:53:30 +0300 Subject: show types in local variable hovers --- crates/ra_analysis/src/hover.rs | 35 ++++++++++++++++++++++++++--------- crates/ra_analysis/src/lib.rs | 2 +- 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/crates/ra_analysis/src/hover.rs b/crates/ra_analysis/src/hover.rs index 758de376e..8217df305 100644 --- a/crates/ra_analysis/src/hover.rs +++ b/crates/ra_analysis/src/hover.rs @@ -14,23 +14,28 @@ pub(crate) fn hover( ) -> Cancelable>> { let file = db.source_file(position.file_id); let mut res = Vec::new(); - let range = if let Some(name_ref) = - find_node_at_offset::(file.syntax(), position.offset) - { + + let mut range = None; + if let Some(name_ref) = find_node_at_offset::(file.syntax(), position.offset) { let navs = crate::goto_defenition::reference_defenition(db, position.file_id, name_ref)?; for nav in navs { res.extend(doc_text_for(db, nav)?) } - name_ref.syntax().range() - } else { + if !res.is_empty() { + range = Some(name_ref.syntax().range()) + } + } + if range.is_none() { let expr: ast::Expr = ctry!(find_node_at_offset(file.syntax(), position.offset)); let frange = FileRange { file_id: position.file_id, range: expr.syntax().range(), }; res.extend(type_of(db, frange)?); - expr.syntax().range() + range = Some(expr.syntax().range()); }; + + let range = ctry!(range); if res.is_empty() { return Ok(None); } @@ -41,7 +46,13 @@ pub(crate) fn hover( pub(crate) fn type_of(db: &RootDatabase, frange: FileRange) -> Cancelable> { let file = db.source_file(frange.file_id); let syntax = file.syntax(); - let node = find_covering_node(syntax, frange.range); + let leaf_node = find_covering_node(syntax, frange.range); + // if we picked identifier, expand to pattern/expression + let node = leaf_node + .ancestors() + .take_while(|it| it.range() == leaf_node.range()) + .find(|&it| ast::Expr::cast(it).is_some() || ast::Pat::cast(it).is_some()) + .unwrap_or(leaf_node); let parent_fn = ctry!(node.ancestors().find_map(ast::FnDef::cast)); let function = ctry!(hir::source_binder::function_from_source( db, @@ -156,7 +167,6 @@ impl NavigationTarget { #[cfg(test)] mod tests { use ra_syntax::TextRange; - use crate::mock_analysis::single_file_with_position; #[test] @@ -168,10 +178,17 @@ mod tests { fn main() { let foo_test = foo()<|>; } - ", + ", ); let hover = analysis.hover(position).unwrap().unwrap(); assert_eq!(hover.range, TextRange::from_to(95.into(), 100.into())); assert_eq!(hover.info, "u32"); } + + #[test] + fn hover_for_local_variable() { + let (analysis, position) = single_file_with_position("fn func(foo: i32) { fo<|>o; }"); + let hover = analysis.hover(position).unwrap().unwrap(); + assert_eq!(hover.info, "i32"); + } } diff --git a/crates/ra_analysis/src/lib.rs b/crates/ra_analysis/src/lib.rs index 4d895b004..390c31c3f 100644 --- a/crates/ra_analysis/src/lib.rs +++ b/crates/ra_analysis/src/lib.rs @@ -228,7 +228,7 @@ impl Query { /// /// Typically, a `NavigationTarget` corresponds to some element in the source /// code, like a function or a struct, but this is not strictly required. -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct NavigationTarget { file_id: FileId, name: SmolStr, -- cgit v1.2.3 From 01cf32c46e152058b81a11f3fe429be2d76cff98 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sat, 5 Jan 2019 21:09:11 +0300 Subject: fix tests --- crates/ra_analysis/src/hover.rs | 50 ++++++++++++++++++++- crates/ra_analysis/tests/test/main.rs | 1 - crates/ra_analysis/tests/test/type_of.rs | 77 -------------------------------- 3 files changed, 49 insertions(+), 79 deletions(-) delete mode 100644 crates/ra_analysis/tests/test/type_of.rs diff --git a/crates/ra_analysis/src/hover.rs b/crates/ra_analysis/src/hover.rs index 8217df305..2cf79eebf 100644 --- a/crates/ra_analysis/src/hover.rs +++ b/crates/ra_analysis/src/hover.rs @@ -167,7 +167,7 @@ impl NavigationTarget { #[cfg(test)] mod tests { use ra_syntax::TextRange; - use crate::mock_analysis::single_file_with_position; + use crate::mock_analysis::{single_file_with_position, single_file_with_range}; #[test] fn hover_shows_type_of_an_expression() { @@ -191,4 +191,52 @@ mod tests { let hover = analysis.hover(position).unwrap().unwrap(); assert_eq!(hover.info, "i32"); } + + #[test] + fn test_type_of_for_function() { + let (analysis, range) = single_file_with_range( + " + pub fn foo() -> u32 { 1 }; + + fn main() { + let foo_test = <|>foo()<|>; + } + ", + ); + + let type_name = analysis.type_of(range).unwrap().unwrap(); + assert_eq!("u32", &type_name); + } + + // FIXME: improve type_of to make this work + #[test] + fn test_type_of_for_expr_1() { + let (analysis, range) = single_file_with_range( + " + fn main() { + let foo = <|>1 + foo_test<|>; + } + ", + ); + + let type_name = analysis.type_of(range).unwrap().unwrap(); + assert_eq!("[unknown]", &type_name); + } + + // FIXME: improve type_of to make this work + #[test] + fn test_type_of_for_expr_2() { + let (analysis, range) = single_file_with_range( + " + fn main() { + let foo: usize = 1; + let bar = <|>1 + foo_test<|>; + } + ", + ); + + let type_name = analysis.type_of(range).unwrap().unwrap(); + assert_eq!("[unknown]", &type_name); + } + } diff --git a/crates/ra_analysis/tests/test/main.rs b/crates/ra_analysis/tests/test/main.rs index e15035304..26da7c10c 100644 --- a/crates/ra_analysis/tests/test/main.rs +++ b/crates/ra_analysis/tests/test/main.rs @@ -1,5 +1,4 @@ mod runnables; -mod type_of; use ra_syntax::TextRange; use test_utils::{assert_eq_dbg, assert_eq_text}; diff --git a/crates/ra_analysis/tests/test/type_of.rs b/crates/ra_analysis/tests/test/type_of.rs deleted file mode 100644 index 9d15b52a8..000000000 --- a/crates/ra_analysis/tests/test/type_of.rs +++ /dev/null @@ -1,77 +0,0 @@ -use ra_analysis::mock_analysis::single_file_with_range; - -#[test] -fn test_type_of_for_function() { - let (analysis, range) = single_file_with_range( - " - pub fn foo() -> u32 { 1 }; - - fn main() { - let foo_test = <|>foo()<|>; - } - ", - ); - - let type_name = analysis.type_of(range).unwrap().unwrap(); - assert_eq!("u32", &type_name); -} - -// FIXME: improve type_of to make this work -#[test] -fn test_type_of_for_num() { - let (analysis, range) = single_file_with_range( - r#" - fn main() { - let foo_test = <|>"foo"<|>; - } - "#, - ); - - assert!(analysis.type_of(range).unwrap().is_none()); -} -// FIXME: improve type_of to make this work -#[test] -fn test_type_of_for_binding() { - let (analysis, range) = single_file_with_range( - " - pub fn foo() -> u32 { 1 }; - - fn main() { - let <|>foo_test<|> = foo(); - } - ", - ); - - assert!(analysis.type_of(range).unwrap().is_none()); -} - -// FIXME: improve type_of to make this work -#[test] -fn test_type_of_for_expr_1() { - let (analysis, range) = single_file_with_range( - " - fn main() { - let foo = <|>1 + foo_test<|>; - } - ", - ); - - let type_name = analysis.type_of(range).unwrap().unwrap(); - assert_eq!("[unknown]", &type_name); -} - -// FIXME: improve type_of to make this work -#[test] -fn test_type_of_for_expr_2() { - let (analysis, range) = single_file_with_range( - " - fn main() { - let foo: usize = 1; - let bar = <|>1 + foo_test<|>; - } - ", - ); - - let type_name = analysis.type_of(range).unwrap().unwrap(); - assert_eq!("[unknown]", &type_name); -} -- cgit v1.2.3