diff options
author | Aleksey Kladov <[email protected]> | 2020-02-26 16:58:32 +0000 |
---|---|---|
committer | GitHub <[email protected]> | 2020-02-26 16:58:32 +0000 |
commit | 913cdcee8f0fe4373627d10d756949b970bcf5c2 (patch) | |
tree | 7f0e57819a98bb908d4511d1c57ea484520373e3 | |
parent | 6ea633c4940d25acea04e4945a8f905e65153c30 (diff) | |
parent | 553254973e24a2c0bdf1475fccbbc4603e8421f0 (diff) |
Merge pull request #3325 from edwin0cheng/skip-trival-token
Skip trival token in original_range
-rw-r--r-- | crates/ra_hir/src/semantics.rs | 12 | ||||
-rw-r--r-- | crates/ra_ide/src/extend_selection.rs | 24 | ||||
-rw-r--r-- | crates/ra_ide/src/hover.rs | 27 | ||||
-rw-r--r-- | crates/ra_syntax/src/algo.rs | 14 |
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 | }; |
9 | use ra_db::{FileId, FileRange}; | 9 | use ra_db::{FileId, FileRange}; |
10 | use ra_syntax::{ | 10 | use 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 | }; |
14 | use rustc_hash::{FxHashMap, FxHashSet}; | 15 | use 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; | |||
5 | use hir::Semantics; | 5 | use hir::Semantics; |
6 | use ra_ide_db::RootDatabase; | 6 | use ra_ide_db::RootDatabase; |
7 | use ra_syntax::{ | 7 | use 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 | ||
172 | fn 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 | |||
182 | fn union_range(range: TextRange, r: TextRange) -> TextRange { | 172 | fn 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; | |||
7 | use rustc_hash::{FxHashMap, FxHashSet}; | 7 | use rustc_hash::{FxHashMap, FxHashSet}; |
8 | 8 | ||
9 | use crate::{ | 9 | use 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 | ||
42 | pub 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` |
41 | pub fn non_trivia_sibling(element: SyntaxElement, direction: Direction) -> Option<SyntaxElement> { | 53 | pub fn non_trivia_sibling(element: SyntaxElement, direction: Direction) -> Option<SyntaxElement> { |
42 | return match element { | 54 | return match element { |