KConfig

KConfigCodeGeneratorBase.cpp
1 /*
2  This file is part of the KDE libraries.
3 
4  SPDX-FileCopyrightText: 2003 Cornelius Schumacher <[email protected]>
5  SPDX-FileCopyrightText: 2003 Waldo Bastian <[email protected]>
6  SPDX-FileCopyrightText: 2003 Zack Rusin <[email protected]>
7  SPDX-FileCopyrightText: 2006 MichaĆ«l Larouche <[email protected]>
8  SPDX-FileCopyrightText: 2008 Allen Winter <[email protected]>
9  SPDX-FileCopyrightText: 2020 Tomaz Cananbrava <[email protected]>
10 
11  SPDX-License-Identifier: LGPL-2.0-or-later
12 */
13 
14 #include "KConfigCodeGeneratorBase.h"
15 #include "KConfigParameters.h"
16 #include "KConfigCommonStructs.h"
17 
18 #include <QTextStream>
19 #include <QLatin1Char>
20 #include <QFileInfo>
21 
22 #include <ostream>
23 #include <QDebug>
24 
25 #include <iostream>
26 
27 KConfigCodeGeneratorBase::KConfigCodeGeneratorBase(
28  const QString &inputFile,
29  const QString &baseDir,
30  const QString &fileName,
31  const KConfigParameters &parameters,
32  ParseResult &parseResult)
33  : parseResult(parseResult), m_inputFile(inputFile), m_baseDir(baseDir), m_fileName(fileName), m_cfg(parameters)
34 {
35  m_file.setFileName(m_fileName);
36  if (!m_file.open(QIODevice::WriteOnly)) {
37  std::cerr << "Can not open '" << qPrintable(m_fileName) << "for writing." << std::endl;
38  exit(1);
39  }
40  m_stream.setDevice(&m_file);
41  m_stream.setCodec("utf-8");
42 
43  if (m_cfg.staticAccessors) {
44  m_this = QStringLiteral("self()->");
45  } else {
46  m_const = QStringLiteral(" const");
47  }
48 }
49 
50 KConfigCodeGeneratorBase::~KConfigCodeGeneratorBase()
51 {
52  save();
53 }
54 
55 void KConfigCodeGeneratorBase::save()
56 {
57  m_file.close();
58 }
59 
60 //TODO: Remove this weird logic and adapt the testcases
61 void KConfigCodeGeneratorBase::indent()
62 {
63  if (m_indentLevel >= 4) {
64  m_indentLevel += 2;
65  } else {
66  m_indentLevel += 4;
67  }
68 }
69 
70 void KConfigCodeGeneratorBase::unindent()
71 {
72  if (m_indentLevel > 4) {
73  m_indentLevel -= 2;
74  } else {
75  m_indentLevel -= 4;
76  }
77 }
78 
79 QString KConfigCodeGeneratorBase::whitespace() const
80 {
81  QString spaces;
82  for (int i = 0; i < m_indentLevel; i++) {
83  spaces.append(QLatin1Char(' '));
84  }
85  return spaces;
86 }
87 
88 void KConfigCodeGeneratorBase::startScope()
89 {
90  m_stream << whitespace() << QLatin1Char('{');
91  m_stream << '\n';
92  indent();
93 }
94 
95 void KConfigCodeGeneratorBase::endScope(ScopeFinalizer finalizer)
96 {
97  unindent();
98  m_stream << whitespace() << QLatin1Char('}');
99  if (finalizer == ScopeFinalizer::Semicolon) {
100  m_stream << ';';
101  }
102  m_stream << '\n';
103 }
104 
105 void KConfigCodeGeneratorBase::start()
106 {
107  const QString m_fileName = QFileInfo(m_inputFile).fileName();
108  m_stream << "// This file is generated by kconfig_compiler_kf5 from " << m_fileName << ".kcfg" << ".\n";
109  m_stream << "// All changes you do to this file will be lost.\n";
110 }
111 
112 void KConfigCodeGeneratorBase::addHeaders(const QStringList &headerList)
113 {
114  for (auto include : qAsConst(headerList)) {
115  if (include.startsWith(QLatin1Char('"'))) {
116  m_stream << "#include " << include << '\n';
117  } else {
118  m_stream << "#include <" << include << ">\n";
119  }
120  }
121 }
122 
123 // adds as many 'namespace foo {' lines to p_out as
124 // there are namespaces in p_ns
125 void KConfigCodeGeneratorBase::beginNamespaces()
126 {
127  if (!m_cfg.nameSpace.isEmpty()) {
128  for (const QString &ns : m_cfg.nameSpace.split(QStringLiteral("::"))) {
129  m_stream << "namespace " << ns << " {\n";
130  }
131  m_stream << '\n';
132  }
133 }
134 
135 // adds as many '}' lines to p_out as
136 // there are namespaces in p_ns
137 void KConfigCodeGeneratorBase::endNamespaces()
138 {
139  if (!m_cfg.nameSpace.isEmpty()) {
140  m_stream << '\n';
141  const int namespaceCount = m_cfg.nameSpace.count(QStringLiteral("::")) + 1;
142  for (int i = 0; i < namespaceCount; ++i) {
143  m_stream << "}\n";
144  }
145  }
146 }
147 
148 // returns the member accesor implementation
149 // which should go in the h file if inline
150 // or the cpp file if not inline
151 QString KConfigCodeGeneratorBase::memberAccessorBody(const CfgEntry *e, bool globalEnums) const
152 {
153  QString result;
154  QTextStream out(&result, QIODevice::WriteOnly);
155  QString n = e->name;
156  QString t = e->type;
157  bool useEnumType = m_cfg.useEnumTypes && t == QLatin1String("Enum");
158 
159  out << "return ";
160  if (useEnumType) {
161  out << "static_cast<" << enumType(e, globalEnums) << ">(";
162  }
163  out << m_this << varPath(n, m_cfg);
164  if (!e->param.isEmpty()) {
165  out << "[i]";
166  }
167  if (useEnumType) {
168  out << ")";
169  }
170  out << ";\n";
171 
172  return result;
173 }
174 
175 void KConfigCodeGeneratorBase::memberImmutableBody(const CfgEntry *e, bool globalEnums)
176 {
177  QString n = e->name;
178  QString t = e->type;
179 
180  stream() << whitespace() << "return " << m_this << "isImmutable( QStringLiteral( \"";
181  if (!e->param.isEmpty()) {
182  stream() << QString(e->paramName).replace(QLatin1String("$(") + e->param + QLatin1Char(')'), QLatin1String("%1")) << "\" ).arg( ";
183  if (e->paramType == QLatin1String("Enum")) {
184  stream() << "QLatin1String( ";
185 
186  if (globalEnums) {
187  stream() << enumName(e->param) << "ToString[i]";
188  } else {
189  stream() << enumName(e->param) << "::enumToString[i]";
190  }
191 
192  stream() << " )";
193  } else {
194  stream() << "i";
195  }
196  stream() << " )";
197  } else {
198  stream() << n << "\" )";
199  }
200  stream() << " );\n";
201 }
202 
203 void KConfigCodeGeneratorBase::createIfSetLogic(const CfgEntry *e, const QString &varExpression)
204 {
205  const QString n = e->name;
206  const QString t = e->type;
207  const bool hasBody = !e->signalList.empty() || m_cfg.generateProperties;
208 
209  m_stream << whitespace() << "if (";
210  if (hasBody) {
211  m_stream << "v != " << varExpression << " && ";
212  }
213 
214  const auto immutablefunction = immutableFunction(n, m_cfg.dpointer ? m_cfg.className : QString());
215  m_stream << "!" << m_this << immutablefunction << "(";
216  if (!e->param.isEmpty()) {
217  m_stream << " i ";
218  }
219  m_stream << "))";
220 }
221 
222 void KConfigCodeGeneratorBase::memberMutatorBody(const CfgEntry *e)
223 {
224  QString n = e->name;
225  QString t = e->type;
226 
227  // HACK: Don't open '{' manually, use startScope / endScope to automatically handle whitespace indentation.
228  if (!e->min.isEmpty()) {
229  if (e->min != QLatin1String("0") || !isUnsigned(t)) { // skip writing "if uint<0" (#187579)
230  m_stream << whitespace() << "if (v < " << e->min << ")\n";
231  m_stream << whitespace() << "{\n";
232  m_stream << whitespace(); addDebugMethod(m_stream, m_cfg, n);
233  m_stream << ": value \" << v << \" is less than the minimum value of " << e->min << "\";\n";
234  m_stream << whitespace() << " v = " << e->min << ";\n";
235  m_stream << whitespace() << "}\n";
236  }
237  }
238 
239  if (!e->max.isEmpty()) {
240  m_stream << '\n';
241  m_stream << whitespace() << "if (v > " << e->max << ")\n";
242  m_stream << whitespace() << "{\n";
243  m_stream << whitespace(); addDebugMethod(m_stream, m_cfg, n);
244  m_stream << ": value \" << v << \" is greater than the maximum value of " << e->max << "\";\n";
245  m_stream << whitespace() << " v = " << e->max << ";\n";
246  m_stream << whitespace() << "}\n\n";
247  }
248 
249  const QString varExpression = m_this + varPath(n, m_cfg) + (e->param.isEmpty() ? QString() : QStringLiteral("[i]"));
250 
251  // TODO: Remove this `hasBody` logic, always use an '{' for the if.
252  const bool hasBody = !e->signalList.empty() || m_cfg.generateProperties;
253 
254  // m_this call creates an `if (someTest ...) that's just to long to throw over the code.
255  createIfSetLogic(e, varExpression);
256  m_stream << (hasBody ? " {" : "") << '\n';
257  m_stream << whitespace() << " " << varExpression << " = v;\n";
258 
259  const auto listSignal = e->signalList;
260  for (const Signal &signal : qAsConst(listSignal)) {
261  if (signal.modify) {
262  m_stream << whitespace() << " Q_EMIT " << m_this << signal.name << "();\n";
263  } else {
264  m_stream << whitespace() << " " << m_this << varPath(QStringLiteral("settingsChanged"), m_cfg)
265  << " |= " << signalEnumName(signal.name) << ";\n";
266  }
267  }
268  if (hasBody) {
269  m_stream << whitespace() << "}\n";
270  }
271 }
QString & append(QChar ch)
QString fileName() const const
QStringList split(const QString &sep, QString::SplitBehavior behavior, Qt::CaseSensitivity cs) const const
QString & replace(int position, int n, QChar after)
int count() const const
KGuiItem save()
Configuration Compiler Configuration.
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Fri Jul 3 2020 22:47:12 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.