diff --git a/bon-macros/src/builder/builder_gen/setters/mod.rs b/bon-macros/src/builder/builder_gen/setters/mod.rs index 9ecc7e72..46a76789 100644 --- a/bon-macros/src/builder/builder_gen/setters/mod.rs +++ b/bon-macros/src/builder/builder_gen/setters/mod.rs @@ -600,24 +600,16 @@ impl SettersItems { .or(common_docs) .unwrap_or(&member.docs); - let setter_names = (&some_fn_name, &option_fn_name); - - let some_fn_docs = { - let header = optional_setter_docs(default, setter_names); - - doc(&header).chain(some_fn_docs.iter().cloned()).collect() - }; + let some_fn_docs = + optional_setter_docs(default, &some_fn_name, &option_fn_name, some_fn_docs); let option_fn_docs = option_fn .and_then(ItemSigConfig::docs) .or(common_docs) .unwrap_or(&member.docs); - let option_fn_docs = { - let header = optional_setter_docs(default, setter_names); - - doc(&header).chain(option_fn_docs.iter().cloned()).collect() - }; + let option_fn_docs = + optional_setter_docs(default, &some_fn_name, &option_fn_name, option_fn_docs); let some_fn = SetterItem { name: some_fn_name, @@ -649,24 +641,39 @@ impl SettersItems { fn optional_setter_docs( default: Option<&str>, - (some_fn, option_fn): (&syn::Ident, &syn::Ident), -) -> String { - let default = default - .map(|default| { - if default.contains('\n') || default.len() > 80 { - format!(" _**Default:**_\n````rust,ignore\n{default}\n````\n\n") - } else { - format!(" _**Default:**_ ```{default}```.\n\n") - } - }) - .unwrap_or_default(); - - format!( - "_**Optional** \ - ([Some](Self::{some_fn}()) / [Option](Self::{option_fn}()) setters).\ - _{default}\ - \n\n" - ) + some_fn: &syn::Ident, + option_fn: &syn::Ident, + doc_comments: &[syn::Attribute], +) -> Vec { + let header = format!( + "_**Optional** ([Some](Self::{some_fn}()) / [Option](Self::{option_fn}()) setters)._" + ); + + let mut attrs = vec![syn::parse_quote!(#[doc = #header])]; + + if let Some(default) = default { + let sep = if doc_comments.is_empty() { "" } else { "\n\n" }; + + if default.contains('\n') || default.len() > 80 { + // `no_doctest` helps to avoid interpreting the code block as + // an "ignored but still runnable" doc test. See details: + // - bon issue: https://github.com/elastio/bon/issues/359 + // - rust issue: https://github.com/rust-lang/rust/issues/63193 + let tail = format!("\n{default}\n````{sep}"); + attrs.extend([ + syn::parse_quote!(#[doc = " _**Default:**_\n"]), + syn::parse_quote!(#[cfg_attr(doctest, doc = "````no_doctest")]), + syn::parse_quote!(#[cfg_attr(not(doctest), doc = "````")]), + syn::parse_quote!(#[doc = #tail]), + ]); + } else { + let doc = format!(" _**Default:**_ ```{default}```.{sep}"); + attrs.push(syn::parse_quote!(#[doc = #doc])); + } + } + + attrs.extend(doc_comments.iter().cloned()); + attrs } fn well_known_default(ty: &syn::Type) -> Option { diff --git a/bon-macros/tests/snapshots/setters_docs_and_vis.rs b/bon-macros/tests/snapshots/setters_docs_and_vis.rs index 465820de..b55bd9e9 100644 --- a/bon-macros/tests/snapshots/setters_docs_and_vis.rs +++ b/bon-macros/tests/snapshots/setters_docs_and_vis.rs @@ -15,9 +15,7 @@ impl SutBuilder { where S::RequiredField: sut_builder::IsUnset, {} - /**_**Optional** ([Some](Self::optional_field()) / [Option](Self::maybe_optional_field()) setters)._ - -*/ + ///_**Optional** ([Some](Self::optional_field()) / [Option](Self::maybe_optional_field()) setters)._ /// Docs on the optional field setters. /// Multiline. pub(in overridden) fn optional_field( @@ -27,9 +25,7 @@ impl SutBuilder { where S::OptionalField: sut_builder::IsUnset, {} - /**_**Optional** ([Some](Self::optional_field()) / [Option](Self::maybe_optional_field()) setters)._ - -*/ + ///_**Optional** ([Some](Self::optional_field()) / [Option](Self::maybe_optional_field()) setters)._ /// Docs on the optional field setters. /// Multiline. pub(in overridden) fn maybe_optional_field( @@ -39,9 +35,8 @@ impl SutBuilder { where S::OptionalField: sut_builder::IsUnset, {} - /**_**Optional** ([Some](Self::default_field()) / [Option](Self::maybe_default_field()) setters)._ _**Default:**_ ```2 + 2 * 3```. - - + ///_**Optional** ([Some](Self::default_field()) / [Option](Self::maybe_default_field()) setters)._ + /** _**Default:**_ ```2 + 2 * 3```. */ /// Docs on the default field setters. @@ -53,9 +48,8 @@ impl SutBuilder { where S::DefaultField: sut_builder::IsUnset, {} - /**_**Optional** ([Some](Self::default_field()) / [Option](Self::maybe_default_field()) setters)._ _**Default:**_ ```2 + 2 * 3```. - - + ///_**Optional** ([Some](Self::default_field()) / [Option](Self::maybe_default_field()) setters)._ + /** _**Default:**_ ```2 + 2 * 3```. */ /// Docs on the default field setters. @@ -67,9 +61,7 @@ impl SutBuilder { where S::DefaultField: sut_builder::IsUnset, {} - /**_**Optional** ([Some](Self::optional_field_with_specific_overrides()) / [Option](Self::maybe_optional_field_with_specific_overrides()) setters)._ - -*/ + ///_**Optional** ([Some](Self::optional_field_with_specific_overrides()) / [Option](Self::maybe_optional_field_with_specific_overrides()) setters)._ /// Docs on some_fn /// Multiline. pub(in some_fn_overridden) fn optional_field_with_specific_overrides( @@ -79,9 +71,7 @@ impl SutBuilder { where S::OptionalFieldWithSpecificOverrides: sut_builder::IsUnset, {} - /**_**Optional** ([Some](Self::optional_field_with_specific_overrides()) / [Option](Self::maybe_optional_field_with_specific_overrides()) setters)._ - -*/ + ///_**Optional** ([Some](Self::optional_field_with_specific_overrides()) / [Option](Self::maybe_optional_field_with_specific_overrides()) setters)._ /// Docs on option_fn /// Multiline. pub(in option_fn_overridden) fn maybe_optional_field_with_specific_overrides( @@ -91,9 +81,8 @@ impl SutBuilder { where S::OptionalFieldWithSpecificOverrides: sut_builder::IsUnset, {} - /**_**Optional** ([Some](Self::default_field_with_specific_overrides()) / [Option](Self::maybe_default_field_with_specific_overrides()) setters)._ _**Default:**_ ```2 + 2 * 3```. - - + ///_**Optional** ([Some](Self::default_field_with_specific_overrides()) / [Option](Self::maybe_default_field_with_specific_overrides()) setters)._ + /** _**Default:**_ ```2 + 2 * 3```. */ /// Docs on some_fn @@ -105,9 +94,8 @@ impl SutBuilder { where S::DefaultFieldWithSpecificOverrides: sut_builder::IsUnset, {} - /**_**Optional** ([Some](Self::default_field_with_specific_overrides()) / [Option](Self::maybe_default_field_with_specific_overrides()) setters)._ _**Default:**_ ```2 + 2 * 3```. - - + ///_**Optional** ([Some](Self::default_field_with_specific_overrides()) / [Option](Self::maybe_default_field_with_specific_overrides()) setters)._ + /** _**Default:**_ ```2 + 2 * 3```. */ /// Docs on option_fn @@ -119,9 +107,7 @@ impl SutBuilder { where S::DefaultFieldWithSpecificOverrides: sut_builder::IsUnset, {} - /**_**Optional** ([Some](Self::optional_field_with_inherited_overrides()) / [Option](Self::maybe_optional_field_with_inherited_overrides()) setters)._ - -*/ + ///_**Optional** ([Some](Self::optional_field_with_inherited_overrides()) / [Option](Self::maybe_optional_field_with_inherited_overrides()) setters)._ /// Common docs /// Multiline. pub(in overridden) fn optional_field_with_inherited_overrides( @@ -131,9 +117,7 @@ impl SutBuilder { where S::OptionalFieldWithInheritedOverrides: sut_builder::IsUnset, {} - /**_**Optional** ([Some](Self::optional_field_with_inherited_overrides()) / [Option](Self::maybe_optional_field_with_inherited_overrides()) setters)._ - -*/ + ///_**Optional** ([Some](Self::optional_field_with_inherited_overrides()) / [Option](Self::maybe_optional_field_with_inherited_overrides()) setters)._ /// Docs on option_fn /// Multiline. pub(in option_fn_overridden) fn maybe_optional_field_with_inherited_overrides( @@ -143,9 +127,8 @@ impl SutBuilder { where S::OptionalFieldWithInheritedOverrides: sut_builder::IsUnset, {} - /**_**Optional** ([Some](Self::default_field_with_inherited_overrides()) / [Option](Self::maybe_default_field_with_inherited_overrides()) setters)._ _**Default:**_ ```2 + 2 * 3```. - - + ///_**Optional** ([Some](Self::default_field_with_inherited_overrides()) / [Option](Self::maybe_default_field_with_inherited_overrides()) setters)._ + /** _**Default:**_ ```2 + 2 * 3```. */ /// Common docs @@ -157,9 +140,8 @@ impl SutBuilder { where S::DefaultFieldWithInheritedOverrides: sut_builder::IsUnset, {} - /**_**Optional** ([Some](Self::default_field_with_inherited_overrides()) / [Option](Self::maybe_default_field_with_inherited_overrides()) setters)._ _**Default:**_ ```2 + 2 * 3```. - - + ///_**Optional** ([Some](Self::default_field_with_inherited_overrides()) / [Option](Self::maybe_default_field_with_inherited_overrides()) setters)._ + /** _**Default:**_ ```2 + 2 * 3```. */ /// Docs on option_fn @@ -171,9 +153,7 @@ impl SutBuilder { where S::DefaultFieldWithInheritedOverrides: sut_builder::IsUnset, {} - /**_**Optional** ([Some](Self::setters_doc_default_skip()) / [Option](Self::maybe_setters_doc_default_skip()) setters)._ - -*/ + ///_**Optional** ([Some](Self::setters_doc_default_skip()) / [Option](Self::maybe_setters_doc_default_skip()) setters)._ fn setters_doc_default_skip( self, value: u32, @@ -181,9 +161,7 @@ impl SutBuilder { where S::SettersDocDefaultSkip: sut_builder::IsUnset, {} - /**_**Optional** ([Some](Self::setters_doc_default_skip()) / [Option](Self::maybe_setters_doc_default_skip()) setters)._ - -*/ + ///_**Optional** ([Some](Self::setters_doc_default_skip()) / [Option](Self::maybe_setters_doc_default_skip()) setters)._ fn maybe_setters_doc_default_skip( mut self, value: Option, @@ -191,9 +169,7 @@ impl SutBuilder { where S::SettersDocDefaultSkip: sut_builder::IsUnset, {} - /**_**Optional** ([Some](Self::setters_doc_default_skip_and_custom_docs_block()) / [Option](Self::maybe_setters_doc_default_skip_and_custom_docs_block()) setters)._ - -*/ + ///_**Optional** ([Some](Self::setters_doc_default_skip_and_custom_docs_block()) / [Option](Self::maybe_setters_doc_default_skip_and_custom_docs_block()) setters)._ /// Custom docs /// Multiline. fn setters_doc_default_skip_and_custom_docs_block( @@ -203,9 +179,7 @@ impl SutBuilder { where S::SettersDocDefaultSkipAndCustomDocsBlock: sut_builder::IsUnset, {} - /**_**Optional** ([Some](Self::setters_doc_default_skip_and_custom_docs_block()) / [Option](Self::maybe_setters_doc_default_skip_and_custom_docs_block()) setters)._ - -*/ + ///_**Optional** ([Some](Self::setters_doc_default_skip_and_custom_docs_block()) / [Option](Self::maybe_setters_doc_default_skip_and_custom_docs_block()) setters)._ /// Custom docs /// Multiline. fn maybe_setters_doc_default_skip_and_custom_docs_block( @@ -215,9 +189,7 @@ impl SutBuilder { where S::SettersDocDefaultSkipAndCustomDocsBlock: sut_builder::IsUnset, {} - /**_**Optional** ([Some](Self::setters_doc_default_skip_from_top_level_on()) / [Option](Self::maybe_setters_doc_default_skip_from_top_level_on()) setters)._ - -*/ + ///_**Optional** ([Some](Self::setters_doc_default_skip_from_top_level_on()) / [Option](Self::maybe_setters_doc_default_skip_from_top_level_on()) setters)._ fn setters_doc_default_skip_from_top_level_on( self, value: u8, @@ -225,9 +197,7 @@ impl SutBuilder { where S::SettersDocDefaultSkipFromTopLevelOn: sut_builder::IsUnset, {} - /**_**Optional** ([Some](Self::setters_doc_default_skip_from_top_level_on()) / [Option](Self::maybe_setters_doc_default_skip_from_top_level_on()) setters)._ - -*/ + ///_**Optional** ([Some](Self::setters_doc_default_skip_from_top_level_on()) / [Option](Self::maybe_setters_doc_default_skip_from_top_level_on()) setters)._ fn maybe_setters_doc_default_skip_from_top_level_on( mut self, value: Option, diff --git a/bon-sandbox/src/attr_default.rs b/bon-sandbox/src/attr_default.rs index 9b0bf078..8f6e20a5 100644 --- a/bon-sandbox/src/attr_default.rs +++ b/bon-sandbox/src/attr_default.rs @@ -10,9 +10,13 @@ reason = "Common `_default` suffix is for better readability" )] pub struct Example { + /// Custom doc comment. + /// Multiline. #[builder(default = (2 + 2) * 10)] small_custom_default: u32, + /// Custom doc comment. + /// Multiline. #[builder(default = Vec::from([ Point { x: 1, y: 2 }, Point { x: 3, y: 4 }, diff --git a/scripts/test-msrv.sh b/scripts/test-msrv.sh index a82b8ca4..05a42e0c 100755 --- a/scripts/test-msrv.sh +++ b/scripts/test-msrv.sh @@ -34,19 +34,21 @@ with_log cd bon step echo '[workspace]' >> Cargo.toml -step cargo update -p proc-macro2 --precise 1.0.101 -step cargo update -p quote --precise 1.0.40 -step cargo update -p once_cell --precise 1.17.2 -step cargo update -p trybuild --precise 1.0.89 -step cargo update -p serde_json --precise 1.0.143 -step cargo update -p serde --precise 1.0.194 -step cargo update -p prettyplease --precise 0.2.17 -step cargo update -p syn --precise 2.0.56 -step cargo update -p tokio --precise 1.29.1 -step cargo update -p expect-test --precise 1.4.1 -step cargo update -p windows-sys --precise 0.52.0 -step cargo update -p libc --precise 0.2.163 -step cargo update -p glob --precise 0.3.2 +step cargo update --precise 1.0.15 -p itoa +step cargo update --precise 1.0.101 -p proc-macro2 +step cargo update --precise 1.0.40 -p quote +step cargo update --precise 1.17.2 -p once_cell +step cargo update --precise 1.0.89 -p trybuild +step cargo update --precise 1.0.143 -p serde_json +step cargo update --precise 1.0.20 -p ryu +step cargo update --precise 1.0.194 -p serde +step cargo update --precise 0.2.17 -p prettyplease +step cargo update --precise 2.0.56 -p syn +step cargo update --precise 1.29.1 -p tokio +step cargo update --precise 1.4.1 -p expect-test +step cargo update --precise 0.52.0 -p windows-sys +step cargo update --precise 0.2.163 -p libc +step cargo update --precise 0.3.2 -p glob export RUSTFLAGS="${RUSTFLAGS:-} --allow unknown-lints"