aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide/src')
-rw-r--r--crates/ra_ide/src/extend_selection.rs24
-rw-r--r--crates/ra_ide/src/hover.rs27
2 files changed, 34 insertions, 17 deletions
diff --git a/crates/ra_ide/src/extend_selection.rs b/crates/ra_ide/src/extend_selection.rs
index 86e6f12d7..2e09bd1ec 100644
--- a/crates/ra_ide/src/extend_selection.rs
+++ b/crates/ra_ide/src/extend_selection.rs
@@ -5,7 +5,7 @@ use std::iter::successors;
5use hir::Semantics; 5use hir::Semantics;
6use ra_ide_db::RootDatabase; 6use ra_ide_db::RootDatabase;
7use ra_syntax::{ 7use ra_syntax::{
8 algo::{self, find_covering_element}, 8 algo::{self, find_covering_element, skip_trivia_token},
9 ast::{self, AstNode, AstToken}, 9 ast::{self, AstNode, AstToken},
10 Direction, NodeOrToken, 10 Direction, NodeOrToken,
11 SyntaxKind::{self, *}, 11 SyntaxKind::{self, *},
@@ -118,14 +118,14 @@ fn extend_tokens_from_range(
118 NodeOrToken::Token(it) => (it.clone(), it), 118 NodeOrToken::Token(it) => (it.clone(), it),
119 }; 119 };
120 120
121 let mut first_token = skip_whitespace(first_token, Direction::Next)?; 121 let mut first_token = skip_trivia_token(first_token, Direction::Next)?;
122 let mut last_token = skip_whitespace(last_token, Direction::Prev)?; 122 let mut last_token = skip_trivia_token(last_token, Direction::Prev)?;
123 123
124 while !first_token.text_range().is_subrange(&original_range) { 124 while !first_token.text_range().is_subrange(&original_range) {
125 first_token = skip_whitespace(first_token.next_token()?, Direction::Next)?; 125 first_token = skip_trivia_token(first_token.next_token()?, Direction::Next)?;
126 } 126 }
127 while !last_token.text_range().is_subrange(&original_range) { 127 while !last_token.text_range().is_subrange(&original_range) {
128 last_token = skip_whitespace(last_token.prev_token()?, Direction::Prev)?; 128 last_token = skip_trivia_token(last_token.prev_token()?, Direction::Prev)?;
129 } 129 }
130 130
131 // compute original mapped token range 131 // compute original mapped token range
@@ -149,14 +149,14 @@ fn extend_tokens_from_range(
149 // Find the first and last text range under expanded parent 149 // Find the first and last text range under expanded parent
150 let first = successors(Some(first_token), |token| { 150 let first = successors(Some(first_token), |token| {
151 let token = token.prev_token()?; 151 let token = token.prev_token()?;
152 skip_whitespace(token, Direction::Prev) 152 skip_trivia_token(token, Direction::Prev)
153 }) 153 })
154 .take_while(validate) 154 .take_while(validate)
155 .last()?; 155 .last()?;
156 156
157 let last = successors(Some(last_token), |token| { 157 let last = successors(Some(last_token), |token| {
158 let token = token.next_token()?; 158 let token = token.next_token()?;
159 skip_whitespace(token, Direction::Next) 159 skip_trivia_token(token, Direction::Next)
160 }) 160 })
161 .take_while(validate) 161 .take_while(validate)
162 .last()?; 162 .last()?;
@@ -169,16 +169,6 @@ fn extend_tokens_from_range(
169 } 169 }
170} 170}
171 171
172fn skip_whitespace(mut token: SyntaxToken, direction: Direction) -> Option<SyntaxToken> {
173 while token.kind() == WHITESPACE {
174 token = match direction {
175 Direction::Next => token.next_token()?,
176 Direction::Prev => token.prev_token()?,
177 }
178 }
179 Some(token)
180}
181
182fn union_range(range: TextRange, r: TextRange) -> TextRange { 172fn union_range(range: TextRange, r: TextRange) -> TextRange {
183 let start = range.start().min(r.start()); 173 let start = range.start().min(r.start());
184 let end = range.end().max(r.end()); 174 let end = range.end().max(r.end());
diff --git a/crates/ra_ide/src/hover.rs b/crates/ra_ide/src/hover.rs
index 29b16e602..177038e20 100644
--- a/crates/ra_ide/src/hover.rs
+++ b/crates/ra_ide/src/hover.rs
@@ -174,6 +174,10 @@ pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeIn
174 .ancestors() 174 .ancestors()
175 .find(|n| ast::Expr::cast(n.clone()).is_some() || ast::Pat::cast(n.clone()).is_some())?; 175 .find(|n| ast::Expr::cast(n.clone()).is_some() || ast::Pat::cast(n.clone()).is_some())?;
176 176
177 // FIXME: Currently `hover::typeof` do not work inside
178 // macro expansion such that if the hover range is pointing to
179 // a string literal, the following type_of will return None.
180 // See also `test_hover_through_literal_string_in_macro`
177 let frange = sema.original_range(&node); 181 let frange = sema.original_range(&node);
178 res.extend(type_of(db, frange).map(rust_code_markup)); 182 res.extend(type_of(db, frange).map(rust_code_markup));
179 if res.is_empty() { 183 if res.is_empty() {
@@ -250,6 +254,11 @@ mod tests {
250 content[hover.range].to_string() 254 content[hover.range].to_string()
251 } 255 }
252 256
257 fn check_hover_no_result(fixture: &str) {
258 let (analysis, position) = analysis_and_position(fixture);
259 assert!(analysis.hover(position).unwrap().is_none());
260 }
261
253 #[test] 262 #[test]
254 fn hover_shows_type_of_an_expression() { 263 fn hover_shows_type_of_an_expression() {
255 let (analysis, position) = single_file_with_position( 264 let (analysis, position) = single_file_with_position(
@@ -775,6 +784,24 @@ fn func(foo: i32) { if true { <|>foo; }; }
775 } 784 }
776 785
777 #[test] 786 #[test]
787 fn test_hover_through_literal_string_in_macro() {
788 // FIXME: Currently `hover::type_of` do not work inside
789 // macro expansion
790 check_hover_no_result(
791 r#"
792 //- /lib.rs
793 macro_rules! arr {
794 ($($tt:tt)*) => { [$($tt)*)] }
795 }
796 fn foo() {
797 let mastered_for_itunes = "";
798 let _ = arr!("Tr<|>acks", &mastered_for_itunes);
799 }
800 "#,
801 );
802 }
803
804 #[test]
778 fn test_hover_non_ascii_space_doc() { 805 fn test_hover_non_ascii_space_doc() {
779 check_hover_result( 806 check_hover_result(
780 " 807 "