Akonadi

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

KDE's Doxygen guidelines are available online.