diff options
Diffstat (limited to 'crates/ra_ide/src/hover.rs')
-rw-r--r-- | crates/ra_ide/src/hover.rs | 98 |
1 files changed, 24 insertions, 74 deletions
diff --git a/crates/ra_ide/src/hover.rs b/crates/ra_ide/src/hover.rs index dfa0f1d97..7ba4bfcac 100644 --- a/crates/ra_ide/src/hover.rs +++ b/crates/ra_ide/src/hover.rs | |||
@@ -6,7 +6,6 @@ use ra_ide_db::{ | |||
6 | RootDatabase, | 6 | RootDatabase, |
7 | }; | 7 | }; |
8 | use ra_syntax::{ | 8 | use ra_syntax::{ |
9 | algo::find_covering_element, | ||
10 | ast::{self, DocCommentsOwner}, | 9 | ast::{self, DocCommentsOwner}, |
11 | match_ast, AstNode, | 10 | match_ast, AstNode, |
12 | SyntaxKind::*, | 11 | SyntaxKind::*, |
@@ -16,7 +15,7 @@ use ra_syntax::{ | |||
16 | use crate::{ | 15 | use crate::{ |
17 | display::{macro_label, rust_code_markup, rust_code_markup_with_doc, ShortLabel}, | 16 | display::{macro_label, rust_code_markup, rust_code_markup_with_doc, ShortLabel}, |
18 | references::classify_name_ref, | 17 | references::classify_name_ref, |
19 | FilePosition, FileRange, RangeInfo, | 18 | FilePosition, RangeInfo, |
20 | }; | 19 | }; |
21 | 20 | ||
22 | /// Contains the results when hovering over an item | 21 | /// Contains the results when hovering over an item |
@@ -174,23 +173,25 @@ pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeIn | |||
174 | .ancestors() | 173 | .ancestors() |
175 | .find(|n| ast::Expr::cast(n.clone()).is_some() || ast::Pat::cast(n.clone()).is_some())?; | 174 | .find(|n| ast::Expr::cast(n.clone()).is_some() || ast::Pat::cast(n.clone()).is_some())?; |
176 | 175 | ||
177 | // if this node is a MACRO_CALL, it means that `descend_into_macros` is failed to resolve. | 176 | let ty = match_ast! { |
178 | // (e.g expanding a builtin macro). So we give up here. | 177 | match node { |
179 | if node.kind() == MACRO_CALL { | 178 | ast::MacroCall(_it) => { |
180 | return None; | 179 | // If this node is a MACRO_CALL, it means that `descend_into_macros` failed to resolve. |
181 | } | 180 | // (e.g expanding a builtin macro). So we give up here. |
182 | 181 | return None; | |
183 | // FIXME: Currently `hover::typeof` do not work inside | 182 | }, |
184 | // macro expansion such that if the hover range is pointing to | 183 | ast::Expr(it) => { |
185 | // a string literal, the following type_of will return None. | 184 | sema.type_of_expr(&it) |
186 | // See also `test_hover_through_literal_string_in_macro` | 185 | }, |
187 | let frange = sema.original_range(&node); | 186 | ast::Pat(it) => { |
188 | res.extend(type_of(db, frange).map(rust_code_markup)); | 187 | sema.type_of_pat(&it) |
189 | if res.is_empty() { | 188 | }, |
190 | return None; | 189 | _ => None, |
191 | } | 190 | } |
192 | let range = node.text_range(); | 191 | }?; |
193 | 192 | ||
193 | res.extend(Some(rust_code_markup(ty.display_truncated(db, None).to_string()))); | ||
194 | let range = sema.original_range(&node).range; | ||
194 | Some(RangeInfo::new(range, res)) | 195 | Some(RangeInfo::new(range, res)) |
195 | } | 196 | } |
196 | 197 | ||
@@ -206,33 +207,12 @@ fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> { | |||
206 | } | 207 | } |
207 | } | 208 | } |
208 | 209 | ||
209 | pub(crate) fn type_of(db: &RootDatabase, frange: FileRange) -> Option<String> { | ||
210 | let sema = Semantics::new(db); | ||
211 | let source_file = sema.parse(frange.file_id); | ||
212 | let leaf_node = find_covering_element(source_file.syntax(), frange.range); | ||
213 | // if we picked identifier, expand to pattern/expression | ||
214 | let node = leaf_node | ||
215 | .ancestors() | ||
216 | .take_while(|it| it.text_range() == leaf_node.text_range()) | ||
217 | .find(|it| ast::Expr::cast(it.clone()).is_some() || ast::Pat::cast(it.clone()).is_some())?; | ||
218 | let ty = if let Some(ty) = ast::Expr::cast(node.clone()).and_then(|e| sema.type_of_expr(&e)) { | ||
219 | ty | ||
220 | } else if let Some(ty) = ast::Pat::cast(node).and_then(|p| sema.type_of_pat(&p)) { | ||
221 | ty | ||
222 | } else { | ||
223 | return None; | ||
224 | }; | ||
225 | Some(ty.display_truncated(db, None).to_string()) | ||
226 | } | ||
227 | |||
228 | #[cfg(test)] | 210 | #[cfg(test)] |
229 | mod tests { | 211 | mod tests { |
230 | use ra_db::FileLoader; | 212 | use ra_db::FileLoader; |
231 | use ra_syntax::TextRange; | 213 | use ra_syntax::TextRange; |
232 | 214 | ||
233 | use crate::mock_analysis::{ | 215 | use crate::mock_analysis::{analysis_and_position, single_file_with_position}; |
234 | analysis_and_position, single_file_with_position, single_file_with_range, | ||
235 | }; | ||
236 | 216 | ||
237 | fn trim_markup(s: &str) -> &str { | 217 | fn trim_markup(s: &str) -> &str { |
238 | s.trim_start_matches("```rust\n").trim_end_matches("\n```") | 218 | s.trim_start_matches("```rust\n").trim_end_matches("\n```") |
@@ -525,37 +505,6 @@ fn func(foo: i32) { if true { <|>foo; }; } | |||
525 | } | 505 | } |
526 | 506 | ||
527 | #[test] | 507 | #[test] |
528 | fn test_type_of_for_function() { | ||
529 | let (analysis, range) = single_file_with_range( | ||
530 | " | ||
531 | pub fn foo() -> u32 { 1 }; | ||
532 | |||
533 | fn main() { | ||
534 | let foo_test = <|>foo()<|>; | ||
535 | } | ||
536 | ", | ||
537 | ); | ||
538 | |||
539 | let type_name = analysis.type_of(range).unwrap().unwrap(); | ||
540 | assert_eq!("u32", &type_name); | ||
541 | } | ||
542 | |||
543 | #[test] | ||
544 | fn test_type_of_for_expr() { | ||
545 | let (analysis, range) = single_file_with_range( | ||
546 | " | ||
547 | fn main() { | ||
548 | let foo: usize = 1; | ||
549 | let bar = <|>1 + foo<|>; | ||
550 | } | ||
551 | ", | ||
552 | ); | ||
553 | |||
554 | let type_name = analysis.type_of(range).unwrap().unwrap(); | ||
555 | assert_eq!("usize", &type_name); | ||
556 | } | ||
557 | |||
558 | #[test] | ||
559 | fn test_hover_infer_associated_method_result() { | 508 | fn test_hover_infer_associated_method_result() { |
560 | let (analysis, position) = single_file_with_position( | 509 | let (analysis, position) = single_file_with_position( |
561 | " | 510 | " |
@@ -791,9 +740,7 @@ fn func(foo: i32) { if true { <|>foo; }; } | |||
791 | 740 | ||
792 | #[test] | 741 | #[test] |
793 | fn test_hover_through_literal_string_in_macro() { | 742 | fn test_hover_through_literal_string_in_macro() { |
794 | // FIXME: Currently `hover::type_of` do not work inside | 743 | let hover_on = check_hover_result( |
795 | // macro expansion | ||
796 | check_hover_no_result( | ||
797 | r#" | 744 | r#" |
798 | //- /lib.rs | 745 | //- /lib.rs |
799 | macro_rules! arr { | 746 | macro_rules! arr { |
@@ -804,7 +751,10 @@ fn func(foo: i32) { if true { <|>foo; }; } | |||
804 | let _ = arr!("Tr<|>acks", &mastered_for_itunes); | 751 | let _ = arr!("Tr<|>acks", &mastered_for_itunes); |
805 | } | 752 | } |
806 | "#, | 753 | "#, |
754 | &["&str"], | ||
807 | ); | 755 | ); |
756 | |||
757 | assert_eq!(hover_on, "\"Tracks\""); | ||
808 | } | 758 | } |
809 | 759 | ||
810 | #[test] | 760 | #[test] |