Warning, file /frameworks/kconfig/src/kconfig_compiler/KConfigCodeGeneratorBase.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
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 "KConfigCodeGeneratorBase.h" 0015 0016 #include <QFileInfo> 0017 #include <QLatin1Char> 0018 0019 #include <QDebug> 0020 #include <ostream> 0021 0022 #include <iostream> 0023 0024 KConfigCodeGeneratorBase::KConfigCodeGeneratorBase(const QString &inputFile, 0025 const QString &baseDir, 0026 const QString &fileName, 0027 const KConfigParameters ¶meters, 0028 ParseResult &parseResult) 0029 : parseResult(parseResult) 0030 , m_inputFile(inputFile) 0031 , m_baseDir(baseDir) 0032 , m_fileName(fileName) 0033 , m_cfg(parameters) 0034 { 0035 m_file.setFileName(m_fileName); 0036 if (!m_file.open(QIODevice::WriteOnly)) { 0037 std::cerr << "Can not open '" << qPrintable(m_fileName) << "for writing." << std::endl; 0038 exit(1); 0039 } 0040 m_stream.setDevice(&m_file); 0041 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 0042 m_stream.setCodec("utf-8"); 0043 #endif 0044 0045 if (m_cfg.staticAccessors) { 0046 m_this = QStringLiteral("self()->"); 0047 } else { 0048 m_const = QStringLiteral(" const"); 0049 } 0050 } 0051 0052 KConfigCodeGeneratorBase::~KConfigCodeGeneratorBase() 0053 { 0054 save(); 0055 } 0056 0057 void KConfigCodeGeneratorBase::save() 0058 { 0059 m_file.close(); 0060 } 0061 0062 // TODO: Remove this weird logic and adapt the testcases 0063 void KConfigCodeGeneratorBase::indent() 0064 { 0065 if (m_indentLevel >= 4) { 0066 m_indentLevel += 2; 0067 } else { 0068 m_indentLevel += 4; 0069 } 0070 } 0071 0072 void KConfigCodeGeneratorBase::unindent() 0073 { 0074 if (m_indentLevel > 4) { 0075 m_indentLevel -= 2; 0076 } else { 0077 m_indentLevel -= 4; 0078 } 0079 } 0080 0081 QString KConfigCodeGeneratorBase::whitespace() const 0082 { 0083 QString spaces; 0084 for (int i = 0; i < m_indentLevel; i++) { 0085 spaces.append(QLatin1Char(' ')); 0086 } 0087 return spaces; 0088 } 0089 0090 void KConfigCodeGeneratorBase::startScope() 0091 { 0092 m_stream << whitespace() << QLatin1Char('{'); 0093 m_stream << '\n'; 0094 indent(); 0095 } 0096 0097 void KConfigCodeGeneratorBase::endScope(ScopeFinalizer finalizer) 0098 { 0099 unindent(); 0100 m_stream << whitespace() << QLatin1Char('}'); 0101 if (finalizer == ScopeFinalizer::Semicolon) { 0102 m_stream << ';'; 0103 } 0104 m_stream << '\n'; 0105 } 0106 0107 void KConfigCodeGeneratorBase::start() 0108 { 0109 const QString m_fileName = QFileInfo(m_inputFile).fileName(); 0110 m_stream << "// This file is generated by kconfig_compiler_kf5 from " << m_fileName << ".kcfg" 0111 << ".\n"; 0112 m_stream << "// All changes you do to this file will be lost.\n"; 0113 } 0114 0115 void KConfigCodeGeneratorBase::addHeaders(const QStringList &headerList) 0116 { 0117 for (const auto &include : headerList) { 0118 if (include.startsWith(QLatin1Char('"'))) { 0119 m_stream << "#include " << include << '\n'; 0120 } else { 0121 m_stream << "#include <" << include << ">\n"; 0122 } 0123 } 0124 } 0125 0126 // adds as many 'namespace foo {' lines to p_out as 0127 // there are namespaces in p_ns 0128 void KConfigCodeGeneratorBase::beginNamespaces() 0129 { 0130 if (!m_cfg.nameSpace.isEmpty()) { 0131 const auto nameSpaceList = m_cfg.nameSpace.split(QStringLiteral("::")); 0132 for (const QString &ns : nameSpaceList) { 0133 m_stream << "namespace " << ns << " {\n"; 0134 } 0135 m_stream << '\n'; 0136 } 0137 } 0138 0139 // adds as many '}' lines to p_out as 0140 // there are namespaces in p_ns 0141 void KConfigCodeGeneratorBase::endNamespaces() 0142 { 0143 if (!m_cfg.nameSpace.isEmpty()) { 0144 m_stream << '\n'; 0145 const int namespaceCount = m_cfg.nameSpace.count(QStringLiteral("::")) + 1; 0146 for (int i = 0; i < namespaceCount; ++i) { 0147 m_stream << "}\n"; 0148 } 0149 } 0150 } 0151 0152 // returns the member accessor implementation 0153 // which should go in the h file if inline 0154 // or the cpp file if not inline 0155 QString KConfigCodeGeneratorBase::memberAccessorBody(const CfgEntry *e, bool globalEnums) const 0156 { 0157 QString result; 0158 QTextStream out(&result, QIODevice::WriteOnly); 0159 QString n = e->name; 0160 QString t = e->type; 0161 bool useEnumType = m_cfg.useEnumTypes && t == QLatin1String("Enum"); 0162 0163 out << "return "; 0164 if (useEnumType) { 0165 out << "static_cast<" << enumType(e, globalEnums) << ">("; 0166 } 0167 out << m_this << varPath(n, m_cfg); 0168 if (!e->param.isEmpty()) { 0169 out << "[i]"; 0170 } 0171 if (useEnumType) { 0172 out << ")"; 0173 } 0174 out << ";\n"; 0175 0176 return result; 0177 } 0178 0179 void KConfigCodeGeneratorBase::memberImmutableBody(const CfgEntry *e, bool globalEnums) 0180 { 0181 stream() << whitespace() << "return " << m_this << "isImmutable( QStringLiteral( \""; 0182 if (!e->param.isEmpty()) { 0183 stream() << QString(e->paramName).replace(QLatin1String("$(%1)").arg(e->param), QLatin1String("%1")) << "\" ).arg( "; 0184 if (e->paramType == QLatin1String("Enum")) { 0185 stream() << "QLatin1String( "; 0186 0187 if (globalEnums) { 0188 stream() << enumName(e->param) << "ToString[i]"; 0189 } else { 0190 stream() << enumName(e->param) << "::enumToString[i]"; 0191 } 0192 0193 stream() << " )"; 0194 } else { 0195 stream() << "i"; 0196 } 0197 stream() << " )"; 0198 } else { 0199 stream() << e->name << "\" )"; 0200 } 0201 stream() << " );\n"; 0202 } 0203 0204 void KConfigCodeGeneratorBase::createIfSetLogic(const CfgEntry *e, const QString &varExpression) 0205 { 0206 const bool hasBody = !e->signalList.empty() || m_cfg.generateProperties; 0207 0208 m_stream << whitespace() << "if ("; 0209 if (hasBody) { 0210 m_stream << "v != " << varExpression << " && "; 0211 } 0212 0213 const auto immutablefunction = immutableFunction(e->name, m_cfg.dpointer ? m_cfg.className : QString{}); 0214 m_stream << "!" << m_this << immutablefunction << "("; 0215 if (!e->param.isEmpty()) { 0216 m_stream << " i "; 0217 } 0218 m_stream << "))"; 0219 } 0220 0221 void KConfigCodeGeneratorBase::memberMutatorBody(const CfgEntry *e) 0222 { 0223 // HACK: Don't open '{' manually, use startScope / endScope to automatically handle whitespace indentation. 0224 if (!e->min.isEmpty()) { 0225 if (e->min != QLatin1String("0") || !isUnsigned(e->type)) { // skip writing "if uint<0" (#187579) 0226 m_stream << whitespace() << "if (v < " << e->min << ")\n"; 0227 m_stream << whitespace() << "{\n"; 0228 m_stream << whitespace(); 0229 addDebugMethod(m_stream, m_cfg, e->name); 0230 m_stream << ": value \" << v << \" is less than the minimum value of " << e->min << "\";\n"; 0231 m_stream << whitespace() << " v = " << e->min << ";\n"; 0232 m_stream << whitespace() << "}\n"; 0233 } 0234 } 0235 0236 if (!e->max.isEmpty()) { 0237 m_stream << '\n'; 0238 m_stream << whitespace() << "if (v > " << e->max << ")\n"; 0239 m_stream << whitespace() << "{\n"; 0240 m_stream << whitespace(); 0241 addDebugMethod(m_stream, m_cfg, e->name); 0242 m_stream << ": value \" << v << \" is greater than the maximum value of " << e->max << "\";\n"; 0243 m_stream << whitespace() << " v = " << e->max << ";\n"; 0244 m_stream << whitespace() << "}\n\n"; 0245 } 0246 0247 const QString varExpression = m_this + varPath(e->name, m_cfg) + (e->param.isEmpty() ? QString{} : QStringLiteral("[i]")); 0248 0249 // TODO: Remove this `hasBody` logic, always use an '{' for the if. 0250 const bool hasBody = !e->signalList.empty() || m_cfg.generateProperties; 0251 0252 // m_this call creates an `if (someTest ...) that's just to long to throw over the code. 0253 createIfSetLogic(e, varExpression); 0254 m_stream << (hasBody ? " {" : "") << '\n'; 0255 m_stream << whitespace() << " " << varExpression << " = v;\n"; 0256 0257 const auto listSignal = e->signalList; 0258 for (const Signal &signal : std::as_const(listSignal)) { 0259 if (signal.modify) { 0260 m_stream << whitespace() << " Q_EMIT " << m_this << signal.name << "();\n"; 0261 } else { 0262 m_stream << whitespace() << " " << m_this << varPath(QStringLiteral("settingsChanged"), m_cfg) << ".insert(" << signalEnumName(signal.name) << ");\n"; 0263 } 0264 } 0265 if (hasBody) { 0266 m_stream << whitespace() << "}\n"; 0267 } 0268 }