Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add docs override attributes for various generated items #139

Merged
merged 6 commits into from
Sep 21, 2024
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
14 changes: 6 additions & 8 deletions bon-macros/src/builder/builder_gen/builder_derives.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,20 @@
use super::builder_params::BuilderDerives;
use super::BuilderGenCtx;
use crate::builder::builder_gen::Member;
use crate::util::prelude::*;
use quote::quote;

impl BuilderGenCtx {
pub(crate) fn builder_derives(&self) -> TokenStream2 {
let derives = match &self.builder_derives {
Some(derives) => derives,
None => return quote!(),
};
let BuilderDerives { clone, debug } = &self.builder_type.derives;

let mut tokens = TokenStream2::new();

if derives.clone.is_present() {
if clone.is_present() {
tokens.extend(self.derive_clone());
}

if derives.debug.is_present() {
if debug.is_present() {
tokens.extend(self.derive_debug());
}

Expand All @@ -39,7 +37,7 @@ impl BuilderGenCtx {
fn derive_clone(&self) -> TokenStream2 {
let generics_decl = &self.generics.decl_without_defaults;
let generic_args = &self.generics.args;
let builder_ident = &self.builder_ident;
let builder_ident = &self.builder_type.ident;

let clone = quote!(::core::clone::Clone);

Expand Down Expand Up @@ -89,7 +87,7 @@ impl BuilderGenCtx {
fn derive_debug(&self) -> TokenStream2 {
let generics_decl = &self.generics.decl_without_defaults;
let generic_args = &self.generics.args;
let builder_ident = &self.builder_ident;
let builder_ident = &self.builder_type.ident;

let debug = quote!(::core::fmt::Debug);

Expand Down
87 changes: 77 additions & 10 deletions bon-macros/src/builder/builder_gen/builder_params.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,41 @@ use syn::parse::Parse;
use syn::spanned::Spanned;
use syn::visit::Visit;

fn parse_finish_fn(meta: &syn::Meta) -> Result<ItemParams> {
ItemParamsParsing {
meta,
allow_vis: false,
reject_self_mentions: Some("builder struct's impl block"),
}
.parse()
}

fn parse_builder_type(meta: &syn::Meta) -> Result<ItemParams> {
ItemParamsParsing {
meta,
allow_vis: false,
reject_self_mentions: Some("builder struct"),
}
.parse()
}

#[derive(Debug, FromMeta)]
pub(crate) struct BuilderParams {
pub(crate) finish_fn: Option<syn::Ident>,
pub(crate) builder_type: Option<syn::Ident>,
#[darling(default, with = parse_finish_fn)]
pub(crate) finish_fn: ItemParams,

#[darling(default, with = parse_builder_type)]
pub(crate) builder_type: ItemParams,

#[darling(multiple)]
pub(crate) on: Vec<OnParams>,

/// Specifies the derives to apply to the builder.
pub(crate) derive: Option<BuilderDerives>,
#[darling(default)]
pub(crate) derive: BuilderDerives,
}

#[derive(Debug, FromMeta)]
#[derive(Debug, Clone, Default, FromMeta)]
pub(crate) struct BuilderDerives {
#[darling(rename = "Clone")]
pub(crate) clone: darling::util::Flag,
Expand Down Expand Up @@ -108,28 +130,55 @@ impl FromMeta for OnParams {
}
}

#[derive(Debug, Default)]
#[derive(Debug, Clone, Default)]
pub(crate) struct ItemParams {
pub(crate) name: Option<syn::Ident>,
pub(crate) vis: Option<syn::Visibility>,
pub(crate) docs: Option<Vec<syn::Attribute>>,
}

impl FromMeta for ItemParams {
fn from_meta(meta: &syn::Meta) -> Result<Self> {
pub(crate) struct ItemParamsParsing<'a> {
pub(crate) meta: &'a syn::Meta,
pub(crate) allow_vis: bool,
pub(crate) reject_self_mentions: Option<&'static str>,
}

impl ItemParamsParsing<'_> {
pub(crate) fn parse(self) -> Result<ItemParams> {
let params = Self::params_from_meta(self.meta)?;

if !self.allow_vis {
if let Some(vis) = &params.vis {
bail!(vis, "visibility can't be overridden for this item");
}
}

if let Some(context) = self.reject_self_mentions {
if let Some(docs) = &params.docs {
super::reject_self_mentions_in_docs(context, docs)?;
}
}

Ok(params)
}

fn params_from_meta(meta: &syn::Meta) -> Result<ItemParams> {
if let syn::Meta::NameValue(meta) = meta {
let val = &meta.value;
let name = syn::parse2(quote!(#val))?;

return Ok(Self {
return Ok(ItemParams {
name: Some(name),
vis: None,
docs: None,
});
}

#[derive(Debug, FromMeta)]
struct Full {
name: Option<syn::Ident>,
vis: Option<syn::Visibility>,
docs: Option<syn::Meta>,
}

let full = Full::from_meta(meta)?;
Expand All @@ -139,18 +188,36 @@ impl FromMeta for ItemParams {
Full {
name: None,
vis: None,
docs: None,
}
);

if is_empty {
bail!(meta, "expected at least one parameter in parentheses");
}

let me = Self {
let docs = full
.docs
.map(|docs| {
let docs = docs.require_list()?;
let docs = docs.parse_args_with(syn::Attribute::parse_outer)?;

for attr in &docs {
if !attr.is_doc() {
bail!(attr, "expected a doc comment");
}
}

Ok(docs)
})
.transpose()?;

let params = ItemParams {
name: full.name,
vis: full.vis,
docs,
};

Ok(me)
Ok(params)
}
}
34 changes: 27 additions & 7 deletions bon-macros/src/builder/builder_gen/input_func.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ use super::{
generic_param_to_arg, AssocMethodCtx, AssocMethodReceiverCtx, BuilderGenCtx, FinishFunc,
FinishFuncBody, Generics, Member, MemberOrigin, RawMember, StartFunc,
};
use crate::builder::builder_gen::builder_params::ItemParams;
use crate::builder::builder_gen::BuilderType;
use crate::normalization::NormalizeSelfTy;
use crate::util::prelude::*;
use darling::util::SpannedValue;
Expand Down Expand Up @@ -134,8 +136,10 @@ impl FuncInputCtx {
}

fn builder_ident(&self) -> syn::Ident {
if let Some(builder_type) = &self.params.base.builder_type {
return builder_type.clone();
let user_override = self.params.base.builder_type.name.as_ref();

if let Some(user_override) = user_override {
return user_override.clone();
}

if self.is_method_new() {
Expand Down Expand Up @@ -326,7 +330,13 @@ impl FuncInputCtx {
self.norm_func.sig.ident.clone()
};

let finish_func_ident = self.params.base.finish_fn.unwrap_or_else(|| {
let ItemParams {
name: finish_func_ident,
vis: _,
docs: finish_func_docs,
} = self.params.base.finish_fn;

let finish_func_ident = finish_func_ident.unwrap_or_else(|| {
// For `new` methods the `build` finisher is more conventional
if is_method_new {
quote::format_ident!("build")
Expand All @@ -335,14 +345,20 @@ impl FuncInputCtx {
}
});

let finish_func_docs = finish_func_docs.unwrap_or_else(|| {
vec![syn::parse_quote! {
/// Finishes building and performs the requested action.
}]
});

let finish_func = FinishFunc {
ident: finish_func_ident,
unsafety: self.norm_func.sig.unsafety,
asyncness: self.norm_func.sig.asyncness,
must_use: get_must_use_attribute(&self.norm_func.attrs)?,
body: Box::new(finish_func_body),
output: self.norm_func.sig.output,
docs: "Finishes building and performs the requested action.".to_owned(),
attrs: finish_func_docs,
};

let fn_allows = self
Expand Down Expand Up @@ -382,20 +398,24 @@ impl FuncInputCtx {
)),
};

let builder_type = BuilderType {
ident: builder_ident,
derives: self.params.base.derive,
docs: self.params.base.builder_type.docs,
};

let ctx = BuilderGenCtx {
members,

allow_attrs,

on_params: self.params.base.on,
builder_derives: self.params.base.derive,

builder_ident,

assoc_method_ctx: receiver,
generics,
vis: self.norm_func.vis,

builder_type,
start_func,
finish_func,
};
Expand Down
Loading