Akonadi

cppgenerator.cpp
1/*
2 SPDX-FileCopyrightText: 2017 Daniel Vrátil <dvratil@kde.og>
3
4 SPDX-License-Identifier: LGPL-2.0-or-later
5*/
6
7#include "cppgenerator.h"
8#include "cpphelper.h"
9#include "nodetree.h"
10#include "typehelper.h"
11
12#include <QDebug>
13
14#include <iostream>
15
16CppGenerator::CppGenerator()
17{
18}
19
20CppGenerator::~CppGenerator()
21{
22}
23
24bool CppGenerator::generate(Node const *node)
25{
26 Q_ASSERT(node->type() == Node::Document);
27
28 mHeaderFile.setFileName(QStringLiteral("protocol_gen.h"));
29 if (!mHeaderFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
30 std::cerr << qPrintable(mHeaderFile.errorString()) << std::endl;
31 return false;
32 }
33 mHeader.setDevice(&mHeaderFile);
34
35 mImplFile.setFileName(QStringLiteral("protocol_gen.cpp"));
36 if (!mImplFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
37 std::cerr << qPrintable(mImplFile.errorString()) << std::endl;
38 return false;
39 }
40 mImpl.setDevice(&mImplFile);
41
42 return generateDocument(static_cast<DocumentNode const *>(node));
43}
44
45void CppGenerator::writeHeaderHeader(DocumentNode const *node)
46{
47 mHeader << "// This is an auto-generated file.\n"
48 "// Any changes to this file will be overwritten\n"
49 "\n"
50 "// clazy:excludeall=function-args-by-value\n"
51 "\n"
52 "namespace Akonadi {\n"
53 "namespace Protocol {\n"
54 "\n"
55 "AKONADIPRIVATE_EXPORT int version();\n"
56 "\n";
57
58 // Forward declarations
59 for (const auto *child : std::as_const(node->children())) {
60 if (child->type() == Node::Class) {
61 mHeader << "class " << static_cast<const ClassNode *>(child)->className() << ";\n";
62 }
63 }
64
65 mHeader << "\n"
66 "} // namespace Protocol\n"
67 "} // namespace Akonadi\n\n";
68}
69
70void CppGenerator::writeHeaderFooter(DocumentNode const * /*node*/)
71{
72 // Nothing to do
73}
74
75void CppGenerator::writeImplHeader(DocumentNode const *node)
76{
77 mImpl << "// This is an auto-generated file.\n"
78 "// Any changes to this file will be overwritten\n"
79 "\n"
80 "// clazy:excludeall=function-args-by-value\n"
81 "\n"
82 "namespace Akonadi {\n"
83 "namespace Protocol {\n"
84 "\n"
85 "int version()\n"
86 "{\n"
87 " return "
88 << node->version()
89 << ";\n"
90 "}\n"
91 "\n";
92}
93
94void CppGenerator::writeImplFooter(DocumentNode const * /*unused*/)
95{
96 mImpl << "} // namespace Protocol\n"
97 "} // namespace Akonadi\n";
98}
99
100bool CppGenerator::generateDocument(DocumentNode const *node)
101{
102 writeHeaderHeader(node);
103 writeImplHeader(node);
104
105 writeImplSerializer(node);
106
107 for (const auto *classNode : node->children()) {
108 if (!generateClass(static_cast<ClassNode const *>(classNode))) {
109 return false;
110 }
111 }
112
113 writeHeaderFooter(node);
114 writeImplFooter(node);
115
116 return true;
117}
118
119void CppGenerator::writeImplSerializer(DocumentNode const *node)
120{
121 mImpl << "void serialize(DataStream &stream, const CommandPtr &cmd)\n"
122 "{\n"
123 " switch (static_cast<int>(cmd->type() | (cmd->isResponse() ? Command::_ResponseBit : 0))) {\n"
124 " case Command::Invalid:\n"
125 " stream << cmdCast<Command>(cmd);\n"
126 " break;\n"
127 " case Command::Invalid | Command::_ResponseBit:\n"
128 " stream << cmdCast<Response>(cmd);\n"
129 " break;\n";
130 for (const auto *child : std::as_const(node->children())) {
131 const auto *classNode = static_cast<ClassNode const *>(child);
132 if (classNode->classType() == ClassNode::Response) {
133 mImpl << " case Command::" << classNode->name()
134 << " | Command::_ResponseBit:\n"
135 " stream << cmdCast<"
136 << classNode->className()
137 << ">(cmd);\n"
138 " break;\n";
139 } else if (classNode->classType() == ClassNode::Command) {
140 mImpl << " case Command::" << classNode->name()
141 << ":\n"
142 " stream << cmdCast<"
143 << classNode->className()
144 << ">(cmd);\n"
145 " break;\n";
146 } else if (classNode->classType() == ClassNode::Notification) {
147 mImpl << " case Command::" << classNode->name()
148 << "Notification:\n"
149 " stream << cmdCast<"
150 << classNode->className()
151 << ">(cmd);\n"
152 " break;\n";
153 }
154 }
155 mImpl << " }\n"
156 "}\n\n";
157
158 mImpl << "CommandPtr deserialize(QIODevice *device)\n"
159 "{\n"
160 " DataStream stream(device);\n"
161 " stream.waitForData(sizeof(Command::Type));\n"
162 " Command::Type cmdType;\n"
163 " if (Q_UNLIKELY(device->peek((char *) &cmdType, sizeof(Command::Type)) != sizeof(Command::Type))) {\n"
164 " throw ProtocolException(\"Failed to peek command type\");\n"
165 " }\n"
166 " CommandPtr cmd;\n"
167 " if (cmdType & Command::_ResponseBit) {\n"
168 " cmd = Factory::response(Command::Type(cmdType & ~Command::_ResponseBit));\n"
169 " } else {\n"
170 " cmd = Factory::command(cmdType);\n"
171 " }\n\n"
172 " switch (static_cast<int>(cmdType)) {\n"
173 " case Command::Invalid:\n"
174 " stream >> cmdCast<Command>(cmd);\n"
175 " return cmd;\n"
176 " case Command::Invalid | Command::_ResponseBit:\n"
177 " stream >> cmdCast<Response>(cmd);\n"
178 " return cmd;\n";
179 for (const auto *child : std::as_const(node->children())) {
180 const auto *classNode = static_cast<ClassNode const *>(child);
181 if (classNode->classType() == ClassNode::Response) {
182 mImpl << " case Command::" << classNode->name()
183 << " | Command::_ResponseBit:\n"
184 " stream >> cmdCast<"
185 << classNode->className()
186 << ">(cmd);\n"
187 " return cmd;\n";
188 } else if (classNode->classType() == ClassNode::Command) {
189 mImpl << " case Command::" << classNode->name()
190 << ":\n"
191 " stream >> cmdCast<"
192 << classNode->className()
193 << ">(cmd);\n"
194 " return cmd;\n";
195 } else if (classNode->classType() == ClassNode::Notification) {
196 mImpl << " case Command::" << classNode->name()
197 << "Notification:\n"
198 " stream >> cmdCast<"
199 << classNode->className()
200 << ">(cmd);\n"
201 " return cmd;\n";
202 }
203 }
204 mImpl << " }\n"
205 " return CommandPtr::create();\n"
206 "}\n"
207 "\n";
208
209 mImpl << "QString debugString(const Command &cmd)\n"
210 "{\n"
211 " QString out;\n"
212 " switch (static_cast<int>(cmd.type() | (cmd.isResponse() ? Command::_ResponseBit : 0))) {\n"
213 " case Command::Invalid:\n"
214 " QDebug(&out).noquote() << static_cast<const Command &>(cmd);\n"
215 " return out;\n"
216 " case Command::Invalid | Command::_ResponseBit:\n"
217 " QDebug(&out).noquote() << static_cast<const Response &>(cmd);\n"
218 " return out;\n";
219 for (const auto *child : std::as_const(node->children())) {
220 const auto *classNode = static_cast<ClassNode const *>(child);
221 if (classNode->classType() == ClassNode::Response) {
222 mImpl << " case Command::" << classNode->name()
223 << " | Command::_ResponseBit:\n"
224 " QDebug(&out).noquote() << static_cast<const "
225 << classNode->className()
226 << " &>(cmd);\n"
227 " return out;\n";
228 } else if (classNode->classType() == ClassNode::Command) {
229 mImpl << " case Command::" << classNode->name()
230 << ":\n"
231 " QDebug(&out).noquote() << static_cast<const "
232 << classNode->className()
233 << " &>(cmd);\n"
234 " return out;\n";
235 } else if (classNode->classType() == ClassNode::Notification) {
236 mImpl << " case Command::" << classNode->name()
237 << "Notification:\n"
238 " QDebug(&out).noquote() << static_cast<const "
239 << classNode->className()
240 << " &>(cmd);\n"
241 " return out;\n";
242 }
243 }
244 mImpl << " }\n"
245 " return QString();\n"
246 "}\n"
247 "\n";
248}
249
250void CppGenerator::writeHeaderEnum(EnumNode const *node)
251{
252 mHeader << " enum " << node->name() << " {\n";
253 for (const auto *enumChild : node->children()) {
254 Q_ASSERT(enumChild->type() == Node::EnumValue);
255 const auto *const valueNode = static_cast<EnumValueNode const *>(enumChild);
256 mHeader << " " << valueNode->name();
257 if (!valueNode->value().isEmpty()) {
258 mHeader << " = " << valueNode->value();
259 }
260 mHeader << ",\n";
261 }
262 mHeader << " };\n";
263 if (node->enumType() == EnumNode::TypeFlag) {
264 mHeader << " Q_DECLARE_FLAGS(" << node->name() << "s, " << node->name() << ")\n\n";
265 }
266}
267
268void CppGenerator::writeHeaderClass(ClassNode const *node)
269{
270 // Begin class
271 const QString parentClass = node->parentClassName();
272 const bool isTypeClass = node->classType() == ClassNode::Class;
273
274 mHeader << "namespace Akonadi {\n"
275 "namespace Protocol {\n\n"
276 "AKONADIPRIVATE_EXPORT DataStream &operator<<(DataStream &stream, const "
277 << node->className()
278 << " &obj);\n"
279 "AKONADIPRIVATE_EXPORT DataStream &operator>>(DataStream &stream, "
280 << node->className()
281 << " &obj);\n"
282 "AKONADIPRIVATE_EXPORT QDebug operator<<(QDebug dbg, const "
283 << node->className()
284 << " &obj);\n"
285 "\n"
286 "using "
287 << node->className() << "Ptr = QSharedPointer<" << node->className()
288 << ">;\n"
289 "\n";
290 if (isTypeClass) {
291 mHeader << "class AKONADIPRIVATE_EXPORT " << node->className() << "\n";
292 } else {
293 mHeader << "class AKONADIPRIVATE_EXPORT " << node->className() << " : public " << parentClass << "\n";
294 }
295 mHeader << "{\n\n"
296 "public:\n";
297
298 // Enums
299 for (const auto *child : node->children()) {
300 if (child->type() == Node::Enum) {
301 const auto *const enumNode = static_cast<EnumNode const *>(child);
302 writeHeaderEnum(enumNode);
303 }
304 }
305
306 // Ctors, dtor
307 for (const auto *child : std::as_const(node->children())) {
308 if (child->type() == Node::Ctor) {
309 const auto *const ctor = static_cast<const CtorNode *>(child);
310 const auto args = ctor->arguments();
311 mHeader << " explicit " << node->className() << "(";
312 for (int i = 0; i < args.count(); ++i) {
313 const auto &arg = args[i];
314 if (TypeHelper::isNumericType(arg.type) || TypeHelper::isBoolType(arg.type)) {
315 mHeader << arg.type << " " << arg.name;
316 } else {
317 mHeader << "const " << arg.type << " &" << arg.name;
318 }
319 if (!arg.defaultValue.isEmpty()) {
320 mHeader << " = " << arg.defaultValue;
321 }
322 if (i < args.count() - 1) {
323 mHeader << ", ";
324 }
325 }
326 mHeader << ");\n";
327 }
328 }
329
330 mHeader << " " << node->className() << "(const " << node->className()
331 << " &) = default;\n"
332 " "
333 << node->className() << "(" << node->className()
334 << " &&) = default;\n"
335 " ~"
336 << node->className()
337 << "() = default;\n"
338 "\n"
339 " "
340 << node->className() << " &operator=(const " << node->className()
341 << " &) = default;\n"
342 " "
343 << node->className() << " &operator=(" << node->className()
344 << " &&) = default;\n"
345 " bool operator==(const "
346 << node->className()
347 << " &other) const;\n"
348 " inline bool operator!=(const "
349 << node->className() << " &other) const { return !operator==(other); }\n";
350
351 // Properties
352 for (const auto *child : node->children()) {
353 if (child->type() == Node::Property) {
354 const auto *const prop = static_cast<PropertyNode const *>(child);
355 if (prop->asReference()) {
356 mHeader << " inline const " << prop->type() << " &" << prop->name() << "() const { return " << prop->mVariableName()
357 << "; }\n"
358 " inline "
359 << prop->type() << " &" << prop->name() << "() { return " << prop->mVariableName() << "; }\n";
360 } else {
361 mHeader << " inline " << prop->type() << " " << prop->name() << "() const { return " << prop->mVariableName() << "; }\n";
362 }
363 if (!prop->readOnly()) {
364 if (auto *setter = prop->setter()) {
365 mHeader << " void " << setter->name << "(const " << setter->type << " &" << prop->name() << ");\n";
366 } else if (!prop->dependencies().isEmpty()) {
367 QString varType;
368 if (TypeHelper::isNumericType(prop->type()) || TypeHelper::isBoolType(prop->type())) {
369 varType = QLatin1Char('(') + prop->type() + QLatin1Char(' ');
370 } else {
371 varType = QLatin1StringView("(const ") + prop->type() + QLatin1StringView(" &");
372 }
373 mHeader << " void " << prop->setterName() << varType << prop->name() << ");\n";
374 } else {
375 QString varType;
376 if (TypeHelper::isNumericType(prop->type()) || TypeHelper::isBoolType(prop->type())) {
377 varType = QLatin1Char('(') + prop->type() + QLatin1Char(' ');
378 } else {
379 varType = QLatin1StringView("(const ") + prop->type() + QLatin1StringView(" &");
380 }
381 mHeader << " inline void " << prop->setterName() << varType << prop->name() << ") { " << prop->mVariableName() << " = " << prop->name()
382 << "; }\n";
383 if (!TypeHelper::isNumericType(prop->type()) && !TypeHelper::isBoolType(prop->type())) {
384 mHeader << " inline void " << prop->setterName() << "(" << prop->type() << " &&" << prop->name() << ") { " << prop->mVariableName()
385 << " = std::move(" << prop->name() << "); }\n";
386 }
387 }
388 }
389 mHeader << "\n";
390 }
391 }
392 mHeader << " void toJson(QJsonObject &stream) const;\n";
393
394 // End of class
395 mHeader << "protected:\n";
396 const auto properties = node->properties();
397 for (const auto *prop : properties) {
398 mHeader << " " << prop->type() << " " << prop->mVariableName();
399 const auto defaultValue = prop->defaultValue();
400 const bool isDefaultValue = !defaultValue.isEmpty();
401 const bool isNumeric = TypeHelper::isNumericType(prop->type());
402 const bool isBool = TypeHelper::isBoolType(prop->type());
403 if (isDefaultValue) {
404 mHeader << " = " << defaultValue;
405 } else if (isNumeric) {
406 mHeader << " = 0";
407 } else if (isBool) {
408 mHeader << " = false";
409 }
410 mHeader << ";\n";
411 }
412
413 mHeader << "\n"
414 "private:\n"
415 " friend AKONADIPRIVATE_EXPORT Akonadi::Protocol::DataStream &operator<<(Akonadi::Protocol::DataStream &stream, const Akonadi::Protocol::"
416 << node->className()
417 << " &obj);\n"
418 " friend AKONADIPRIVATE_EXPORT Akonadi::Protocol::DataStream &operator>>(Akonadi::Protocol::DataStream &stream, Akonadi::Protocol::"
419 << node->className()
420 << " &obj);\n"
421 " friend AKONADIPRIVATE_EXPORT QDebug operator<<(QDebug dbg, const Akonadi::Protocol::"
422 << node->className()
423 << " &obj);\n"
424 "};\n\n"
425 "} // namespace Protocol\n"
426 "} // namespace Akonadi\n"
427 "\n";
428 mHeader << "Q_DECLARE_METATYPE(Akonadi::Protocol::" << node->className() << ")\n\n";
429 if (node->classType() != ClassNode::Class) {
430 mHeader << "Q_DECLARE_METATYPE(Akonadi::Protocol::" << node->className() << "Ptr)\n\n";
431 }
432}
433
434void CppGenerator::writeImplSerializer(PropertyNode const *node, const char *streamingOperator)
435{
436 const auto deps = node->dependencies();
437 if (deps.isEmpty()) {
438 mImpl << " stream " << streamingOperator << " obj." << node->mVariableName() << ";\n";
439 } else {
440 mImpl << " if (";
441 auto it = deps.cend();
442 while (1 + 1 == 2) {
443 --it;
444 const QString mVar = it.key();
445 mImpl << "(obj."
446 << "m" << mVar[0].toUpper() << QStringView(mVar).mid(1) << " & " << it.value() << ")";
447 if (it == deps.cbegin()) {
448 break;
449 } else {
450 mImpl << " && ";
451 }
452 }
453 mImpl << ") {\n"
454 " stream "
455 << streamingOperator << " obj." << node->mVariableName()
456 << ";\n"
457 " }\n";
458 }
459}
460
461void CppGenerator::writeImplClass(ClassNode const *node)
462{
463 const QString parentClass = node->parentClassName();
464 const auto &children = node->children();
465 const auto properties = node->properties();
466
467 // Ctors
468 for (const auto *child : children) {
469 if (child->type() == Node::Ctor) {
470 const auto *const ctor = static_cast<CtorNode const *>(child);
471 const auto args = ctor->arguments();
472 mImpl << node->className() << "::" << node->className() << "(";
473 for (int i = 0; i < args.count(); ++i) {
474 const auto &arg = args[i];
475 if (TypeHelper::isNumericType(arg.type) || TypeHelper::isBoolType(arg.type)) {
476 mImpl << arg.type << " " << arg.name;
477 } else {
478 mImpl << "const " << arg.type << " &" << arg.name;
479 }
480 if (i < args.count() - 1) {
481 mImpl << ", ";
482 }
483 }
484 mImpl << ")\n";
485 char startChar = ',';
486 if (!parentClass.isEmpty()) {
487 const QString type = node->name() + ((node->classType() == ClassNode::Notification) ? QStringLiteral("Notification") : QString());
488 mImpl << " : " << parentClass << "(Command::" << type << ")\n";
489 } else {
490 startChar = ':';
491 }
492 for (const auto *prop : properties) {
493 auto arg = std::find_if(args.cbegin(), args.cend(), [prop](const CtorNode::Argument &arg) {
494 return arg.name == prop->name();
495 });
496 if (arg != args.cend()) {
497 mImpl << " " << startChar << " " << prop->mVariableName() << "(" << arg->name << ")\n";
498 startChar = ',';
499 }
500 }
501 mImpl << "{\n"
502 "}\n"
503 "\n";
504 }
505 }
506
507 // Comparison operator
508 mImpl << "bool " << node->className() << "::operator==(const " << node->className()
509 << " &other) const\n"
510 "{\n";
511 mImpl << " return true // simplifies generation\n";
512 if (!parentClass.isEmpty()) {
513 mImpl << " && " << parentClass << "::operator==(other)\n";
514 }
515 for (const auto *prop : properties) {
516 if (prop->isPointer()) {
517 mImpl << " && *" << prop->mVariableName() << " == *other." << prop->mVariableName() << "\n";
518 } else if (TypeHelper::isContainer(prop->type())) {
519 mImpl << " && containerComparator(" << prop->mVariableName() << ", other." << prop->mVariableName() << ")\n";
520 } else {
521 mImpl << " && " << prop->mVariableName() << " == other." << prop->mVariableName() << "\n";
522 }
523 }
524 mImpl << " ;\n"
525 "}\n"
526 "\n";
527
528 // non-trivial setters
529 for (const auto *prop : properties) {
530 if (prop->readOnly()) {
531 continue;
532 }
533
534 if (auto *const setter = prop->setter()) {
535 mImpl << "void " << node->className() << "::" << setter->name << "(const " << setter->type
536 << " &val)\n"
537 "{\n";
538 if (!setter->append.isEmpty()) {
539 mImpl << " m" << setter->append[0].toUpper() << QStringView(setter->append).mid(1) << " << val;\n";
540 }
541 if (!setter->remove.isEmpty()) {
542 const QString mVar = QLatin1StringView("m") + setter->remove[0].toUpper() + QStringView(setter->remove).mid(1);
543 mImpl << " auto it = std::find(" << mVar << ".begin(), " << mVar
544 << ".end(), val);\n"
545 " if (it != "
546 << mVar
547 << ".end()) {\n"
548 " "
549 << mVar
550 << ".erase(it);\n"
551 " }\n";
552 }
553 writeImplPropertyDependencies(prop);
554 mImpl << "}\n\n";
555 } else if (!prop->dependencies().isEmpty()) {
556 if (TypeHelper::isNumericType(prop->type()) || TypeHelper::isBoolType(prop->type())) {
557 mImpl << "void " << node->className() << "::" << prop->setterName() << "(" << prop->type()
558 << " val)\n"
559 "{\n"
560 " "
561 << prop->mVariableName() << " = val;\n";
562
563 } else {
564 mImpl << "void " << node->className() << "::" << prop->setterName() << "(const " << prop->type()
565 << " &val)\n"
566 "{\n"
567 " "
568 << prop->mVariableName() << " = val;\n";
569 }
570 writeImplPropertyDependencies(prop);
571 mImpl << "}\n\n";
572 }
573 }
574
575 // serialize
576 auto serializeProperties = properties;
577 CppHelper::sortMembersForSerialization(serializeProperties);
578
579 mImpl << "DataStream &operator<<(DataStream &stream, const " << node->className()
580 << " &obj)\n"
581 "{\n";
582 if (!parentClass.isEmpty()) {
583 mImpl << " stream << static_cast<const " << parentClass << " &>(obj);\n";
584 }
585 for (const auto *prop : std::as_const(serializeProperties)) {
586 writeImplSerializer(prop, "<<");
587 }
588 mImpl << " return stream;\n"
589 "}\n"
590 "\n";
591
592 // deserialize
593 mImpl << "DataStream &operator>>(DataStream &stream, " << node->className()
594 << " &obj)\n"
595 "{\n";
596 if (!parentClass.isEmpty()) {
597 mImpl << " stream >> static_cast<" << parentClass << " &>(obj);\n";
598 }
599 for (const auto *prop : std::as_const(serializeProperties)) {
600 writeImplSerializer(prop, ">>");
601 }
602 mImpl << " return stream;\n"
603 "}\n"
604 "\n";
605
606 // debug
607 mImpl << "QDebug operator<<(QDebug dbg, const " << node->className()
608 << " &obj)\n"
609 "{\n";
610 if (!parentClass.isEmpty()) {
611 mImpl << " dbg.noquote() << static_cast<const " << parentClass << " &>(obj)\n";
612 } else {
613 mImpl << " dbg.noquote()\n";
614 }
615
616 for (const auto *prop : std::as_const(serializeProperties)) {
617 if (prop->isPointer()) {
618 mImpl << " << \"" << prop->name() << ":\" << *obj." << prop->mVariableName() << " << \"\\n\"\n";
619 } else if (TypeHelper::isContainer(prop->type())) {
620 mImpl << " << \"" << prop->name()
621 << ": [\\n\";\n"
622 " for (const auto &type : std::as_const(obj."
623 << prop->mVariableName()
624 << ")) {\n"
625 " dbg.noquote() << \" \" << ";
626 if (TypeHelper::isPointerType(TypeHelper::containerType(prop->type()))) {
627 mImpl << "*type";
628 } else {
629 mImpl << "type";
630 }
631 mImpl << " << \"\\n\";\n"
632 " }\n"
633 " dbg.noquote() << \"]\\n\"\n";
634 } else {
635 mImpl << " << \"" << prop->name() << ":\" << obj." << prop->mVariableName() << " << \"\\n\"\n";
636 }
637 }
638 mImpl << " ;\n"
639 " return dbg;\n"
640 "}\n"
641 "\n";
642
643 // toJson
644 mImpl << "void " << node->className()
645 << "::toJson(QJsonObject &json) const\n"
646 "{\n";
647 if (!parentClass.isEmpty()) {
648 mImpl << " static_cast<const " << parentClass << " *>(this)->toJson(json);\n";
649 } else if (serializeProperties.isEmpty()) {
650 mImpl << " Q_UNUSED(json)\n";
651 }
652 for (const auto *prop : std::as_const(serializeProperties)) {
653 if (prop->isPointer()) {
654 mImpl << " {\n"
655 " QJsonObject jsonObject;\n"
656 " "
657 << prop->mVariableName()
658 << "->toJson(jsonObject);\n"
659 " json[QStringLiteral(\""
660 << prop->name()
661 << "\")] = jsonObject;\n"
662 " }\n";
663 } else if (TypeHelper::isContainer(prop->type())) {
664 const auto &containerType = TypeHelper::containerType(prop->type());
665 mImpl << " {\n"
666 " QJsonArray jsonArray;\n"
667 " for (const auto &type : std::as_const("
668 << prop->mVariableName() << ")) {\n";
669 if (TypeHelper::isPointerType(containerType)) {
670 mImpl << " QJsonObject jsonObject;\n"
671 " type->toJson(jsonObject); /* "
672 << containerType
673 << " */\n"
674 " jsonArray.append(jsonObject);\n";
675 } else if (TypeHelper::isNumericType(containerType) || TypeHelper::isBoolType(containerType)) {
676 mImpl << " jsonArray.append(type); /* " << containerType << " */\n";
677 } else if (containerType == QLatin1StringView("QByteArray")) {
678 mImpl << " jsonArray.append(QString::fromUtf8(type)); /* " << containerType << "*/\n";
679 } else if (TypeHelper::isBuiltInType(containerType)) {
680 if (TypeHelper::containerType(prop->type()) == QLatin1StringView("Akonadi::Protocol::ChangeNotification::Relation")) {
681 mImpl << " QJsonObject jsonObject;\n"
682 " type.toJson(jsonObject); /* "
683 << containerType
684 << " */\n"
685 " jsonArray.append(jsonObject);\n";
686 } else {
687 mImpl << " jsonArray.append(type); /* " << containerType << " */\n";
688 }
689 } else {
690 mImpl << " QJsonObject jsonObject;\n"
691 " type.toJson(jsonObject); /* "
692 << containerType
693 << " */\n"
694 " jsonArray.append(jsonObject);\n";
695 }
696 mImpl << " }\n"
697 << " json[QStringLiteral(\"" << prop->name() << "\")] = jsonArray;\n"
698 << " }\n";
699 } else if (prop->type() == QLatin1StringView("uint")) {
700 mImpl << " json[QStringLiteral(\"" << prop->name() << "\")] = static_cast<int>(" << prop->mVariableName() << ");/* " << prop->type() << " */\n";
701 } else if (TypeHelper::isNumericType(prop->type()) || TypeHelper::isBoolType(prop->type())) {
702 mImpl << " json[QStringLiteral(\"" << prop->name() << "\")] = " << prop->mVariableName() << ";/* " << prop->type() << " */\n";
703 } else if (TypeHelper::isBuiltInType(prop->type())) {
704 if (prop->type() == QLatin1StringView("QStringList")) {
705 mImpl << " json[QStringLiteral(\"" << prop->name() << "\")] = QJsonArray::fromStringList(" << prop->mVariableName() << ");/* "
706 << prop->type() << " */\n";
707 } else if (prop->type() == QLatin1StringView("QDateTime")) {
708 mImpl << " json[QStringLiteral(\"" << prop->name() << "\")] = " << prop->mVariableName() << ".toString()/* " << prop->type() << " */;\n";
709 } else if (prop->type() == QLatin1StringView("QByteArray")) {
710 mImpl << " json[QStringLiteral(\"" << prop->name() << "\")] = QString::fromUtf8(" << prop->mVariableName() << ")/* " << prop->type()
711 << " */;\n";
712 } else if (prop->type() == QLatin1StringView("Scope")) {
713 mImpl << " {\n"
714 " QJsonObject jsonObject;\n"
715 " "
716 << prop->mVariableName() << ".toJson(jsonObject); /* " << prop->type()
717 << " */\n"
718 " json[QStringLiteral(\""
719 << prop->name() << "\")] = "
720 << "jsonObject;\n"
721 " }\n";
722 } else if (prop->type() == QLatin1StringView("Tristate")) {
723 mImpl << " switch (" << prop->mVariableName()
724 << ") {\n;"
725 " case Tristate::True:\n"
726 " json[QStringLiteral(\""
727 << prop->name()
728 << "\")] = QStringLiteral(\"True\");\n"
729 " break;\n"
730 " case Tristate::False:\n"
731 " json[QStringLiteral(\""
732 << prop->name()
733 << "\")] = QStringLiteral(\"False\");\n"
734 " break;\n"
735 " case Tristate::Undefined:\n"
736 " json[QStringLiteral(\""
737 << prop->name()
738 << "\")] = QStringLiteral(\"Undefined\");\n"
739 " break;\n"
740 " }\n";
741 } else if (prop->type() == QLatin1StringView("Akonadi::Protocol::Attributes")) {
742 mImpl << " {\n"
743 " QJsonObject jsonObject;\n"
744 " auto i = "
745 << prop->mVariableName()
746 << ".constBegin();\n"
747 " const auto &end = "
748 << prop->mVariableName()
749 << ".constEnd();\n"
750 " while (i != end) {\n"
751 " jsonObject[QString::fromUtf8(i.key())] = QString::fromUtf8(i.value());\n"
752 " ++i;\n"
753 " }\n"
754 " json[QStringLiteral(\""
755 << prop->name()
756 << "\")] = jsonObject;\n"
757 " }\n";
758 } else if (prop->isEnum()) {
759 mImpl << " json[QStringLiteral(\"" << prop->name() << "\")] = static_cast<int>(" << prop->mVariableName() << ");/* " << prop->type()
760 << "*/\n";
761 } else {
762 mImpl << " json[QStringLiteral(\"" << prop->name() << "\")] = " << prop->mVariableName() << ";/* " << prop->type() << "*/\n";
763 }
764 } else {
765 mImpl << " {\n"
766 " QJsonObject jsonObject;\n"
767 " "
768 << prop->mVariableName() << ".toJson(jsonObject); /* " << prop->type()
769 << " */\n"
770 " json[QStringLiteral(\""
771 << prop->name()
772 << "\")] = jsonObject;\n"
773 " }\n";
774 }
775 }
776 mImpl << "}\n"
777 "\n";
778}
779
780void CppGenerator::writeImplPropertyDependencies(const PropertyNode *node)
781{
782 const auto deps = node->dependencies();
783 QString key;
784 QStringList values;
785 QString enumType;
786 for (auto it = deps.cbegin(), end = deps.cend(); it != end; ++it) {
787 if (key != it.key()) {
788 key = it.key();
789 const auto children = node->parent()->children();
790 for (const auto *child : children) {
791 if (child->type() == Node::Property && child != node) {
792 const auto *prop = static_cast<const PropertyNode *>(child);
793 if (prop->name() == key) {
794 enumType = prop->type();
795 break;
796 }
797 }
798 }
799 if (!values.isEmpty()) {
800 mImpl << " m" << key[0].toUpper() << QStringView(key).mid(1) << " |= " << enumType << "(" << values.join(QLatin1StringView(" | ")) << ");\n";
801 values.clear();
802 }
803 }
804 values << *it;
805 }
806
807 if (!values.isEmpty()) {
808 mImpl << " m" << key[0].toUpper() << QStringView(key).mid(1) << " |= " << enumType << "(" << values.join(QLatin1StringView(" | ")) << ");\n";
809 }
810}
811
812bool CppGenerator::generateClass(ClassNode const *node)
813{
814 writeHeaderClass(node);
815
816 mImpl << "\n\n/************************* " << node->className() << " *************************/\n\n";
817 writeImplClass(node);
818
819 return true;
820}
virtual QString type() const
Definition nodetree.cpp:47
VehicleSection::Type type(QStringView coachNumber, QStringView coachClassification)
KGuiItem properties()
void clear()
bool isEmpty() const const
bool isEmpty() const const
QString mid(qsizetype position, qsizetype n) const const
QString & remove(QChar ch, Qt::CaseSensitivity cs)
QString toUpper() const const
QString join(QChar separator) const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2025 The KDE developers.
Generated on Fri Jan 24 2025 11:49:57 by doxygen 1.13.2 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.