aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2019-12-17 13:37:32 +0000
committerGitHub <[email protected]>2019-12-17 13:37:32 +0000
commit4a58522119955f36d95212be902fe3ab79c5e922 (patch)
tree56905131854a5d820a9c2b5e7d9e80484e763b41
parenta26840d603e672bace319f45b28dd615de1b0c2d (diff)
parent3ba4b3c554ee94cf96d62c57f9bb80eaff19beed (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.rs2
-rw-r--r--crates/ra_hir_expand/src/lib.rs13
-rw-r--r--crates/ra_ide/src/expand.rs84
-rw-r--r--crates/ra_ide/src/goto_definition.rs34
-rw-r--r--crates/ra_mbe/src/lib.rs1
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};
60pub use hir_expand::{ 60pub use hir_expand::{
61 name::Name, HirFileId, InFile, MacroCallId, MacroCallLoc, MacroDefId, MacroFile, 61 name::Name, HirFileId, InFile, MacroCallId, MacroCallLoc, MacroDefId, MacroFile, Origin,
62}; 62};
63pub use hir_ty::{display::HirDisplay, CallableDef}; 63pub 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
217pub use mbe::Origin;
218
217impl ExpansionInfo { 219impl 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.
2use std::iter::successors; 2use std::iter::successors;
3 3
4use hir::InFile; 4use hir::{InFile, Origin};
5use ra_db::FileId; 5use ra_db::FileId;
6use ra_syntax::{ast, AstNode, SyntaxNode, SyntaxToken, TextRange}; 6use ra_syntax::{ast, AstNode, SyntaxNode, SyntaxToken, TextRange};
7 7
8use crate::{db::RootDatabase, FileRange}; 8use crate::{db::RootDatabase, FileRange};
9 9
10pub(crate) fn original_range(db: &RootDatabase, node: InFile<&SyntaxNode>) -> FileRange { 10pub(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
27fn 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)]
223mod tests { 223mod 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)]
107pub enum Origin { 108pub enum Origin {
108 Def, 109 Def,
109 Call, 110 Call,