Skip to content

Commit 9abdf6a

Browse files
Integrate ParsedAttrbiutes struct, containing a map of all attributes
1 parent aa718f6 commit 9abdf6a

File tree

11 files changed

+184
-106
lines changed

11 files changed

+184
-106
lines changed

crates/cxx-qt-gen/src/parser/attribute.rs

Lines changed: 57 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,14 @@
44
// SPDX-License-Identifier: MIT OR Apache-2.0
55

66
use crate::{parser, syntax::path::path_compare_str};
7+
use std::collections::btree_map::Entry;
78
use std::collections::BTreeMap;
89
use syn::{spanned::Spanned, Attribute, Error, Result};
910

10-
pub struct ParsedAttribute<'a> {
11-
pub cxx_qt_attrs: BTreeMap<&'a str, &'a Attribute>,
12-
pub passthrough_attrs: BTreeMap<&'a str, &'a Attribute>,
11+
#[derive(Clone)]
12+
pub struct ParsedAttributes {
13+
pub cxx_qt_attrs: BTreeMap<String, Vec<Attribute>>,
14+
pub passthrough_attrs: Vec<Attribute>,
1315
}
1416

1517
/// Iterate the attributes of the method to extract cfg attributes
@@ -30,20 +32,28 @@ pub fn extract_docs(attrs: &[Attribute]) -> Vec<Attribute> {
3032
.collect()
3133
}
3234

33-
impl<'a> ParsedAttribute<'a> {
35+
impl<'a> ParsedAttributes {
3436
/// Collects a Map of all attributes found from the allowed list
3537
/// Will error if an attribute which is not in the allowed list is found
3638
pub fn require_attributes(
37-
attrs: &'a [Attribute],
39+
mut attrs: Vec<Attribute>,
3840
allowed: &'a [&str],
39-
) -> Result<ParsedAttribute<'a>> {
40-
let mut output = BTreeMap::default();
41-
for attr in attrs {
41+
) -> Result<ParsedAttributes> {
42+
let mut output = BTreeMap::<String, Vec<Attribute>>::default();
43+
for attr in attrs.drain(..) {
4244
let index = allowed
4345
.iter()
4446
.position(|string| path_compare_str(attr.meta.path(), &parser::split_path(string)));
4547
if let Some(index) = index {
46-
output.insert(allowed[index], attr); // TODO: Doesn't error on duplicates
48+
// TODO: ATTR Doesn't error on duplicates / distinguish allowed and disallowed duplicates
49+
match output.entry(allowed[index].into()) {
50+
Entry::Occupied(mut entry) => {
51+
entry.get_mut().push(attr);
52+
}
53+
Entry::Vacant(entry) => {
54+
entry.insert(vec![attr]);
55+
}
56+
}
4757
} else {
4858
return Err(Error::new(
4959
attr.span(),
@@ -56,23 +66,54 @@ impl<'a> ParsedAttribute<'a> {
5666
}
5767
Ok(Self {
5868
cxx_qt_attrs: output,
59-
passthrough_attrs: Default::default(),
69+
passthrough_attrs: Default::default(), // TODO: ATTR Pass the actual docs, cfgs, etc... here
6070
})
6171
}
6272

73+
// TODO: ATTR Can this return references instead?
74+
pub fn extract_docs(&self) -> Vec<Attribute> {
75+
self.cxx_qt_attrs
76+
.values()
77+
.flatten()
78+
.filter(|attr| path_compare_str(attr.meta.path(), &["doc"]))
79+
.map(|attr| (*attr).clone())
80+
.collect()
81+
}
82+
83+
// TODO: ATTR Can this return references instead
84+
pub fn extract_cfgs(&self) -> Vec<Attribute> {
85+
self.cxx_qt_attrs
86+
.values()
87+
.flatten()
88+
.filter(|attr| path_compare_str(attr.meta.path(), &["cfg"]))
89+
.map(|attr| (*attr).clone())
90+
.collect()
91+
}
92+
93+
/// Returns all the attributes stored within the struct
94+
pub fn all_attrs(&self) -> Vec<&Attribute> {
95+
self.cxx_qt_attrs.values().flatten().collect()
96+
}
97+
98+
/// Returns all the attributes stored within the struct (CLONE) WIP
99+
pub fn clone_attrs(&self) -> Vec<Attribute> {
100+
self.cxx_qt_attrs
101+
.values()
102+
.flatten()
103+
.cloned()
104+
.collect::<Vec<_>>()
105+
}
106+
63107
// Wrapper methods for the internal BTreeMaps
64108
// TODO: Refactor usage to use more specialised methods / rename
65109

66110
/// Search in first the CXX-Qt, and then passthrough attributes by key
67-
pub fn get(&self, key: &str) -> Option<&Attribute> {
68-
self.cxx_qt_attrs
69-
.get(key)
70-
.or(self.passthrough_attrs.get(key))
71-
.map(|attr| &**attr)
111+
pub fn get(&self, key: &str) -> Option<&Vec<Attribute>> {
112+
self.cxx_qt_attrs.get(key) // TODO: Check passthrough here too
72113
}
73114

74115
/// Check if CXX-Qt or passthrough attributes contains a particular key
75116
pub fn contains_key(&self, key: &str) -> bool {
76-
self.cxx_qt_attrs.contains_key(key) || self.passthrough_attrs.contains_key(key)
117+
self.cxx_qt_attrs.contains_key(key) // TODO: Check in passthrough too
77118
}
78119
}

crates/cxx-qt-gen/src/parser/externcxxqt.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
//
44
// SPDX-License-Identifier: MIT OR Apache-2.0
55

6-
use crate::parser::attribute::ParsedAttribute;
6+
use crate::parser::attribute::ParsedAttributes;
77
use crate::{
88
parser::{externqobject::ParsedExternQObject, signals::ParsedSignal, CaseConversion},
99
syntax::{attribute::attribute_get_path, expr::expr_to_string},
@@ -34,16 +34,18 @@ impl ParsedExternCxxQt {
3434
parent_namespace: Option<&str>,
3535
) -> Result<Self> {
3636
// TODO: support cfg on foreign mod blocks
37-
let attrs = ParsedAttribute::require_attributes(
38-
&foreign_mod.attrs,
37+
let attrs = ParsedAttributes::require_attributes(
38+
foreign_mod.attrs,
3939
&["namespace", "auto_cxx_name", "auto_rust_name"],
4040
)?;
4141

4242
let auto_case = CaseConversion::from_attrs(&attrs.cxx_qt_attrs)?;
4343

4444
let namespace = attrs
4545
.get("namespace")
46-
.map(|attr| -> Result<String> {
46+
.map(|attrs| -> Result<String> {
47+
// TODO: ATTR won't error on duplicate
48+
let attr = attrs.first().expect("NO NAMESPACE!!"); // TODO: ATTR this needs to be proper
4749
expr_to_string(&attr.meta.require_name_value()?.value)
4850
})
4951
.transpose()?;

crates/cxx-qt-gen/src/parser/externqobject.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
//
44
// SPDX-License-Identifier: MIT OR Apache-2.0
55
use crate::naming::Name;
6-
use crate::parser::attribute::ParsedAttribute;
6+
use crate::parser::attribute::ParsedAttributes;
77
use crate::parser::{parse_base_type, CaseConversion};
88
use syn::{ForeignItemType, Ident, Result};
99

@@ -33,14 +33,15 @@ impl ParsedExternQObject {
3333
module_ident: &Ident,
3434
parent_namespace: Option<&str>,
3535
) -> Result<ParsedExternQObject> {
36-
let attrs = ParsedAttribute::require_attributes(&ty.attrs, &Self::ALLOWED_ATTRS)?;
36+
// TODO: ATTR Can this be done without clone
37+
let attrs = ParsedAttributes::require_attributes(ty.attrs.clone(), &Self::ALLOWED_ATTRS)?;
3738

3839
let base_class = parse_base_type(&attrs.cxx_qt_attrs)?;
3940

4041
Ok(Self {
4142
name: Name::from_ident_and_attrs(
4243
&ty.ident,
43-
&ty.attrs,
44+
&attrs.clone_attrs(),
4445
parent_namespace,
4546
Some(module_ident),
4647
CaseConversion::none(),

crates/cxx-qt-gen/src/parser/externrustqt.rs

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
// SPDX-License-Identifier: MIT OR Apache-2.0
55

66
use crate::naming::cpp::err_unsupported_item;
7-
use crate::parser::attribute::ParsedAttribute;
7+
use crate::parser::attribute::ParsedAttributes;
88
use crate::parser::inherit::ParsedInheritedMethod;
99
use crate::parser::method::ParsedMethod;
1010
use crate::parser::qobject::ParsedQObject;
@@ -39,8 +39,8 @@ impl ParsedExternRustQt {
3939
parent_namespace: Option<&str>,
4040
) -> Result<Self> {
4141
// TODO: support cfg on foreign mod blocks
42-
let attrs = ParsedAttribute::require_attributes(
43-
&foreign_mod.attrs,
42+
let attrs = ParsedAttributes::require_attributes(
43+
foreign_mod.attrs,
4444
&["namespace", "auto_cxx_name", "auto_rust_name"],
4545
)?;
4646

@@ -51,9 +51,19 @@ impl ParsedExternRustQt {
5151
..Default::default()
5252
};
5353

54+
// TODO: ATTR This needs to be proper
5455
let namespace = attrs
5556
.get("namespace")
56-
.map(|attr| expr_to_string(&attr.meta.require_name_value()?.value))
57+
.map(|attrs| {
58+
expr_to_string(
59+
&attrs
60+
.first()
61+
.expect("NO NAMESPACE!!")
62+
.meta
63+
.require_name_value()?
64+
.value,
65+
)
66+
})
5767
.transpose()?
5868
.or_else(|| parent_namespace.map(String::from));
5969

crates/cxx-qt-gen/src/parser/inherit.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
//
44
// SPDX-License-Identifier: MIT OR Apache-2.0
55

6-
use crate::parser::attribute::{extract_cfgs, extract_docs, ParsedAttribute};
76
use crate::parser::{method::MethodFields, CaseConversion};
87
use core::ops::Deref;
98
use quote::format_ident;
@@ -31,12 +30,12 @@ impl ParsedInheritedMethod {
3130
];
3231

3332
pub fn parse(method: ForeignItemFn, auto_case: CaseConversion) -> Result<Self> {
34-
ParsedAttribute::require_attributes(&method.attrs, &Self::ALLOWED_ATTRS)?;
35-
let docs = extract_docs(&method.attrs);
36-
let cfgs = extract_cfgs(&method.attrs);
33+
let method_fields = MethodFields::parse(method, auto_case, &Self::ALLOWED_ATTRS)?;
3734

35+
let docs = method_fields.attrs.extract_docs();
36+
let cfgs = method_fields.attrs.extract_cfgs();
3837
Ok(Self {
39-
method_fields: MethodFields::parse(method, auto_case)?,
38+
method_fields,
4039
docs,
4140
cfgs,
4241
})

crates/cxx-qt-gen/src/parser/method.rs

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// SPDX-FileContributor: Andrew Hayzen <[email protected]>
33
//
44
// SPDX-License-Identifier: MIT OR Apache-2.0
5-
use crate::parser::attribute::{extract_cfgs, ParsedAttribute};
5+
use crate::parser::attribute::{extract_cfgs, ParsedAttributes};
66
use crate::parser::CaseConversion;
77
use crate::{
88
naming::Name,
@@ -34,7 +34,7 @@ impl ParsedQInvokableSpecifiers {
3434
}
3535
}
3636

37-
fn from_attrs(attrs: BTreeMap<&str, &Attribute>) -> HashSet<ParsedQInvokableSpecifiers> {
37+
fn from_attrs(attrs: BTreeMap<String, Vec<Attribute>>) -> HashSet<ParsedQInvokableSpecifiers> {
3838
let mut output = HashSet::new();
3939
for specifier in [
4040
ParsedQInvokableSpecifiers::Final,
@@ -121,15 +121,14 @@ impl ParsedMethod {
121121
auto_case: CaseConversion,
122122
unsafe_block: bool,
123123
) -> Result<Self> {
124-
let fields = MethodFields::parse(method, auto_case)?;
125-
let attrs =
126-
ParsedAttribute::require_attributes(&fields.method.attrs, &Self::ALLOWED_ATTRS)?;
124+
let fields = MethodFields::parse(method, auto_case, &Self::ALLOWED_ATTRS)?;
127125
let cfgs = extract_cfgs(&fields.method.attrs);
128126

129127
// Determine if the method is invokable
130-
let is_qinvokable = attrs.contains_key("qinvokable");
131-
let is_pure = attrs.contains_key("cxx_pure");
132-
let specifiers = ParsedQInvokableSpecifiers::from_attrs(attrs.cxx_qt_attrs);
128+
let is_qinvokable = fields.attrs.contains_key("qinvokable");
129+
let is_pure = fields.attrs.contains_key("cxx_pure");
130+
// TODO: Can this be done without clone
131+
let specifiers = ParsedQInvokableSpecifiers::from_attrs(fields.attrs.cxx_qt_attrs.clone());
133132

134133
Ok(Self {
135134
method_fields: fields,
@@ -166,18 +165,30 @@ pub struct MethodFields {
166165
pub parameters: Vec<ParsedFunctionParameter>,
167166
pub safe: bool,
168167
pub name: Name,
168+
pub attrs: ParsedAttributes,
169169
}
170170

171171
impl MethodFields {
172-
pub fn parse(method: ForeignItemFn, auto_case: CaseConversion) -> Result<Self> {
172+
pub fn parse(
173+
method: ForeignItemFn,
174+
auto_case: CaseConversion,
175+
allowed: &[&str],
176+
) -> Result<Self> {
177+
// TODO: Remove this clone?
178+
let attrs = ParsedAttributes::require_attributes(method.attrs.clone(), allowed)?;
173179
let self_receiver = foreignmod::self_type_from_foreign_fn(&method.sig)?;
174180
let (qobject_ident, mutability) = types::extract_qobject_ident(&self_receiver.ty)?;
175181
let mutable = mutability.is_some();
176182

177183
let parameters = ParsedFunctionParameter::parse_all_ignoring_receiver(&method.sig)?;
178184
let safe = method.sig.unsafety.is_none();
179-
let name =
180-
Name::from_ident_and_attrs(&method.sig.ident, &method.attrs, None, None, auto_case)?;
185+
let name = Name::from_ident_and_attrs(
186+
&method.sig.ident,
187+
&attrs.clone_attrs(),
188+
None,
189+
None,
190+
auto_case,
191+
)?;
181192

182193
Ok(MethodFields {
183194
method,
@@ -186,6 +197,7 @@ impl MethodFields {
186197
parameters,
187198
safe,
188199
name,
200+
attrs,
189201
})
190202
}
191203

0 commit comments

Comments
 (0)