diff options
Diffstat (limited to 'crates/hir_expand')
-rw-r--r-- | crates/hir_expand/src/lib.rs | 72 |
1 files changed, 69 insertions, 3 deletions
diff --git a/crates/hir_expand/src/lib.rs b/crates/hir_expand/src/lib.rs index 2633fd8f7..3edcadf0d 100644 --- a/crates/hir_expand/src/lib.rs +++ b/crates/hir_expand/src/lib.rs | |||
@@ -20,11 +20,11 @@ pub use mbe::{ExpandError, ExpandResult}; | |||
20 | use std::hash::Hash; | 20 | use std::hash::Hash; |
21 | use std::sync::Arc; | 21 | use std::sync::Arc; |
22 | 22 | ||
23 | use base_db::{impl_intern_key, salsa, CrateId, FileId}; | 23 | use base_db::{impl_intern_key, salsa, CrateId, FileId, FileRange}; |
24 | use syntax::{ | 24 | use syntax::{ |
25 | algo, | 25 | algo::{self, skip_trivia_token}, |
26 | ast::{self, AstNode}, | 26 | ast::{self, AstNode}, |
27 | SyntaxNode, SyntaxToken, TextSize, | 27 | Direction, SyntaxNode, SyntaxToken, TextRange, TextSize, |
28 | }; | 28 | }; |
29 | 29 | ||
30 | use crate::ast_id_map::FileAstId; | 30 | use crate::ast_id_map::FileAstId; |
@@ -445,6 +445,72 @@ impl InFile<SyntaxNode> { | |||
445 | } | 445 | } |
446 | } | 446 | } |
447 | 447 | ||
448 | impl<'a> InFile<&'a SyntaxNode> { | ||
449 | pub fn original_file_range(self, db: &dyn db::AstDatabase) -> FileRange { | ||
450 | if let Some(range) = original_range_opt(db, self) { | ||
451 | let original_file = range.file_id.original_file(db); | ||
452 | if range.file_id == original_file.into() { | ||
453 | return FileRange { file_id: original_file, range: range.value }; | ||
454 | } | ||
455 | |||
456 | log::error!("Fail to mapping up more for {:?}", range); | ||
457 | return FileRange { file_id: range.file_id.original_file(db), range: range.value }; | ||
458 | } | ||
459 | |||
460 | // Fall back to whole macro call | ||
461 | if let Some(expansion) = self.file_id.expansion_info(db) { | ||
462 | if let Some(call_node) = expansion.call_node() { | ||
463 | return FileRange { | ||
464 | file_id: call_node.file_id.original_file(db), | ||
465 | range: call_node.value.text_range(), | ||
466 | }; | ||
467 | } | ||
468 | } | ||
469 | |||
470 | FileRange { file_id: self.file_id.original_file(db), range: self.value.text_range() } | ||
471 | } | ||
472 | } | ||
473 | |||
474 | fn original_range_opt( | ||
475 | db: &dyn db::AstDatabase, | ||
476 | node: InFile<&SyntaxNode>, | ||
477 | ) -> Option<InFile<TextRange>> { | ||
478 | let expansion = node.file_id.expansion_info(db)?; | ||
479 | |||
480 | // the input node has only one token ? | ||
481 | let single = skip_trivia_token(node.value.first_token()?, Direction::Next)? | ||
482 | == skip_trivia_token(node.value.last_token()?, Direction::Prev)?; | ||
483 | |||
484 | Some(node.value.descendants().find_map(|it| { | ||
485 | let first = skip_trivia_token(it.first_token()?, Direction::Next)?; | ||
486 | let first = ascend_call_token(db, &expansion, node.with_value(first))?; | ||
487 | |||
488 | let last = skip_trivia_token(it.last_token()?, Direction::Prev)?; | ||
489 | let last = ascend_call_token(db, &expansion, node.with_value(last))?; | ||
490 | |||
491 | if (!single && first == last) || (first.file_id != last.file_id) { | ||
492 | return None; | ||
493 | } | ||
494 | |||
495 | Some(first.with_value(first.value.text_range().cover(last.value.text_range()))) | ||
496 | })?) | ||
497 | } | ||
498 | |||
499 | fn ascend_call_token( | ||
500 | db: &dyn db::AstDatabase, | ||
501 | expansion: &ExpansionInfo, | ||
502 | token: InFile<SyntaxToken>, | ||
503 | ) -> Option<InFile<SyntaxToken>> { | ||
504 | let (mapped, origin) = expansion.map_token_up(token.as_ref())?; | ||
505 | if origin != Origin::Call { | ||
506 | return None; | ||
507 | } | ||
508 | if let Some(info) = mapped.file_id.expansion_info(db) { | ||
509 | return ascend_call_token(db, &info, mapped); | ||
510 | } | ||
511 | Some(mapped) | ||
512 | } | ||
513 | |||
448 | impl InFile<SyntaxToken> { | 514 | impl InFile<SyntaxToken> { |
449 | pub fn ancestors_with_macros( | 515 | pub fn ancestors_with_macros( |
450 | self, | 516 | self, |