@@ -29,8 +29,9 @@ use smallvec::{smallvec, SmallVec};
29
29
use stdx:: TupleExt ;
30
30
use syntax:: {
31
31
algo:: skip_trivia_token,
32
- ast:: { self , HasAttrs as _, HasGenericParams , HasLoopBody } ,
33
- match_ast, AstNode , Direction , SyntaxKind , SyntaxNode , SyntaxNodePtr , SyntaxToken , TextSize ,
32
+ ast:: { self , HasAttrs as _, HasGenericParams , HasLoopBody , IsString as _} ,
33
+ match_ast, AstNode , AstToken , Direction , SyntaxKind , SyntaxNode , SyntaxNodePtr , SyntaxToken ,
34
+ TextRange , TextSize ,
34
35
} ;
35
36
36
37
use crate :: {
@@ -49,7 +50,7 @@ pub enum DescendPreference {
49
50
None ,
50
51
}
51
52
52
- #[ derive( Debug , Clone , PartialEq , Eq ) ]
53
+ #[ derive( Debug , Copy , Clone , PartialEq , Eq ) ]
53
54
pub enum PathResolution {
54
55
/// An item
55
56
Def ( ModuleDef ) ,
@@ -402,6 +403,41 @@ impl<'db> SemanticsImpl<'db> {
402
403
)
403
404
}
404
405
406
+ pub fn resolve_offset_in_format_args (
407
+ & self ,
408
+ string : ast:: String ,
409
+ offset : TextSize ,
410
+ ) -> Option < ( TextRange , Option < PathResolution > ) > {
411
+ debug_assert ! ( offset <= string. syntax( ) . text_range( ) . len( ) ) ;
412
+ let literal = string. syntax ( ) . parent ( ) . filter ( |it| it. kind ( ) == SyntaxKind :: LITERAL ) ?;
413
+ let format_args = ast:: FormatArgsExpr :: cast ( literal. parent ( ) ?) ?;
414
+ let source_analyzer = & self . analyze_no_infer ( format_args. syntax ( ) ) ?;
415
+ let format_args = self . wrap_node_infile ( format_args) ;
416
+ source_analyzer. resolve_offset_in_format_args ( self . db , format_args. as_ref ( ) , offset)
417
+ }
418
+
419
+ pub fn check_for_format_args_template (
420
+ & self ,
421
+ original_token : SyntaxToken ,
422
+ offset : TextSize ,
423
+ ) -> Option < ( TextRange , Option < PathResolution > ) > {
424
+ if let Some ( original_string) = ast:: String :: cast ( original_token. clone ( ) ) {
425
+ if let Some ( quote) = original_string. open_quote_text_range ( ) {
426
+ return self
427
+ . descend_into_macros ( DescendPreference :: SameText , original_token. clone ( ) )
428
+ . into_iter ( )
429
+ . find_map ( |token| {
430
+ self . resolve_offset_in_format_args (
431
+ ast:: String :: cast ( token) ?,
432
+ offset - quote. end ( ) ,
433
+ )
434
+ } )
435
+ . map ( |( range, res) | ( range + quote. end ( ) , res) ) ;
436
+ }
437
+ }
438
+ None
439
+ }
440
+
405
441
/// Maps a node down by mapping its first and last token down.
406
442
pub fn descend_node_into_attributes < N : AstNode > ( & self , node : N ) -> SmallVec < [ N ; 1 ] > {
407
443
// This might not be the correct way to do this, but it works for now
@@ -419,24 +455,27 @@ impl<'db> SemanticsImpl<'db> {
419
455
420
456
if first == last {
421
457
// node is just the token, so descend the token
422
- self . descend_into_macros_impl ( first, 0 . into ( ) , & mut |InFile { value, .. } | {
423
- if let Some ( node) = value. parent_ancestors ( ) . find_map ( N :: cast) {
458
+ self . descend_into_macros_impl ( first, & mut |InFile { value, .. } | {
459
+ if let Some ( node) = value
460
+ . parent_ancestors ( )
461
+ . take_while ( |it| it. text_range ( ) == value. text_range ( ) )
462
+ . find_map ( N :: cast)
463
+ {
424
464
res. push ( node)
425
465
}
426
466
ControlFlow :: Continue ( ( ) )
427
467
} ) ;
428
468
} else {
429
469
// Descend first and last token, then zip them to look for the node they belong to
430
470
let mut scratch: SmallVec < [ _ ; 1 ] > = smallvec ! [ ] ;
431
- self . descend_into_macros_impl ( first, 0 . into ( ) , & mut |token| {
471
+ self . descend_into_macros_impl ( first, & mut |token| {
432
472
scratch. push ( token) ;
433
473
ControlFlow :: Continue ( ( ) )
434
474
} ) ;
435
475
436
476
let mut scratch = scratch. into_iter ( ) ;
437
477
self . descend_into_macros_impl (
438
478
last,
439
- 0 . into ( ) ,
440
479
& mut |InFile { value : last, file_id : last_fid } | {
441
480
if let Some ( InFile { value : first, file_id : first_fid } ) = scratch. next ( ) {
442
481
if first_fid == last_fid {
@@ -467,7 +506,6 @@ impl<'db> SemanticsImpl<'db> {
467
506
& self ,
468
507
mode : DescendPreference ,
469
508
token : SyntaxToken ,
470
- offset : TextSize ,
471
509
) -> SmallVec < [ SyntaxToken ; 1 ] > {
472
510
enum Dp < ' t > {
473
511
SameText ( & ' t str ) ,
@@ -487,7 +525,7 @@ impl<'db> SemanticsImpl<'db> {
487
525
DescendPreference :: None => Dp :: None ,
488
526
} ;
489
527
let mut res = smallvec ! [ ] ;
490
- self . descend_into_macros_impl ( token. clone ( ) , offset , & mut |InFile { value, .. } | {
528
+ self . descend_into_macros_impl ( token. clone ( ) , & mut |InFile { value, .. } | {
491
529
let is_a_match = match mode {
492
530
Dp :: SameText ( text) => value. text ( ) == text,
493
531
Dp :: SameKind ( preferred_kind) => {
@@ -513,7 +551,6 @@ impl<'db> SemanticsImpl<'db> {
513
551
& self ,
514
552
mode : DescendPreference ,
515
553
token : SyntaxToken ,
516
- offset : TextSize ,
517
554
) -> SyntaxToken {
518
555
enum Dp < ' t > {
519
556
SameText ( & ' t str ) ,
@@ -533,7 +570,7 @@ impl<'db> SemanticsImpl<'db> {
533
570
DescendPreference :: None => Dp :: None ,
534
571
} ;
535
572
let mut res = token. clone ( ) ;
536
- self . descend_into_macros_impl ( token. clone ( ) , offset , & mut |InFile { value, .. } | {
573
+ self . descend_into_macros_impl ( token. clone ( ) , & mut |InFile { value, .. } | {
537
574
let is_a_match = match mode {
538
575
Dp :: SameText ( text) => value. text ( ) == text,
539
576
Dp :: SameKind ( preferred_kind) => {
@@ -558,9 +595,6 @@ impl<'db> SemanticsImpl<'db> {
558
595
fn descend_into_macros_impl (
559
596
& self ,
560
597
token : SyntaxToken ,
561
- // FIXME: We might want this to be Option<TextSize> to be able to opt out of subrange
562
- // mapping, specifically for node downmapping
563
- _offset : TextSize ,
564
598
f : & mut dyn FnMut ( InFile < SyntaxToken > ) -> ControlFlow < ( ) > ,
565
599
) {
566
600
// FIXME: Clean this up
@@ -729,7 +763,7 @@ impl<'db> SemanticsImpl<'db> {
729
763
offset : TextSize ,
730
764
) -> impl Iterator < Item = impl Iterator < Item = SyntaxNode > + ' _ > + ' _ {
731
765
node. token_at_offset ( offset)
732
- . map ( move |token| self . descend_into_macros ( DescendPreference :: None , token, offset ) )
766
+ . map ( move |token| self . descend_into_macros ( DescendPreference :: None , token) )
733
767
. map ( |descendants| {
734
768
descendants. into_iter ( ) . map ( move |it| self . token_ancestors_with_macros ( it) )
735
769
} )
0 commit comments