File indexing completed on 2024-05-12 03:54:30

0001 /*
0002     This file is part of the KDE libraries.
0003 
0004     SPDX-FileCopyrightText: 2003 Cornelius Schumacher <schumacher@kde.org>
0005     SPDX-FileCopyrightText: 2003 Waldo Bastian <bastian@kde.org>
0006     SPDX-FileCopyrightText: 2003 Zack Rusin <zack@kde.org>
0007     SPDX-FileCopyrightText: 2006 Michaƫl Larouche <michael.larouche@kdemail.net>
0008     SPDX-FileCopyrightText: 2008 Allen Winter <winter@kde.org>
0009     SPDX-FileCopyrightText: 2020 Tomaz Cananbrava <tcanabrava@kde.org>
0010 
0011     SPDX-License-Identifier: LGPL-2.0-or-later
0012 */
0013 
0014 #include "KConfigHeaderGenerator.h"
0015 
0016 #include <QDebug>
0017 #include <QTextStream>
0018 #include <iostream>
0019 
0020 KConfigHeaderGenerator::KConfigHeaderGenerator(const QString &inputFile, const QString &baseDir, const KConfigParameters &cfg, ParseResult &result)
0021     : KConfigCodeGeneratorBase(inputFile, baseDir, baseDir + cfg.baseName + QLatin1Char('.') + cfg.headerExtension, cfg, result)
0022 {
0023 }
0024 
0025 void KConfigHeaderGenerator::start()
0026 {
0027     KConfigCodeGeneratorBase::start();
0028     startHeaderGuards();
0029     createHeaders();
0030 
0031     beginNamespaces();
0032 
0033     createForwardDeclarations();
0034 
0035     doClassDefinition();
0036 
0037     endNamespaces();
0038     endHeaderGuards();
0039 }
0040 
0041 void KConfigHeaderGenerator::doClassDefinition()
0042 {
0043     stream() << "class " << cfg().visibility << cfg().className << " : public " << cfg().inherits << '\n';
0044     startScope();
0045 
0046     // Add Q_OBJECT macro if the config need signals.
0047     if (!parseResult.signalList.isEmpty() || cfg().generateProperties) {
0048         stream() << "  Q_OBJECT\n";
0049     }
0050     stream() << "  public:\n";
0051     implementEnums();
0052     createConstructor();
0053     createDestructor();
0054 
0055     for (const auto *entry : std::as_const(parseResult.entries)) {
0056         const QString returnType = (cfg().useEnumTypes && entry->type == QLatin1String("Enum")) ? enumType(entry, cfg().globalEnums) : cppType(entry->type);
0057 
0058         createSetters(entry);
0059         createProperties(entry, returnType);
0060         createImmutableProperty(entry);
0061         createGetters(entry, returnType);
0062         createImmutableGetters(entry);
0063         createDefaultValueMember(entry);
0064         createItemAcessors(entry, returnType);
0065     }
0066 
0067     createSignals();
0068     stream() << "  protected:\n";
0069     createSingleton();
0070 
0071     // TODO: Move those to functions too.
0072     if (parseResult.hasNonModifySignals) {
0073         stream() << whitespace() << "bool usrSave() override;\n";
0074     }
0075 
0076     // Member variables
0077     if (!cfg().memberVariables.isEmpty() //
0078         && cfg().memberVariables != QLatin1String("private") //
0079         && cfg().memberVariables != QLatin1String("dpointer")) {
0080         stream() << "  " << cfg().memberVariables << ":\n";
0081     }
0082 
0083     // Class Parameters
0084     for (const auto &parameter : std::as_const(parseResult.parameters)) {
0085         stream() << whitespace() << "" << cppType(parameter.type) << " mParam" << parameter.name << ";\n";
0086     }
0087 
0088     createNonDPointerHelpers();
0089     createDPointer();
0090 
0091     if (cfg().customAddons) {
0092         stream() << whitespace() << "// Include custom additions\n";
0093         stream() << whitespace() << "#include \"" << cfg().baseName << "_addons." << cfg().headerExtension << "\"\n";
0094     }
0095 
0096     endScope(ScopeFinalizer::Semicolon);
0097 }
0098 
0099 void KConfigHeaderGenerator::createHeaders()
0100 {
0101     addHeaders(cfg().headerIncludes);
0102     if (cfg().headerIncludes.size()) {
0103         stream() << '\n';
0104     }
0105 
0106     if (!cfg().singleton && parseResult.parameters.isEmpty()) {
0107         addHeaders({QStringLiteral("qglobal.h")});
0108     }
0109 
0110     if (cfg().inherits == QLatin1String("KCoreConfigSkeleton")) {
0111         addHeaders({QStringLiteral("kcoreconfigskeleton.h")});
0112     } else {
0113         addHeaders({QStringLiteral("kconfigskeleton.h")});
0114     }
0115 
0116     addHeaders({QStringLiteral("QCoreApplication"), QStringLiteral("QDebug")});
0117     if (!cfg().dpointer && parseResult.hasNonModifySignals) {
0118         addHeaders({QStringLiteral("QSet")});
0119     }
0120     stream() << '\n';
0121 
0122     addHeaders(parseResult.includes);
0123     if (parseResult.includes.size()) {
0124         stream() << '\n';
0125     }
0126 }
0127 
0128 void KConfigHeaderGenerator::startHeaderGuards()
0129 {
0130     const bool hasNamespace = !cfg().nameSpace.isEmpty();
0131     const QString namespaceName = QString(QString(cfg().nameSpace).replace(QLatin1String("::"), QLatin1String("_"))).toUpper();
0132     const QString namespaceStr = hasNamespace ? namespaceName + QLatin1Char('_') : QString{};
0133     const QString defineName = namespaceStr + cfg().className.toUpper() + QStringLiteral("_H");
0134 
0135     stream() << "#ifndef " << defineName << '\n';
0136     stream() << "#define " << defineName << '\n';
0137     stream() << '\n';
0138 }
0139 
0140 void KConfigHeaderGenerator::endHeaderGuards()
0141 {
0142     stream() << '\n';
0143     stream() << "#endif";
0144     stream() << '\n';
0145     // HACK: Original files ended with two last newlines, add them.
0146     stream() << '\n';
0147 }
0148 
0149 void KConfigHeaderGenerator::implementChoiceEnums(const CfgEntry *entry, const CfgEntry::Choices &choices)
0150 {
0151     const QList<CfgEntry::Choice> chlist = choices.choices;
0152 
0153     if (chlist.isEmpty()) {
0154         return;
0155     }
0156 
0157     QStringList values;
0158     for (const auto &choice : std::as_const(chlist)) {
0159         values.append(choices.prefix + choice.name);
0160     }
0161 
0162     if (choices.name().isEmpty()) {
0163         if (cfg().globalEnums) {
0164             stream() << whitespace() << "enum " << enumName(entry->name, entry->choices) << " { " << values.join(QStringLiteral(", ")) << " };\n";
0165             if (cfg().generateProperties) {
0166                 stream() << whitespace() << "Q_ENUM(" << enumName(entry->name, entry->choices) << ")\n";
0167             }
0168         } else {
0169             // Create an automatically named enum
0170             stream() << whitespace() << "class " << enumName(entry->name, entry->choices) << '\n';
0171             stream() << whitespace() << "{\n";
0172             stream() << whitespace() << "  public:\n";
0173             stream() << whitespace() << "  enum type { " << values.join(QStringLiteral(", ")) << ", COUNT };\n";
0174             stream() << whitespace() << "};\n";
0175         }
0176     } else if (!choices.external()) {
0177         // Create a named enum
0178         stream() << whitespace() << "enum " << enumName(entry->name, entry->choices) << " { " << values.join(QStringLiteral(", ")) << " };\n";
0179     }
0180 }
0181 
0182 void KConfigHeaderGenerator::implementValueEnums(const CfgEntry *entry, const QStringList &values)
0183 {
0184     if (values.isEmpty()) {
0185         return;
0186     }
0187 
0188     if (cfg().globalEnums) {
0189         // ### FIXME!!
0190         // make the following string table an index-based string search!
0191         // ###
0192         stream() << whitespace() << "enum " << enumName(entry->param) << " { " << values.join(QStringLiteral(", ")) << " };\n";
0193         stream() << whitespace() << "static const char* const " << enumName(entry->param) << "ToString[];\n";
0194     } else {
0195         stream() << whitespace() << "class " << enumName(entry->param) << '\n';
0196         stream() << whitespace() << "{\n";
0197         stream() << whitespace() << "  public:\n";
0198         stream() << whitespace() << "  enum type { " << values.join(QStringLiteral(", ")) << ", COUNT };\n";
0199         stream() << whitespace() << "  static const char* const enumToString[];\n";
0200         stream() << whitespace() << "};\n";
0201     }
0202 }
0203 
0204 void KConfigHeaderGenerator::implementEnums()
0205 {
0206     if (!parseResult.entries.size()) {
0207         return;
0208     }
0209 
0210     for (const auto *entry : std::as_const(parseResult.entries)) {
0211         const CfgEntry::Choices &choices = entry->choices;
0212         const QStringList values = entry->paramValues;
0213 
0214         implementChoiceEnums(entry, choices);
0215         implementValueEnums(entry, values);
0216     }
0217     stream() << '\n';
0218 }
0219 
0220 void KConfigHeaderGenerator::createSignals()
0221 {
0222     // Signal definition.
0223     if (parseResult.signalList.isEmpty()) {
0224         return;
0225     }
0226 
0227     stream() << "\n    enum {\n";
0228 
0229     // HACK: Use C-Style for add a comma in all but the last element,
0230     // just to make the source generated code equal to the old one.
0231     // When we are sure, revert this to a range-based-for and just add
0232     // a last comma, as it's valid c++.
0233     for (int i = 0, end = parseResult.signalList.size(); i < end; i++) {
0234         auto signal = parseResult.signalList.at(i);
0235         stream() << whitespace() << "  " << signalEnumName(signal.name) << " = " << (i + 1);
0236         if (i != end - 1) {
0237             stream() << ",\n";
0238         }
0239     }
0240     stream() << '\n';
0241     stream() << whitespace() << "};\n\n";
0242 
0243     stream() << "  Q_SIGNALS:";
0244     for (const Signal &signal : std::as_const(parseResult.signalList)) {
0245         stream() << '\n';
0246         if (!signal.label.isEmpty()) {
0247             stream() << whitespace() << "/**\n";
0248             stream() << whitespace() << "  " << signal.label << '\n';
0249             stream() << whitespace() << "*/\n";
0250         }
0251         stream() << whitespace() << "void " << signal.name << "(";
0252 
0253         auto it = signal.arguments.cbegin();
0254         const auto itEnd = signal.arguments.cend();
0255         while (it != itEnd) {
0256             Param argument = *it;
0257             QString type = param(argument.type);
0258             if (cfg().useEnumTypes && argument.type == QLatin1String("Enum")) {
0259                 for (const auto *entry : std::as_const(parseResult.entries)) {
0260                     if (entry->name == argument.name) {
0261                         type = enumType(entry, cfg().globalEnums);
0262                         break;
0263                     }
0264                 }
0265             }
0266             stream() << type << " " << argument.name;
0267             if (++it != itEnd) {
0268                 stream() << ", ";
0269             }
0270         }
0271         stream() << ");\n";
0272     }
0273     stream() << '\n';
0274 
0275     stream() << "  private:\n";
0276     stream() << whitespace() << "void itemChanged(quint64 signalFlag);\n";
0277     stream() << '\n';
0278 }
0279 
0280 void KConfigHeaderGenerator::createDPointer()
0281 {
0282     if (!cfg().dpointer) {
0283         return;
0284     }
0285 
0286     // use a private class for both member variables and items
0287     stream() << "  private:\n";
0288     for (const auto *entry : std::as_const(parseResult.entries)) {
0289         if (cfg().allDefaultGetters || cfg().defaultGetters.contains(entry->name)) {
0290             stream() << whitespace() << "";
0291             if (cfg().staticAccessors) {
0292                 stream() << "static ";
0293             }
0294             stream() << cppType(entry->type) << " " << getDefaultFunction(entry->name) << "_helper(";
0295             if (!entry->param.isEmpty()) {
0296                 stream() << " " << cppType(entry->paramType) << " i ";
0297             }
0298             stream() << ")" << Const() << ";\n";
0299         }
0300     }
0301     stream() << whitespace() << "" << cfg().className << "Private *d;\n";
0302 }
0303 
0304 void KConfigHeaderGenerator::createConstructor()
0305 {
0306     if (cfg().singleton) {
0307         stream() << whitespace() << "static " << cfg().className << " *self();\n";
0308         if (parseResult.cfgFileNameArg) {
0309             stream() << whitespace() << "static void instance(const QString& cfgfilename);\n";
0310             stream() << whitespace() << "static void instance(KSharedConfig::Ptr config);\n";
0311         }
0312         return;
0313     }
0314 
0315     stream() << whitespace() << "" << cfg().className << "(";
0316     if (parseResult.cfgFileNameArg) {
0317         if (cfg().forceStringFilename) {
0318             stream() << " const QString &cfgfilename" << (parseResult.parameters.isEmpty() ? " = QString()" : ", ");
0319         } else if (parseResult.cfgStateConfig) {
0320             stream() << " KSharedConfig::Ptr config" << (parseResult.parameters.isEmpty() ? " = KSharedConfig::openStateConfig()" : ", ");
0321         } else {
0322             stream() << " KSharedConfig::Ptr config" << (parseResult.parameters.isEmpty() ? " = KSharedConfig::openConfig()" : ", ");
0323         }
0324     }
0325     if (cfg().forceStringFilename && parseResult.cfgStateConfig) {
0326         std::cerr << "One can not use ForceStringFilename and use the stateConfig attribute, consider "
0327                      "removing the ForceStringFilename kcfgc option if you want to use state data"
0328                   << std::endl;
0329     }
0330 
0331     bool first = true;
0332     for (const auto &parameter : std::as_const(parseResult.parameters)) {
0333         if (first) {
0334             first = false;
0335         } else {
0336             stream() << ",";
0337         }
0338 
0339         stream() << " " << param(parameter.type) << " " << parameter.name;
0340     }
0341 
0342     if (cfg().parentInConstructor) {
0343         if (parseResult.cfgFileNameArg || !parseResult.parameters.isEmpty()) {
0344             stream() << ",";
0345         }
0346         stream() << " QObject *parent = nullptr";
0347     }
0348     stream() << " );\n";
0349 }
0350 
0351 void KConfigHeaderGenerator::createDestructor()
0352 {
0353     stream() << whitespace() << "~" << cfg().className << "() override;\n\n";
0354 }
0355 
0356 void KConfigHeaderGenerator::createForwardDeclarations()
0357 {
0358     // Private class declaration
0359     if (cfg().dpointer) {
0360         stream() << "class " << cfg().className << "Private;\n\n";
0361     }
0362 }
0363 
0364 void KConfigHeaderGenerator::createProperties(const CfgEntry *entry, const QString &returnType)
0365 {
0366     if (!cfg().generateProperties) {
0367         return;
0368     }
0369     stream() << whitespace() << "Q_PROPERTY(" << returnType << ' ' << getFunction(entry->name);
0370     stream() << " READ " << getFunction(entry->name);
0371 
0372     if (cfg().allMutators || cfg().mutators.contains(entry->name)) {
0373         const QString signal = changeSignalName(entry->name);
0374         stream() << " WRITE " << setFunction(entry->name);
0375         stream() << " NOTIFY " << signal;
0376 
0377         // If we have the modified signal, we'll also need
0378         // the changed signal as well
0379         Signal s;
0380         s.name = signal;
0381         s.modify = true;
0382         parseResult.signalList.append(s);
0383     } else {
0384         stream() << " CONSTANT";
0385     }
0386     stream() << ")\n";
0387 }
0388 
0389 void KConfigHeaderGenerator::createImmutableProperty(const CfgEntry *entry)
0390 {
0391     if (!cfg().generateProperties) {
0392         return;
0393     }
0394     stream() << whitespace();
0395     stream() << "Q_PROPERTY(bool " << immutableFunction(entry->name);
0396     stream() << " READ " << immutableFunction(entry->name);
0397     stream() << " CONSTANT)\n";
0398 }
0399 
0400 void KConfigHeaderGenerator::createSetters(const CfgEntry *entry)
0401 {
0402     // Manipulator
0403     if (!cfg().allMutators && !cfg().mutators.contains(entry->name)) {
0404         return;
0405     }
0406 
0407     stream() << whitespace() << "/**\n";
0408     stream() << whitespace() << "  Set " << entry->label << '\n';
0409     stream() << whitespace() << "*/\n";
0410 
0411     if (cfg().staticAccessors) {
0412         stream() << whitespace() << "static\n";
0413     }
0414 
0415     stream() << whitespace() << "void " << setFunction(entry->name) << "( ";
0416     if (!entry->param.isEmpty()) {
0417         stream() << cppType(entry->paramType) << " i, ";
0418     }
0419 
0420     stream() << (cfg().useEnumTypes && entry->type == QLatin1String("Enum") ? enumType(entry, cfg().globalEnums) : param(entry->type));
0421 
0422     stream() << " v )";
0423 
0424     // function body inline only if not using dpointer
0425     // for BC mode
0426     if (!cfg().dpointer) {
0427         stream() << '\n';
0428         startScope();
0429         memberMutatorBody(entry);
0430         endScope();
0431         stream() << '\n';
0432     } else {
0433         stream() << ";\n\n";
0434     }
0435 }
0436 
0437 void KConfigHeaderGenerator::createGetters(const CfgEntry *entry, const QString &returnType)
0438 {
0439     // Accessor
0440     stream() << whitespace() << "/**\n";
0441     stream() << whitespace() << "  Get " << entry->label << '\n';
0442     stream() << whitespace() << "*/\n";
0443     if (cfg().staticAccessors) {
0444         stream() << whitespace() << "static\n";
0445     }
0446     stream() << whitespace() << "";
0447     stream() << returnType;
0448     stream() << " " << getFunction(entry->name) << "(";
0449     if (!entry->param.isEmpty()) {
0450         stream() << " " << cppType(entry->paramType) << " i ";
0451     }
0452     stream() << ")" << Const();
0453 
0454     // function body inline only if not using dpointer
0455     // for BC mode
0456     if (!cfg().dpointer) {
0457         stream() << '\n';
0458         startScope();
0459         stream() << whitespace() << memberAccessorBody(entry, cfg().globalEnums);
0460         endScope();
0461         stream() << '\n';
0462     } else {
0463         stream() << ";\n\n";
0464     }
0465 }
0466 
0467 void KConfigHeaderGenerator::createImmutableGetters(const CfgEntry *entry)
0468 {
0469     stream() << whitespace() << "/**\n";
0470     stream() << whitespace() << "  Is " << entry->label << " Immutable\n";
0471     stream() << whitespace() << "*/\n";
0472     // Immutable
0473     if (cfg().staticAccessors) {
0474         stream() << whitespace() << "static\n";
0475     }
0476     stream() << whitespace() << "";
0477     stream() << "bool " << immutableFunction(entry->name) << "(";
0478     if (!entry->param.isEmpty()) {
0479         stream() << " " << cppType(entry->paramType) << " i ";
0480     }
0481     stream() << ")" << Const();
0482     // function body inline only if not using dpointer
0483     // for BC mode
0484     if (!cfg().dpointer) {
0485         stream() << '\n';
0486         startScope();
0487         memberImmutableBody(entry, cfg().globalEnums);
0488         endScope();
0489         stream() << '\n';
0490     } else {
0491         stream() << ";\n\n";
0492     }
0493 }
0494 
0495 void KConfigHeaderGenerator::createItemAcessors(const CfgEntry *entry, const QString &returnType)
0496 {
0497     Q_UNUSED(returnType)
0498 
0499     // Item accessor
0500     if (!cfg().itemAccessors) {
0501         return;
0502     }
0503 
0504     const QString declType = entry->signalList.isEmpty() ? QStringLiteral("Item") + itemType(entry->type) : QStringLiteral("KConfigCompilerSignallingItem");
0505 
0506     stream() << whitespace() << "/**\n";
0507     stream() << whitespace() << "  Get Item object corresponding to " << entry->name << "()" << '\n';
0508     stream() << whitespace() << "*/\n";
0509     stream() << whitespace() << declType << " *" << getFunction(entry->name) << "Item(";
0510     if (!entry->param.isEmpty()) {
0511         stream() << " " << cppType(entry->paramType) << " i ";
0512     }
0513     stream() << ")";
0514     if (!cfg().dpointer) {
0515         stream() << '\n';
0516         startScope();
0517         stream() << whitespace() << itemAccessorBody(entry, cfg());
0518         endScope();
0519     } else {
0520         stream() << ";\n";
0521     }
0522 
0523     stream() << '\n';
0524 }
0525 
0526 void KConfigHeaderGenerator::createDefaultValueMember(const CfgEntry *entry)
0527 {
0528     // Default value Accessor
0529     if (!((cfg().allDefaultGetters || cfg().defaultGetters.contains(entry->name)) && !entry->defaultValue.isEmpty())) {
0530         return;
0531     }
0532     stream() << whitespace() << "/**\n";
0533     stream() << whitespace() << "  Get " << entry->label << " default value\n";
0534     stream() << whitespace() << "*/\n";
0535     if (cfg().staticAccessors) {
0536         stream() << whitespace() << "static\n";
0537     }
0538     stream() << whitespace() << "";
0539     if (cfg().useEnumTypes && entry->type == QLatin1String("Enum")) {
0540         stream() << enumType(entry, cfg().globalEnums);
0541     } else {
0542         stream() << cppType(entry->type);
0543     }
0544     stream() << " " << getDefaultFunction(entry->name) << "(";
0545     if (!entry->param.isEmpty()) {
0546         stream() << " " << cppType(entry->paramType) << " i ";
0547     }
0548     stream() << ")" << Const() << '\n';
0549     stream() << whitespace() << "{\n";
0550     stream() << whitespace() << "    return ";
0551     if (cfg().useEnumTypes && entry->type == QLatin1String("Enum")) {
0552         stream() << "static_cast<" << enumType(entry, cfg().globalEnums) << ">(";
0553     }
0554     stream() << getDefaultFunction(entry->name) << "_helper(";
0555     if (!entry->param.isEmpty()) {
0556         stream() << " i ";
0557     }
0558     stream() << ")";
0559     if (cfg().useEnumTypes && entry->type == QLatin1String("Enum")) {
0560         stream() << ")";
0561     }
0562     stream() << ";\n";
0563     stream() << whitespace() << "}\n";
0564     stream() << '\n';
0565 }
0566 
0567 void KConfigHeaderGenerator::createSingleton()
0568 {
0569     // Private constructor for singleton
0570     if (!cfg().singleton) {
0571         return;
0572     }
0573 
0574     stream() << whitespace() << "" << cfg().className << "(";
0575     if (parseResult.cfgFileNameArg) {
0576         stream() << "KSharedConfig::Ptr config";
0577     }
0578     if (cfg().parentInConstructor) {
0579         if (parseResult.cfgFileNameArg) {
0580             stream() << ", ";
0581         }
0582         stream() << "QObject *parent = nullptr";
0583     }
0584     stream() << ");\n";
0585     stream() << whitespace() << "friend class " << cfg().className << "Helper;\n\n";
0586 }
0587 
0588 void KConfigHeaderGenerator::createNonDPointerHelpers()
0589 {
0590     if (cfg().memberVariables == QLatin1String("dpointer")) {
0591         return;
0592     }
0593 
0594     QString group;
0595     for (const auto *entry : std::as_const(parseResult.entries)) {
0596         if (entry->group != group) {
0597             group = entry->group;
0598             stream() << '\n';
0599             stream() << whitespace() << "// " << group << '\n';
0600         }
0601         stream() << whitespace() << "" << cppType(entry->type) << " " << varName(entry->name, cfg());
0602         if (!entry->param.isEmpty()) {
0603             stream() << QStringLiteral("[%1]").arg(entry->paramMax + 1);
0604         }
0605         stream() << ";\n";
0606 
0607         if (cfg().allDefaultGetters || cfg().defaultGetters.contains(entry->name)) {
0608             stream() << whitespace() << "";
0609             if (cfg().staticAccessors) {
0610                 stream() << "static ";
0611             }
0612             stream() << cppType(entry->type) << " " << getDefaultFunction(entry->name) << "_helper(";
0613             if (!entry->param.isEmpty()) {
0614                 stream() << " " << cppType(entry->paramType) << " i ";
0615             }
0616             stream() << ")" << Const() << ";\n";
0617         }
0618     }
0619 
0620     stream() << "\n  private:\n";
0621     if (cfg().itemAccessors) {
0622         for (const auto *entry : std::as_const(parseResult.entries)) {
0623             const QString declType =
0624                 entry->signalList.isEmpty() ? QStringLiteral("Item") + itemType(entry->type) : QStringLiteral("KConfigCompilerSignallingItem");
0625             stream() << whitespace() << declType << " *" << itemVar(entry, cfg());
0626             if (!entry->param.isEmpty()) {
0627                 stream() << QStringLiteral("[%1]").arg(entry->paramMax + 1);
0628             }
0629             stream() << ";\n";
0630         }
0631     }
0632 
0633     if (parseResult.hasNonModifySignals) {
0634         stream() << whitespace() << "QSet<quint64> " << varName(QStringLiteral("settingsChanged"), cfg()) << ";\n";
0635     }
0636 }