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"));
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()
bool open(FILE *fh, OpenMode mode, FileHandleFlags handleFlags)
void setFileName(const QString &name)
QString errorString() const const
void clear()
bool isEmpty() const const
bool isEmpty() const const
QString toUpper() const const
QString join(QChar separator) const const
QStringView mid(qsizetype start, qsizetype length) const const
void setDevice(QIODevice *device)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri Nov 29 2024 11:49:12 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.