aboutsummaryrefslogtreecommitdiff
path: root/src/kconfig_compiler/KConfigSourceGenerator.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/kconfig_compiler/KConfigSourceGenerator.cpp')
-rw-r--r--src/kconfig_compiler/KConfigSourceGenerator.cpp657
1 files changed, 657 insertions, 0 deletions
diff --git a/src/kconfig_compiler/KConfigSourceGenerator.cpp b/src/kconfig_compiler/KConfigSourceGenerator.cpp
new file mode 100644
index 00000000..1949b420
--- /dev/null
+++ b/src/kconfig_compiler/KConfigSourceGenerator.cpp
@@ -0,0 +1,657 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2020 Tomaz Cananbrava (tcanabrava@kde.org)
+ Copyright (c) 2003 Cornelius Schumacher <schumacher@kde.org>
+ Copyright (c) 2003 Waldo Bastian <bastian@kde.org>
+ Copyright (c) 2003 Zack Rusin <zack@kde.org>
+ Copyright (c) 2006 Michaƫl Larouche <michael.larouche@kdemail.net>
+ Copyright (c) 2008 Allen Winter <winter@kde.org>
+ Copyright (C) 2020 Tomaz Cananbrava (tcanabrava@kde.org)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "KConfigSourceGenerator.h"
+#include "KConfigCommonStructs.h"
+
+
+KConfigSourceGenerator::KConfigSourceGenerator(
+ const QString& inputFile,
+ const QString& baseDir,
+ const KConfigXTParameters &cfg,
+ ParseResult &parseResult)
+ : KConfigCodeGeneratorBase(inputFile, baseDir, baseDir + cfg.baseName + QLatin1Char('.') + cfg.sourceExtension, cfg, parseResult)
+{
+}
+
+void KConfigSourceGenerator::start()
+{
+ KConfigCodeGeneratorBase::start();
+ stream << endl;
+ createHeaders();
+
+ if (!cfg.nameSpace.isEmpty()) {
+ stream << "using namespace " << cfg.nameSpace << ";";
+ stream << endl << endl;
+ }
+
+ createPrivateDPointerImplementation();
+ createSingletonImplementation();
+ createPreamble();
+ doConstructor();
+ doGetterSetterDPointerMode();
+ createDefaultValueGetterSetter();
+ createDestructor();
+ createNonModifyingSignalsHelper();
+ createSignalFlagsHandler();
+ includeMoc();
+}
+
+void KConfigSourceGenerator::createHeaders()
+{
+ QString headerName = cfg.baseName + QLatin1Char('.') + cfg.headerExtension;
+
+ // TODO: Make addQuotes return a string instead of replacing it inplace.
+ addQuotes(headerName);
+
+ addHeaders({ headerName });
+ stream << endl;
+
+ addHeaders(cfg.sourceIncludes);
+ if (cfg.setUserTexts && cfg.translationSystem == KConfigXTParameters::KdeTranslation) {
+ addHeaders({QStringLiteral("klocalizedstring.h")});
+ stream << endl;
+ }
+
+ // Header required by singleton implementation
+ if (cfg.singleton) {
+ addHeaders({QStringLiteral("qglobal.h"), QStringLiteral("QFile")});
+
+ // HACK: Add single line to fix test.
+ if (cfg.singleton && parseResult.cfgFileNameArg) {
+ stream << endl;
+ }
+ }
+
+ if (cfg.singleton && parseResult.cfgFileNameArg) {
+ addHeaders({QStringLiteral("QDebug")});
+ }
+
+ if (cfg.singleton) {
+ stream << endl;
+ }
+}
+
+void KConfigSourceGenerator::createPrivateDPointerImplementation()
+{
+ // private class implementation
+ if (!cfg.dpointer) {
+ return;
+ }
+
+ QString group;
+ beginNamespaces();
+ stream << "class " << cfg.className << "Private" << endl;
+ stream << "{" << endl;
+ stream << " public:" << endl;
+
+ // Create Members
+ for (auto *entry : qAsConst(parseResult.entries)) {
+ if (entry->group != group) {
+ group = entry->group;
+ stream << endl;
+ stream << " // " << group << endl;
+ }
+ stream << " " << cppType(entry->type) << " " << varName(entry->name, cfg);
+ if (!entry->param.isEmpty()) {
+ stream << QStringLiteral("[%1]").arg(entry->paramMax + 1);
+ }
+ stream << ";" << endl;
+ }
+ stream << endl << " // items" << endl;
+
+ // Create Items.
+ for (auto *entry : qAsConst(parseResult.entries)) {
+ const QString declType = entry->signalList.isEmpty()
+ ? QString(cfg.inherits + QStringLiteral("::Item") + itemType(entry->type))
+ : QStringLiteral("KConfigCompilerSignallingItem");
+
+ stream << " " << declType << " *" << itemVar( entry, cfg );
+ if (!entry->param.isEmpty()) {
+ stream << QStringLiteral("[%1]").arg(entry->paramMax + 1);
+ }
+ stream << ";" << endl;
+ }
+
+ if (parseResult.hasNonModifySignals) {
+ stream << " uint " << varName(QStringLiteral("settingsChanged"), cfg) << ";" << endl;
+ }
+
+ stream << "};" << endl << endl;
+ endNamespaces();
+}
+
+void KConfigSourceGenerator::createSingletonImplementation()
+{
+ // Singleton implementation
+ if (!cfg.singleton) {
+ return;
+ }
+
+ beginNamespaces();
+ stream << "class " << cfg.className << "Helper" << endl;
+ stream << '{' << endl;
+ stream << " public:" << endl;
+ stream << " " << cfg.className << "Helper() : q(nullptr) {}" << endl;
+ stream << " ~" << cfg.className << "Helper() { delete q; }" << endl;
+ stream << " " << cfg.className << "Helper(const " << cfg.className << "Helper&) = delete;" << endl;
+ stream << " " << cfg.className << "Helper& operator=(const " << cfg.className << "Helper&) = delete;" << endl;
+ stream << " " << cfg.className << " *q;" << endl;
+ stream << "};" << endl;
+ endNamespaces();
+
+ stream << "Q_GLOBAL_STATIC(" << cfg.className << "Helper, s_global" << cfg.className << ")" << endl;
+
+ stream << cfg.className << " *" << cfg.className << "::self()" << endl;
+ stream << "{" << endl;
+ if (parseResult.cfgFileNameArg) {
+ stream << " if (!s_global" << cfg.className << "()->q)" << endl;
+ stream << " qFatal(\"you need to call " << cfg.className << "::instance before using\");" << endl;
+ } else {
+ stream << " if (!s_global" << cfg.className << "()->q) {" << endl;
+ stream << " new " << cfg.className << ';' << endl;
+ stream << " s_global" << cfg.className << "()->q->read();" << endl;
+ stream << " }" << endl << endl;
+ }
+ stream << " return s_global" << cfg.className << "()->q;" << endl;
+ stream << "}" << endl << endl;
+
+ if (parseResult.cfgFileNameArg) {
+ auto instance = [this] (const QString &type, const QString &arg, bool isString) {
+ stream << "void " << cfg.className << "::instance(" << type << " " << arg << ")" << endl;
+ stream << "{" << endl;
+ stream << " if (s_global" << cfg.className << "()->q) {" << endl;
+ stream << " qDebug() << \"" << cfg.className << "::instance called after the first use - ignoring\";" << endl;
+ stream << " return;" << endl;
+ stream << " }" << endl;
+ stream << " new " << cfg.className << "(";
+ if (isString) {
+ stream << "KSharedConfig::openConfig(" << arg << ")";
+ } else {
+ stream << "std::move(" << arg << ")";
+ }
+ stream << ");" << endl;
+ stream << " s_global" << cfg.className << "()->q->read();" << endl;
+ stream << "}" << endl << endl;
+ };
+ instance(QStringLiteral("const QString&"), QStringLiteral("cfgfilename"), true);
+ instance(QStringLiteral("KSharedConfig::Ptr"), QStringLiteral("config"), false);
+ }
+}
+
+void KConfigSourceGenerator::createPreamble()
+{
+ QString cppPreamble;
+ for (const auto entry : qAsConst(parseResult.entries)) {
+ if (entry->paramValues.isEmpty()) {
+ continue;
+ }
+
+ cppPreamble += QStringLiteral("const char* const ") + cfg.className + QStringLiteral("::") + enumName(entry->param);
+ cppPreamble += cfg.globalEnums
+ ? QStringLiteral("ToString[] = { \"") + entry->paramValues.join(QStringLiteral("\", \"")) + QStringLiteral("\" };\n")
+ : QStringLiteral("::enumToString[] = { \"") + entry->paramValues.join(QStringLiteral("\", \"")) + QStringLiteral("\" };\n");
+ }
+
+ if (!cppPreamble.isEmpty()) {
+ stream << cppPreamble << endl;
+ }
+}
+
+void KConfigSourceGenerator::createConstructorParameterList()
+{
+ if (parseResult.cfgFileNameArg) {
+ if (!cfg.forceStringFilename) {
+ stream << " KSharedConfig::Ptr config";
+ } else {
+ stream << " const QString& config";
+ }
+ stream << (parseResult.parameters.isEmpty() ? "" : ",");
+ }
+
+ for (QList<Param>::ConstIterator it = parseResult.parameters.constBegin();
+ it != parseResult.parameters.constEnd(); ++it) {
+ if (it != parseResult.parameters.constBegin()) {
+ stream << ",";
+ }
+ stream << " " << param((*it).type) << " " << (*it).name;
+ }
+
+ if (cfg.parentInConstructor) {
+ if (parseResult.cfgFileNameArg || !parseResult.parameters.isEmpty()) {
+ stream << ",";
+ }
+ stream << " QObject *parent";
+ }
+
+}
+
+void KConfigSourceGenerator::createParentConstructorCall()
+{
+ stream << cfg.inherits << "(";
+ if (!parseResult.cfgFileName.isEmpty()) {
+ stream << " QStringLiteral( \"" << parseResult.cfgFileName << "\" ";
+ }
+ if (parseResult.cfgFileNameArg) {
+ if (! cfg.forceStringFilename) {
+ stream << " std::move( config ) ";
+ } else {
+ stream << " config ";
+ }
+ }
+ if (!parseResult.cfgFileName.isEmpty()) {
+ stream << ") ";
+ }
+ stream << ")" << endl;
+}
+
+void KConfigSourceGenerator::createInitializerList()
+{
+ for (const auto &parameter : qAsConst(parseResult.parameters)) {
+ stream << " , mParam" << parameter.name << "(" << parameter.name << ")" << endl;
+ }
+
+ if (parseResult.hasNonModifySignals && !cfg.dpointer) {
+ stream << " , " << varName(QStringLiteral("settingsChanged"), cfg) << "(0)" << endl;
+ }
+}
+
+void KConfigSourceGenerator::createEnums(const CfgEntry *entry)
+{
+ if (entry->type != QLatin1String("Enum")) {
+ return;
+ }
+ stream << " QList<" << cfg.inherits << "::ItemEnum::Choice> values" << entry->name << ";" << endl;
+
+ for (const auto &choice : qAsConst(entry->choices.choices)) {
+ stream << " {" << endl;
+ stream << " " << cfg.inherits << "::ItemEnum::Choice choice;" << endl;
+ stream << " choice.name = QStringLiteral(\"" << choice.name << "\");" << endl;
+ if (cfg.setUserTexts) {
+ if (!choice.label.isEmpty()) {
+ stream << " choice.label = "
+ << translatedString(cfg, choice.label, choice.context)
+ << ";" << endl;
+ }
+ if (!choice.toolTip.isEmpty()) {
+ stream << " choice.toolTip = "
+ << translatedString(cfg, choice.toolTip, choice.context)
+ << ";" << endl;
+ }
+ if (!choice.whatsThis.isEmpty()) {
+ stream << " choice.whatsThis = "
+ << translatedString(cfg, choice.whatsThis, choice.context)
+ << ";" << endl;
+ }
+ }
+ stream << " values" << entry->name << ".append( choice );" << endl;
+ stream << " }" << endl;
+ }
+}
+
+void KConfigSourceGenerator::createNormalEntry(const CfgEntry *entry, const QString& key)
+{
+ stream << " " << itemPath(entry, cfg) << " = "
+ << newItem(entry, key, entry->defaultValue, cfg) << endl;
+
+ if (!entry->min.isEmpty()) {
+ stream << " " << itemPath(entry, cfg) << "->setMinValue(" << entry->min << ");" << endl;
+ }
+ if (!entry->max.isEmpty()) {
+ stream << " " << itemPath(entry, cfg) << "->setMaxValue(" << entry->max << ");" << endl;
+ }
+
+ if (cfg.setUserTexts) {
+ stream << userTextsFunctions(entry, cfg);
+ }
+
+ if (cfg.allNotifiers || cfg.notifiers.contains(entry->name)) {
+ stream << " " << itemPath(entry, cfg) << "->setWriteFlags(KConfigBase::Notify);" << endl;
+ }
+
+ stream << " addItem( " << itemPath(entry, cfg);
+ QString quotedName = entry->name;
+ addQuotes(quotedName);
+ if (quotedName != key) {
+ stream << ", QStringLiteral( \"" << entry->name << "\" )";
+ }
+ stream << " );" << endl;
+}
+
+void KConfigSourceGenerator::createIndexedEntry(const CfgEntry *entry, const QString& key)
+{
+ for (int i = 0; i <= entry->paramMax; i++) {
+ QString itemVarStr(itemPath(entry, cfg) + QStringLiteral("[%1]").arg(i));
+
+ QString defaultStr = !entry->paramDefaultValues[i].isEmpty() ? entry->paramDefaultValues[i]
+ : !entry->defaultValue.isEmpty() ? paramString(entry->defaultValue, entry, i)
+ : defaultValue(entry->type);
+
+ stream << " " << itemVarStr << " = "
+ << newItem(entry, paramString(key, entry, i), defaultStr, cfg, QStringLiteral("[%1]").arg(i)) << endl;
+
+ if (cfg.setUserTexts) {
+ stream << userTextsFunctions(entry, cfg, itemVarStr, entry->paramName);
+ }
+
+ // Make mutators for enum parameters work by adding them with $(..) replaced by the
+ // param name. The check for isImmutable in the set* functions doesn't have the param
+ // name available, just the corresponding enum value (int), so we need to store the
+ // param names in a separate static list!.
+ const bool isEnum = entry->paramType == QLatin1String("Enum");
+ const QString arg = isEnum ? entry->paramValues[i] : QString::number(i);
+
+ QString paramName = entry->paramName;
+
+ stream << " addItem( " << itemVarStr << ", QStringLiteral( \"";
+ stream << paramName.replace(QStringLiteral("$(") + entry->param + QLatin1Char(')'), QLatin1String("%1")).arg( arg );
+ stream << "\" ) );" << endl;
+ }
+}
+
+void KConfigSourceGenerator::handleCurrentGroupChange(const CfgEntry *entry)
+{
+ if (entry->group == mCurrentGroup) {
+ return;
+ }
+
+ // HACK: This fixes one spacing line in the diff. Remove this in the future and adapt the testcases.
+ static bool first = true;
+ if (!entry->group.isEmpty()) {
+ if (!first) {
+ stream << endl;
+ }
+ first = false;
+ }
+
+ mCurrentGroup = entry->group;
+ stream << " setCurrentGroup( " << paramString(mCurrentGroup, parseResult.parameters) << " );";
+ stream << endl << endl;
+}
+
+void KConfigSourceGenerator::doConstructor()
+{
+ // Constructor
+ stream << cfg.className << "::" << cfg.className << "(";
+ createConstructorParameterList();
+ stream << " )" << endl;
+ stream << " : ";
+ createParentConstructorCall();
+ createInitializerList();
+
+ stream << "{" << endl;
+
+ if (cfg.parentInConstructor) {
+ stream << " setParent(parent);" << endl;
+ }
+
+ if (cfg.dpointer) {
+ stream << " d = new " << cfg.className << "Private;" << endl;
+ if (parseResult.hasNonModifySignals) {
+ stream << " " << varPath(QStringLiteral("settingsChanged"), cfg) << " = 0;" << endl;
+ }
+ }
+
+ // Needed in case the singleton class is used as baseclass for
+ // another singleton.
+ if (cfg.singleton) {
+ stream << " Q_ASSERT(!s_global" << cfg.className << "()->q);" << endl;
+ stream << " s_global" << cfg.className << "()->q = this;" << endl;
+ }
+
+ if (!parseResult.signalList.isEmpty()) {
+ // this cast to base-class pointer-to-member is valid C++
+ // https://stackoverflow.com/questions/4272909/is-it-safe-to-upcast-a-method-pointer-and-use-it-with-base-class-pointer/
+ stream << " KConfigCompilerSignallingItem::NotifyFunction notifyFunction ="
+ << " static_cast<KConfigCompilerSignallingItem::NotifyFunction>(&"
+ << cfg.className << "::itemChanged);" << endl;
+
+ stream << endl;
+ }
+
+ for (auto *entry : qAsConst(parseResult.entries)) {
+ handleCurrentGroupChange(entry);
+
+ const QString key = paramString(entry->key, parseResult.parameters);
+ if (!entry->code.isEmpty()) {
+ stream << entry->code << endl;
+ }
+ createEnums(entry);
+
+ if (!cfg.dpointer) {
+ stream << itemDeclaration(entry, cfg);
+ }
+
+ if (entry->param.isEmpty()) {
+ createNormalEntry(entry, key);
+ } else {
+ createIndexedEntry(entry, key);
+ }
+ }
+
+ stream << "}" << endl << endl;
+}
+
+void KConfigSourceGenerator::createGetterDPointerMode(const CfgEntry *entry)
+{
+ // Accessor
+ if (cfg.useEnumTypes && entry->type == QLatin1String("Enum")) {
+ stream << enumType(entry, cfg.globalEnums);
+ } else {
+ stream << cppType(entry->type);
+ }
+
+ stream << " " << getFunction(entry->name, cfg.className) << "(";
+ if (!entry->param.isEmpty()) {
+ stream << " " << cppType(entry->paramType) << " i ";
+ }
+ stream << ")" << Const << endl;
+
+ // function body inline only if not using dpointer
+ // for BC mode
+ startScope();
+ // HACK: Fix memberAccessorBody
+ stream << " " << memberAccessorBody(entry, cfg.globalEnums);
+ endScope();
+ stream << endl;
+}
+
+void KConfigSourceGenerator::createSetterDPointerMode(const CfgEntry *entry)
+{
+ // Manipulator
+ if (!(cfg.allMutators || cfg.mutators.contains(entry->name))) {
+ return;
+ }
+
+ stream << "void " << setFunction(entry->name, cfg.className) << "( ";
+ if (!entry->param.isEmpty()) {
+ stream << cppType(entry->paramType) << " i, ";
+ }
+
+ if (cfg.useEnumTypes && entry->type == QLatin1String("Enum")) {
+ stream << enumType(entry, cfg.globalEnums);
+ } else {
+ stream << param(entry->type);
+ }
+ stream << " v )" << endl;
+
+ // function body inline only if not using dpointer
+ // for BC mode
+ startScope();
+ memberMutatorBody(entry);
+ endScope();
+ stream << endl;
+}
+
+void KConfigSourceGenerator::createItemGetterDPointerMode(const CfgEntry *entry)
+{
+ // Item accessor
+ if (!cfg.itemAccessors) {
+ return;
+ }
+ stream << endl;
+ stream << cfg.inherits << "::Item" << itemType(entry->type) << " *"
+ << getFunction(entry->name, cfg.className) << "Item(";
+ if (!entry->param.isEmpty()) {
+ stream << " " << cppType(entry->paramType) << " i ";
+ }
+ stream << ")" << endl;
+ startScope();
+ stream << " " << itemAccessorBody(entry, cfg);
+ endScope();
+}
+
+void KConfigSourceGenerator::doGetterSetterDPointerMode()
+{
+ if (!cfg.dpointer) {
+ return;
+ }
+
+ // setters and getters go in Cpp if in dpointer mode
+ for (auto *entry : qAsConst(parseResult.entries)) {
+ createSetterDPointerMode(entry);
+ createGetterDPointerMode(entry);
+ createItemGetterDPointerMode(entry);
+ stream << endl;
+ }
+}
+
+void KConfigSourceGenerator::createDefaultValueGetterSetter()
+{
+ // default value getters always go in Cpp
+ for (auto *entry : qAsConst(parseResult.entries)) {
+ QString n = entry->name;
+ QString t = entry->type;
+
+ // Default value Accessor, as "helper" function
+ if ((cfg.allDefaultGetters || cfg.defaultGetters.contains(n)) && !entry->defaultValue.isEmpty()) {
+ stream << cppType(t) << " " << getDefaultFunction(n, cfg.className) << "_helper(";
+ if (!entry->param.isEmpty()) {
+ stream << " " << cppType(entry->paramType) << " i ";
+ }
+ stream << ")" << Const << endl;
+ startScope();
+ stream << memberGetDefaultBody(entry) << endl;
+ endScope();
+ stream << endl;
+ }
+ }
+}
+
+void KConfigSourceGenerator::createDestructor()
+{
+ stream << cfg.className << "::~" << cfg.className << "()" << endl;
+ startScope();
+ if (cfg.dpointer) {
+ stream << " delete d;" << endl;
+ }
+ if (cfg.singleton) {
+ stream << " s_global" << cfg.className << "()->q = nullptr;" << endl;
+ }
+ endScope();
+ stream << endl;
+}
+
+void KConfigSourceGenerator::createNonModifyingSignalsHelper()
+{
+ if (!parseResult.hasNonModifySignals) {
+ return;
+ }
+ stream << "bool " << cfg.className << "::" << "usrSave()" << endl;
+ startScope();
+ stream << " const bool res = " << cfg.inherits << "::usrSave();" << endl;
+ stream << " if (!res) return false;" << endl << endl;
+ for (const Signal &signal : qAsConst(parseResult.signalList)) {
+ if (signal.modify) {
+ continue;
+ }
+
+ stream << " if ( " << varPath(QStringLiteral("settingsChanged"), cfg) << " & " << signalEnumName(signal.name) << " )" << endl;
+ stream << " Q_EMIT " << signal.name << "(";
+ QList<Param>::ConstIterator it, itEnd = signal.arguments.constEnd();
+ for (it = signal.arguments.constBegin(); it != itEnd;) {
+ Param argument = *it;
+ bool cast = false;
+ if (cfg.useEnumTypes && argument.type == QLatin1String("Enum")) {
+ for (int i = 0, end = parseResult.entries.count(); i < end; ++i) {
+ if (parseResult.entries.at(i)->name == argument.name) {
+ stream << "static_cast<" << enumType(parseResult.entries.at(i), cfg.globalEnums) << ">(";
+ cast = true;
+ break;
+ }
+ }
+ }
+ stream << varPath(argument.name, cfg);
+ if (cast) {
+ stream << ")";
+ }
+ if (++it != itEnd) {
+ stream << ", ";
+ }
+ }
+
+ stream << ");" << endl;
+ }
+
+ stream << " " << varPath(QStringLiteral("settingsChanged"), cfg) << " = 0;" << endl;
+ stream << " return true;" << endl;
+ endScope();
+}
+
+void KConfigSourceGenerator::createSignalFlagsHandler()
+{
+ if (parseResult.signalList.isEmpty()) {
+ return;
+ }
+
+ stream << endl;
+ stream << "void " << cfg.className << "::" << "itemChanged(quint64 flags) {" << endl;
+ if (parseResult.hasNonModifySignals)
+ stream << " " << varPath(QStringLiteral("settingsChanged"), cfg) << " |= flags;" << endl;
+
+ if (!parseResult.signalList.isEmpty())
+ stream << endl;
+
+ for (const Signal &signal : qAsConst(parseResult.signalList)) {
+ if (signal.modify) {
+ stream << " if ( flags & " << signalEnumName(signal.name) << " ) {" << endl;
+ stream << " Q_EMIT " << signal.name << "();" << endl;
+ stream << " }" << endl;
+ }
+ }
+
+ stream << "}" << endl;
+}
+
+void KConfigSourceGenerator::includeMoc() {
+ const QString mocFileName = cfg.baseName + QStringLiteral(".moc");
+
+ if (parseResult.signalList.count() || cfg.generateProperties) {
+ // Add includemoc if they are signals defined.
+ stream << endl;
+ stream << "#include \"" << mocFileName << "\"" << endl;
+ stream << endl;
+ }
+}