7 #include "cppgenerator.h"
10 #include "typehelper.h"
16 CppGenerator::CppGenerator()
20 CppGenerator::~CppGenerator()
24 bool CppGenerator::generate(
Node const *node)
26 Q_ASSERT(node->
type() == Node::Document);
28 mHeaderFile.setFileName(QStringLiteral(
"protocol_gen.h"));
30 std::cerr << qPrintable(mHeaderFile.errorString()) << std::endl;
33 mHeader.setDevice(&mHeaderFile);
35 mImplFile.setFileName(QStringLiteral(
"protocol_gen.cpp"));
37 std::cerr << qPrintable(mImplFile.errorString()) << std::endl;
40 mImpl.setDevice(&mImplFile);
42 return generateDocument(
static_cast<DocumentNode
const *
>(node));
45 void CppGenerator::writeHeaderHeader(DocumentNode
const *node)
47 mHeader <<
"// This is an auto-generated file.\n"
48 "// Any changes to this file will be overwritten\n"
50 "// clazy:excludeall=function-args-by-value\n"
52 "namespace Akonadi {\n"
53 "namespace Protocol {\n"
55 "AKONADIPRIVATE_EXPORT int version();\n"
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";
66 "} // namespace Protocol\n"
67 "} // namespace Akonadi\n\n";
70 void CppGenerator::writeHeaderFooter(DocumentNode
const * )
75 void CppGenerator::writeImplHeader(DocumentNode
const *node)
77 mImpl <<
"// This is an auto-generated file.\n"
78 "// Any changes to this file will be overwritten\n"
80 "// clazy:excludeall=function-args-by-value\n"
82 "namespace Akonadi {\n"
83 "namespace Protocol {\n"
94 void CppGenerator::writeImplFooter(DocumentNode
const * )
96 mImpl <<
"} // namespace Protocol\n"
97 "} // namespace Akonadi\n";
100 bool CppGenerator::generateDocument(DocumentNode
const *node)
102 writeHeaderHeader(node);
103 writeImplHeader(node);
105 writeImplSerializer(node);
107 for (
const auto *classNode : node->children()) {
108 if (!generateClass(
static_cast<ClassNode
const *
>(classNode))) {
113 writeHeaderFooter(node);
114 writeImplFooter(node);
119 void CppGenerator::writeImplSerializer(DocumentNode
const *node)
121 mImpl <<
"void serialize(DataStream &stream, const CommandPtr &cmd)\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"
127 " case Command::Invalid | Command::_ResponseBit:\n"
128 " stream << cmdCast<Response>(cmd);\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()
139 }
else if (classNode->classType() == ClassNode::Command) {
140 mImpl <<
" case Command::" << classNode->name()
142 " stream << cmdCast<"
143 << classNode->className()
146 }
else if (classNode->classType() == ClassNode::Notification) {
147 mImpl <<
" case Command::" << classNode->name()
149 " stream << cmdCast<"
150 << classNode->className()
158 mImpl <<
"CommandPtr deserialize(QIODevice *device)\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"
167 " if (cmdType & Command::_ResponseBit) {\n"
168 " cmd = Factory::response(Command::Type(cmdType & ~Command::_ResponseBit));\n"
170 " cmd = Factory::command(cmdType);\n"
172 " switch (static_cast<int>(cmdType)) {\n"
173 " case Command::Invalid:\n"
174 " stream >> cmdCast<Command>(cmd);\n"
176 " case Command::Invalid | Command::_ResponseBit:\n"
177 " stream >> cmdCast<Response>(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()
188 }
else if (classNode->classType() == ClassNode::Command) {
189 mImpl <<
" case Command::" << classNode->name()
191 " stream >> cmdCast<"
192 << classNode->className()
195 }
else if (classNode->classType() == ClassNode::Notification) {
196 mImpl <<
" case Command::" << classNode->name()
198 " stream >> cmdCast<"
199 << classNode->className()
205 " return CommandPtr::create();\n"
209 mImpl <<
"QString debugString(const Command &cmd)\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"
216 " case Command::Invalid | Command::_ResponseBit:\n"
217 " QDebug(&out).noquote() << static_cast<const Response &>(cmd);\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()
228 }
else if (classNode->classType() == ClassNode::Command) {
229 mImpl <<
" case Command::" << classNode->name()
231 " QDebug(&out).noquote() << static_cast<const "
232 << classNode->className()
235 }
else if (classNode->classType() == ClassNode::Notification) {
236 mImpl <<
" case Command::" << classNode->name()
238 " QDebug(&out).noquote() << static_cast<const "
239 << classNode->className()
245 " return QString();\n"
250 void CppGenerator::writeHeaderEnum(EnumNode
const *node)
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();
263 if (node->enumType() == EnumNode::TypeFlag) {
264 mHeader <<
" Q_DECLARE_FLAGS(" << node->name() <<
"s, " << node->name() <<
")\n\n";
268 void CppGenerator::writeHeaderClass(ClassNode
const *node)
271 const QString parentClass = node->parentClassName();
272 const bool isTypeClass = node->classType() == ClassNode::Class;
274 mHeader <<
"namespace Akonadi {\n"
275 "namespace Protocol {\n\n"
276 "AKONADIPRIVATE_EXPORT DataStream &operator<<(DataStream &stream, const "
279 "AKONADIPRIVATE_EXPORT DataStream &operator>>(DataStream &stream, "
282 "AKONADIPRIVATE_EXPORT QDebug operator<<(QDebug dbg, const "
287 << node->className() <<
"Ptr = QSharedPointer<" << node->className()
291 mHeader <<
"class AKONADIPRIVATE_EXPORT " << node->className() <<
"\n";
293 mHeader <<
"class AKONADIPRIVATE_EXPORT " << node->className() <<
" : public " << parentClass <<
"\n";
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);
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;
317 mHeader <<
"const " << arg.type <<
" &" << arg.name;
319 if (!arg.defaultValue.isEmpty()) {
320 mHeader <<
" = " << arg.defaultValue;
322 if (i < args.count() - 1) {
330 mHeader <<
" " << node->className() <<
"(const " << node->className()
331 <<
" &) = default;\n"
333 << node->className() <<
"(" << node->className()
334 <<
" &&) = default;\n"
340 << node->className() <<
" &operator=(const " << node->className()
341 <<
" &) = default;\n"
343 << node->className() <<
" &operator=(" << node->className()
344 <<
" &&) = default;\n"
345 " bool operator==(const "
347 <<
" &other) const;\n"
348 " inline bool operator!=(const "
349 << node->className() <<
" &other) const { return !operator==(other); }\n";
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()
359 << prop->type() <<
" &" << prop->name() <<
"() { return " << prop->mVariableName() <<
"; }\n";
361 mHeader <<
" inline " << prop->type() <<
" " << prop->name() <<
"() const { return " << prop->mVariableName() <<
"; }\n";
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()) {
368 if (TypeHelper::isNumericType(prop->type()) || TypeHelper::isBoolType(prop->type())) {
373 mHeader <<
" void " << prop->setterName() << varType << prop->name() <<
");\n";
376 if (TypeHelper::isNumericType(prop->type()) || TypeHelper::isBoolType(prop->type())) {
381 mHeader <<
" inline void " << prop->setterName() << varType << prop->name() <<
") { " << prop->mVariableName() <<
" = " << prop->name()
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";
392 mHeader <<
" void toJson(QJsonObject &stream) const;\n";
395 mHeader <<
"protected:\n";
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) {
408 mHeader <<
" = false";
415 " friend AKONADIPRIVATE_EXPORT Akonadi::Protocol::DataStream &operator<<(Akonadi::Protocol::DataStream &stream, const Akonadi::Protocol::"
418 " friend AKONADIPRIVATE_EXPORT Akonadi::Protocol::DataStream &operator>>(Akonadi::Protocol::DataStream &stream, Akonadi::Protocol::"
421 " friend AKONADIPRIVATE_EXPORT QDebug operator<<(QDebug dbg, const Akonadi::Protocol::"
425 "} // namespace Protocol\n"
426 "} // namespace Akonadi\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";
434 void CppGenerator::writeImplSerializer(PropertyNode
const *node,
const char *streamingOperator)
436 const auto deps = node->dependencies();
437 if (deps.isEmpty()) {
438 mImpl <<
" stream " << streamingOperator <<
" obj." << node->mVariableName() <<
";\n";
441 auto it = deps.cend();
447 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
452 <<
" & " << it.value() <<
")";
453 if (it == deps.cbegin()) {
461 << streamingOperator <<
" obj." << node->mVariableName()
467 void CppGenerator::writeImplClass(ClassNode
const *node)
469 const QString parentClass = node->parentClassName();
470 const auto &children = node->children();
474 for (
const auto *child : children) {
475 if (child->type() == Node::Ctor) {
476 const auto *
const ctor =
static_cast<CtorNode
const *
>(child);
477 const auto args = ctor->arguments();
478 mImpl << node->className() <<
"::" << node->className() <<
"(";
479 for (
int i = 0; i < args.count(); ++i) {
480 const auto &arg = args[i];
481 if (TypeHelper::isNumericType(arg.type) || TypeHelper::isBoolType(arg.type)) {
482 mImpl << arg.type <<
" " << arg.name;
484 mImpl <<
"const " << arg.type <<
" &" << arg.name;
486 if (i < args.count() - 1) {
491 char startChar =
',';
493 const QString type = node->name() + ((node->classType() == ClassNode::Notification) ? QStringLiteral(
"Notification") :
QString());
494 mImpl <<
" : " << parentClass <<
"(Command::" <<
type <<
")\n";
498 for (
const auto *prop : properties) {
499 auto arg = std::find_if(args.cbegin(), args.cend(), [prop](
const CtorNode::Argument &arg) {
500 return arg.name == prop->name();
502 if (arg != args.cend()) {
503 mImpl <<
" " << startChar <<
" " << prop->mVariableName() <<
"(" << arg->name <<
")\n";
514 mImpl <<
"bool " << node->className() <<
"::operator==(const " << node->className()
515 <<
" &other) const\n"
517 mImpl <<
" return true // simplifies generation\n";
519 mImpl <<
" && " << parentClass <<
"::operator==(other)\n";
521 for (
const auto *prop : properties) {
522 if (prop->isPointer()) {
523 mImpl <<
" && *" << prop->mVariableName() <<
" == *other." << prop->mVariableName() <<
"\n";
524 }
else if (TypeHelper::isContainer(prop->type())) {
525 mImpl <<
" && containerComparator(" << prop->mVariableName() <<
", other." << prop->mVariableName() <<
")\n";
527 mImpl <<
" && " << prop->mVariableName() <<
" == other." << prop->mVariableName() <<
"\n";
535 for (
const auto *prop : properties) {
536 if (prop->readOnly()) {
540 if (
auto *
const setter = prop->setter()) {
541 mImpl <<
"void " << node->className() <<
"::" << setter->name <<
"(const " << setter->type
544 if (!setter->append.isEmpty()) {
546 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
553 if (!setter->remove.isEmpty()) {
555 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
556 + setter->remove.midRef(1);
560 mImpl <<
" auto it = std::find(" << mVar <<
".begin(), " << mVar
570 writeImplPropertyDependencies(prop);
572 }
else if (!prop->dependencies().isEmpty()) {
573 if (TypeHelper::isNumericType(prop->type()) || TypeHelper::isBoolType(prop->type())) {
574 mImpl <<
"void " << node->className() <<
"::" << prop->setterName() <<
"(" << prop->type()
578 << prop->mVariableName() <<
" = val;\n";
581 mImpl <<
"void " << node->className() <<
"::" << prop->setterName() <<
"(const " << prop->type()
585 << prop->mVariableName() <<
" = val;\n";
587 writeImplPropertyDependencies(prop);
594 CppHelper::sortMembersForSerialization(serializeProperties);
596 mImpl <<
"DataStream &operator<<(DataStream &stream, const " << node->className()
600 mImpl <<
" stream << static_cast<const " << parentClass <<
" &>(obj);\n";
602 for (
const auto *prop : std::as_const(serializeProperties)) {
603 writeImplSerializer(prop,
"<<");
605 mImpl <<
" return stream;\n"
610 mImpl <<
"DataStream &operator>>(DataStream &stream, " << node->className()
614 mImpl <<
" stream >> static_cast<" << parentClass <<
" &>(obj);\n";
616 for (
const auto *prop : std::as_const(serializeProperties)) {
617 writeImplSerializer(prop,
">>");
619 mImpl <<
" return stream;\n"
624 mImpl <<
"QDebug operator<<(QDebug dbg, const " << node->className()
628 mImpl <<
" dbg.noquote() << static_cast<const " << parentClass <<
" &>(obj)\n";
630 mImpl <<
" dbg.noquote()\n";
633 for (
const auto *prop : std::as_const(serializeProperties)) {
634 if (prop->isPointer()) {
635 mImpl <<
" << \"" << prop->name() <<
":\" << *obj." << prop->mVariableName() <<
" << \"\\n\"\n";
636 }
else if (TypeHelper::isContainer(prop->type())) {
637 mImpl <<
" << \"" << prop->name()
639 " for (const auto &type : std::as_const(obj."
640 << prop->mVariableName()
642 " dbg.noquote() << \" \" << ";
643 if (TypeHelper::isPointerType(TypeHelper::containerType(prop->type()))) {
648 mImpl <<
" << \"\\n\";\n"
650 " dbg.noquote() << \"]\\n\"\n";
652 mImpl <<
" << \"" << prop->name() <<
":\" << obj." << prop->mVariableName() <<
" << \"\\n\"\n";
661 mImpl <<
"void " << node->className()
662 <<
"::toJson(QJsonObject &json) const\n"
665 mImpl <<
" static_cast<const " << parentClass <<
" *>(this)->toJson(json);\n";
666 }
else if (serializeProperties.isEmpty()) {
667 mImpl <<
" Q_UNUSED(json)\n";
669 for (
const auto *prop : std::as_const(serializeProperties)) {
670 if (prop->isPointer()) {
672 " QJsonObject jsonObject;\n"
674 << prop->mVariableName()
675 <<
"->toJson(jsonObject);\n"
676 " json[QStringLiteral(\""
678 <<
"\")] = jsonObject;\n"
680 }
else if (TypeHelper::isContainer(prop->type())) {
681 const auto &containerType = TypeHelper::containerType(prop->type());
683 " QJsonArray jsonArray;\n"
684 " for (const auto &type : std::as_const("
685 << prop->mVariableName() <<
")) {\n";
686 if (TypeHelper::isPointerType(containerType)) {
687 mImpl <<
" QJsonObject jsonObject;\n"
688 " type->toJson(jsonObject); /* "
691 " jsonArray.append(jsonObject);\n";
692 }
else if (TypeHelper::isNumericType(containerType) || TypeHelper::isBoolType(containerType)) {
693 mImpl <<
" jsonArray.append(type); /* " << containerType <<
" */\n";
695 mImpl <<
" jsonArray.append(QString::fromUtf8(type)); /* " << containerType <<
"*/\n";
696 }
else if (TypeHelper::isBuiltInType(containerType)) {
697 if (TypeHelper::containerType(prop->type()) ==
QLatin1String(
"Akonadi::Protocol::ChangeNotification::Relation")) {
698 mImpl <<
" QJsonObject jsonObject;\n"
699 " type.toJson(jsonObject); /* "
702 " jsonArray.append(jsonObject);\n";
704 mImpl <<
" jsonArray.append(type); /* " << containerType <<
" */\n";
707 mImpl <<
" QJsonObject jsonObject;\n"
708 " type.toJson(jsonObject); /* "
711 " jsonArray.append(jsonObject);\n";
714 <<
" json[QStringLiteral(\"" << prop->name() <<
"\")] = jsonArray;\n"
717 mImpl <<
" json[QStringLiteral(\"" << prop->name() <<
"\")] = static_cast<int>(" << prop->mVariableName() <<
");/* " << prop->type() <<
" */\n";
718 }
else if (TypeHelper::isNumericType(prop->type()) || TypeHelper::isBoolType(prop->type())) {
719 mImpl <<
" json[QStringLiteral(\"" << prop->name() <<
"\")] = " << prop->mVariableName() <<
";/* " << prop->type() <<
" */\n";
720 }
else if (TypeHelper::isBuiltInType(prop->type())) {
722 mImpl <<
" json[QStringLiteral(\"" << prop->name() <<
"\")] = QJsonArray::fromStringList(" << prop->mVariableName() <<
");/* "
723 << prop->type() <<
" */\n";
725 mImpl <<
" json[QStringLiteral(\"" << prop->name() <<
"\")] = " << prop->mVariableName() <<
".toString()/* " << prop->type() <<
" */;\n";
727 mImpl <<
" json[QStringLiteral(\"" << prop->name() <<
"\")] = QString::fromUtf8(" << prop->mVariableName() <<
")/* " << prop->type()
731 " QJsonObject jsonObject;\n"
733 << prop->mVariableName() <<
".toJson(jsonObject); /* " << prop->type()
735 " json[QStringLiteral(\""
736 << prop->name() <<
"\")] = "
740 mImpl <<
" switch (" << prop->mVariableName()
742 " case Tristate::True:\n"
743 " json[QStringLiteral(\""
745 <<
"\")] = QStringLiteral(\"True\");\n"
747 " case Tristate::False:\n"
748 " json[QStringLiteral(\""
750 <<
"\")] = QStringLiteral(\"False\");\n"
752 " case Tristate::Undefined:\n"
753 " json[QStringLiteral(\""
755 <<
"\")] = QStringLiteral(\"Undefined\");\n"
758 }
else if (prop->type() ==
QLatin1String(
"Akonadi::Protocol::Attributes")) {
760 " QJsonObject jsonObject;\n"
762 << prop->mVariableName()
763 <<
".constBegin();\n"
764 " const auto &end = "
765 << prop->mVariableName()
767 " while (i != end) {\n"
768 " jsonObject[QString::fromUtf8(i.key())] = QString::fromUtf8(i.value());\n"
771 " json[QStringLiteral(\""
773 <<
"\")] = jsonObject;\n"
775 }
else if (prop->type() ==
QLatin1String(
"ModifySubscriptionCommand::ModifiedParts")
776 || prop->type() ==
QLatin1String(
"ModifyTagCommand::ModifiedParts")
777 || prop->type() ==
QLatin1String(
"ModifyCollectionCommand::ModifiedParts")
778 || prop->type() ==
QLatin1String(
"ModifyItemsCommand::ModifiedParts")
779 || prop->type() ==
QLatin1String(
"CreateItemCommand::MergeModes")) {
780 mImpl <<
" json[QStringLiteral(\"" << prop->name() <<
"\")] = static_cast<int>(" << prop->mVariableName() <<
");/* " << prop->type()
783 mImpl <<
" json[QStringLiteral(\"" << prop->name() <<
"\")] = " << prop->mVariableName() <<
";/* " << prop->type() <<
"*/\n";
787 " QJsonObject jsonObject;\n"
789 << prop->mVariableName() <<
".toJson(jsonObject); /* " << prop->type()
791 " json[QStringLiteral(\""
793 <<
"\")] = jsonObject;\n"
801 void CppGenerator::writeImplPropertyDependencies(
const PropertyNode *node)
803 const auto deps = node->dependencies();
807 for (
auto it = deps.cbegin(), end = deps.cend(); it != end; ++it) {
808 if (key != it.key()) {
810 const auto children = node->parent()->children();
811 for (
const auto *child : children) {
812 if (child->type() == Node::Property && child != node) {
813 const auto *prop =
static_cast<const PropertyNode *
>(child);
814 if (prop->name() == key) {
815 enumType = prop->type();
821 mImpl <<
" m" << key[0].
toUpper()
831 mImpl <<
" m" << key[0].
toUpper()
837 bool CppGenerator::generateClass(ClassNode
const *node)
839 writeHeaderClass(node);
841 mImpl <<
"\n\n/************************* " << node->className() <<
" *************************/\n\n";
842 writeImplClass(node);