Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions bon-macros/src/builder/builder_gen/getters.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,14 @@ impl<'a> GettersCtx<'a> {
let member_pascal = &self.member.name.pascal;
let state_mod = &self.base.state_mod.ident;
let const_ = &self.base.const_;
let fn_modifiers = self.member.respan(quote!(#vis #const_));

Ok(quote! {
// It's important to keep the span of `self` the same across all
// references to it. Otherwise `self`s that have different spans will
// be treated as totally different symbols due to the hygiene rules.
let self_ = quote!(self);

Ok(quote_spanned! {self.member.span=>
#( #docs )*
#[allow(
// This is intentional. We want the builder syntax to compile away
Expand All @@ -63,7 +69,7 @@ impl<'a> GettersCtx<'a> {
)]
#[inline(always)]
#[must_use = "this method has no side effects; it only returns a value"]
#vis #const_ fn #name(&self) -> #return_ty
#(#fn_modifiers)* fn #name(&#self_) -> #return_ty
where
#state_var::#member_pascal: #state_mod::IsSet,
{
Expand Down
1 change: 1 addition & 0 deletions bon-macros/src/builder/builder_gen/input_fn/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,7 @@ impl<'a> FnInputCtx<'a> {
attrs: &arg.norm.attrs,
ident: pat.ident.clone(),
ty,
span: pat.ident.span(),
})
})
.collect::<Result<Vec<_>>>()?;
Expand Down
2 changes: 2 additions & 0 deletions bon-macros/src/builder/builder_gen/input_struct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use crate::normalization::{GenericsNamespace, SyntaxVariant};
use crate::parsing::{ItemSigConfig, SpannedKey};
use crate::util::prelude::*;
use std::borrow::Cow;
use syn::spanned::Spanned;
use syn::visit::Visit;
use syn::visit_mut::VisitMut;

Expand Down Expand Up @@ -110,6 +111,7 @@ impl StructInputCtx {
attrs: &norm_field.attrs,
ident,
ty,
span: orig_field.ident.span(),
})
})
.collect::<Result<Vec<_>>>()?;
Expand Down
10 changes: 9 additions & 1 deletion bon-macros/src/builder/builder_gen/member/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ pub(crate) struct RawMember<'a> {
pub(crate) attrs: &'a [syn::Attribute],
pub(crate) ident: syn::Ident,
pub(crate) ty: SyntaxVariant<Box<syn::Type>>,
pub(crate) span: Span,
}

impl Member {
Expand Down Expand Up @@ -157,7 +158,12 @@ impl Member {
let mut named_count = 0;

for (member, config) in members {
let RawMember { attrs, ident, ty } = member;
let RawMember {
attrs,
ident,
ty,
span: _,
} = member;

if let Some(value) = config.skip {
output.push(Self::Skip(SkipMember {
Expand Down Expand Up @@ -206,6 +212,7 @@ impl Member {
ty,
config,
docs,
span: member.span,
};

member.merge_on_config(on)?;
Expand Down Expand Up @@ -278,6 +285,7 @@ impl PosFnMember {
attrs: _,
ident,
ty,
span: _,
} = member;

let mut me = Self {
Expand Down
14 changes: 14 additions & 0 deletions bon-macros/src/builder/builder_gen/member/named.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use crate::builder::builder_gen::top_level_config::OnConfig;
use crate::normalization::SyntaxVariant;
use crate::parsing::{ItemSigConfig, SpannedKey};
use crate::util::prelude::*;
use proc_macro2::TokenTree;

#[derive(Debug)]
pub(crate) struct MemberName {
Expand Down Expand Up @@ -90,6 +91,9 @@ pub(crate) struct NamedMember {

/// Parameters configured by the user explicitly via attributes
pub(crate) config: MemberConfig,

/// Preserve a span the documentation for the member's methods should link to.
pub(crate) span: Span,
}

impl NamedMember {
Expand Down Expand Up @@ -303,4 +307,14 @@ impl NamedMember {

Ok(())
}

/// Respan the tokens with the member's span. This is important to make
/// rustdoc's source links point to the original member's location.
pub(crate) fn respan(&self, tokens: TokenStream) -> impl Iterator<Item = TokenTree> {
let span = self.span;
tokens.into_iter().map(move |mut token| {
token.set_span(span);
token
})
}
}
3 changes: 3 additions & 0 deletions bon-macros/src/builder/builder_gen/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,9 @@ impl BuilderGenCtx {

Ok(quote! {
#allows
// Ignore dead code warnings because some setter/getter methods may
// not be used
#[allow(dead_code)]
#[automatically_derived]
impl<
#(#generics_decl,)*
Expand Down
10 changes: 8 additions & 2 deletions bon-macros/src/builder/builder_gen/setters/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -449,8 +449,14 @@ impl<'a> SettersCtx<'a> {
let pats = imp.inputs.iter().map(|(pat, _)| pat);
let types = imp.inputs.iter().map(|(_, ty)| ty);
let const_ = &self.base.const_;
let fn_modifiers = self.member.respan(quote!(#vis #const_));

quote! {
// It's important to keep the span of `self` the same across all
// references to it. Otherwise `self`s that have different spans will
// be treated as totally different symbols due to the hygiene rules.
let self_ = quote!(self);

quote_spanned! {self.member.span=>
#( #docs )*
#[allow(
// This is intentional. We want the builder syntax to compile away
Expand All @@ -463,7 +469,7 @@ impl<'a> SettersCtx<'a> {
clippy::missing_const_for_fn,
)]
#[inline(always)]
#vis #const_ fn #name(#maybe_mut self, #( #pats: #types ),*) -> #return_type
#(#fn_modifiers)* fn #name(#maybe_mut #self_, #( #pats: #types ),*) -> #return_type
#where_clause
{
#body
Expand Down
3 changes: 2 additions & 1 deletion bon-macros/src/util/ident.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::util::prelude::*;
use ident_case::RenameRule;
use syn::spanned::Spanned;

pub(crate) trait IdentExt {
/// Converts the ident (assumed to be in `snake_case`) to `PascalCase` without
Expand Down Expand Up @@ -45,7 +46,7 @@ impl IdentExt for syn::Ident {
renamed.push('_');
}

Self::new(&renamed, Span::call_site())
Self::new(&renamed, renamed.span())
}

fn pascal_to_snake_case(&self) -> Self {
Expand Down
1 change: 1 addition & 0 deletions bon-macros/tests/snapshots/setters_docs_and_vis.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#[allow(unused_parens)]
#[allow(dead_code)]
#[automatically_derived]
#[allow(deprecated)]
impl<S: sut_builder::State> SutBuilder<S> {
Expand Down
2 changes: 1 addition & 1 deletion bon-sandbox/src/attr_default.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ pub struct Example {
standard_string_default: String,
}

struct Point {
pub struct Point {
x: u32,
y: u32,
}
3 changes: 3 additions & 0 deletions bon-sandbox/src/state_mod/comprehensive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ pub struct Example {
#[builder(required)]
required_option: Option<u64>,

/// # Errors
///
/// Non-integer strings will be rejected.
#[builder(with = |x: &str| -> Result<_, std::num::ParseIntError> { x.parse() })]
with: u32,
}