@@ -29,8 +29,9 @@ use smallvec::{smallvec, SmallVec};
2929use stdx:: TupleExt ;
3030use syntax:: {
3131 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 ,
3435} ;
3536
3637use crate :: {
@@ -49,7 +50,7 @@ pub enum DescendPreference {
4950 None ,
5051}
5152
52- #[ derive( Debug , Clone , PartialEq , Eq ) ]
53+ #[ derive( Debug , Copy , Clone , PartialEq , Eq ) ]
5354pub enum PathResolution {
5455 /// An item
5556 Def ( ModuleDef ) ,
@@ -402,6 +403,41 @@ impl<'db> SemanticsImpl<'db> {
402403 )
403404 }
404405
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+
405441 /// Maps a node down by mapping its first and last token down.
406442 pub fn descend_node_into_attributes < N : AstNode > ( & self , node : N ) -> SmallVec < [ N ; 1 ] > {
407443 // This might not be the correct way to do this, but it works for now
@@ -419,24 +455,27 @@ impl<'db> SemanticsImpl<'db> {
419455
420456 if first == last {
421457 // 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+ {
424464 res. push ( node)
425465 }
426466 ControlFlow :: Continue ( ( ) )
427467 } ) ;
428468 } else {
429469 // Descend first and last token, then zip them to look for the node they belong to
430470 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| {
432472 scratch. push ( token) ;
433473 ControlFlow :: Continue ( ( ) )
434474 } ) ;
435475
436476 let mut scratch = scratch. into_iter ( ) ;
437477 self . descend_into_macros_impl (
438478 last,
439- 0 . into ( ) ,
440479 & mut |InFile { value : last, file_id : last_fid } | {
441480 if let Some ( InFile { value : first, file_id : first_fid } ) = scratch. next ( ) {
442481 if first_fid == last_fid {
@@ -467,7 +506,6 @@ impl<'db> SemanticsImpl<'db> {
467506 & self ,
468507 mode : DescendPreference ,
469508 token : SyntaxToken ,
470- offset : TextSize ,
471509 ) -> SmallVec < [ SyntaxToken ; 1 ] > {
472510 enum Dp < ' t > {
473511 SameText ( & ' t str ) ,
@@ -487,7 +525,7 @@ impl<'db> SemanticsImpl<'db> {
487525 DescendPreference :: None => Dp :: None ,
488526 } ;
489527 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, .. } | {
491529 let is_a_match = match mode {
492530 Dp :: SameText ( text) => value. text ( ) == text,
493531 Dp :: SameKind ( preferred_kind) => {
@@ -513,7 +551,6 @@ impl<'db> SemanticsImpl<'db> {
513551 & self ,
514552 mode : DescendPreference ,
515553 token : SyntaxToken ,
516- offset : TextSize ,
517554 ) -> SyntaxToken {
518555 enum Dp < ' t > {
519556 SameText ( & ' t str ) ,
@@ -533,7 +570,7 @@ impl<'db> SemanticsImpl<'db> {
533570 DescendPreference :: None => Dp :: None ,
534571 } ;
535572 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, .. } | {
537574 let is_a_match = match mode {
538575 Dp :: SameText ( text) => value. text ( ) == text,
539576 Dp :: SameKind ( preferred_kind) => {
@@ -558,9 +595,6 @@ impl<'db> SemanticsImpl<'db> {
558595 fn descend_into_macros_impl (
559596 & self ,
560597 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 ,
564598 f : & mut dyn FnMut ( InFile < SyntaxToken > ) -> ControlFlow < ( ) > ,
565599 ) {
566600 // FIXME: Clean this up
@@ -729,7 +763,7 @@ impl<'db> SemanticsImpl<'db> {
729763 offset : TextSize ,
730764 ) -> impl Iterator < Item = impl Iterator < Item = SyntaxNode > + ' _ > + ' _ {
731765 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) )
733767 . map ( |descendants| {
734768 descendants. into_iter ( ) . map ( move |it| self . token_ancestors_with_macros ( it) )
735769 } )
0 commit comments