cxx_qt_gen/generator/cpp/
inherit.rs

1// SPDX-FileCopyrightText: 2023 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
2// SPDX-FileContributor: Leon Matthes <leon.matthes@kdab.com>
3// SPDX-License-Identifier: MIT OR Apache-2.0
4
5use indoc::formatdoc;
6
7use crate::{
8    generator::cpp::{fragment::CppFragment, qobject::GeneratedCppQObjectBlocks},
9    naming::cpp::syn_type_to_cpp_return_type,
10    naming::TypeNames,
11    parser::inherit::ParsedInheritedMethod,
12};
13
14use syn::Result;
15
16pub fn generate(
17    inherited_methods: &[&ParsedInheritedMethod],
18    base_class: &Option<String>,
19    type_names: &TypeNames,
20) -> Result<GeneratedCppQObjectBlocks> {
21    let mut result = GeneratedCppQObjectBlocks::default();
22
23    for &method in inherited_methods {
24        let return_type = syn_type_to_cpp_return_type(&method.method.sig.output, type_names)?;
25        // Note that no qobject macro with no base class is an error
26        //
27        // So a default of QObject is fine here
28        let base_class = base_class.as_deref().unwrap_or("QObject");
29
30        result.methods.push(CppFragment::Header(formatdoc! {
31        r#"
32              template <class... Args>
33              {return_type} {wrapper_ident}(Args ...args){mutability}
34              {{
35                  return {base_class}::{func_ident}(args...);
36              }}"#,
37        mutability = if method.mutable { "" } else { " const" },
38        func_ident = method.name.cxx_unqualified(),
39        wrapper_ident = method.wrapper_ident(),
40        return_type = return_type.unwrap_or_else(|| "void".to_string()),
41        base_class = base_class
42        }));
43    }
44
45    Ok(result)
46}
47
48#[cfg(test)]
49mod tests {
50    use pretty_assertions::assert_str_eq;
51    use syn::{parse_quote, ForeignItemFn};
52
53    use super::*;
54    use crate::generator::cpp::property::tests::require_header;
55    use crate::parser::inherit::ParsedInheritedMethod;
56    use crate::parser::CaseConversion;
57
58    fn generate_from_foreign(
59        method: ForeignItemFn,
60        base_class: Option<&str>,
61    ) -> Result<GeneratedCppQObjectBlocks> {
62        let method = ParsedInheritedMethod::parse(method, CaseConversion::none())?;
63        let inherited_methods = vec![&method];
64        let base_class = base_class.map(|s| s.to_owned());
65        generate(&inherited_methods, &base_class, &TypeNames::default())
66    }
67
68    fn assert_generated_eq(expected: &str, generated: &GeneratedCppQObjectBlocks) {
69        assert_eq!(generated.methods.len(), 1);
70        let header = require_header(&generated.methods[0]).unwrap();
71        assert_str_eq!(header, expected);
72    }
73
74    #[test]
75    fn test_immutable() {
76        let generated = generate_from_foreign(
77            parse_quote! {
78                fn test(self: &T, a: B, b: C);
79            },
80            Some("TestBaseClass"),
81        )
82        .unwrap();
83
84        assert_generated_eq(
85            indoc::indoc! {"
86                template <class... Args>
87                void testCxxQtInherit(Args ...args) const
88                {
89                    return TestBaseClass::test(args...);
90                }"
91            },
92            &generated,
93        );
94    }
95
96    #[test]
97    fn test_mutable() {
98        let generated = generate_from_foreign(
99            parse_quote! {
100                fn test(self: Pin<&mut T>);
101            },
102            Some("TestBaseClass"),
103        )
104        .unwrap();
105
106        assert_generated_eq(
107            indoc::indoc! {"
108                template <class... Args>
109                void testCxxQtInherit(Args ...args)
110                {
111                    return TestBaseClass::test(args...);
112                }"
113            },
114            &generated,
115        );
116    }
117
118    #[test]
119    fn test_default_base_class() {
120        let generated = generate_from_foreign(
121            parse_quote! {
122                fn test(self: &T);
123            },
124            None,
125        )
126        .unwrap();
127
128        assert_generated_eq(
129            indoc::indoc! {"
130                template <class... Args>
131                void testCxxQtInherit(Args ...args) const
132                {
133                    return QObject::test(args...);
134                }"
135            },
136            &generated,
137        );
138    }
139}