@@ -5,8 +5,8 @@ use clippy_utils::source::{SpanRangeExt, expand_past_previous_comma};
5
5
use clippy_utils:: { is_in_test, sym} ;
6
6
use rustc_ast:: token:: LitKind ;
7
7
use rustc_ast:: {
8
- FormatArgPosition , FormatArgPositionKind , FormatArgs , FormatArgsPiece , FormatOptions , FormatPlaceholder ,
9
- FormatTrait ,
8
+ FormatArgPosition , FormatArgPositionKind , FormatArgs , FormatArgsPiece , FormatCount , FormatOptions ,
9
+ FormatPlaceholder , FormatTrait ,
10
10
} ;
11
11
use rustc_errors:: Applicability ;
12
12
use rustc_hir:: { Expr , Impl , Item , ItemKind } ;
@@ -556,12 +556,7 @@ fn check_literal(cx: &LateContext<'_>, format_args: &FormatArgs, name: &str) {
556
556
// Decrement the index of the remaining by the number of replaced positional arguments
557
557
if !suggestion. is_empty ( ) {
558
558
for piece in & format_args. template {
559
- if let Some ( ( span, index) ) = positional_arg_piece_span ( piece)
560
- && suggestion. iter ( ) . all ( |( s, _) | * s != span)
561
- {
562
- let decrement = replaced_position. iter ( ) . filter ( |i| * * i < index) . count ( ) ;
563
- suggestion. push ( ( span, format ! ( "{{{}}}" , index. saturating_sub( decrement) ) ) ) ;
564
- }
559
+ relocalize_format_args_indexes ( piece, & mut suggestion, & replaced_position) ;
565
560
}
566
561
}
567
562
@@ -574,7 +569,7 @@ fn check_literal(cx: &LateContext<'_>, format_args: &FormatArgs, name: &str) {
574
569
}
575
570
}
576
571
577
- /// Extract Span and its index from the given `piece`, iff it's positional argument.
572
+ /// Extract Span and its index from the given `piece`, if it's positional argument.
578
573
fn positional_arg_piece_span ( piece : & FormatArgsPiece ) -> Option < ( Span , usize ) > {
579
574
match piece {
580
575
FormatArgsPiece :: Placeholder ( FormatPlaceholder {
@@ -591,6 +586,57 @@ fn positional_arg_piece_span(piece: &FormatArgsPiece) -> Option<(Span, usize)> {
591
586
}
592
587
}
593
588
589
+ /// Relocalizes the indexes of positional arguments in the format string
590
+ fn relocalize_format_args_indexes (
591
+ piece : & FormatArgsPiece ,
592
+ suggestion : & mut Vec < ( Span , String ) > ,
593
+ replaced_position : & [ usize ] ,
594
+ ) {
595
+ if let FormatArgsPiece :: Placeholder ( FormatPlaceholder {
596
+ argument :
597
+ FormatArgPosition {
598
+ index : Ok ( index) ,
599
+ // Only consider positional arguments
600
+ kind : FormatArgPositionKind :: Number ,
601
+ span : Some ( span) ,
602
+ } ,
603
+ format_options,
604
+ ..
605
+ } ) = piece
606
+ {
607
+ if suggestion. iter ( ) . any ( |( s, _) | s. overlaps ( * span) ) {
608
+ // If the span is already in the suggestion, we don't need to process it again
609
+ return ;
610
+ }
611
+
612
+ // lambda to get the decremented index based on the replaced positions
613
+ let decremented_index = |index : usize | -> usize {
614
+ let decrement = replaced_position. iter ( ) . filter ( |& & i| i < index) . count ( ) ;
615
+ index - decrement
616
+ } ;
617
+
618
+ suggestion. push ( ( * span, decremented_index ( * index) . to_string ( ) ) ) ;
619
+
620
+ // If there are format options, we need to handle them as well
621
+ if * format_options != FormatOptions :: default ( ) {
622
+ // lambda to process width and precision format counts and add them to the suggestion
623
+ let mut process_format_count = |count : & Option < FormatCount > , formatter : & dyn Fn ( usize ) -> String | {
624
+ if let Some ( FormatCount :: Argument ( FormatArgPosition {
625
+ index : Ok ( format_arg_index) ,
626
+ kind : FormatArgPositionKind :: Number ,
627
+ span : Some ( format_arg_span) ,
628
+ } ) ) = count
629
+ {
630
+ suggestion. push ( ( * format_arg_span, formatter ( decremented_index ( * format_arg_index) ) ) ) ;
631
+ }
632
+ } ;
633
+
634
+ process_format_count ( & format_options. width , & |index : usize | format ! ( "{index}$" ) ) ;
635
+ process_format_count ( & format_options. precision , & |index : usize | format ! ( ".{index}$" ) ) ;
636
+ }
637
+ }
638
+ }
639
+
594
640
/// Removes the raw marker, `#`s and quotes from a str, and returns if the literal is raw
595
641
///
596
642
/// `r#"a"#` -> (`a`, true)
0 commit comments