Skip to content

Commit

Permalink
Fix issue
Browse files Browse the repository at this point in the history
  • Loading branch information
JelteF committed Jul 3, 2024
1 parent 85a18f1 commit efb2d7d
Show file tree
Hide file tree
Showing 5 changed files with 170 additions and 38 deletions.
87 changes: 73 additions & 14 deletions impl/src/fmt/debug.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use crate::utils::{
Either, Spanning,
};

use super::{trait_name_to_attribute_name, ContainerAttributes, FmtAttribute};
use super::{parsing, trait_name_to_attribute_name, ContainerAttributes, FmtAttribute};

/// Expands a [`fmt::Debug`] derive macro.
///
Expand Down Expand Up @@ -222,16 +222,69 @@ impl<'a> Expansion<'a> {
Ok(())
}

fn used_arguments<'s>(
&self,
format_string: &'s str,
) -> impl Iterator<Item = &'s str>
where
'a: 's,
{
parsing::format_string_formats(format_string)
.into_iter()
.flatten()
.flat_map(|f| match f.arg {
Some(parsing::Argument::Identifier(name)) => Some(name),
_ => None,
})
}

fn field_idents(&self) -> impl Iterator<Item = Ident> + '_ {
self.fields
.iter()
.enumerate()
.map(|(i, f)| f.ident.clone().unwrap_or_else(|| format_ident!("_{i}")))
}

fn field_params<'selff, 's>(
&'selff self,
format_string: &'s str,
) -> impl Iterator<Item = TokenStream> + 's
where
'a: 's,
'selff: 's,
{
let used_arguments: Vec<&'s str> = self.used_arguments(format_string).collect();
self.field_idents().filter_map(move |var| {
if used_arguments.contains(&var.to_string().as_str()) {
Some(quote! { #var = *#var })
} else {
None
}
})
}

/// Generates [`Debug::fmt()`] implementation for a struct or an enum variant.
///
/// [`Debug::fmt()`]: std::fmt::Debug::fmt()
fn generate_body(&self) -> syn::Result<TokenStream> {
if let Some(fmt) = &self.attr.fmt {
return Ok(if let Some((expr, trait_ident)) = fmt.transparent_call() {
quote! { derive_more::core::fmt::#trait_ident::fmt(&(#expr), __derive_more_f) }
} else {
quote! { derive_more::core::write!(__derive_more_f, #fmt) }
});
let format_string = fmt.lit.value();
return Ok(
if let Some((expr, trait_ident)) = fmt.transparent_call() {
let expr = if self.field_idents().any(|var| {
self.used_arguments(&format_string)
.any(|arg| arg == var.to_string().as_str())
}) {
quote! { #expr }
} else {
quote! { &(#expr) }
};
quote! { derive_more::core::fmt::#trait_ident::fmt(#expr, __derive_more_f) }
} else {
let field_params = self.field_params(&format_string);
quote! { derive_more::core::write!(__derive_more_f, #fmt, #(#field_params),*) }
},
);
};

match self.fields {
Expand Down Expand Up @@ -266,12 +319,15 @@ impl<'a> Expansion<'a> {
exhaustive = false;
Ok::<_, syn::Error>(out)
}
Some(FieldAttribute::Right(fmt_attr)) => Ok(quote! {
derive_more::__private::DebugTuple::field(
#out,
&derive_more::core::format_args!(#fmt_attr),
Some(FieldAttribute::Right(fmt_attr)) => {
let format_string = fmt_attr.lit.value();
let field_params = self.field_params(&format_string);
Ok(quote! {
derive_more::__private::DebugTuple::field(
#out,
&derive_more::core::format_args!(#fmt_attr, #(#field_params),*),
)
}),
})},
None => {
let ident = format_ident!("_{i}");
Ok(quote! {
Expand Down Expand Up @@ -308,13 +364,16 @@ impl<'a> Expansion<'a> {
exhaustive = false;
Ok::<_, syn::Error>(out)
}
Some(FieldAttribute::Right(fmt_attr)) => Ok(quote! {
Some(FieldAttribute::Right(fmt_attr)) => {
let format_string = fmt_attr.lit.value();
let field_params = self.field_params(&format_string);
Ok(quote! {
derive_more::core::fmt::DebugStruct::field(
#out,
#field_str,
&derive_more::core::format_args!(#fmt_attr),
&derive_more::core::format_args!(#fmt_attr, #(#field_params),*),
)
}),
})},
None => Ok(quote! {
derive_more::core::fmt::DebugStruct::field(#out, #field_str, &#field_ident)
}),
Expand Down
55 changes: 53 additions & 2 deletions impl/src/fmt/display.rs
Original file line number Diff line number Diff line change
Expand Up @@ -304,10 +304,20 @@ impl<'a> Expansion<'a> {
fn generate_body_impl(&self) -> syn::Result<TokenStream> {
match &self.attrs.fmt {
Some(fmt) => {
let format_string = fmt.lit.value();
Ok(if let Some((expr, trait_ident)) = fmt.transparent_call() {
quote! { derive_more::core::fmt::#trait_ident::fmt(&(#expr), __derive_more_f) }
let expr = if self.field_idents().any(|var| {
self.used_arguments(&format_string)
.any(|arg| arg == var.to_string().as_str())
}) {
quote! { #expr }
} else {
quote! { &(#expr) }
};
quote! { derive_more::core::fmt::#trait_ident::fmt(#expr, __derive_more_f) }
} else {
quote! { derive_more::core::write!(__derive_more_f, #fmt) }
let field_params = self.field_params(&format_string);
quote! { derive_more::core::write!(__derive_more_f, #fmt, #(#field_params),*) }
})
}
None if self.fields.is_empty() => {
Expand Down Expand Up @@ -341,6 +351,47 @@ impl<'a> Expansion<'a> {
}
}

fn used_arguments<'s>(
&self,
format_string: &'s str,
) -> impl Iterator<Item = &'s str>
where
'a: 's,
{
parsing::format_string_formats(format_string)
.into_iter()
.flatten()
.flat_map(|f| match f.arg {
Some(parsing::Argument::Identifier(name)) => Some(name),
_ => None,
})
}

fn field_idents(&self) -> impl Iterator<Item = syn::Ident> + '_ {
self.fields
.iter()
.enumerate()
.map(|(i, f)| f.ident.clone().unwrap_or_else(|| format_ident!("_{i}")))
}

fn field_params<'selff, 's>(
&'selff self,
format_string: &'s str,
) -> impl Iterator<Item = TokenStream> + 's
where
'a: 's,
'selff: 's,
{
let used_arguments: Vec<&'s str> = self.used_arguments(format_string).collect();
self.field_idents().filter_map(move |var| {
if used_arguments.contains(&var.to_string().as_str()) {
Some(quote! { #var = *#var })
} else {
None
}
})
}

/// Generates trait bounds for a struct or an enum variant.
fn generate_bounds(&self) -> Vec<syn::WherePredicate> {
let mut bounds: Vec<syn::WherePredicate> =
Expand Down
6 changes: 4 additions & 2 deletions impl/src/fmt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,14 +113,16 @@ impl Parse for FmtAttribute {
fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
Self::check_legacy_fmt(input)?;

Ok(Self {
let mut parsed = Self {
lit: input.parse()?,
comma: input
.peek(token::Comma)
.then(|| input.parse())
.transpose()?,
args: input.parse_terminated(FmtArgument::parse, token::Comma)?,
})
};
parsed.args.pop_punct();
Ok(parsed)
}
}

Expand Down
28 changes: 24 additions & 4 deletions tests/debug.rs
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,18 @@ mod structs {
field: &'a i32,
}

#[derive(Debug)]
#[debug("{_0:p}")]
struct TupleTransparent<'a> (
&'a i32,
);

#[derive(Debug)]
#[debug("{field:p}")]
struct StructTransparent<'a> {
field: &'a i32,
}

#[test]
fn assert() {
let a = 42;
Expand All @@ -273,6 +285,14 @@ mod structs {
format!("{:?}", Struct { field: &a }),
format!("Struct {{ field: {0:p}.{0:p} }}", &a),
);
assert_eq!(
format!("{:?}", TupleTransparent(&a)),
format!("{0:p}", &a),
);
assert_eq!(
format!("{:?}", StructTransparent { field: &a }),
format!("{0:p}", &a),
);
}
}
}
Expand Down Expand Up @@ -564,11 +584,11 @@ mod structs {
use derive_more::Debug;

#[derive(Debug)]
#[debug("{_0:p} * {_1:p}", _0 = self.0)]
#[debug("{_0:p} * {_1:p}")]
struct Tuple<'a, 'b>(&'a u8, &'b bool);

#[derive(Debug)]
#[debug("{a:p} * {b:p}", a = self.a)]
#[debug("{a:p} * {b:p}")]
struct Struct<'a, 'b> {
a: &'a u8,
b: &'b bool,
Expand Down Expand Up @@ -1305,7 +1325,7 @@ mod generic {

#[derive(Debug)]
struct AliasedFieldNamedGenericStruct<T> {
#[debug("{field1}", field1 = field2)]
#[debug("{field3}", field3 = field2)]
field1: T,
field2: i32,
}
Expand Down Expand Up @@ -1423,7 +1443,7 @@ mod generic {
}

#[derive(Debug)]
struct AliasedFieldUnnamedGenericStruct<T>(#[debug("{_0}", _0 = _1)] T, i32);
struct AliasedFieldUnnamedGenericStruct<T>(#[debug("{_2}", _2 = _1)] T, i32);
#[test]
fn aliased_field_unnamed_generic_struct() {
assert_eq!(
Expand Down
32 changes: 16 additions & 16 deletions tests/display.rs
Original file line number Diff line number Diff line change
Expand Up @@ -448,7 +448,7 @@ mod structs {
}

#[derive(Display)]
#[display("{}", format_args!("{field:p}"))]
#[display("{}", format_args!("{field:p}", field = *field))]
struct StructPointer<'a> {
field: &'a i32,
}
Expand Down Expand Up @@ -567,15 +567,15 @@ mod structs {

#[derive(Display)]
#[display(
"{_0} {ident} {_1} {} {}",
_1, _0 + _1, ident = 123, _1 = _0,
"{_0} {ident} {_2} {} {}",
_1, _0 + _1, ident = 123, _2 = _0,
)]
struct Tuple(i32, i32);

#[derive(Display)]
#[display(
"{field1} {ident} {field2} {} {}",
field2, field1 + field2, ident = 123, field2 = field1,
"{field1} {ident} {field3} {} {}",
field2, field1 + field2, ident = 123, field3 = field1,
)]
struct Struct {
field1: i32,
Expand Down Expand Up @@ -1009,7 +1009,7 @@ mod enums {

#[derive(Display)]
enum Pointer<'a> {
#[display("{:p}", _0)]
#[display("{:p}", *_0)]
A(&'a i32),
#[display("{field:p}")]
B { field: &'a u8 },
Expand Down Expand Up @@ -1120,9 +1120,9 @@ mod enums {

#[derive(Display)]
enum Pointer<'a> {
#[display("{}", format_args!("{:p}", _0))]
#[display("{}", format_args!("{:p}", *_0))]
A(&'a i32),
#[display("{}", format_args!("{field:p}"))]
#[display("{}", format_args!("{field:p}", field = *field))]
B { field: &'a u8 },
}

Expand Down Expand Up @@ -1165,13 +1165,13 @@ mod enums {
#[display("named")]
StrNamed { field1: i32, field2: i32 },
#[display(
"{_0} {ident} {_1} {} {}",
_1, _0 + _1, ident = 123, _1 = _0,
"{_0} {ident} {_2} {} {}",
_1, _0 + _1, ident = 123, _2 = _0,
)]
InterpolatedUnnamed(i32, i32),
#[display(
"{field1} {ident} {field2} {} {}",
field2, field1 + field2, ident = 123, field2 = field1,
"{field1} {ident} {field3} {} {}",
field2, field1 + field2, ident = 123, field3 = field1,
)]
InterpolatedNamed { field1: i32, field2: i32 },
}
Expand Down Expand Up @@ -1270,7 +1270,7 @@ mod enums {

#[derive(Display)]
enum Pointer<'a> {
#[display("{:p}", _1)]
#[display("{:p}", *_1)]
A(&'a f64, &'a f32),
#[display("{a:p}")]
B { a: &'a f64, b: &'a f32 },
Expand Down Expand Up @@ -2076,7 +2076,7 @@ mod generic {
struct TupleUpperExp<T>(T);

#[derive(Display)]
#[display("{:p}", _0)]
#[display("{_0:p}")]
struct TuplePointer<T>(T);

#[derive(Display)]
Expand Down Expand Up @@ -2124,7 +2124,7 @@ mod generic {
}

#[derive(Display)]
#[display("{:p}", field)]
#[display("{field:p}")]
struct StructPointer<T> {
field: T,
}
Expand Down Expand Up @@ -2187,7 +2187,7 @@ mod generic {

#[derive(Display)]
enum EnumPointer<A, B> {
#[display("{:p}", _0)]
#[display("{_0:p}")]
A(A),
#[display("{field:p}")]
B { field: B },
Expand Down

0 comments on commit efb2d7d

Please sign in to comment.