aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_expand
diff options
context:
space:
mode:
Diffstat (limited to 'crates/hir_expand')
-rw-r--r--crates/hir_expand/src/lib.rs72
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};
20use std::hash::Hash; 20use std::hash::Hash;
21use std::sync::Arc; 21use std::sync::Arc;
22 22
23use base_db::{impl_intern_key, salsa, CrateId, FileId}; 23use base_db::{impl_intern_key, salsa, CrateId, FileId, FileRange};
24use syntax::{ 24use 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
30use crate::ast_id_map::FileAstId; 30use crate::ast_id_map::FileAstId;
@@ -445,6 +445,72 @@ impl InFile<SyntaxNode> {
445 } 445 }
446} 446}
447 447
448impl<'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
474fn 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
499fn 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
448impl InFile<SyntaxToken> { 514impl InFile<SyntaxToken> {
449 pub fn ancestors_with_macros( 515 pub fn ancestors_with_macros(
450 self, 516 self,