Skip to content

Commit fcf99c1

Browse files
authored
Make rustdoc source links for setters/getters/other_items reference original member (#345)
1 parent 40042ef commit fcf99c1

File tree

11 files changed

+52
-7
lines changed

11 files changed

+52
-7
lines changed

bon-macros/src/builder/builder_gen/getters.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,14 @@ impl<'a> GettersCtx<'a> {
5353
let member_pascal = &self.member.name.pascal;
5454
let state_mod = &self.base.state_mod.ident;
5555
let const_ = &self.base.const_;
56+
let fn_modifiers = self.member.respan(quote!(#vis #const_));
5657

57-
Ok(quote! {
58+
// It's important to keep the span of `self` the same across all
59+
// references to it. Otherwise `self`s that have different spans will
60+
// be treated as totally different symbols due to the hygiene rules.
61+
let self_ = quote!(self);
62+
63+
Ok(quote_spanned! {self.member.span=>
5864
#( #docs )*
5965
#[allow(
6066
// This is intentional. We want the builder syntax to compile away
@@ -63,7 +69,7 @@ impl<'a> GettersCtx<'a> {
6369
)]
6470
#[inline(always)]
6571
#[must_use = "this method has no side effects; it only returns a value"]
66-
#vis #const_ fn #name(&self) -> #return_ty
72+
#(#fn_modifiers)* fn #name(&#self_) -> #return_ty
6773
where
6874
#state_var::#member_pascal: #state_mod::IsSet,
6975
{

bon-macros/src/builder/builder_gen/input_fn/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,7 @@ impl<'a> FnInputCtx<'a> {
296296
attrs: &arg.norm.attrs,
297297
ident: pat.ident.clone(),
298298
ty,
299+
span: pat.ident.span(),
299300
})
300301
})
301302
.collect::<Result<Vec<_>>>()?;

bon-macros/src/builder/builder_gen/input_struct.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use crate::normalization::{GenericsNamespace, SyntaxVariant};
88
use crate::parsing::{ItemSigConfig, SpannedKey};
99
use crate::util::prelude::*;
1010
use std::borrow::Cow;
11+
use syn::spanned::Spanned;
1112
use syn::visit::Visit;
1213
use syn::visit_mut::VisitMut;
1314

@@ -110,6 +111,7 @@ impl StructInputCtx {
110111
attrs: &norm_field.attrs,
111112
ident,
112113
ty,
114+
span: orig_field.ident.span(),
113115
})
114116
})
115117
.collect::<Result<Vec<_>>>()?;

bon-macros/src/builder/builder_gen/member/mod.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ pub(crate) struct RawMember<'a> {
9595
pub(crate) attrs: &'a [syn::Attribute],
9696
pub(crate) ident: syn::Ident,
9797
pub(crate) ty: SyntaxVariant<Box<syn::Type>>,
98+
pub(crate) span: Span,
9899
}
99100

100101
impl Member {
@@ -157,7 +158,12 @@ impl Member {
157158
let mut named_count = 0;
158159

159160
for (member, config) in members {
160-
let RawMember { attrs, ident, ty } = member;
161+
let RawMember {
162+
attrs,
163+
ident,
164+
ty,
165+
span: _,
166+
} = member;
161167

162168
if let Some(value) = config.skip {
163169
output.push(Self::Skip(SkipMember {
@@ -206,6 +212,7 @@ impl Member {
206212
ty,
207213
config,
208214
docs,
215+
span: member.span,
209216
};
210217

211218
member.merge_on_config(on)?;
@@ -278,6 +285,7 @@ impl PosFnMember {
278285
attrs: _,
279286
ident,
280287
ty,
288+
span: _,
281289
} = member;
282290

283291
let mut me = Self {

bon-macros/src/builder/builder_gen/member/named.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use crate::builder::builder_gen::top_level_config::OnConfig;
55
use crate::normalization::SyntaxVariant;
66
use crate::parsing::{ItemSigConfig, SpannedKey};
77
use crate::util::prelude::*;
8+
use proc_macro2::TokenTree;
89

910
#[derive(Debug)]
1011
pub(crate) struct MemberName {
@@ -90,6 +91,9 @@ pub(crate) struct NamedMember {
9091

9192
/// Parameters configured by the user explicitly via attributes
9293
pub(crate) config: MemberConfig,
94+
95+
/// Preserve a span the documentation for the member's methods should link to.
96+
pub(crate) span: Span,
9397
}
9498

9599
impl NamedMember {
@@ -303,4 +307,14 @@ impl NamedMember {
303307

304308
Ok(())
305309
}
310+
311+
/// Respan the tokens with the member's span. This is important to make
312+
/// rustdoc's source links point to the original member's location.
313+
pub(crate) fn respan(&self, tokens: TokenStream) -> impl Iterator<Item = TokenTree> {
314+
let span = self.span;
315+
tokens.into_iter().map(move |mut token| {
316+
token.set_span(span);
317+
token
318+
})
319+
}
306320
}

bon-macros/src/builder/builder_gen/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,9 @@ impl BuilderGenCtx {
136136

137137
Ok(quote! {
138138
#allows
139+
// Ignore dead code warnings because some setter/getter methods may
140+
// not be used
141+
#[allow(dead_code)]
139142
#[automatically_derived]
140143
impl<
141144
#(#generics_decl,)*

bon-macros/src/builder/builder_gen/setters/mod.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -449,8 +449,14 @@ impl<'a> SettersCtx<'a> {
449449
let pats = imp.inputs.iter().map(|(pat, _)| pat);
450450
let types = imp.inputs.iter().map(|(_, ty)| ty);
451451
let const_ = &self.base.const_;
452+
let fn_modifiers = self.member.respan(quote!(#vis #const_));
452453

453-
quote! {
454+
// It's important to keep the span of `self` the same across all
455+
// references to it. Otherwise `self`s that have different spans will
456+
// be treated as totally different symbols due to the hygiene rules.
457+
let self_ = quote!(self);
458+
459+
quote_spanned! {self.member.span=>
454460
#( #docs )*
455461
#[allow(
456462
// This is intentional. We want the builder syntax to compile away
@@ -463,7 +469,7 @@ impl<'a> SettersCtx<'a> {
463469
clippy::missing_const_for_fn,
464470
)]
465471
#[inline(always)]
466-
#vis #const_ fn #name(#maybe_mut self, #( #pats: #types ),*) -> #return_type
472+
#(#fn_modifiers)* fn #name(#maybe_mut #self_, #( #pats: #types ),*) -> #return_type
467473
#where_clause
468474
{
469475
#body

bon-macros/src/util/ident.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use crate::util::prelude::*;
22
use ident_case::RenameRule;
3+
use syn::spanned::Spanned;
34

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

48-
Self::new(&renamed, Span::call_site())
49+
Self::new(&renamed, renamed.span())
4950
}
5051

5152
fn pascal_to_snake_case(&self) -> Self {

bon-macros/tests/snapshots/setters_docs_and_vis.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#[allow(unused_parens)]
2+
#[allow(dead_code)]
23
#[automatically_derived]
34
#[allow(deprecated)]
45
impl<S: sut_builder::State> SutBuilder<S> {

bon-sandbox/src/attr_default.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ pub struct Example {
2828
standard_string_default: String,
2929
}
3030

31-
struct Point {
31+
pub struct Point {
3232
x: u32,
3333
y: u32,
3434
}

0 commit comments

Comments
 (0)