aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_hir/src/semantics.rs12
-rw-r--r--crates/ra_ide/src/extend_selection.rs24
-rw-r--r--crates/ra_ide/src/hover.rs27
-rw-r--r--crates/ra_syntax/src/algo.rs14
4 files changed, 54 insertions, 23 deletions
diff --git a/crates/ra_hir/src/semantics.rs b/crates/ra_hir/src/semantics.rs
index 0b40bf9af..5b0b94e34 100644
--- a/crates/ra_hir/src/semantics.rs
+++ b/crates/ra_hir/src/semantics.rs
@@ -8,8 +8,9 @@ use hir_def::{
8}; 8};
9use ra_db::{FileId, FileRange}; 9use ra_db::{FileId, FileRange};
10use ra_syntax::{ 10use ra_syntax::{
11 algo::find_covering_element, ast, match_ast, AstNode, NodeOrToken, SyntaxElement, SyntaxNode, 11 algo::{find_covering_element, skip_trivia_token},
12 SyntaxToken, TextRange, TextUnit, 12 ast, match_ast, AstNode, Direction, NodeOrToken, SyntaxElement, SyntaxNode, SyntaxToken,
13 TextRange, TextUnit,
13}; 14};
14use rustc_hash::{FxHashMap, FxHashSet}; 15use rustc_hash::{FxHashMap, FxHashSet};
15 16
@@ -384,11 +385,12 @@ fn original_range_and_origin(
384 }; 385 };
385 386
386 // the input node has only one token ? 387 // the input node has only one token ?
387 let single = node.value.first_token()? == node.value.last_token()?; 388 let single = skip_trivia_token(node.value.first_token()?, Direction::Next)?
389 == skip_trivia_token(node.value.last_token()?, Direction::Prev)?;
388 390
389 return Some(node.value.descendants().find_map(|it| { 391 return Some(node.value.descendants().find_map(|it| {
390 let first = it.first_token()?; 392 let first = skip_trivia_token(it.first_token()?, Direction::Next)?;
391 let last = it.last_token()?; 393 let last = skip_trivia_token(it.last_token()?, Direction::Prev)?;
392 394
393 if !single && first == last { 395 if !single && first == last {
394 return None; 396 return None;
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 "
diff --git a/crates/ra_syntax/src/algo.rs b/crates/ra_syntax/src/algo.rs
index f14bcbb35..ebf59288a 100644
--- a/crates/ra_syntax/src/algo.rs
+++ b/crates/ra_syntax/src/algo.rs
@@ -7,7 +7,8 @@ use ra_text_edit::TextEditBuilder;
7use rustc_hash::{FxHashMap, FxHashSet}; 7use rustc_hash::{FxHashMap, FxHashSet};
8 8
9use crate::{ 9use crate::{
10 AstNode, Direction, NodeOrToken, SyntaxElement, SyntaxNode, SyntaxNodePtr, TextRange, TextUnit, 10 AstNode, Direction, NodeOrToken, SyntaxElement, SyntaxNode, SyntaxNodePtr, SyntaxToken,
11 TextRange, TextUnit,
11}; 12};
12 13
13/// Returns ancestors of the node at the offset, sorted by length. This should 14/// Returns ancestors of the node at the offset, sorted by length. This should
@@ -37,6 +38,17 @@ pub fn find_node_at_offset<N: AstNode>(syntax: &SyntaxNode, offset: TextUnit) ->
37 ancestors_at_offset(syntax, offset).find_map(N::cast) 38 ancestors_at_offset(syntax, offset).find_map(N::cast)
38} 39}
39 40
41/// Skip to next non `trivia` token
42pub fn skip_trivia_token(mut token: SyntaxToken, direction: Direction) -> Option<SyntaxToken> {
43 while token.kind().is_trivia() {
44 token = match direction {
45 Direction::Next => token.next_token()?,
46 Direction::Prev => token.prev_token()?,
47 }
48 }
49 Some(token)
50}
51
40/// Finds the first sibling in the given direction which is not `trivia` 52/// Finds the first sibling in the given direction which is not `trivia`
41pub fn non_trivia_sibling(element: SyntaxElement, direction: Direction) -> Option<SyntaxElement> { 53pub fn non_trivia_sibling(element: SyntaxElement, direction: Direction) -> Option<SyntaxElement> {
42 return match element { 54 return match element {