1/*
2 This file is part of the KDE libraries.
3
4 SPDX-FileCopyrightText: 2003 Cornelius Schumacher <schumacher@kde.org>
5 SPDX-FileCopyrightText: 2003 Waldo Bastian <bastian@kde.org>
6 SPDX-FileCopyrightText: 2003 Zack Rusin <zack@kde.org>
7 SPDX-FileCopyrightText: 2006 Michaƫl Larouche <michael.larouche@kdemail.net>
8 SPDX-FileCopyrightText: 2008 Allen Winter <winter@kde.org>
9 SPDX-FileCopyrightText: 2020 Tomaz Cananbrava <tcanabrava@kde.org>
10
11 SPDX-License-Identifier: LGPL-2.0-or-later
12*/
13
14#include "KConfigHeaderGenerator.h"
15
16#include <QDebug>
17#include <QTextStream>
18#include <iostream>
19
20KConfigHeaderGenerator::KConfigHeaderGenerator(const QString &inputFile, const QString &baseDir, const KConfigParameters &cfg, ParseResult &result)
21 : KConfigCodeGeneratorBase(inputFile, baseDir, baseDir + cfg.baseName + QLatin1Char('.') + cfg.headerExtension, cfg, result)
22{
23}
24
25void KConfigHeaderGenerator::start()
26{
27 KConfigCodeGeneratorBase::start();
28 startHeaderGuards();
29 createHeaders();
30
31 beginNamespaces();
32
33 createForwardDeclarations();
34
35 doClassDefinition();
36
37 endNamespaces();
38 endHeaderGuards();
39}
40
41void KConfigHeaderGenerator::doClassDefinition()
42{
43 stream() << "class " << cfg().visibility << cfg().className << " : public " << cfg().inherits << '\n';
44 startScope();
45
46 // Add Q_OBJECT macro if the config need signals.
47 if (!parseResult.signalList.isEmpty() || cfg().generateProperties) {
48 stream() << " Q_OBJECT\n";
49 }
50
51 if (cfg().qmlRegistration) {
52 stream() << " QML_ELEMENT\n";
53
54 if (cfg().singleton) {
55 stream() << " QML_SINGLETON\n";
56 }
57
58 if (cfg().qmlUncreatable) {
59 stream() << " QML_UNCREATABLE(\"\")\n";
60 }
61 }
62 stream() << " public:\n";
63 implementEnums();
64 createConstructor();
65 createDestructor();
66
67 for (const auto *entry : std::as_const(t&: parseResult.entries)) {
68 const QString returnType = (cfg().useEnumTypes && entry->type == QLatin1String("Enum")) ? enumType(e: entry, globalEnums: cfg().globalEnums) : cppType(t: entry->type);
69
70 createSetters(entry);
71 createProperties(entry, returnType);
72 createImmutableProperty(entry);
73 createDefaultValueProperty(entry, returnType);
74 createGetters(entry, returnType);
75 createImmutableGetters(entry);
76 createDefaultValueMember(entry);
77 createItemAcessors(entry, returnType);
78 }
79
80 createSignals();
81 stream() << " protected:\n";
82 createSingleton();
83
84 // TODO: Move those to functions too.
85 if (parseResult.hasNonModifySignals) {
86 stream() << whitespace() << "bool usrSave() override;\n";
87 }
88
89 // Member variables
90 if (!cfg().memberVariables.isEmpty() //
91 && cfg().memberVariables != QLatin1String("private") //
92 && cfg().memberVariables != QLatin1String("dpointer")) {
93 stream() << " " << cfg().memberVariables << ":\n";
94 }
95
96 // Class Parameters
97 for (const auto &parameter : std::as_const(t&: parseResult.parameters)) {
98 stream() << whitespace() << "" << cppType(t: parameter.type) << " mParam" << parameter.name << ";\n";
99 }
100
101 createNonDPointerHelpers();
102 createDPointer();
103
104 if (cfg().customAddons) {
105 stream() << whitespace() << "// Include custom additions\n";
106 stream() << whitespace() << "#include \"" << cfg().baseName << "_addons." << cfg().headerExtension << "\"\n";
107 }
108
109 endScope(finalizer: ScopeFinalizer::Semicolon);
110}
111
112void KConfigHeaderGenerator::createHeaders()
113{
114 addHeaders(header: cfg().headerIncludes);
115 if (!cfg().headerIncludes.isEmpty()) {
116 stream() << '\n';
117 }
118
119 if (!cfg().singleton && parseResult.parameters.isEmpty()) {
120 addHeaders(header: {QStringLiteral("qglobal.h")});
121 }
122
123 if (cfg().inherits == QLatin1String("KCoreConfigSkeleton")) {
124 addHeaders(header: {QStringLiteral("kcoreconfigskeleton.h")});
125 } else {
126 addHeaders(header: {QStringLiteral("kconfigskeleton.h")});
127 }
128
129 addHeaders(header: {QStringLiteral("QCoreApplication"), QStringLiteral("QDebug")});
130 if (!cfg().dpointer && parseResult.hasNonModifySignals) {
131 addHeaders(header: {QStringLiteral("QSet")});
132 }
133
134 if (cfg().qmlRegistration) {
135 addHeaders(header: {QStringLiteral("qqmlintegration.h")});
136 }
137
138 stream() << '\n';
139
140 addHeaders(header: parseResult.includes);
141 if (!parseResult.includes.isEmpty()) {
142 stream() << '\n';
143 }
144}
145
146void KConfigHeaderGenerator::startHeaderGuards()
147{
148 const bool hasNamespace = !cfg().nameSpace.isEmpty();
149 const QString namespaceName = QString(QString(cfg().nameSpace).replace(before: QLatin1String("::"), after: QLatin1String("_"))).toUpper();
150 const QString namespaceStr = hasNamespace ? namespaceName + QLatin1Char('_') : QString{};
151 const QString defineName = namespaceStr + cfg().className.toUpper() + QStringLiteral("_H");
152
153 stream() << "#ifndef " << defineName << '\n';
154 stream() << "#define " << defineName << '\n';
155 stream() << '\n';
156}
157
158void KConfigHeaderGenerator::endHeaderGuards()
159{
160 stream() << '\n';
161 stream() << "#endif";
162 stream() << '\n';
163 // HACK: Original files ended with two last newlines, add them.
164 stream() << '\n';
165}
166
167void KConfigHeaderGenerator::implementChoiceEnums(const CfgEntry *entry, const CfgEntry::Choices &choices)
168{
169 const QList<CfgEntry::Choice> chlist = choices.choices;
170
171 if (chlist.isEmpty()) {
172 return;
173 }
174
175 QStringList values;
176 for (const auto &choice : std::as_const(t: chlist)) {
177 values.append(t: choices.prefix + choice.name);
178 }
179
180 if (choices.name().isEmpty()) {
181 if (cfg().globalEnums) {
182 stream() << whitespace() << "enum " << enumName(n: entry->name, c: entry->choices) << " { " << values.join(QStringLiteral(", ")) << " };\n";
183 if (cfg().generateProperties) {
184 stream() << whitespace() << "Q_ENUM(" << enumName(n: entry->name, c: entry->choices) << ")\n";
185 }
186 } else {
187 // Create an automatically named enum
188 stream() << whitespace() << "class " << enumName(n: entry->name, c: entry->choices) << '\n';
189 stream() << whitespace() << "{\n";
190 stream() << whitespace() << " public:\n";
191 stream() << whitespace() << " enum type { " << values.join(QStringLiteral(", ")) << ", COUNT };\n";
192 stream() << whitespace() << "};\n";
193 }
194 } else if (!choices.external()) {
195 // Create a named enum
196 stream() << whitespace() << "enum " << enumName(n: entry->name, c: entry->choices) << " { " << values.join(QStringLiteral(", ")) << " };\n";
197 if (cfg().generateProperties) {
198 stream() << whitespace() << "Q_ENUM(" << enumName(n: entry->name, c: entry->choices) << ")\n";
199 }
200 }
201}
202
203void KConfigHeaderGenerator::implementValueEnums(const CfgEntry *entry, const QStringList &values)
204{
205 if (values.isEmpty()) {
206 return;
207 }
208
209 if (cfg().globalEnums) {
210 // ### FIXME!!
211 // make the following string table an index-based string search!
212 // ###
213 stream() << whitespace() << "enum " << enumName(n: entry->param) << " { " << values.join(QStringLiteral(", ")) << " };\n";
214 stream() << whitespace() << "static const char* const " << enumName(n: entry->param) << "ToString[];\n";
215 } else {
216 stream() << whitespace() << "class " << enumName(n: entry->param) << '\n';
217 stream() << whitespace() << "{\n";
218 stream() << whitespace() << " public:\n";
219 stream() << whitespace() << " enum type { " << values.join(QStringLiteral(", ")) << ", COUNT };\n";
220 stream() << whitespace() << " static const char* const enumToString[];\n";
221 stream() << whitespace() << "};\n";
222 }
223}
224
225void KConfigHeaderGenerator::implementEnums()
226{
227 if (parseResult.entries.isEmpty()) {
228 return;
229 }
230
231 for (const auto *entry : std::as_const(t&: parseResult.entries)) {
232 const CfgEntry::Choices &choices = entry->choices;
233 const QStringList values = entry->paramValues;
234
235 implementChoiceEnums(entry, choices);
236 implementValueEnums(entry, values);
237 }
238 stream() << '\n';
239}
240
241void KConfigHeaderGenerator::createSignals()
242{
243 // Signal definition.
244 if (parseResult.signalList.isEmpty()) {
245 return;
246 }
247
248 stream() << "\n enum {\n";
249
250 // HACK: Use C-Style for add a comma in all but the last element,
251 // just to make the source generated code equal to the old one.
252 // When we are sure, revert this to a range-based-for and just add
253 // a last comma, as it's valid c++.
254 for (int i = 0, end = parseResult.signalList.size(); i < end; i++) {
255 auto signal = parseResult.signalList.at(i);
256 stream() << whitespace() << " " << signalEnumName(signalName: signal.name) << " = " << (i + 1);
257 if (i != end - 1) {
258 stream() << ",\n";
259 }
260 }
261 stream() << '\n';
262 stream() << whitespace() << "};\n\n";
263
264 stream() << " Q_SIGNALS:";
265 for (const Signal &signal : std::as_const(t&: parseResult.signalList)) {
266 stream() << '\n';
267 if (!signal.label.isEmpty()) {
268 stream() << whitespace() << "/**\n";
269 stream() << whitespace() << " " << signal.label << '\n';
270 stream() << whitespace() << "*/\n";
271 }
272 stream() << whitespace() << "void " << signal.name << "(";
273
274 auto it = signal.arguments.cbegin();
275 const auto itEnd = signal.arguments.cend();
276 while (it != itEnd) {
277 Param argument = *it;
278 QString type = param(t: argument.type);
279 if (cfg().useEnumTypes && argument.type == QLatin1String("Enum")) {
280 for (const auto *entry : std::as_const(t&: parseResult.entries)) {
281 if (entry->name == argument.name) {
282 type = enumType(e: entry, globalEnums: cfg().globalEnums);
283 break;
284 }
285 }
286 }
287 stream() << type << " " << argument.name;
288 if (++it != itEnd) {
289 stream() << ", ";
290 }
291 }
292 stream() << ");\n";
293 }
294 stream() << '\n';
295
296 stream() << " private:\n";
297 stream() << whitespace() << "void itemChanged(quint64 signalFlag);\n";
298 stream() << '\n';
299}
300
301void KConfigHeaderGenerator::createDPointer()
302{
303 if (!cfg().dpointer) {
304 return;
305 }
306
307 // use a private class for both member variables and items
308 stream() << " private:\n";
309 for (const auto *entry : std::as_const(t&: parseResult.entries)) {
310 if (cfg().allDefaultGetters || cfg().defaultGetters.contains(str: entry->name)) {
311 stream() << whitespace() << "";
312 if (cfg().staticAccessors) {
313 stream() << "static ";
314 }
315 stream() << cppType(t: entry->type) << " " << getDefaultFunction(n: entry->name) << "_helper(";
316 if (!entry->param.isEmpty()) {
317 stream() << " " << cppType(t: entry->paramType) << " i ";
318 }
319 stream() << ")" << Const() << ";\n";
320 }
321 }
322 stream() << whitespace() << "" << cfg().className << "Private *d;\n";
323}
324
325void KConfigHeaderGenerator::createConstructor()
326{
327 if (cfg().singleton) {
328 stream() << whitespace() << "static " << cfg().className << " *self();\n";
329
330 if (cfg().qmlRegistration) {
331 stream() << whitespace() << "static " << cfg().className << " *create(QQmlEngine *, QJSEngine *);\n";
332 }
333
334 if (parseResult.cfgFileNameArg) {
335 stream() << whitespace() << "static void instance(const QString& cfgfilename);\n";
336 stream() << whitespace() << "static void instance(KSharedConfig::Ptr config);\n";
337 }
338 return;
339 }
340
341 stream() << whitespace() << "" << cfg().className << "(";
342 if (cfg().kConfigConstructor) {
343 stream() << " std::unique_ptr<KConfig> config";
344 } else if (parseResult.cfgFileNameArg) {
345 if (cfg().forceStringFilename) {
346 stream() << " const QString &cfgfilename" << (parseResult.parameters.isEmpty() ? " = QString()" : ", ");
347 } else if (parseResult.cfgStateConfig) {
348 stream() << " KSharedConfig::Ptr config" << (parseResult.parameters.isEmpty() ? " = KSharedConfig::openStateConfig()" : ", ");
349 } else {
350 stream() << " KSharedConfig::Ptr config" << (parseResult.parameters.isEmpty() ? " = KSharedConfig::openConfig()" : ", ");
351 }
352 }
353 if (cfg().forceStringFilename && parseResult.cfgStateConfig) {
354 std::cerr << "One can not use ForceStringFilename and use the stateConfig attribute, consider "
355 "removing the ForceStringFilename kcfgc option if you want to use state data"
356 << std::endl;
357 }
358
359 bool first = true;
360 for (const auto &parameter : std::as_const(t&: parseResult.parameters)) {
361 if (first) {
362 first = false;
363 } else {
364 stream() << ",";
365 }
366
367 stream() << " " << param(t: parameter.type) << " " << parameter.name;
368 }
369
370 if (cfg().parentInConstructor) {
371 if (parseResult.cfgFileNameArg || !parseResult.parameters.isEmpty() || cfg().kConfigConstructor) {
372 stream() << ",";
373 }
374 stream() << " QObject *parent = nullptr";
375 }
376 stream() << " );\n";
377}
378
379void KConfigHeaderGenerator::createDestructor()
380{
381 stream() << whitespace() << "~" << cfg().className << "() override;\n\n";
382}
383
384void KConfigHeaderGenerator::createForwardDeclarations()
385{
386 // Private class declaration
387 if (cfg().dpointer) {
388 stream() << "class " << cfg().className << "Private;\n\n";
389 }
390
391 if (cfg().qmlRegistration && cfg().singleton) {
392 stream() << "class QQmlEngine;\n";
393 stream() << "class QJSEngine;\n\n";
394 }
395}
396
397void KConfigHeaderGenerator::createProperties(const CfgEntry *entry, const QString &returnType)
398{
399 if (!cfg().generateProperties) {
400 return;
401 }
402 stream() << whitespace() << "Q_PROPERTY(" << returnType << ' ' << getFunction(n: entry->name);
403 stream() << " READ " << getFunction(n: entry->name);
404
405 if (cfg().allMutators || cfg().mutators.contains(str: entry->name)) {
406 const QString signal = changeSignalName(n: entry->name);
407 stream() << " WRITE " << setFunction(n: entry->name);
408 stream() << " NOTIFY " << signal;
409
410 // If we have the modified signal, we'll also need
411 // the changed signal as well
412 Signal s;
413 s.name = signal;
414 s.modify = true;
415 parseResult.signalList.append(t: s);
416 } else {
417 stream() << " CONSTANT";
418 }
419 stream() << ")\n";
420}
421
422void KConfigHeaderGenerator::createImmutableProperty(const CfgEntry *entry)
423{
424 if (!cfg().generateProperties) {
425 return;
426 }
427 stream() << whitespace();
428 stream() << "Q_PROPERTY(bool " << immutableFunction(n: entry->name);
429 stream() << " READ " << immutableFunction(n: entry->name);
430 stream() << " CONSTANT)\n";
431}
432
433void KConfigHeaderGenerator::createDefaultValueProperty(const CfgEntry *entry, const QString &returnType)
434{
435 if (!cfg().generateProperties) {
436 return;
437 }
438
439 if (!((cfg().allDefaultGetters || cfg().defaultGetters.contains(str: entry->name)) && !entry->defaultValue.isEmpty())) {
440 return;
441 }
442
443 stream() << whitespace();
444 stream() << "Q_PROPERTY(" << returnType << ' ' << getDefaultFunction(n: entry->name);
445 stream() << " READ " << getDefaultFunction(n: entry->name);
446 stream() << " CONSTANT)\n";
447}
448
449void KConfigHeaderGenerator::createSetters(const CfgEntry *entry)
450{
451 // Manipulator
452 if (!cfg().allMutators && !cfg().mutators.contains(str: entry->name)) {
453 return;
454 }
455
456 stream() << whitespace() << "/**\n";
457 stream() << whitespace() << " Set " << entry->label << '\n';
458 stream() << whitespace() << "*/\n";
459
460 if (cfg().staticAccessors) {
461 stream() << whitespace() << "static\n";
462 }
463
464 stream() << whitespace() << "void " << setFunction(n: entry->name) << "( ";
465 if (!entry->param.isEmpty()) {
466 stream() << cppType(t: entry->paramType) << " i, ";
467 }
468
469 stream() << (cfg().useEnumTypes && entry->type == QLatin1String("Enum") ? enumType(e: entry, globalEnums: cfg().globalEnums) : param(t: entry->type));
470
471 stream() << " v )";
472
473 // function body inline only if not using dpointer
474 // for BC mode
475 if (!cfg().dpointer) {
476 stream() << '\n';
477 startScope();
478 memberMutatorBody(e: entry);
479 endScope();
480 stream() << '\n';
481 } else {
482 stream() << ";\n\n";
483 }
484}
485
486void KConfigHeaderGenerator::createGetters(const CfgEntry *entry, const QString &returnType)
487{
488 // Accessor
489 stream() << whitespace() << "/**\n";
490 stream() << whitespace() << " Get " << entry->label << '\n';
491 stream() << whitespace() << "*/\n";
492 if (cfg().staticAccessors) {
493 stream() << whitespace() << "static\n";
494 }
495 stream() << whitespace() << "";
496 stream() << returnType;
497 stream() << " " << getFunction(n: entry->name) << "(";
498 if (!entry->param.isEmpty()) {
499 stream() << " " << cppType(t: entry->paramType) << " i ";
500 }
501 stream() << ")" << Const();
502
503 // function body inline only if not using dpointer
504 // for BC mode
505 if (!cfg().dpointer) {
506 stream() << '\n';
507 startScope();
508 stream() << whitespace() << memberAccessorBody(e: entry, globalEnums: cfg().globalEnums);
509 endScope();
510 stream() << '\n';
511 } else {
512 stream() << ";\n\n";
513 }
514}
515
516void KConfigHeaderGenerator::createImmutableGetters(const CfgEntry *entry)
517{
518 stream() << whitespace() << "/**\n";
519 stream() << whitespace() << " Is " << entry->label << " Immutable\n";
520 stream() << whitespace() << "*/\n";
521 // Immutable
522 if (cfg().staticAccessors) {
523 stream() << whitespace() << "static\n";
524 }
525 stream() << whitespace() << "";
526 stream() << "bool " << immutableFunction(n: entry->name) << "(";
527 if (!entry->param.isEmpty()) {
528 stream() << " " << cppType(t: entry->paramType) << " i ";
529 }
530 stream() << ")" << Const();
531 // function body inline only if not using dpointer
532 // for BC mode
533 if (!cfg().dpointer) {
534 stream() << '\n';
535 startScope();
536 memberImmutableBody(e: entry, globalEnums: cfg().globalEnums);
537 endScope();
538 stream() << '\n';
539 } else {
540 stream() << ";\n\n";
541 }
542}
543
544void KConfigHeaderGenerator::createItemAcessors(const CfgEntry *entry, const QString &returnType)
545{
546 Q_UNUSED(returnType)
547
548 // Item accessor
549 if (!cfg().itemAccessors) {
550 return;
551 }
552
553 const QString declType = entry->signalList.isEmpty() ? QStringLiteral("Item") + itemType(type: entry->type) : QStringLiteral("KConfigCompilerSignallingItem");
554
555 stream() << whitespace() << "/**\n";
556 stream() << whitespace() << " Get Item object corresponding to " << entry->name << "()" << '\n';
557 stream() << whitespace() << "*/\n";
558 stream() << whitespace() << declType << " *" << getFunction(n: entry->name) << "Item(";
559 if (!entry->param.isEmpty()) {
560 stream() << " " << cppType(t: entry->paramType) << " i ";
561 }
562 stream() << ")";
563 if (!cfg().dpointer) {
564 stream() << '\n';
565 startScope();
566 stream() << whitespace() << itemAccessorBody(e: entry, cfg: cfg());
567 endScope();
568 } else {
569 stream() << ";\n";
570 }
571
572 stream() << '\n';
573}
574
575void KConfigHeaderGenerator::createDefaultValueMember(const CfgEntry *entry)
576{
577 // Default value Accessor
578 if (!((cfg().allDefaultGetters || cfg().defaultGetters.contains(str: entry->name)) && !entry->defaultValue.isEmpty())) {
579 return;
580 }
581 stream() << whitespace() << "/**\n";
582 stream() << whitespace() << " Get " << entry->label << " default value\n";
583 stream() << whitespace() << "*/\n";
584 if (cfg().staticAccessors) {
585 stream() << whitespace() << "static\n";
586 }
587 stream() << whitespace() << "";
588 if (cfg().useEnumTypes && entry->type == QLatin1String("Enum")) {
589 stream() << enumType(e: entry, globalEnums: cfg().globalEnums);
590 } else {
591 stream() << cppType(t: entry->type);
592 }
593 stream() << " " << getDefaultFunction(n: entry->name) << "(";
594 if (!entry->param.isEmpty()) {
595 stream() << " " << cppType(t: entry->paramType) << " i ";
596 }
597 stream() << ")" << Const() << '\n';
598 stream() << whitespace() << "{\n";
599 stream() << whitespace() << " return ";
600 if (cfg().useEnumTypes && entry->type == QLatin1String("Enum")) {
601 stream() << "static_cast<" << enumType(e: entry, globalEnums: cfg().globalEnums) << ">(";
602 }
603 stream() << getDefaultFunction(n: entry->name) << "_helper(";
604 if (!entry->param.isEmpty()) {
605 stream() << " i ";
606 }
607 stream() << ")";
608 if (cfg().useEnumTypes && entry->type == QLatin1String("Enum")) {
609 stream() << ")";
610 }
611 stream() << ";\n";
612 stream() << whitespace() << "}\n";
613 stream() << '\n';
614}
615
616void KConfigHeaderGenerator::createSingleton()
617{
618 // Private constructor for singleton
619 if (!cfg().singleton) {
620 return;
621 }
622
623 stream() << whitespace() << "" << cfg().className << "(";
624 if (parseResult.cfgFileNameArg) {
625 stream() << "KSharedConfig::Ptr config";
626 }
627 if (cfg().parentInConstructor) {
628 if (parseResult.cfgFileNameArg) {
629 stream() << ", ";
630 }
631 stream() << "QObject *parent = nullptr";
632 }
633 stream() << ");\n";
634 stream() << whitespace() << "friend class " << cfg().className << "Helper;\n\n";
635}
636
637void KConfigHeaderGenerator::createNonDPointerHelpers()
638{
639 if (cfg().memberVariables == QLatin1String("dpointer")) {
640 return;
641 }
642
643 QString group;
644 for (const auto *entry : std::as_const(t&: parseResult.entries)) {
645 if (entry->group != group) {
646 group = entry->group;
647 stream() << '\n';
648 stream() << whitespace() << "// " << group << '\n';
649 }
650 stream() << whitespace() << "" << cppType(t: entry->type) << " " << varName(n: entry->name, cfg: cfg());
651 if (!entry->param.isEmpty()) {
652 stream() << QStringLiteral("[%1]").arg(a: entry->paramMax + 1);
653 }
654 stream() << ";\n";
655
656 if (cfg().allDefaultGetters || cfg().defaultGetters.contains(str: entry->name)) {
657 stream() << whitespace() << "";
658 if (cfg().staticAccessors) {
659 stream() << "static ";
660 }
661 stream() << cppType(t: entry->type) << " " << getDefaultFunction(n: entry->name) << "_helper(";
662 if (!entry->param.isEmpty()) {
663 stream() << " " << cppType(t: entry->paramType) << " i ";
664 }
665 stream() << ")" << Const() << ";\n";
666 }
667 }
668
669 if (cfg().itemAccessors || parseResult.hasNonModifySignals) {
670 stream() << "\n private:\n";
671 }
672 if (cfg().itemAccessors) {
673 for (const auto *entry : std::as_const(t&: parseResult.entries)) {
674 const QString declType =
675 entry->signalList.isEmpty() ? QStringLiteral("Item") + itemType(type: entry->type) : QStringLiteral("KConfigCompilerSignallingItem");
676 stream() << whitespace() << declType << " *" << itemVar(e: entry, cfg: cfg());
677 if (!entry->param.isEmpty()) {
678 stream() << QStringLiteral("[%1]").arg(a: entry->paramMax + 1);
679 }
680 stream() << ";\n";
681 }
682 }
683
684 if (parseResult.hasNonModifySignals) {
685 stream() << whitespace() << "QSet<quint64> " << varName(QStringLiteral("settingsChanged"), cfg: cfg()) << ";\n";
686 }
687}
688

source code of kconfig/src/kconfig_compiler/KConfigHeaderGenerator.cpp