Skip to content

Commit 0f5448c

Browse files
carlosmnbilelmoussaoui
authored andcommitted
glib-macros: Properties: copy property docs to getter
We take the docs directly preceding a `#[property]` and copy them into the generated getter method.
1 parent 039e7d5 commit 0f5448c

File tree

2 files changed

+44
-22
lines changed

2 files changed

+44
-22
lines changed

glib-macros/src/lib.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1344,6 +1344,10 @@ pub fn cstr_bytes(item: TokenStream) -> TokenStream {
13441344
/// * `connect_$property_notify()`
13451345
/// * `notify_$property()`
13461346
///
1347+
/// # Documentation
1348+
///
1349+
/// Doc comments preceding a `#[property]` attribute will be copied to the generated getter method.
1350+
///
13471351
/// ## Extension trait
13481352
/// You can choose to move the method definitions to a trait by using `#[properties(wrapper_type = super::MyType, ext_trait = MyTypePropertiesExt)]`.
13491353
/// The trait name is optional, and defaults to `MyTypePropertiesExt`, where `MyType` is extracted from the wrapper type.
@@ -1407,7 +1411,9 @@ pub fn cstr_bytes(item: TokenStream) -> TokenStream {
14071411
/// pub struct Foo {
14081412
/// #[property(get, set = Self::set_fizz)]
14091413
/// fizz: RefCell<String>,
1414+
/// /// The author's name
14101415
/// #[property(name = "author-name", get, set, type = String, member = name)]
1416+
/// /// The author's childhood nickname
14111417
/// #[property(name = "author-nick", get, set, type = String, member = nick)]
14121418
/// author: RefCell<Author>,
14131419
/// #[property(get, set, explicit_notify, lax_validation)]

glib-macros/src/properties.rs

Lines changed: 38 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use syn::parse::Parse;
1212
use syn::punctuated::Punctuated;
1313
use syn::spanned::Spanned;
1414
use syn::Token;
15-
use syn::{parse_quote_spanned, LitStr};
15+
use syn::{parse_quote_spanned, Attribute, LitStr};
1616

1717
pub struct PropsMacroInput {
1818
wrapper_ty: syn::Path,
@@ -255,6 +255,7 @@ struct PropDesc {
255255
field_ident: syn::Ident,
256256
ty: syn::Type,
257257
name: syn::LitStr,
258+
comments: Vec<Attribute>,
258259
override_class: Option<syn::Type>,
259260
override_interface: Option<syn::Type>,
260261
nullable: bool,
@@ -271,6 +272,7 @@ impl PropDesc {
271272
attrs_span: proc_macro2::Span,
272273
field_ident: syn::Ident,
273274
field_ty: syn::Type,
275+
comments: Vec<Attribute>,
274276
attrs: ReceivedAttrs,
275277
) -> syn::Result<Self> {
276278
let ReceivedAttrs {
@@ -321,6 +323,7 @@ impl PropDesc {
321323
field_ident,
322324
ty,
323325
name,
326+
comments,
324327
override_class,
325328
override_interface,
326329
nullable,
@@ -524,26 +527,33 @@ fn expand_set_property_fn(props: &[PropDesc]) -> TokenStream2 {
524527
}
525528

526529
fn parse_fields(fields: syn::Fields) -> syn::Result<Vec<PropDesc>> {
527-
fields
528-
.into_iter()
529-
.flat_map(|field| {
530-
let syn::Field {
531-
ident, attrs, ty, ..
532-
} = field;
533-
attrs
534-
.into_iter()
535-
.filter(|a| a.path().is_ident("property"))
536-
.map(move |prop_attrs| {
537-
let span = prop_attrs.span();
538-
PropDesc::new(
539-
span,
540-
ident.as_ref().unwrap().clone(),
541-
ty.clone(),
542-
prop_attrs.parse_args()?,
543-
)
544-
})
545-
})
546-
.collect::<syn::Result<_>>()
530+
let mut properties = vec![];
531+
532+
for field in fields.into_iter() {
533+
let syn::Field {
534+
ident, attrs, ty, ..
535+
} = field;
536+
// Store the comments until the next `#[property]` we see and then attach them to it.
537+
let mut comments: Vec<Attribute> = vec![];
538+
for prop_attr in attrs.iter() {
539+
if prop_attr.path().is_ident("doc") {
540+
comments.push(prop_attr.clone());
541+
} else if prop_attr.path().is_ident("property") {
542+
let span = prop_attr.span();
543+
let existing_comments = comments;
544+
comments = vec![];
545+
properties.push(PropDesc::new(
546+
span,
547+
ident.as_ref().unwrap().clone(),
548+
ty.clone(),
549+
existing_comments,
550+
prop_attr.parse_args()?,
551+
)?);
552+
}
553+
}
554+
}
555+
556+
Ok(properties)
547557
}
548558

549559
/// Converts a glib property name to a correct rust ident
@@ -567,7 +577,7 @@ fn expand_impl_getset_properties(props: &[PropDesc]) -> Vec<syn::ImplItemFn> {
567577
let ident = name_to_ident(name);
568578
let ty = &p.ty;
569579

570-
let getter = p.get.is_some().then(|| {
580+
let mut getter: Option<syn::ImplItemFn> = p.get.is_some().then(|| {
571581
let span = p.attrs_span;
572582
parse_quote_spanned!(span=>
573583
#[must_use]
@@ -578,6 +588,12 @@ fn expand_impl_getset_properties(props: &[PropDesc]) -> Vec<syn::ImplItemFn> {
578588
)
579589
});
580590

591+
if let Some(ref mut getter) = getter {
592+
for lit in &p.comments {
593+
getter.attrs.push(lit.clone());
594+
}
595+
}
596+
581597
let setter = (p.set.is_some() && !p.is_construct_only).then(|| {
582598
let ident = format_ident!("set_{}", ident);
583599
let target_ty = quote!(<<#ty as #crate_ident::property::Property>::Value as #crate_ident::prelude::HasParamSpec>::SetValue);

0 commit comments

Comments
 (0)