bon_macros/builder/builder_gen/input_fn/validation.rs
1use crate::util::prelude::*;
2use syn::visit::Visit;
3
4impl super::FnInputCtx<'_> {
5 pub(super) fn validate(&self) -> Result {
6 if self.impl_ctx.is_none() {
7 let explanation = "\
8 but #[bon] attribute is absent on top of the impl block; this \
9 additional #[bon] attribute on the impl block is required for \
10 the macro to see the type of `Self` and properly generate \
11 the builder struct definition adjacently to the impl block.";
12
13 if let Some(receiver) = &self.fn_item.orig.sig.receiver() {
14 bail!(
15 &receiver.self_token,
16 "function contains a `self` parameter {explanation}"
17 );
18 }
19
20 let mut ctx = FindSelfReference::default();
21 ctx.visit_item_fn(&self.fn_item.orig);
22 if let Some(self_span) = ctx.self_span {
23 bail!(
24 &self_span,
25 "function contains a `Self` type reference {explanation}"
26 );
27 }
28 }
29
30 Ok(())
31 }
32
33 pub(crate) fn warnings(&self) -> TokenStream {
34 // We used to emit some warnings here previously, but then that logic
35 // was removed. The code for the `warnings()` method was preserved just
36 // in case if we need to issue some new warnings again. However, it's not
37 // critical. Feel free to eliminate this method if you feel like it.
38 let _ = self;
39
40 TokenStream::new()
41 }
42}
43
44#[derive(Default)]
45struct FindSelfReference {
46 self_span: Option<Span>,
47}
48
49impl Visit<'_> for FindSelfReference {
50 fn visit_item(&mut self, _: &syn::Item) {
51 // Don't recurse into nested items. We are interested in the reference
52 // to `Self` on the current item level
53 }
54
55 fn visit_path(&mut self, path: &syn::Path) {
56 if self.self_span.is_some() {
57 return;
58 }
59 syn::visit::visit_path(self, path);
60
61 let first_segment = match path.segments.first() {
62 Some(first_segment) => first_segment,
63 _ => return,
64 };
65
66 if first_segment.ident == "Self" {
67 self.self_span = Some(first_segment.ident.span());
68 }
69 }
70}