|
@@ -1,8 +1,8 @@
|
|
|
-use std::{collections::HashSet, str::FromStr};
|
|
|
+use std::str::FromStr;
|
|
|
|
|
|
use proc_macro2::{Span, TokenStream};
|
|
|
|
|
|
-use quote::{quote, ToTokens, TokenStreamExt};
|
|
|
+use quote::{quote, quote_spanned, ToTokens, TokenStreamExt};
|
|
|
use syn::{
|
|
|
parse::{Parse, ParseStream},
|
|
|
*,
|
|
@@ -188,20 +188,10 @@ impl ToTokens for IfmtInput {
|
|
|
for segment in self.segments.iter() {
|
|
|
match segment {
|
|
|
Segment::Literal(s) => format_literal += &s.replace('{', "{{").replace('}', "}}"),
|
|
|
- Segment::Formatted(FormattedSegment {
|
|
|
- format_args,
|
|
|
- segment,
|
|
|
- }) => {
|
|
|
+ Segment::Formatted(FormattedSegment { format_args, .. }) => {
|
|
|
format_literal += "{";
|
|
|
- match segment {
|
|
|
- FormattedSegmentType::Expr(_) => {
|
|
|
- format_literal += &expr_counter.to_string();
|
|
|
- expr_counter += 1;
|
|
|
- }
|
|
|
- FormattedSegmentType::Ident(ident) => {
|
|
|
- format_literal += &ident.to_string();
|
|
|
- }
|
|
|
- }
|
|
|
+ format_literal += &expr_counter.to_string();
|
|
|
+ expr_counter += 1;
|
|
|
format_literal += ":";
|
|
|
format_literal += format_args;
|
|
|
format_literal += "}";
|
|
@@ -209,43 +199,29 @@ impl ToTokens for IfmtInput {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ let span = match self.source.as_ref() {
|
|
|
+ Some(source) => source.span(),
|
|
|
+ None => Span::call_site(),
|
|
|
+ };
|
|
|
+
|
|
|
let positional_args = self.segments.iter().filter_map(|seg| {
|
|
|
- if let Segment::Formatted(FormattedSegment {
|
|
|
- segment: FormattedSegmentType::Expr(expr),
|
|
|
- ..
|
|
|
- }) = seg
|
|
|
- {
|
|
|
- Some(expr)
|
|
|
+ if let Segment::Formatted(FormattedSegment { segment, .. }) = seg {
|
|
|
+ let mut segment = segment.clone();
|
|
|
+ // We set the span of the ident here, so that we can use it in diagnostics
|
|
|
+ if let FormattedSegmentType::Ident(ident) = &mut segment {
|
|
|
+ ident.set_span(span);
|
|
|
+ }
|
|
|
+ Some(segment)
|
|
|
} else {
|
|
|
None
|
|
|
}
|
|
|
});
|
|
|
|
|
|
- // remove duplicate idents
|
|
|
- let named_args_idents: HashSet<_> = self
|
|
|
- .segments
|
|
|
- .iter()
|
|
|
- .filter_map(|seg| {
|
|
|
- if let Segment::Formatted(FormattedSegment {
|
|
|
- segment: FormattedSegmentType::Ident(ident),
|
|
|
- ..
|
|
|
- }) = seg
|
|
|
- {
|
|
|
- Some(ident)
|
|
|
- } else {
|
|
|
- None
|
|
|
- }
|
|
|
- })
|
|
|
- .collect();
|
|
|
- let named_args = named_args_idents
|
|
|
- .iter()
|
|
|
- .map(|ident| quote!(#ident = #ident));
|
|
|
-
|
|
|
- quote! {
|
|
|
+ quote_spanned! {
|
|
|
+ span =>
|
|
|
::std::format_args!(
|
|
|
#format_literal
|
|
|
#(, #positional_args)*
|
|
|
- #(, #named_args)*
|
|
|
)
|
|
|
}
|
|
|
.to_tokens(tokens)
|