• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

davidcole1340 / ext-php-rs / 16811996119

07 Aug 2025 05:54PM UTC coverage: 27.144%. Remained the same
16811996119

Pull #543

github

Xenira
chore(clippy): fix new clippy findings
Pull Request #543: chore(clippy): fix new clippy findings

1127 of 4152 relevant lines covered (27.14%)

5.67 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/crates/macros/src/class.rs
1
use darling::util::Flag;
2
use darling::{FromAttributes, FromMeta, ToTokens};
3
use proc_macro2::TokenStream;
4
use quote::quote;
5
use syn::{Attribute, Expr, Fields, ItemStruct};
6

7
use crate::helpers::get_docs;
8
use crate::parsing::{PhpRename, RenameRule};
9
use crate::prelude::*;
10

11
#[derive(FromAttributes, Debug, Default)]
12
#[darling(attributes(php), forward_attrs(doc), default)]
13
pub struct StructAttributes {
14
    /// The name of the PHP class. Defaults to the same name as the struct.
15
    #[darling(flatten)]
16
    rename: PhpRename,
17
    /// A modifier function which should accept one argument, a `ClassBuilder`,
18
    /// and return the same object. Allows the user to modify the class before
19
    /// it is built.
20
    modifier: Option<syn::Ident>,
21
    /// An expression of `ClassFlags` to be applied to the class.
22
    flags: Option<syn::Expr>,
23
    extends: Option<ClassEntryAttribute>,
24
    #[darling(multiple)]
25
    implements: Vec<ClassEntryAttribute>,
26
    attrs: Vec<Attribute>,
27
}
28

29
#[derive(FromMeta, Debug)]
30
pub struct ClassEntryAttribute {
31
    ce: syn::Expr,
32
    stub: String,
33
}
34

35
pub fn parser(mut input: ItemStruct) -> Result<TokenStream> {
×
36
    let attr = StructAttributes::from_attributes(&input.attrs)?;
×
37
    let ident = &input.ident;
38
    let name = attr.rename.rename(ident.to_string(), RenameRule::Pascal);
39
    let docs = get_docs(&attr.attrs)?;
×
40
    input.attrs.retain(|attr| !attr.path().is_ident("php"));
×
41

42
    let fields = match &mut input.fields {
×
43
        Fields::Named(fields) => parse_fields(fields.named.iter_mut())?,
×
44
        _ => vec![],
×
45
    };
46

47
    let class_impl = generate_registered_class_impl(
48
        ident,
49
        &name,
50
        attr.modifier.as_ref(),
51
        attr.extends.as_ref(),
52
        &attr.implements,
53
        &fields,
54
        attr.flags.as_ref(),
55
        &docs,
56
    );
57

58
    Ok(quote! {
59
        #input
60
        #class_impl
61

62
        ::ext_php_rs::class_derives!(#ident);
63
    })
64
}
65

66
#[derive(FromAttributes, Debug, Default)]
67
#[darling(attributes(php), forward_attrs(doc), default)]
68
struct PropAttributes {
69
    prop: Flag,
70
    #[darling(flatten)]
71
    rename: PhpRename,
72
    flags: Option<Expr>,
73
    attrs: Vec<Attribute>,
74
}
75

76
fn parse_fields<'a>(fields: impl Iterator<Item = &'a mut syn::Field>) -> Result<Vec<Property<'a>>> {
×
77
    let mut result = vec![];
×
78
    for field in fields {
×
79
        let attr = PropAttributes::from_attributes(&field.attrs)?;
×
80
        if attr.prop.is_present() {
×
81
            let ident = field
×
82
                .ident
×
83
                .as_ref()
84
                .ok_or_else(|| err!("Only named fields can be properties."))?;
×
85
            let docs = get_docs(&attr.attrs)?;
×
86
            field.attrs.retain(|attr| !attr.path().is_ident("php"));
×
87

88
            result.push(Property { ident, attr, docs });
×
89
        }
90
    }
91

92
    Ok(result)
×
93
}
94

95
#[derive(Debug)]
96
struct Property<'a> {
97
    pub ident: &'a syn::Ident,
98
    pub attr: PropAttributes,
99
    pub docs: Vec<String>,
100
}
101

102
impl Property<'_> {
103
    pub fn name(&self) -> String {
×
104
        self.attr
×
105
            .rename
×
106
            .rename(self.ident.to_string(), RenameRule::Camel)
×
107
    }
108
}
109

110
/// Generates an implementation of `RegisteredClass` for struct `ident`.
111
#[allow(clippy::too_many_arguments)]
112
fn generate_registered_class_impl(
×
113
    ident: &syn::Ident,
114
    class_name: &str,
115
    modifier: Option<&syn::Ident>,
116
    extends: Option<&ClassEntryAttribute>,
117
    implements: &[ClassEntryAttribute],
118
    fields: &[Property],
119
    flags: Option<&syn::Expr>,
120
    docs: &[String],
121
) -> TokenStream {
122
    let modifier = modifier.option_tokens();
×
123

124
    let fields = fields.iter().map(|prop| {
×
125
        let name = prop.name();
×
126
        let ident = prop.ident;
×
127
        let flags = prop
×
128
            .attr
×
129
            .flags
×
130
            .as_ref()
×
131
            .map(ToTokens::to_token_stream)
×
132
            .unwrap_or(quote! { ::ext_php_rs::flags::PropertyFlags::Public });
×
133
        let docs = &prop.docs;
×
134

135
        quote! {
×
136
            (#name, ::ext_php_rs::internal::property::PropertyInfo {
137
                prop: ::ext_php_rs::props::Property::field(|this: &mut Self| &mut this.#ident),
138
                flags: #flags,
139
                docs: &[#(#docs,)*]
140
            })
141
        }
142
    });
143

144
    let flags = match flags {
×
145
        Some(flags) => flags.to_token_stream(),
×
146
        None => quote! { ::ext_php_rs::flags::ClassFlags::empty() }.to_token_stream(),
×
147
    };
148

149
    let docs = quote! {
×
150
        #(#docs,)*
151
    };
152

153
    let extends = if let Some(extends) = extends {
×
154
        let ce = &extends.ce;
155
        let stub = &extends.stub;
156
        quote! {
157
            Some((#ce, #stub))
158
        }
159
    } else {
160
        quote! { None }
×
161
    };
162

163
    let implements = implements.iter().map(|imp| {
×
164
        let ce = &imp.ce;
×
165
        let stub = &imp.stub;
×
166
        quote! {
×
167
            (#ce, #stub)
168
        }
169
    });
170

171
    quote! {
×
172
        impl ::ext_php_rs::class::RegisteredClass for #ident {
173
            const CLASS_NAME: &'static str = #class_name;
174
            const BUILDER_MODIFIER: ::std::option::Option<
175
                fn(::ext_php_rs::builders::ClassBuilder) -> ::ext_php_rs::builders::ClassBuilder
176
            > = #modifier;
177
            const EXTENDS: ::std::option::Option<
178
                ::ext_php_rs::class::ClassEntryInfo
179
            > = #extends;
180
            const IMPLEMENTS: &'static [::ext_php_rs::class::ClassEntryInfo] = &[
181
                #(#implements,)*
182
            ];
183
            const FLAGS: ::ext_php_rs::flags::ClassFlags = #flags;
184
            const DOC_COMMENTS: &'static [&'static str] = &[
185
                #docs
186
            ];
187

188
            #[inline]
189
            fn get_metadata() -> &'static ::ext_php_rs::class::ClassMetadata<Self> {
190
                static METADATA: ::ext_php_rs::class::ClassMetadata<#ident> =
191
                    ::ext_php_rs::class::ClassMetadata::new();
192
                &METADATA
193
            }
194

195
            fn get_properties<'a>() -> ::std::collections::HashMap<
196
                &'static str, ::ext_php_rs::internal::property::PropertyInfo<'a, Self>
197
            > {
198
                use ::std::iter::FromIterator;
199
                ::std::collections::HashMap::from_iter([
200
                    #(#fields,)*
201
                ])
202
            }
203

204
            #[inline]
205
            fn method_builders() -> ::std::vec::Vec<
206
                (::ext_php_rs::builders::FunctionBuilder<'static>, ::ext_php_rs::flags::MethodFlags)
207
            > {
208
                use ::ext_php_rs::internal::class::PhpClassImpl;
209
                ::ext_php_rs::internal::class::PhpClassImplCollector::<Self>::default().get_methods()
210
            }
211

212
            #[inline]
213
            fn constructor() -> ::std::option::Option<::ext_php_rs::class::ConstructorMeta<Self>> {
214
                use ::ext_php_rs::internal::class::PhpClassImpl;
215
                ::ext_php_rs::internal::class::PhpClassImplCollector::<Self>::default().get_constructor()
216
            }
217

218
            #[inline]
219
            fn constants() -> &'static [(&'static str, &'static dyn ::ext_php_rs::convert::IntoZvalDyn, &'static [&'static str])] {
220
                use ::ext_php_rs::internal::class::PhpClassImpl;
221
                ::ext_php_rs::internal::class::PhpClassImplCollector::<Self>::default().get_constants()
222
            }
223
        }
224
    }
225
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc