diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2019-12-17 13:37:32 +0000 |
---|---|---|
committer | GitHub <[email protected]> | 2019-12-17 13:37:32 +0000 |
commit | 4a58522119955f36d95212be902fe3ab79c5e922 (patch) | |
tree | 56905131854a5d820a9c2b5e7d9e80484e763b41 | |
parent | a26840d603e672bace319f45b28dd615de1b0c2d (diff) | |
parent | 3ba4b3c554ee94cf96d62c57f9bb80eaff19beed (diff) |
Merge #2562
2562: Fix NavigationTarget ranges r=matklad a=edwin0cheng
Fix the issue described in https://github.com/rust-analyzer/rust-analyzer/pull/2544#issuecomment-565572553
This PR change the order for finding `full_range` of `focus_range` in following orders:
1. map both ranges to macro_call
2. map focus range to a token inside macro call, and full range to the whole of macro call
3. map both ranges to the whole of macro call
And fix the corresponding tests and make these tests easily to follow.
Co-authored-by: Edwin Cheng <[email protected]>
-rw-r--r-- | crates/ra_hir/src/lib.rs | 2 | ||||
-rw-r--r-- | crates/ra_hir_expand/src/lib.rs | 13 | ||||
-rw-r--r-- | crates/ra_ide/src/expand.rs | 84 | ||||
-rw-r--r-- | crates/ra_ide/src/goto_definition.rs | 34 | ||||
-rw-r--r-- | crates/ra_mbe/src/lib.rs | 1 |
5 files changed, 86 insertions, 48 deletions
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs index 451b227a6..2e52a1f5c 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs | |||
@@ -58,6 +58,6 @@ pub use hir_def::{ | |||
58 | type_ref::Mutability, | 58 | type_ref::Mutability, |
59 | }; | 59 | }; |
60 | pub use hir_expand::{ | 60 | pub use hir_expand::{ |
61 | name::Name, HirFileId, InFile, MacroCallId, MacroCallLoc, MacroDefId, MacroFile, | 61 | name::Name, HirFileId, InFile, MacroCallId, MacroCallLoc, MacroDefId, MacroFile, Origin, |
62 | }; | 62 | }; |
63 | pub use hir_ty::{display::HirDisplay, CallableDef}; | 63 | pub use hir_ty::{display::HirDisplay, CallableDef}; |
diff --git a/crates/ra_hir_expand/src/lib.rs b/crates/ra_hir_expand/src/lib.rs index 94e1e466a..cb4e1950b 100644 --- a/crates/ra_hir_expand/src/lib.rs +++ b/crates/ra_hir_expand/src/lib.rs | |||
@@ -214,7 +214,13 @@ pub struct ExpansionInfo { | |||
214 | exp_map: Arc<mbe::TokenMap>, | 214 | exp_map: Arc<mbe::TokenMap>, |
215 | } | 215 | } |
216 | 216 | ||
217 | pub use mbe::Origin; | ||
218 | |||
217 | impl ExpansionInfo { | 219 | impl ExpansionInfo { |
220 | pub fn call_node(&self) -> Option<InFile<SyntaxNode>> { | ||
221 | Some(self.arg.with_value(self.arg.value.parent()?)) | ||
222 | } | ||
223 | |||
218 | pub fn map_token_down(&self, token: InFile<&SyntaxToken>) -> Option<InFile<SyntaxToken>> { | 224 | pub fn map_token_down(&self, token: InFile<&SyntaxToken>) -> Option<InFile<SyntaxToken>> { |
219 | assert_eq!(token.file_id, self.arg.file_id); | 225 | assert_eq!(token.file_id, self.arg.file_id); |
220 | let range = token.value.text_range().checked_sub(self.arg.value.text_range().start())?; | 226 | let range = token.value.text_range().checked_sub(self.arg.value.text_range().start())?; |
@@ -228,7 +234,10 @@ impl ExpansionInfo { | |||
228 | Some(self.expanded.with_value(token)) | 234 | Some(self.expanded.with_value(token)) |
229 | } | 235 | } |
230 | 236 | ||
231 | pub fn map_token_up(&self, token: InFile<&SyntaxToken>) -> Option<InFile<SyntaxToken>> { | 237 | pub fn map_token_up( |
238 | &self, | ||
239 | token: InFile<&SyntaxToken>, | ||
240 | ) -> Option<(InFile<SyntaxToken>, Origin)> { | ||
232 | let token_id = self.exp_map.token_by_range(token.value.text_range())?; | 241 | let token_id = self.exp_map.token_by_range(token.value.text_range())?; |
233 | 242 | ||
234 | let (token_id, origin) = self.macro_def.0.map_id_up(token_id); | 243 | let (token_id, origin) = self.macro_def.0.map_id_up(token_id); |
@@ -242,7 +251,7 @@ impl ExpansionInfo { | |||
242 | let range = token_map.range_by_token(token_id)?; | 251 | let range = token_map.range_by_token(token_id)?; |
243 | let token = algo::find_covering_element(&tt.value, range + tt.value.text_range().start()) | 252 | let token = algo::find_covering_element(&tt.value, range + tt.value.text_range().start()) |
244 | .into_token()?; | 253 | .into_token()?; |
245 | Some(tt.with_value(token)) | 254 | Some((tt.with_value(token), origin)) |
246 | } | 255 | } |
247 | } | 256 | } |
248 | 257 | ||
diff --git a/crates/ra_ide/src/expand.rs b/crates/ra_ide/src/expand.rs index 661628ae4..7a22bb0a4 100644 --- a/crates/ra_ide/src/expand.rs +++ b/crates/ra_ide/src/expand.rs | |||
@@ -1,56 +1,66 @@ | |||
1 | //! Utilities to work with files, produced by macros. | 1 | //! Utilities to work with files, produced by macros. |
2 | use std::iter::successors; | 2 | use std::iter::successors; |
3 | 3 | ||
4 | use hir::InFile; | 4 | use hir::{InFile, Origin}; |
5 | use ra_db::FileId; | 5 | use ra_db::FileId; |
6 | use ra_syntax::{ast, AstNode, SyntaxNode, SyntaxToken, TextRange}; | 6 | use ra_syntax::{ast, AstNode, SyntaxNode, SyntaxToken, TextRange}; |
7 | 7 | ||
8 | use crate::{db::RootDatabase, FileRange}; | 8 | use crate::{db::RootDatabase, FileRange}; |
9 | 9 | ||
10 | pub(crate) fn original_range(db: &RootDatabase, node: InFile<&SyntaxNode>) -> FileRange { | 10 | pub(crate) fn original_range(db: &RootDatabase, node: InFile<&SyntaxNode>) -> FileRange { |
11 | let expansion = match node.file_id.expansion_info(db) { | 11 | if let Some((range, Origin::Call)) = original_range_and_origin(db, node) { |
12 | None => { | 12 | return range; |
13 | } | ||
14 | |||
15 | if let Some(expansion) = node.file_id.expansion_info(db) { | ||
16 | if let Some(call_node) = expansion.call_node() { | ||
13 | return FileRange { | 17 | return FileRange { |
14 | file_id: node.file_id.original_file(db), | 18 | file_id: call_node.file_id.original_file(db), |
15 | range: node.value.text_range(), | 19 | range: call_node.value.text_range(), |
16 | } | 20 | }; |
17 | } | 21 | } |
18 | Some(it) => it, | 22 | } |
19 | }; | 23 | |
24 | FileRange { file_id: node.file_id.original_file(db), range: node.value.text_range() } | ||
25 | } | ||
26 | |||
27 | fn original_range_and_origin( | ||
28 | db: &RootDatabase, | ||
29 | node: InFile<&SyntaxNode>, | ||
30 | ) -> Option<(FileRange, Origin)> { | ||
31 | let expansion = node.file_id.expansion_info(db)?; | ||
32 | |||
33 | // the input node has only one token ? | ||
34 | let single = node.value.first_token()? == node.value.last_token()?; | ||
35 | |||
20 | // FIXME: We should handle recurside macro expansions | 36 | // FIXME: We should handle recurside macro expansions |
37 | let (range, origin) = node.value.descendants().find_map(|it| { | ||
38 | let first = it.first_token()?; | ||
39 | let last = it.last_token()?; | ||
21 | 40 | ||
22 | let range = node.value.descendants_with_tokens().find_map(|it| { | 41 | if !single && first == last { |
23 | match it.as_token() { | 42 | return None; |
24 | // FIXME: Remove this branch after all `tt::TokenTree`s have a proper `TokenId`, | ||
25 | // and return the range of the overall macro expansions if mapping first and last tokens fails. | ||
26 | Some(token) => { | ||
27 | let token = expansion.map_token_up(node.with_value(&token))?; | ||
28 | Some(token.with_value(token.value.text_range())) | ||
29 | } | ||
30 | None => { | ||
31 | // Try to map first and last tokens of node, and, if success, return the union range of mapped tokens | ||
32 | let n = it.into_node()?; | ||
33 | let first = expansion.map_token_up(node.with_value(&n.first_token()?))?; | ||
34 | let last = expansion.map_token_up(node.with_value(&n.last_token()?))?; | ||
35 | |||
36 | // FIXME: Is is possible ? | ||
37 | if first.file_id != last.file_id { | ||
38 | return None; | ||
39 | } | ||
40 | |||
41 | // FIXME: Add union method in TextRange | ||
42 | let range = union_range(first.value.text_range(), last.value.text_range()); | ||
43 | Some(first.with_value(range)) | ||
44 | } | ||
45 | } | 43 | } |
46 | }); | ||
47 | 44 | ||
48 | return match range { | 45 | // Try to map first and last tokens of node, and, if success, return the union range of mapped tokens |
49 | Some(it) => FileRange { file_id: it.file_id.original_file(db), range: it.value }, | 46 | let (first, first_origin) = expansion.map_token_up(node.with_value(&first))?; |
50 | None => { | 47 | let (last, last_origin) = expansion.map_token_up(node.with_value(&last))?; |
51 | FileRange { file_id: node.file_id.original_file(db), range: node.value.text_range() } | 48 | |
49 | if first.file_id != last.file_id || first_origin != last_origin { | ||
50 | return None; | ||
52 | } | 51 | } |
53 | }; | 52 | |
53 | // FIXME: Add union method in TextRange | ||
54 | Some(( | ||
55 | first.with_value(union_range(first.value.text_range(), last.value.text_range())), | ||
56 | first_origin, | ||
57 | )) | ||
58 | })?; | ||
59 | |||
60 | return Some(( | ||
61 | FileRange { file_id: range.file_id.original_file(db), range: range.value }, | ||
62 | origin, | ||
63 | )); | ||
54 | 64 | ||
55 | fn union_range(a: TextRange, b: TextRange) -> TextRange { | 65 | fn union_range(a: TextRange, b: TextRange) -> TextRange { |
56 | let start = a.start().min(b.start()); | 66 | let start = a.start().min(b.start()); |
diff --git a/crates/ra_ide/src/goto_definition.rs b/crates/ra_ide/src/goto_definition.rs index 27052d72b..bee8e9df2 100644 --- a/crates/ra_ide/src/goto_definition.rs +++ b/crates/ra_ide/src/goto_definition.rs | |||
@@ -221,7 +221,7 @@ fn named_target(db: &RootDatabase, node: InFile<&SyntaxNode>) -> Option<Navigati | |||
221 | 221 | ||
222 | #[cfg(test)] | 222 | #[cfg(test)] |
223 | mod tests { | 223 | mod tests { |
224 | use test_utils::covers; | 224 | use test_utils::{assert_eq_text, covers}; |
225 | 225 | ||
226 | use crate::mock_analysis::analysis_and_position; | 226 | use crate::mock_analysis::analysis_and_position; |
227 | 227 | ||
@@ -234,6 +234,24 @@ mod tests { | |||
234 | nav.assert_match(expected); | 234 | nav.assert_match(expected); |
235 | } | 235 | } |
236 | 236 | ||
237 | fn check_goto_with_range_content(fixture: &str, expected: &str, expected_range: &str) { | ||
238 | let (analysis, pos) = analysis_and_position(fixture); | ||
239 | |||
240 | let mut navs = analysis.goto_definition(pos).unwrap().unwrap().info; | ||
241 | assert_eq!(navs.len(), 1); | ||
242 | let nav = navs.pop().unwrap(); | ||
243 | let file_text = analysis.file_text(pos.file_id).unwrap(); | ||
244 | |||
245 | let actual_full_range = &file_text[nav.full_range()]; | ||
246 | let actual_range = &file_text[nav.range()]; | ||
247 | |||
248 | test_utils::assert_eq_text!( | ||
249 | &format!("{}|{}", actual_full_range, actual_range), | ||
250 | expected_range | ||
251 | ); | ||
252 | nav.assert_match(expected); | ||
253 | } | ||
254 | |||
237 | #[test] | 255 | #[test] |
238 | fn goto_definition_works_in_items() { | 256 | fn goto_definition_works_in_items() { |
239 | check_goto( | 257 | check_goto( |
@@ -363,28 +381,27 @@ mod tests { | |||
363 | 381 | ||
364 | #[test] | 382 | #[test] |
365 | fn goto_definition_works_for_macro_defined_fn_with_arg() { | 383 | fn goto_definition_works_for_macro_defined_fn_with_arg() { |
366 | check_goto( | 384 | check_goto_with_range_content( |
367 | " | 385 | " |
368 | //- /lib.rs | 386 | //- /lib.rs |
369 | macro_rules! define_fn { | 387 | macro_rules! define_fn { |
370 | ($name:ident) => (fn $name() {}) | 388 | ($name:ident) => (fn $name() {}) |
371 | } | 389 | } |
372 | 390 | ||
373 | define_fn!( | 391 | define_fn!(foo); |
374 | foo | ||
375 | ) | ||
376 | 392 | ||
377 | fn bar() { | 393 | fn bar() { |
378 | <|>foo(); | 394 | <|>foo(); |
379 | } | 395 | } |
380 | ", | 396 | ", |
381 | "foo FN_DEF FileId(1) [80; 83) [80; 83)", | 397 | "foo FN_DEF FileId(1) [64; 80) [75; 78)", |
398 | "define_fn!(foo);|foo", | ||
382 | ); | 399 | ); |
383 | } | 400 | } |
384 | 401 | ||
385 | #[test] | 402 | #[test] |
386 | fn goto_definition_works_for_macro_defined_fn_no_arg() { | 403 | fn goto_definition_works_for_macro_defined_fn_no_arg() { |
387 | check_goto( | 404 | check_goto_with_range_content( |
388 | " | 405 | " |
389 | //- /lib.rs | 406 | //- /lib.rs |
390 | macro_rules! define_fn { | 407 | macro_rules! define_fn { |
@@ -397,7 +414,8 @@ mod tests { | |||
397 | <|>foo(); | 414 | <|>foo(); |
398 | } | 415 | } |
399 | ", | 416 | ", |
400 | "foo FN_DEF FileId(1) [39; 42) [39; 42)", | 417 | "foo FN_DEF FileId(1) [51; 64) [51; 64)", |
418 | "define_fn!();|define_fn!();", | ||
401 | ); | 419 | ); |
402 | } | 420 | } |
403 | 421 | ||
diff --git a/crates/ra_mbe/src/lib.rs b/crates/ra_mbe/src/lib.rs index 0d2d43bef..ce2deadf6 100644 --- a/crates/ra_mbe/src/lib.rs +++ b/crates/ra_mbe/src/lib.rs | |||
@@ -104,6 +104,7 @@ impl Shift { | |||
104 | } | 104 | } |
105 | } | 105 | } |
106 | 106 | ||
107 | #[derive(Debug, Eq, PartialEq)] | ||
107 | pub enum Origin { | 108 | pub enum Origin { |
108 | Def, | 109 | Def, |
109 | Call, | 110 | Call, |