• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

pcolby / doxlee / 9338212492

02 Jun 2024 12:22PM UTC coverage: 79.689% (+1.8%) from 77.929%
9338212492

push

github

pcolby
Skip unimplemented XML elements for now (instead of ignoring)

73 of 73 new or added lines in 1 file covered. (100.0%)

4 existing lines in 1 file now uncovered.

820 of 1029 relevant lines covered (79.69%)

3435.2 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

83.45
/src/doxml.cpp
1
// SPDX-FileCopyrightText: 2021-2024 Paul Colby <git@colby.id.au>
2
// SPDX-License-Identifier: LGPL-3.0-or-later
3

4
#include "doxml.h"
5

6
#include "variant.h"
7

8
#include <QCoreApplication>
9
#include <QDebug>
10
#include <QJsonDocument> /// \todo Remove; only for early dev / debugging.
11

12
/// Shorten the QStringLiteral macro for readability.
13
#define QSL(str) QStringLiteral(str)
14

15
/// Shorten QCoreApplication::translate calls for readability.
16
#define QTR(str) QCoreApplication::translate("doxml", str)
17

18
namespace doxlee {
19

20
namespace doxml {
21

22
static Q_LOGGING_CATEGORY(lc, "doxlee.doxml", QtInfoMsg);
1,056✔
23

24
QPair<QStringList,QStringList> kinds(const QDir &doxmlDir)
72✔
25
{
26
    return kinds(doxmlDir.absoluteFilePath(QSL("index.xsd")));
126✔
27
}
28

29
QPair<QStringList,QStringList> kinds(const QString &indexXsdPath)
72✔
30
{
31
    // Open the file for reading.
32
    QFile file(indexXsdPath);
72✔
33
    if (!file.open(QIODevice::ReadOnly|QIODevice::Text)) {
72✔
34
        qCWarning(lc).noquote() << QTR("Error opening file for reading: %1").arg(indexXsdPath);
×
35
        return { };
36
    }
37

38
    QStringList compoundKinds, memberKinds;
54✔
39

40
    // Parse the opening <schema> element.
41
    QXmlStreamReader xml(&file);
72✔
42
    if (!xml.readNextStartElement()) {
72✔
43
        qCWarning(lc).noquote() << QTR("Invalid XML file: %1 - %2").arg(indexXsdPath, xml.errorString());
×
44
        return { };
45
    }
46
    if (xml.name() != QSL("schema")) {
90✔
47
        qCWarning(lc).noquote() << QTR("File is not a Doxygen XML index schema: %1 - %2")
×
48
            .arg(indexXsdPath, xml.name().toString());
×
49
        return { };
50
    }
51

52
    // Parse the contained 'kind' elements.
53
    while ((!xml.atEnd()) && (xml.readNextStartElement())) {
576✔
54
        if (xml.name() == QSL("simpleType")) {
1,008✔
55
            const QString nameAttribute = xml.attributes().value(QSL("name")).toString();
252✔
56
            if ((nameAttribute == QSL("CompoundKind")) || (nameAttribute == QSL("MemberKind"))) {
252✔
57
                while ((!xml.atEnd()) && (xml.readNextStartElement())) {
288✔
58
                    if (xml.name() == QSL("restriction")) {
288✔
59
                        QStringList &kindsList = (nameAttribute == QLatin1String("CompoundKind"))
252✔
60
                            ? compoundKinds : memberKinds;
144✔
61
                        while ((!xml.atEnd()) && (xml.readNextStartElement())) {
2,184✔
62
                            if (xml.name() == QSL("enumeration")) {
4,080✔
63
                                kindsList.append(xml.attributes().value(QSL("value")).toString());
3,570✔
64
                            }
65
                            xml.skipCurrentElement();
2,040✔
66
                        }
67
                    } else xml.skipCurrentElement();
×
68
                }
69
            } else xml.skipCurrentElement();
×
70
        } else xml.skipCurrentElement();
396✔
71
    }
72
    qCInfo(lc).noquote() << QTR("Parsed %1 compound kind(s), and %2 member kind(s) from %3")
180✔
73
        .arg(compoundKinds.size()).arg(memberKinds.size()).arg(indexXsdPath);
126✔
74
    return { compoundKinds, memberKinds };
72✔
75
}
144✔
76

77
QVariantMap parseIndex(const QDir &doxmlDir, const bool extraIndexes)
72✔
78
{
79
    return parseIndex(doxmlDir.absoluteFilePath(QSL("index.xml")), extraIndexes);
126✔
80
}
81

82
QVariantMap parseIndex(const QString &indexXmlPath, const bool extraIndexes)
72✔
83
{
84
    // Open the file for reading.
85
    QFile file(indexXmlPath);
72✔
86
    if (!file.open(QIODevice::ReadOnly|QIODevice::Text)) {
72✔
87
        qCWarning(lc).noquote() << QTR("Error opening file for reading: %1").arg(indexXmlPath);
×
88
        return QVariantMap();
89
    }
90

91
    // Parse the opening <doxygenindex> element.
92
    QXmlStreamReader xml(&file);
72✔
93
    if (!xml.readNextStartElement()) {
72✔
94
        qCWarning(lc).noquote() << QTR("Invalid XML file: %1 - %2").arg(indexXmlPath, xml.errorString());
×
95
        return QVariantMap();
96
    }
97
    qCDebug(lc) << xml.name() << "version" << xml.attributes().value(QSL("version"))
90✔
98
             << xml.attributes().value(QSL("xml:lang")).toString();
×
99
    if (xml.name() != QSL("doxygenindex")) {
90✔
100
        qCWarning(lc).noquote() << QTR("File is not a Doxygen XML index: %1 - %2")
×
101
                                .arg(indexXmlPath, xml.name().toString());
×
102
        return QVariantMap();
103
    }
104
    QVariantMap indexMap;
54✔
105
    indexMap.insert(QSL("doxygenVersion"), xml.attributes().value(QSL("version")).toString());
180✔
106
    indexMap.insert(QSL("doxygenLanguage"), xml.attributes().value(QSL("xml:lang")).toString());
180✔
107

108
    // Parse the contained <compound> elements.
109
    QVariantList compounds;
54✔
110
    while ((!xml.atEnd()) && (xml.readNextStartElement())) {
2,160✔
111
        if (xml.name() == QSL("compound")) {
4,176✔
112
            QVariantMap compound;
1,566✔
113
            compound.insert(QSL("refid"), xml.attributes().value(QSL("refid")).toString());
5,220✔
114
            compound.insert(QSL("kind"), xml.attributes().value(QSL("kind")).toString());
5,220✔
115
            if ((!xml.readNextStartElement()) || (xml.name() != QSL("name"))) {
4,176✔
116
                qCWarning(lc).noquote() << QTR(" %1:%2:%3 <compound> does not begin with <name>")
×
117
                    .arg(indexXmlPath).arg(xml.lineNumber()).arg(xml.columnNumber());
×
118
                return QVariantMap();
119
            }
120
            compound.insert(QSL("name"), xml.readElementText());
3,654✔
121
            //qCDebug(lc) << __func__ << "compound" << compound;
122
            QVariantList members;
1,566✔
123
            while ((!xml.atEnd()) && (xml.readNextStartElement())) {
5,328✔
124
                if (xml.name() == QSL("member")) {
6,480✔
125
                    QVariantMap member;
2,430✔
126
                    member.insert(QSL("refid"), xml.attributes().value(QSL("refid")).toString());
8,100✔
127
                    member.insert(QSL("kind"), xml.attributes().value(QSL("kind")).toString());
8,100✔
128
                    if ((!xml.readNextStartElement()) || (xml.name() != QSL("name"))) {
6,480✔
129
                        qCWarning(lc).noquote() << QTR("%1:%2:%3 <member> does not begin with <name>")
×
130
                            .arg(indexXmlPath).arg(xml.lineNumber()).arg(xml.columnNumber());
×
131
                        return QVariantMap();
132
                    }
133
                    member.insert(QSL("name"), xml.readElementText());
5,670✔
134
                    //qCDebug(lc) << __func__ << "member" << member;
135
                    members.append(member);
5,670✔
136
                    xml.skipCurrentElement();
3,240✔
137
                } else {
810✔
138
                    qCWarning(lc).noquote() << QTR("Skipping unknown <%1> element at %2:%3:%4")
×
139
                        .arg(xml.name().toString(), indexXmlPath).arg(xml.lineNumber()).arg(xml.columnNumber());
×
140
                    xml.skipCurrentElement();
×
141
                }
142
            }
143
            compound.insert(QSL("members"), members);
3,654✔
144
            compounds.append(compound);
3,654✔
145
        } else {
522✔
146
            qCWarning(lc).noquote() << QTR("Skipping unknown <%1> element at %2:%3:%4")
×
147
                .arg(xml.name().toString(), indexXmlPath).arg(xml.lineNumber()).arg(xml.columnNumber());
×
148
            xml.skipCurrentElement();
×
149
        }
150
    }
151
    qCInfo(lc).noquote() << QTR("Parsed %1 compound(s) from %2").arg(compounds.size()).arg(indexXmlPath);
180✔
152
    indexMap.insert(QSL("compoundsList"), compounds);
126✔
153
    if (extraIndexes) {
72✔
154
        #if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
155
        indexMap.insert(doxml::extraIndexes(compounds));
126✔
156
        #else
157
        const QVariantMap extra = doxml::extraIndexes(compounds);
158
        for (auto iter = extra.constBegin(); iter != extra.constEnd(); ++iter) {
159
            indexMap.insert(iter.key(), iter.value());
160
        }
161
        #endif
162
    }
163
    return indexMap;
164
}
72✔
165

166
QVariantMap extraIndexes(const QVariantList &compounds)
72✔
167
{
168
    QHash<QString,QVariantList> compoundsByKind, membersByKind;
54✔
169
    QVariantMap compoundsByRefId, membersByRefId;
54✔
170
    for (const QVariant &compound: compounds) {
2,160✔
171
        const QVariantMap compoundMap = compound.toMap();
2,088✔
172
        {
173
            const QString kind = compoundMap.value(QSL("kind")).toString();
4,176✔
174
            const QString refid = compoundMap.value(QSL("refid")).toString();
4,176✔
175
            compoundsByKind[kind].append(compound);
2,088✔
176
            compoundsByRefId.insert(refid, compound);
2,088✔
177
        }
522✔
178

179
        const QVariantList members = compoundMap.value(QSL("members")).toList();
4,176✔
180
        for (const QVariant &member: members) {
5,328✔
181
            const QVariantMap memberMap = member.toMap();
3,240✔
182
            const QString kind = memberMap.value(QSL("kind")).toString();
6,480✔
183
            const QString refid = memberMap.value(QSL("refid")).toString();
6,480✔
184
            membersByKind[kind].append(member);
3,240✔
185
            membersByRefId.insert(refid, member);
3,240✔
186
        }
810✔
187
    }
522✔
188
    for (QVariantList &compoundsList: compoundsByKind) sortBy(compoundsList, QSL("name"));
888✔
189
    for (QVariantList &membersList: membersByKind)     sortBy(membersList,   QSL("name"));
720✔
190
    return QVariantMap{
191
        { QSL("compoundsByKind" ), toVariant(compoundsByKind) },
144✔
192
        { QSL("compoundsByRefId"), compoundsByRefId           },
72✔
193
        { QSL("membersByKind"   ), toVariant(membersByKind)   },
144✔
194
        { QSL("membersByRefId"  ), membersByRefId             },
72✔
195
    };
558✔
196
}
72✔
197

198
QVariantMap parseCompound(const QDir &doxmlDir, const QString &refId)
384✔
199
{
200
    return parseCompound(doxmlDir.absoluteFilePath(QSL("%1.xml").arg(refId)));
672✔
201
}
202

203
QVariantMap parseCompound(const QString &compoundXmlPath)
384✔
204
{
205
    // Open the compound XML file.
206
    QFile file(compoundXmlPath);
384✔
207
    if (!file.open(QIODevice::ReadOnly|QIODevice::Text)) {
384✔
208
        qCWarning(lc).noquote() << QTR("Error opening file for reading: %1").arg(compoundXmlPath);
×
209
        return QVariantMap();
210
    }
211

212
    // Parse, and fetch the compoundDef element.
213
    QXmlStreamReader xml(&file);
384✔
214
    const QVariantMap compoundDef = toVariant(xml).value(QSL("doxygen")).toMap().value(QSL("compounddef")).toMap();
768✔
215
    if (compoundDef.isEmpty()) {
384✔
216
        qCWarning(lc).noquote() << QTR("Error reading compond defintion: %1").arg(compoundXmlPath);
×
217
        return QVariantMap();
218
    }
219
    qCDebug(lc).noquote() << QJsonDocument::fromVariant(compoundDef).toJson();
480✔
220

221
    // Map the compoundDef properties to our own compound map.
222
    QVariantMap compound{
223
        { QSL("name"), compoundDef.value(QSL("compoundname")).toMap().value(QSL(".Characters")) },
768✔
224
        /// \todo Provide stand way of fetch, and trimming, all text from each of these...
225
        // { QSL("brief"),       compoundDef.value(QSL("briefdescription")).toMap().value(QSL(".Characters")) },
226
        // { QSL("description"), compoundDef.value(QSL("fulldescription" )).toMap().value(QSL(".Characters")) },
227
    };
1,152✔
228

229
    // Copy call compoundDef attributes to top-level compound properties.
230
    for (const QVariant &attribute: compoundDef) {
5,760✔
231
        const auto map = attribute.toMap();
5,376✔
232
        const auto name = map.find(QSL("QualifiedName"));
5,376✔
233
        const auto value = map.find(QSL("Value"));
5,376✔
234
        if ((name != map.constEnd()) && (value != map.constEnd())) {
5,376✔
235
            compound.insert(name->toString(), *value);
2,814✔
236
        }
237
    }
1,344✔
238

239
    /// \todo More parsing here...
240

241
    qCDebug(lc).noquote() << QJsonDocument::fromVariant(compound).toJson();
480✔
242
    return compound;
243
}
384✔
244

245
} // namespace doxml
246

247
Doxml::Doxml(const QString &doxmlDir) : doxmlDir(doxmlDir)
2,160✔
248
{
249

250
}
2,160✔
251

252
// bool Doxml::isValid() const
253
// {
254
//     return false; /// \todo.
255
// }
256

257
QString Doxml::location(const QXmlStreamReader &xml) const
72✔
258
{
259
    return (currentXmlFilePath.isNull()) ? QStringLiteral("%1:%2").arg(xml.lineNumber()).arg(xml.columnNumber())
156✔
260
        : QStringLiteral("%1:%2:%3").arg(currentXmlFilePath).arg(xml.lineNumber()).arg(xml.columnNumber());
246✔
261
}
262

263
void Doxml::logError(const QXmlStreamReader &xml) const
8✔
264
{
265
    Q_ASSERT(xml.hasError());
266
    qCCritical(lc).noquote().nospace() << xml.errorString() << " [" << location(xml) << ']';
18✔
267
}
8✔
268

269
void Doxml::logWarning(const QString &message, const QXmlStreamReader &xml) const
16✔
270
{
271
    Q_ASSERT(!xml.hasError());
272
    qCWarning(lc).noquote().nospace() << message << " [" << location(xml) << ']';
36✔
273
}
16✔
274

275
void Doxml::logWarning(const Warning &warning, const QXmlStreamReader &xml) const
8✔
276
{
277
    QString message;
6✔
278
    switch (warning) {
8✔
279
    case Warning::UnexpectedElement:
8✔
280
        message = QTR("Ignoring unexpected element: %1").arg(xml.name());
16✔
281
        break;
8✔
282
    default:
×
283
        Q_ASSERT_X(false, "logWarning", "Unknown warning");
284
        message = QTR("Unknown warning");
×
285
        break;
×
286
    }
287
    logWarning(message, xml);
8✔
288
}
8✔
289

290
/*!
291
 * Returns an XML Numeric Character Reference as a QString.
292
 *
293
 * QChar and QString use UCS2 and UTF-16, but XML references can represent UCS4 characters. Indeed, for Doxygen XML,
294
 * the numeric characer references are emoji characters, which all two big for UCS2. So, the resulting Unicode character
295
 * cannot fit in a QChar. Instead we return a QString, with a UTF-16 encoding, so QString::size() will typically be 2,
296
 * even though it's constains only a single Unicode character (two 16-bit values in UTF-16 format).
297
 *
298
 * \see https://www.w3.org/TR/xml/#dt-charref
299
 */
300
QString Doxml::parseNumericCharacterReference(const QStringView &view)
16✔
301
{
302
    if (!view.startsWith(QSL("&#"))) {
16✔
303
        qWarning(lc) << QTR("Numeric character reference does not start with \"&#\": %1").arg(view);
×
304
        return QString();
305
    }
306
    if (!view.endsWith(QLatin1Char(';'))) {
307
        qWarning(lc) << QTR("Numeric character reference does not end with ';': %1").arg(view);
×
308
        return QString();
309
    }
310
    const int base = view.startsWith(QSL("&#x")) ? 16 : 10;
28✔
311
    const qsizetype pos = (base == 16) ? 3 : 2;
16✔
312
    const QStringView numberView = view.mid(pos, (view.size()-pos-1));
16✔
313

314
    bool ok;
315
    const char32_t codePoint=numberView.toString().toULong(&ok, base);
16✔
316
    if (!ok) {
16✔
317
        qWarning(lc) << QTR("Failed to convert numeric character reference to integer: %1").arg(numberView);
×
318
        return QString();
319
    }
320

321
    const QString result = QString::fromUcs4(&codePoint, 1);
12✔
322
    if (result.isNull()) {
16✔
323
        qWarning(lc) << QTR("Failed to parse Unicode codepoint: %1 (%2)").arg(codePoint).arg(view);
×
324
    }
325
    return result;
326
}
4✔
327

328

329
QVariantMap Doxml::parseCompound(QXmlStreamReader &xml) const
1,376✔
330
{
331
    if (!xml.readNextStartElement()) {
1,376✔
332
        Q_ASSERT(xml.hasError());
333
        return { };
334
    }
335
    if (xml.name() != QSL("doxygen")) {
1,720✔
336
        xml.raiseError(QTR("Root element is not \"doxygen\""));
×
337
        return { };
338
    }
339
    return parseCompound_DoxygenType(xml);
1,376✔
340
}
341

342
QVariantMap Doxml::parseCompound_DoxygenType(QXmlStreamReader &xml) const
1,384✔
343
{
344
    Q_ASSERT(xml.name() == QSL("doxygen"));
345

346
    QVariantMap map {
347
        { QSL("version"), xml.attributes().value(QSL("version")).toString() },
2,768✔
348
        { QSL("language"), xml.attributes().value(QSL("xml:lang")).toString() },
2,768✔
349
    };
6,574✔
350

351
    QVariantList compounds;
1,038✔
352
    while ((!xml.atEnd()) && (xml.readNextStartElement())) {
2,760✔
353
        if (xml.name() == QSL("compounddef")) {
2,752✔
354
            compounds.append(parseCompound_compounddefType(xml));
2,408✔
355
        } else {
UNCOV
356
            logWarning(Warning::UnexpectedElement, xml);
×
UNCOV
357
            xml.skipCurrentElement();
×
358
        }
359
    }
360
    qCDebug(lc).noquote() << QTR("Parsed %1 compounds(s) from %2").arg(compounds.size()).arg(currentXmlFilePath);
1,730✔
361
    map.insert(QSL("compounds"), compounds);
2,422✔
362
    return map;
1,384✔
363
}
346✔
364

365
QVariantMap Doxml::parseCompound_compounddefType(QXmlStreamReader &xml) const
1,384✔
366
{
367
    Q_ASSERT(xml.name() == QSL("compounddef"));
368

369
    const QXmlStreamAttributes attributes = xml.attributes();
1,384✔
370
    QVariantMap map {
371
        { QSL("id"), attributes.value(QSL("id")).toString() },
2,768✔
372
        { QSL("kind"), attributes.value(QSL("kind")).toString() },
2,768✔
373
        { QSL("protection"), attributes.value(QSL("prot")).toString() },
2,768✔
374
    };
8,996✔
375
    {
376
        const QStringView attributeValue = attributes.value(QSL("language"));
1,730✔
377
        if (!attributeValue.isNull()) {
1,384✔
378
            map.insert(QSL("language"), attributeValue.toString());
1,610✔
379
        }
380
    }
381
    for (const QString &attributeName: QStringList{ QSL("final"), QSL("inline"), QSL("sealed"), QSL("abstract") }) {
13,840✔
382
        const QStringView attributeValue = attributes.value(attributeName);
5,536✔
383
        if (!attributeValue.isNull()) {
5,536✔
384
            map.insert(attributeName, attributeValue == QSL("yes"));
24✔
385
        }
386
    }
387

388
    QVariantList basecompoundref, derivedcompoundref, includes, includedby, innermodule, innerdir, innerfile,
1,038✔
389
        innerclass, innerconcept, innernamespace, innerpage, innergroup, qualifier, sectiondef;
1,038✔
390
    while ((!xml.atEnd()) && (xml.readNextStartElement())) {
9,640✔
391
        if (xml.name() == QSL("compoundname")) {
16,512✔
392
            map.insert(QSL("compoundname"), xml.readElementText());
2,408✔
393
        }
394

395
        else if (xml.name() == QSL("title")) {
13,760✔
396
            map.insert(QSL("title"), xml.readElementText());
784✔
397
        }
398

399
        else if (xml.name() == QSL("basecompoundref")) {
12,864✔
400
            basecompoundref.append(parseCompound_compoundRefType(xml));
168✔
401
        }
402

403
        else if (xml.name() == QSL("derivedcompoundref")) {
12,672✔
404
            derivedcompoundref.append(parseCompound_compoundRefType(xml));
154✔
405
        }
406

407
        else if (xml.name() == QSL("includes")) {
12,496✔
408
            includes.append(parseCompound_incType(xml));
112✔
409
        }
410

411
        else if (xml.name() == QSL("includedby")) {
12,368✔
412
            includedby.append(parseCompound_incType(xml));
×
413
        }
414

415
        else if (xml.name() == QSL("incdepgraph")) {
12,368✔
416
            map.insert(QSL("incdepgraph"), parseCompound_graphType(xml));
28✔
417
        }
418

419
        else if (xml.name() == QSL("invincdepgraph")) {
12,336✔
420
            map.insert(QSL("invincdepgraph"), parseCompound_graphType(xml));
×
421
        }
422

423
        else if (xml.name() == QSL("innermodule")) {
12,336✔
424
            innermodule.append(parseCompound_refType(xml));
×
425
        }
426

427
        else if (xml.name() == QSL("innerdir")) {
12,336✔
428
            innerdir.append(parseCompound_refType(xml));
×
429
        }
430

431
        else if (xml.name() == QSL("innerfile")) {
12,336✔
432
            innerfile.append(parseCompound_refType(xml));
42✔
433
        }
434

435
        else if (xml.name() == QSL("innerclass")) {
12,288✔
436
            innerclass.append(parseCompound_refType(xml));
574✔
437
        }
438

439
        else if (xml.name() == QSL("innerconcept")) {
11,632✔
440
            innerconcept.append(parseCompound_refType(xml));
×
441
        }
442

443
        else if (xml.name() == QSL("innernamespace")) {
11,632✔
444
            innernamespace.append(parseCompound_refType(xml));
112✔
445
        }
446

447
        else if (xml.name() == QSL("innerpage")) {
11,504✔
448
            innerpage.append(parseCompound_refType(xml));
14✔
449
        }
450

451
        else if (xml.name() == QSL("innergroup")) {
11,488✔
452
            innergroup.append(parseCompound_refType(xml));
56✔
453
        }
454

455
        else if (xml.name() == QSL("qualifier")) {
11,424✔
456
            map.insert(QSL("qualifier"), xml.readElementText());
×
457
        }
458

459
        else if (xml.name() == QSL("templateparamlist")) {
11,424✔
460
            map.insert(QSL("templateparamlist"), parseCompound_templateparamlistType(xml));
28✔
461
        }
462

463
        else if (xml.name() == QSL("sectiondef")) {
11,392✔
464
            sectiondef.append(parseCompound_sectiondefType(xml));
1,610✔
465
        }
466

467
        else if (xml.name() == QSL("tableofcontents")) {
9,552✔
468
            map.insert(QSL("tableofcontents"), parseCompound_tableofcontentsType(xml));
28✔
469
        }
470

471
        else if (xml.name() == QSL("requiresclause")) {
9,520✔
472
            map.insert(QSL("requiresclause"), parseCompound_linkedTextType(xml));
×
473
        }
474

475
        else if (xml.name() == QSL("initializer")) {
9,520✔
476
            map.insert(QSL("initializer"), parseCompound_linkedTextType(xml));
×
477
        }
478

479
        else if (xml.name() == QSL("briefdescription")) {
9,520✔
480
            map.insert(QSL("briefdescription"), parseCompound_descriptionType(xml));
2,408✔
481
        }
482

483
        else if (xml.name() == QSL("detaileddescription")) {
6,768✔
484
            map.insert(QSL("detaileddescription"), parseCompound_descriptionType(xml));
2,408✔
485
        }
486

487
        else if (xml.name() == QSL("exports")) {
4,016✔
488
            map.insert(QSL("exports"), parseCompound_exportsType(xml));
×
489
        }
490

491
        else if (xml.name() == QSL("inheritancegraph")) {
4,016✔
492
            map.insert(QSL("inheritancegraph"), parseCompound_graphType(xml));
210✔
493
        }
494

495
        else if (xml.name() == QSL("collaborationgraph")) {
3,776✔
496
            map.insert(QSL("collaborationgraph"), parseCompound_graphType(xml));
168✔
497
        }
498

499
        else if (xml.name() == QSL("programlisting")) {
3,584✔
500
            map.insert(QSL("programlisting"), parseCompound_listingType(xml));
×
501
        }
502

503
        else if (xml.name() == QSL("location")) {
3,584✔
504
            map.insert(QSL("location"), parseCompound_locationType(xml));
2,254✔
505
        }
506

507
        else if (xml.name() == QSL("listofallmembers")) {
1,008✔
508
            map.insert(QSL("listofallmembers"), parseCompound_listofallmembersType(xml));
882✔
509
        }
510

511
        else {
UNCOV
512
            logWarning(Warning::UnexpectedElement, xml);
×
UNCOV
513
            xml.skipCurrentElement();
×
514
        }
515
    }
516

517
    #define DOXLEE_INSERT_IF_NOT_EMPTY(name) if (!name.isEmpty()) { map.insert(QSL(#name), name); }
518
    DOXLEE_INSERT_IF_NOT_EMPTY(basecompoundref)
1,456✔
519
    DOXLEE_INSERT_IF_NOT_EMPTY(derivedcompoundref)
1,420✔
520
    DOXLEE_INSERT_IF_NOT_EMPTY(includes)
1,432✔
521
    DOXLEE_INSERT_IF_NOT_EMPTY(includedby)
1,384✔
522
    DOXLEE_INSERT_IF_NOT_EMPTY(innermodule)
1,384✔
523
    DOXLEE_INSERT_IF_NOT_EMPTY(innerdir)
1,384✔
524
    DOXLEE_INSERT_IF_NOT_EMPTY(innerfile)
1,402✔
525
    DOXLEE_INSERT_IF_NOT_EMPTY(innerclass)
1,510✔
526
    DOXLEE_INSERT_IF_NOT_EMPTY(innerconcept)
1,384✔
527
    DOXLEE_INSERT_IF_NOT_EMPTY(innernamespace)
1,420✔
528
    DOXLEE_INSERT_IF_NOT_EMPTY(innerpage)
1,390✔
529
    DOXLEE_INSERT_IF_NOT_EMPTY(innergroup)
1,396✔
530
    DOXLEE_INSERT_IF_NOT_EMPTY(qualifier)
1,384✔
531
    DOXLEE_INSERT_IF_NOT_EMPTY(sectiondef)
1,906✔
532
    #undef DOXLEE_INSERT_IF_NOT_EMPTY
533
    return map;
1,384✔
534
}
346✔
535

536
QVariantMap Doxml::parseCompound_listofallmembersType(QXmlStreamReader &xml) const
512✔
537
{
538
    /// \todo Implement Doxml::parseCompound_listofallmembersType().
539
    xml.skipCurrentElement();
512✔
540
    return {};
512✔
541
}
542

543
QVariantMap Doxml::parseCompound_memberRefType(QXmlStreamReader &xml) const
8✔
544
{
545
    /// \todo Implement Doxml::parseCompound_memberRefType().
546
    xml.skipCurrentElement();
8✔
547
    return {};
8✔
548
}
549

550
QVariantMap Doxml::parseCompound_docHtmlOnlyType(QXmlStreamReader &xml) const
8✔
551
{
552
    /// \todo Implement Doxml::parseCompound_docHtmlOnlyType().
553
    xml.skipCurrentElement();
8✔
554
    return {};
8✔
555
}
556

557
QVariantMap Doxml::parseCompound_compoundRefType(QXmlStreamReader &xml) const
192✔
558
{
559
    /// \todo Implement Doxml::parseCompound_compoundRefType().
560
    xml.skipCurrentElement();
192✔
561
    return {};
192✔
562
}
563

564
QVariantMap Doxml::parseCompound_reimplementType(QXmlStreamReader &xml) const
8✔
565
{
566
    /// \todo Implement Doxml::parseCompound_reimplementType().
567
    xml.skipCurrentElement();
8✔
568
    return {};
8✔
569
}
570

571
QVariantMap Doxml::parseCompound_incType(QXmlStreamReader &xml) const
72✔
572
{
573
    /// \todo Implement Doxml::parseCompound_incType().
574
    xml.skipCurrentElement();
72✔
575
    return {};
72✔
576
}
577

578
QVariantMap Doxml::parseCompound_exportsType(QXmlStreamReader &xml) const
8✔
579
{
580
    /// \todo Implement Doxml::parseCompound_exportsType().
581
    xml.skipCurrentElement();
8✔
582
    return {};
8✔
583
}
584

585
QVariantMap Doxml::parseCompound_exportType(QXmlStreamReader &xml) const
8✔
586
{
587
    /// \todo Implement Doxml::parseCompound_exportType().
588
    xml.skipCurrentElement();
8✔
589
    return {};
8✔
590
}
591

592
QVariantMap Doxml::parseCompound_refType(QXmlStreamReader &xml) const
464✔
593
{
594
    /// \todo Implement Doxml::parseCompound_refType().
595
    xml.skipCurrentElement();
464✔
596
    return {};
464✔
597
}
598

599
QVariantMap Doxml::parseCompound_refTextType(QXmlStreamReader &xml) const
8✔
600
{
601
    /// \todo Implement Doxml::parseCompound_refTextType().
602
    xml.skipCurrentElement();
8✔
603
    return {};
8✔
604
}
605

606
QVariantMap Doxml::parseCompound_MemberType(QXmlStreamReader &xml) const
8✔
607
{
608
    /// \todo Implement Doxml::parseCompound_MemberType().
609
    xml.skipCurrentElement();
8✔
610
    return {};
8✔
611
}
612

613
QVariantMap Doxml::parseCompound_sectiondefType(QXmlStreamReader &xml) const
928✔
614
{
615
    /// \todo Implement Doxml::parseCompound_sectiondefType().
616
    xml.skipCurrentElement();
928✔
617
    return {};
928✔
618
}
619

620
QVariantMap Doxml::parseCompound_memberdefType(QXmlStreamReader &xml) const
8✔
621
{
622
    Q_ASSERT(xml.name() == QSL("memberdef"));
623

624
    const QXmlStreamAttributes attributes = xml.attributes();
8✔
625
    QVariantMap map {
626
        { QSL("kind"), attributes.value(QSL("kind")).toString() },
16✔
627
        { QSL("id"), attributes.value(QSL("id")).toString() },
16✔
628
        { QSL("protection"), attributes.value(QSL("prot")).toString() },
16✔
629
        { QSL("static"), attributes.value(QSL("prot")) == QSL("yes") },
18✔
630
    };
66✔
631
    for (const QString &attributeName: QStringList{ QSL("refqual"), QSL("virt"), QSL("accessor") }) {
64✔
632
        const QStringView attributeValue = attributes.value(attributeName);
24✔
633
        if (!attributeValue.isNull()) {
24✔
634
            map.insert(attributeName, attributeValue.toString());
×
635
        }
636
    }
637
    for (const QString &attributeName: QStringList{
638
        QSL("extern"), QSL("strong"), QSL("const"), QSL("explicit"), QSL("inline"), QSL("volatile"), QSL("mutable"),
6✔
639
        QSL("noexcept"), QSL("constexpr"), QSL("readable"), QSL("writable"), QSL("initonly"), QSL("settable"),
6✔
640
        QSL("privatesettable"), QSL("protectedsettable"), QSL("gettable"), QSL("privategettable"),
6✔
641
        QSL("protectedgettable"), QSL("final"), QSL("sealed"), QSL("new"), QSL("add"), QSL("remove"), QSL("raise"),
6✔
642
        QSL("optional"), QSL("required"), QSL("attribute"), QSL("property"), QSL("readonly"), QSL("bound"),
6✔
643
        QSL("removable"), QSL("constrained"), QSL("transient"), QSL("maybevoid"), QSL("maybedefault"),
6✔
644
        QSL("maybeambiguous"),
6✔
645
    }) {
592✔
646
        const QStringView attributeValue = attributes.value(attributeName);
288✔
647
        if (!attributeValue.isNull()) {
288✔
648
            map.insert(attributeName, attributeValue == QSL("yes"));
×
649
        }
650
    }
651

652
    QVariantList reimplements, reimplementedby, qualifier, param, enumvalue, references, referencedby;
6✔
653
    while ((!xml.atEnd()) && (xml.readNextStartElement())) {
8✔
654
        if (xml.name() == QSL("templateparamlist")) {
×
655
            map.insert(QSL("templateparamlist"), parseCompound_templateparamlistType(xml));
×
656
        }
657

658
        else if (xml.name() == QSL("type")) {
×
659
            map.insert(QSL("type"), parseCompound_linkedTextType(xml));
×
660
        }
661

662
        else if (xml.name() == QSL("definition")) {
×
663
            map.insert(QSL("definition"), xml.readElementText());
×
664
        }
665

666
        else if (xml.name() == QSL("argsstring")) {
×
667
            map.insert(QSL("argsstring"), xml.readElementText());
×
668
        }
669

670
        else if (xml.name() == QSL("name")) {
×
671
            map.insert(QSL("name"), xml.readElementText());
×
672
        }
673

674
        else if (xml.name() == QSL("qualifiedname")) {
×
675
            map.insert(QSL("qualifiedname"), xml.readElementText());
×
676
        }
677

678
        else if (xml.name() == QSL("read")) {
×
679
            map.insert(QSL("read"), xml.readElementText());
×
680
        }
681

682
        else if (xml.name() == QSL("write")) {
×
683
            map.insert(QSL("write"), xml.readElementText());
×
684
        }
685

686
        else if (xml.name() == QSL("bitfield")) {
×
687
            map.insert(QSL("bitfield"), xml.readElementText());
×
688
        }
689

690
        else if (xml.name() == QSL("reimplements")) {
×
691
            reimplements.append(parseCompound_reimplementType(xml));
×
692
        }
693

694
        else if (xml.name() == QSL("reimplementedby")) {
×
695
            reimplementedby.append(parseCompound_reimplementType(xml));
×
696
        }
697

698
        else if (xml.name() == QSL("qualifier")) {
×
699
            map.insert(QSL("qualifier"), xml.readElementText());
×
700
        }
701

702
        else if (xml.name() == QSL("param")) {
×
703
            param.append(parseCompound_paramType(xml));
×
704
        }
705

706
        else if (xml.name() == QSL("enumvalue")) {
×
707
            enumvalue.append(parseCompound_enumvalueType(xml));
×
708
        }
709

710
        else if (xml.name() == QSL("requiresclause")) {
×
711
            map.insert(QSL("requiresclause"), parseCompound_linkedTextType(xml));
×
712

713
        }
714

715
        else if (xml.name() == QSL("initializer")) {
×
716
            map.insert(QSL("initializer"), parseCompound_linkedTextType(xml));
×
717
        }
718

719
        else if (xml.name() == QSL("exceptions")) {
×
720
           map.insert(QSL("exceptions"), parseCompound_linkedTextType(xml));
×
721
        }
722

723
        else if (xml.name() == QSL("briefdescription")) {
×
724
          map.insert(QSL("briefdescription"), parseCompound_descriptionType(xml));
×
725
        }
726

727
        else if (xml.name() == QSL("detaileddescription")) {
×
728
          map.insert(QSL("detaileddescription"), parseCompound_descriptionType(xml));
×
729
        }
730

731
        else if (xml.name() == QSL("inbodydescription")) {
×
732
          map.insert(QSL("inbodydescription"), parseCompound_descriptionType(xml));
×
733
        }
734

735
        else if (xml.name() == QSL("location")) {
×
736
          map.insert(QSL("location"), parseCompound_locationType(xml));
×
737
        }
738

739
        else if (xml.name() == QSL("references")) {
×
740
            references.append(parseCompound_referenceType(xml));
×
741
        }
742

743
        else if (xml.name() == QSL("referencedby")) {
×
744
            referencedby.append(parseCompound_referenceType(xml));
×
745
        }
746

747
        else {
748
            logWarning(Warning::UnexpectedElement, xml);
×
749
            xml.skipCurrentElement();
×
750
        }
751
    }
752

753
    #define DOXLEE_INSERT_IF_NOT_EMPTY(name) if (!name.isEmpty()) { map.insert(QSL(#name), name); }
754
    DOXLEE_INSERT_IF_NOT_EMPTY(reimplements)
8✔
755
    DOXLEE_INSERT_IF_NOT_EMPTY(reimplementedby)
8✔
756
    DOXLEE_INSERT_IF_NOT_EMPTY(qualifier)
8✔
757
    DOXLEE_INSERT_IF_NOT_EMPTY(param)
8✔
758
    DOXLEE_INSERT_IF_NOT_EMPTY(enumvalue)
8✔
759
    DOXLEE_INSERT_IF_NOT_EMPTY(references)
8✔
760
    DOXLEE_INSERT_IF_NOT_EMPTY(referencedby)
8✔
761
    #undef DOXLEE_INSERT_IF_NOT_EMPTY
762
    return map;
8✔
763
}
2✔
764

765
QVariantMap Doxml::parseCompound_descriptionType(QXmlStreamReader &xml) const
2,760✔
766
{
767
    /// \todo Implement Doxml::parseCompound_descriptionType().
768
    xml.skipCurrentElement();
2,760✔
769
    return {};
2,760✔
770
}
771

772
QVariantMap Doxml::parseCompound_enumvalueType(QXmlStreamReader &xml) const
8✔
773
{
774
    /// \todo Implement Doxml::parseCompound_enumvalueType().
775
    xml.skipCurrentElement();
8✔
776
    return {};
8✔
777
}
778

779
QVariantMap Doxml::parseCompound_templateparamlistType(QXmlStreamReader &xml) const
24✔
780
{
781
    /// \todo Implement Doxml::parseCompound_templateparamlistType().
782
    xml.skipCurrentElement();
24✔
783
    return {};
24✔
784
}
785

786
QVariantMap Doxml::parseCompound_paramType(QXmlStreamReader &xml) const
8✔
787
{
788
    /// \todo Implement Doxml::parseCompound_paramType().
789
    xml.skipCurrentElement();
8✔
790
    return {};
8✔
791
}
792

793
QVariantMap Doxml::parseCompound_linkedTextType(QXmlStreamReader &xml) const
8✔
794
{
795
    /// \todo Implement Doxml::parseCompound_linkedTextType().
796
    xml.skipCurrentElement();
8✔
797
    return {};
8✔
798
}
799

800
QVariantMap Doxml::parseCompound_graphType(QXmlStreamReader &xml) const
240✔
801
{
802
    /// \todo Implement Doxml::parseCompound_graphType().
803
    xml.skipCurrentElement();
240✔
804
    return {};
240✔
805
}
806

807
QVariantMap Doxml::parseCompound_nodeType(QXmlStreamReader &xml) const
8✔
808
{
809
    /// \todo Implement Doxml::parseCompound_nodeType().
810
    xml.skipCurrentElement();
8✔
811
    return {};
8✔
812
}
813

814
QVariantMap Doxml::parseCompound_childnodeType(QXmlStreamReader &xml) const
8✔
815
{
816
    /// \todo Implement Doxml::parseCompound_childnodeType().
817
    xml.skipCurrentElement();
8✔
818
    return {};
8✔
819
}
820

821
QVariantMap Doxml::parseCompound_linkType(QXmlStreamReader &xml) const
8✔
822
{
823
    /// \todo Implement Doxml::parseCompound_linkType().
824
    xml.skipCurrentElement();
8✔
825
    return {};
8✔
826
}
827

828
QVariantMap Doxml::parseCompound_listingType(QXmlStreamReader &xml) const
8✔
829
{
830
    /// \todo Implement Doxml::parseCompound_listingType().
831
    xml.skipCurrentElement();
8✔
832
    return {};
8✔
833
}
834

835
QVariantMap Doxml::parseCompound_codelineType(QXmlStreamReader &xml) const
8✔
836
{
837
    /// \todo Implement Doxml::parseCompound_codelineType().
838
    xml.skipCurrentElement();
8✔
839
    return {};
8✔
840
}
841

842
QVariantMap Doxml::parseCompound_highlightType(QXmlStreamReader &xml) const
8✔
843
{
844
    /// \todo Implement Doxml::parseCompound_highlightType().
845
    xml.skipCurrentElement();
8✔
846
    return {};
8✔
847
}
848

849
QVariantMap Doxml::parseCompound_spType(QXmlStreamReader &xml) const
8✔
850
{
851
    /// \todo Implement Doxml::parseCompound_spType().
852
    xml.skipCurrentElement();
8✔
853
    return {};
8✔
854
}
855

856
QVariantMap Doxml::parseCompound_referenceType(QXmlStreamReader &xml) const
8✔
857
{
858
    /// \todo Implement Doxml::parseCompound_referenceType().
859
    xml.skipCurrentElement();
8✔
860
    return {};
8✔
861
}
862

863
QVariantMap Doxml::parseCompound_locationType(QXmlStreamReader &xml) const
1,296✔
864
{
865
    /// \todo Implement Doxml::parseCompound_locationType().
866
    xml.skipCurrentElement();
1,296✔
867
    return {};
1,296✔
868
}
869

870
QVariantMap Doxml::parseCompound_docSect1Type(QXmlStreamReader &xml) const
8✔
871
{
872
    /// \todo Implement Doxml::parseCompound_docSect1Type().
873
    xml.skipCurrentElement();
8✔
874
    return {};
8✔
875
}
876

877
QVariantMap Doxml::parseCompound_docSect2Type(QXmlStreamReader &xml) const
8✔
878
{
879
    /// \todo Implement Doxml::parseCompound_docSect2Type().
880
    xml.skipCurrentElement();
8✔
881
    return {};
8✔
882
}
883

884
QVariantMap Doxml::parseCompound_docSect3Type(QXmlStreamReader &xml) const
8✔
885
{
886
    /// \todo Implement Doxml::parseCompound_docSect3Type().
887
    xml.skipCurrentElement();
8✔
888
    return {};
8✔
889
}
890

891
QVariantMap Doxml::parseCompound_docSect4Type(QXmlStreamReader &xml) const
8✔
892
{
893
    /// \todo Implement Doxml::parseCompound_docSect4Type().
894
    xml.skipCurrentElement();
8✔
895
    return {};
8✔
896
}
897

898
QVariantMap Doxml::parseCompound_docInternalType(QXmlStreamReader &xml) const
8✔
899
{
900
    /// \todo Implement Doxml::parseCompound_docInternalType().
901
    xml.skipCurrentElement();
8✔
902
    return {};
8✔
903
}
904

905
QVariantMap Doxml::parseCompound_docInternalS1Type(QXmlStreamReader &xml) const
8✔
906
{
907
    /// \todo Implement Doxml::parseCompound_docInternalS1Type().
908
    xml.skipCurrentElement();
8✔
909
    return {};
8✔
910
}
911

912
QVariantMap Doxml::parseCompound_docInternalS2Type(QXmlStreamReader &xml) const
8✔
913
{
914
    /// \todo Implement Doxml::parseCompound_docInternalS2Type().
915
    xml.skipCurrentElement();
8✔
916
    return {};
8✔
917
}
918

919
QVariantMap Doxml::parseCompound_docInternalS3Type(QXmlStreamReader &xml) const
8✔
920
{
921
    /// \todo Implement Doxml::parseCompound_docInternalS3Type().
922
    xml.skipCurrentElement();
8✔
923
    return {};
8✔
924
}
925

926
QVariantMap Doxml::parseCompound_docInternalS4Type(QXmlStreamReader &xml) const
8✔
927
{
928
    /// \todo Implement Doxml::parseCompound_docInternalS4Type().
929
    xml.skipCurrentElement();
8✔
930
    return {};
8✔
931
}
932

933
QVariantMap Doxml::parseCompound_docTitleType(QXmlStreamReader &xml) const
8✔
934
{
935
    /// \todo Implement Doxml::parseCompound_docTitleType().
936
    xml.skipCurrentElement();
8✔
937
    return {};
8✔
938
}
939

940
QVariantMap Doxml::parseCompound_docSummaryType(QXmlStreamReader &xml) const
8✔
941
{
942
    /// \todo Implement Doxml::parseCompound_docSummaryType().
943
    xml.skipCurrentElement();
8✔
944
    return {};
8✔
945
}
946

947
QVariantMap Doxml::parseCompound_docParaType(QXmlStreamReader &xml) const
8✔
948
{
949
    /// \todo Implement Doxml::parseCompound_docParaType().
950
    xml.skipCurrentElement();
8✔
951
    return {};
8✔
952
}
953

954
QVariantMap Doxml::parseCompound_docMarkupType(QXmlStreamReader &xml) const
8✔
955
{
956
    /// \todo Implement Doxml::parseCompound_docMarkupType().
957
    xml.skipCurrentElement();
8✔
958
    return {};
8✔
959
}
960

961
QVariantMap Doxml::parseCompound_docURLLink(QXmlStreamReader &xml) const
8✔
962
{
963
    /// \todo Implement Doxml::parseCompound_docURLLink().
964
    xml.skipCurrentElement();
8✔
965
    return {};
8✔
966
}
967

968
QVariantMap Doxml::parseCompound_docAnchorType(QXmlStreamReader &xml) const
8✔
969
{
970
    /// \todo Implement Doxml::parseCompound_docAnchorType().
971
    xml.skipCurrentElement();
8✔
972
    return {};
8✔
973
}
974

975
QVariantMap Doxml::parseCompound_docFormulaType(QXmlStreamReader &xml) const
8✔
976
{
977
    /// \todo Implement Doxml::parseCompound_docFormulaType().
978
    xml.skipCurrentElement();
8✔
979
    return {};
8✔
980
}
981

982
QVariantMap Doxml::parseCompound_docIndexEntryType(QXmlStreamReader &xml) const
8✔
983
{
984
    /// \todo Implement Doxml::parseCompound_docIndexEntryType().
985
    xml.skipCurrentElement();
8✔
986
    return {};
8✔
987
}
988

989
QVariantMap Doxml::parseCompound_docListType(QXmlStreamReader &xml) const
8✔
990
{
991
    /// \todo Implement Doxml::parseCompound_docListType().
992
    xml.skipCurrentElement();
8✔
993
    return {};
8✔
994
}
995

996
QVariantMap Doxml::parseCompound_docListItemType(QXmlStreamReader &xml) const
8✔
997
{
998
    /// \todo Implement Doxml::parseCompound_docListItemType().
999
    xml.skipCurrentElement();
8✔
1000
    return {};
8✔
1001
}
1002

1003
QVariantMap Doxml::parseCompound_docSimpleSectType(QXmlStreamReader &xml) const
8✔
1004
{
1005
    /// \todo Implement Doxml::parseCompound_docSimpleSectType().
1006
    xml.skipCurrentElement();
8✔
1007
    return {};
8✔
1008
}
1009

1010
QVariantMap Doxml::parseCompound_docVarListEntryType(QXmlStreamReader &xml) const
8✔
1011
{
1012
    /// \todo Implement Doxml::parseCompound_docVarListEntryType().
1013
    xml.skipCurrentElement();
8✔
1014
    return {};
8✔
1015
}
1016

1017
QVariantMap Doxml::parseCompound_docVariableListType(QXmlStreamReader &xml) const
8✔
1018
{
1019
    /// \todo Implement Doxml::parseCompound_docVariableListType().
1020
    xml.skipCurrentElement();
8✔
1021
    return {};
8✔
1022
}
1023

1024
QVariantMap Doxml::parseCompound_docRefTextType(QXmlStreamReader &xml) const
8✔
1025
{
1026
    /// \todo Implement Doxml::parseCompound_docRefTextType().
1027
    xml.skipCurrentElement();
8✔
1028
    return {};
8✔
1029
}
1030

1031
QVariantMap Doxml::parseCompound_docTableType(QXmlStreamReader &xml) const
8✔
1032
{
1033
    /// \todo Implement Doxml::parseCompound_docTableType().
1034
    xml.skipCurrentElement();
8✔
1035
    return {};
8✔
1036
}
1037

1038
QVariantMap Doxml::parseCompound_docRowType(QXmlStreamReader &xml) const
8✔
1039
{
1040
    /// \todo Implement Doxml::parseCompound_docRowType().
1041
    xml.skipCurrentElement();
8✔
1042
    return {};
8✔
1043
}
1044

1045
QVariantMap Doxml::parseCompound_docEntryType(QXmlStreamReader &xml) const
8✔
1046
{
1047
    /// \todo Implement Doxml::parseCompound_docEntryType().
1048
    xml.skipCurrentElement();
8✔
1049
    return {};
8✔
1050
}
1051

1052
QVariantMap Doxml::parseCompound_docCaptionType(QXmlStreamReader &xml) const
8✔
1053
{
1054
    /// \todo Implement Doxml::parseCompound_docCaptionType().
1055
    xml.skipCurrentElement();
8✔
1056
    return {};
8✔
1057
}
1058

1059
QVariantMap Doxml::parseCompound_docHeadingType(QXmlStreamReader &xml) const
8✔
1060
{
1061
    /// \todo Implement Doxml::parseCompound_docHeadingType().
1062
    xml.skipCurrentElement();
8✔
1063
    return {};
8✔
1064
}
1065

1066
QVariantMap Doxml::parseCompound_docImageType(QXmlStreamReader &xml) const
8✔
1067
{
1068
    /// \todo Implement Doxml::parseCompound_docImageType().
1069
    xml.skipCurrentElement();
8✔
1070
    return {};
8✔
1071
}
1072

1073
QVariantMap Doxml::parseCompound_docDotMscType(QXmlStreamReader &xml) const
8✔
1074
{
1075
    /// \todo Implement Doxml::parseCompound_docDotMscType().
1076
    xml.skipCurrentElement();
8✔
1077
    return {};
8✔
1078
}
1079

1080
QVariantMap Doxml::parseCompound_docImageFileType(QXmlStreamReader &xml) const
8✔
1081
{
1082
    /// \todo Implement Doxml::parseCompound_docImageFileType().
1083
    xml.skipCurrentElement();
8✔
1084
    return {};
8✔
1085
}
1086

1087
QVariantMap Doxml::parseCompound_docPlantumlType(QXmlStreamReader &xml) const
8✔
1088
{
1089
    /// \todo Implement Doxml::parseCompound_docPlantumlType().
1090
    xml.skipCurrentElement();
8✔
1091
    return {};
8✔
1092
}
1093

1094
QVariantMap Doxml::parseCompound_docTocItemType(QXmlStreamReader &xml) const
8✔
1095
{
1096
    /// \todo Implement Doxml::parseCompound_docTocItemType().
1097
    xml.skipCurrentElement();
8✔
1098
    return {};
8✔
1099
}
1100

1101
QVariantMap Doxml::parseCompound_docTocListType(QXmlStreamReader &xml) const
8✔
1102
{
1103
    /// \todo Implement Doxml::parseCompound_docTocListType().
1104
    xml.skipCurrentElement();
8✔
1105
    return {};
8✔
1106
}
1107

1108
QVariantMap Doxml::parseCompound_docLanguageType(QXmlStreamReader &xml) const
8✔
1109
{
1110
    /// \todo Implement Doxml::parseCompound_docLanguageType().
1111
    xml.skipCurrentElement();
8✔
1112
    return {};
8✔
1113
}
1114

1115
QVariantMap Doxml::parseCompound_docParamListType(QXmlStreamReader &xml) const
8✔
1116
{
1117
    /// \todo Implement Doxml::parseCompound_docParamListType().
1118
    xml.skipCurrentElement();
8✔
1119
    return {};
8✔
1120
}
1121

1122
QVariantMap Doxml::parseCompound_docParamListItem(QXmlStreamReader &xml) const
8✔
1123
{
1124
    /// \todo Implement Doxml::parseCompound_docParamListItem().
1125
    xml.skipCurrentElement();
8✔
1126
    return {};
8✔
1127
}
1128

1129
QVariantMap Doxml::parseCompound_docParamNameList(QXmlStreamReader &xml) const
8✔
1130
{
1131
    /// \todo Implement Doxml::parseCompound_docParamNameList().
1132
    xml.skipCurrentElement();
8✔
1133
    return {};
8✔
1134
}
1135

1136
QVariantMap Doxml::parseCompound_docParamType(QXmlStreamReader &xml) const
8✔
1137
{
1138
    /// \todo Implement Doxml::parseCompound_docParamType().
1139
    xml.skipCurrentElement();
8✔
1140
    return {};
8✔
1141
}
1142

1143
QVariantMap Doxml::parseCompound_docParamName(QXmlStreamReader &xml) const
8✔
1144
{
1145
    /// \todo Implement Doxml::parseCompound_docParamName().
1146
    xml.skipCurrentElement();
8✔
1147
    return {};
8✔
1148
}
1149

1150
QVariantMap Doxml::parseCompound_docXRefSectType(QXmlStreamReader &xml) const
8✔
1151
{
1152
    /// \todo Implement Doxml::parseCompound_docXRefSectType().
1153
    xml.skipCurrentElement();
8✔
1154
    return {};
8✔
1155
}
1156

1157
QVariantMap Doxml::parseCompound_docCopyType(QXmlStreamReader &xml) const
8✔
1158
{
1159
    /// \todo Implement Doxml::parseCompound_docCopyType().
1160
    xml.skipCurrentElement();
8✔
1161
    return {};
8✔
1162
}
1163

1164
QVariantMap Doxml::parseCompound_docDetailsType(QXmlStreamReader &xml) const
8✔
1165
{
1166
    /// \todo Implement Doxml::parseCompound_docDetailsType().
1167
    xml.skipCurrentElement();
8✔
1168
    return {};
8✔
1169
}
1170

1171
QVariantMap Doxml::parseCompound_docBlockQuoteType(QXmlStreamReader &xml) const
8✔
1172
{
1173
    /// \todo Implement Doxml::parseCompound_docBlockQuoteType().
1174
    xml.skipCurrentElement();
8✔
1175
    return {};
8✔
1176
}
1177

1178
QVariantMap Doxml::parseCompound_docParBlockType(QXmlStreamReader &xml) const
8✔
1179
{
1180
    /// \todo Implement Doxml::parseCompound_docParBlockType().
1181
    xml.skipCurrentElement();
8✔
1182
    return {};
8✔
1183
}
1184

1185
QVariantMap Doxml::parseCompound_docEmptyType(QXmlStreamReader &xml) const
8✔
1186
{
1187
    /// \todo Implement Doxml::parseCompound_docEmptyType().
1188
    xml.skipCurrentElement();
8✔
1189
    return {};
8✔
1190
}
1191

1192
QVariantList Doxml::parseCompound_tableofcontentsType(QXmlStreamReader &xml) const
104✔
1193
{
1194
    Q_ASSERT(xml.name() == QSL("tableofcontents"));
1195
    QVariantList sections;
78✔
1196
    while ((!xml.atEnd()) && (xml.readNextStartElement())) {
232✔
1197
        if (xml.name() == QSL("tocsect")) {
256✔
1198
            sections.append(parseCompound_tableofcontentsKindType(xml));
224✔
1199
        } else {
1200
            logWarning(Warning::UnexpectedElement, xml);
×
1201
            xml.skipCurrentElement();
×
1202
        }
1203
    }
1204
    return sections;
104✔
1205
}
1206

1207
QVariantMap Doxml::parseCompound_tableofcontentsKindType(QXmlStreamReader &xml) const
144✔
1208
{
1209
    Q_ASSERT(xml.name() == QSL("tocsect"));
1210

1211
    if ((!xml.readNextStartElement()) || (xml.name() != QSL("name"))) {
288✔
1212
        xml.raiseError(QTR("<tocsect> does not begin with <name>"));
×
1213
        return { };
1214
    }
1215
    QVariantMap map { { QSL("name"), xml.readElementText() } };
468✔
1216

1217
    if ((!xml.readNextStartElement()) || (xml.name() != QSL("reference"))) {
288✔
1218
        xml.raiseError(QTR("<tocsect> does not contain <reference>"));
×
1219
        return { };
1220
    }
1221
    map.insert(QSL("reference"), xml.readElementText());
252✔
1222

1223
    QVariantList tableofcontentsList; // A list of lists. Not sure why Doxygen models it that way.
108✔
1224
    while ((!xml.atEnd()) && (xml.readNextStartElement())) {
224✔
1225
        if (xml.name() == QSL("tableofcontents")) {
160✔
1226
            tableofcontentsList.append(parseCompound_tableofcontentsType(xml));
160✔
1227
        } else {
1228
            logWarning(Warning::UnexpectedElement, xml);
×
1229
            xml.skipCurrentElement();
×
1230
        }
1231
    }
1232
    if (!tableofcontentsList.isEmpty()) {
144✔
1233
        map.insert(QSL("tableofcontents"), tableofcontentsList);
140✔
1234
    }
1235
    return map;
1236
}
36✔
1237

1238
QVariantMap Doxml::parseCompound_docEmojiType(QXmlStreamReader &xml) const
8✔
1239
{
1240
    const auto unicode = xml.attributes().value(QSL("unicode"));
15✔
1241
    const auto value = parseNumericCharacterReference(unicode);
8✔
1242
    if (value.isNull()) {
8✔
1243
        logWarning(QTR("Invalid numeric character reference: %1").arg(unicode), xml);
×
1244
    }
1245
    return {
1246
        { QSL("name"), xml.attributes().value(QSL("name")).toString() },
16✔
1247
        { QSL("unicode"), unicode.toString() },
10✔
1248
        { QSL("value"), value },
8✔
1249
    };
54✔
1250
}
2✔
1251

1252
QVariantMap Doxml::parseDoxyfile(QXmlStreamReader &xml) const
8✔
1253
{
1254
    if (!xml.readNextStartElement()) {
8✔
1255
        Q_ASSERT(xml.hasError());
1256
        return { };
1257
    }
1258
    if (xml.name() != QSL("doxyfile")) {
10✔
1259
        xml.raiseError(QTR("Root element is not \"doxyfile\""));
×
1260
        return { };
1261
    }
1262
    return parseDoxyfile_DoxygenFileType(xml);
8✔
1263
}
1264

1265
QVariantMap Doxml::parseDoxyfile_DoxygenFileType(QXmlStreamReader &xml) const
16✔
1266
{
1267
    Q_ASSERT(xml.name() == QSL("doxyfile"));
1268

1269
    QVariantMap map;
12✔
1270
    map.insert(QSL("version"), xml.attributes().value(QSL("version")).toString());
40✔
1271
    map.insert(QSL("language"), xml.attributes().value(QSL("xml:lang")).toString());
40✔
1272

1273
    QVariantMap options;
12✔
1274
    while ((!xml.atEnd()) && (xml.readNextStartElement())) {
112✔
1275
        if (xml.name() == QSL("option")) {
192✔
1276
            options.insert(parseDoxyfile_OptionType(xml));
168✔
1277
        } else {
1278
            logWarning(Warning::UnexpectedElement, xml);
×
1279
            xml.skipCurrentElement();
×
1280
        }
1281
    }
1282
    qCDebug(lc).noquote() << QTR("Parsed %1 options(s) from %2").arg(options.size()).arg(currentXmlFilePath);
20✔
1283
    map.insert(QSL("options"), options);
28✔
1284
    return map;
16✔
1285
}
4✔
1286

1287
QVariantMap Doxml::parseDoxyfile_OptionType(QXmlStreamReader &xml) const
144✔
1288
{
1289
    Q_ASSERT(xml.name() == QSL("option"));
1290
    const auto attributes = xml.attributes();
144✔
1291
    const auto id = attributes.value(QSL("id"));
270✔
1292
    const auto type = attributes.value(QSL("type"));
270✔
1293
    if (type == QSL("int")) {
144✔
1294
        return { { id.toString(), xml.readElementText(QXmlStreamReader::IncludeChildElements).toInt() } };
72✔
1295
    } else if (type == QSL("bool")) {
120✔
1296
        return { { id.toString(), xml.readElementText(QXmlStreamReader::IncludeChildElements) == QSL("YES") } };
108✔
1297
    } else if (type == QSL("string")) {
72✔
1298
        return { { id.toString(), xml.readElementText(QXmlStreamReader::IncludeChildElements) } };
60✔
1299
    } else if (type == QSL("stringlist")) {
48✔
1300
        QStringList values;
36✔
1301
        while ((!xml.atEnd()) && (xml.readNextStartElement())) {
96✔
1302
            if (xml.name() == QSL("value")) {
120✔
1303
                values.append(xml.readElementText());
84✔
1304
            } else {
1305
                logWarning(Warning::UnexpectedElement, xml);
×
1306
                xml.skipCurrentElement();
×
1307
            }
1308
        }
1309
        return { { id.toString(), values } };
108✔
1310
    }
1311
    logWarning(QTR("Treating Doxyfile option \"%1\" of unknown type \"%2\" as string").arg(id, type), xml);
×
1312
    return { { id.toString(), xml.readElementText(QXmlStreamReader::IncludeChildElements) } };
×
1313
}
1314

1315
QVariantMap Doxml::parseIndex(QXmlStreamReader &xml) const
8✔
1316
{
1317
    if (!xml.readNextStartElement()) {
8✔
1318
        Q_ASSERT(xml.hasError());
1319
        return { };
1320
    }
1321
    if (xml.name() != QSL("doxygenindex")) {
10✔
1322
        xml.raiseError(QTR("Root element is not \"doxygenindex\""));
×
1323
        return { };
1324
    }
1325
    return parseIndex_DoxygenType(xml);
8✔
1326
}
1327

1328
QVariantMap Doxml::parseIndex_DoxygenType(QXmlStreamReader &xml) const
16✔
1329
{
1330
    Q_ASSERT(xml.name() == QSL("doxygenindex"));
1331

1332
    QVariantMap map {
1333
        { QSL("version"), xml.attributes().value(QSL("version")).toString() },
32✔
1334
        { QSL("language"), xml.attributes().value(QSL("xml:lang")).toString() },
32✔
1335
    };
78✔
1336

1337
    QVariantList compounds;
12✔
1338
    while ((!xml.atEnd()) && (xml.readNextStartElement())) {
32✔
1339
        if (xml.name() == QSL("compound")) {
32✔
1340
            compounds.append(parseIndex_CompoundType(xml));
28✔
1341
        } else {
1342
            logWarning(Warning::UnexpectedElement, xml);
×
1343
            xml.skipCurrentElement();
×
1344
        }
1345
    }
1346
    qCDebug(lc).noquote() << QTR("Parsed %1 compounds(s) from %2").arg(compounds.size()).arg(currentXmlFilePath);
20✔
1347
    map.insert(QSL("compounds"), compounds);
28✔
1348
    return map;
16✔
1349
}
4✔
1350

1351
QVariantMap Doxml::parseIndex_CompoundType(QXmlStreamReader &xml) const
32✔
1352
{
1353
    Q_ASSERT(xml.name() == QSL("compound"));
1354
    QVariantMap map {
1355
        { QSL("refid"), xml.attributes().value(QSL("refid")).toString() },
64✔
1356
        { QSL("kind"),  xml.attributes().value(QSL("kind")).toString() },
64✔
1357
    };
152✔
1358

1359
    if ((!xml.readNextStartElement()) || (xml.name() != QSL("name"))) {
64✔
1360
        xml.raiseError(QTR("<compound> does not begin with <name>"));
×
1361
        return { };
1362
    }
1363
    map.insert(QSL("name"), xml.readElementText());
56✔
1364

1365
    QVariantList members;
24✔
1366
    while ((!xml.atEnd()) && (xml.readNextStartElement())) {
48✔
1367
        if (xml.name() == QSL("member")) {
32✔
1368
            members.append(parseIndex_MemberType(xml));
28✔
1369
        } else {
1370
            logWarning(Warning::UnexpectedElement, xml);
×
1371
            xml.skipCurrentElement();
×
1372
        }
1373
    }
1374
    map.insert(QSL("members"), members);
56✔
1375
    return map;
1376
}
8✔
1377

1378
QVariantMap Doxml::parseIndex_MemberType(QXmlStreamReader &xml) const
24✔
1379
{
1380
    Q_ASSERT(xml.name() == QSL("member"));
1381
    QVariantMap map {
1382
        { QSL("refid"), xml.attributes().value(QSL("refid")).toString() },
48✔
1383
        { QSL("kind"),  xml.attributes().value(QSL("kind")).toString() },
48✔
1384
    };
114✔
1385
    if ((!xml.readNextStartElement()) || (xml.name() != QSL("name"))) {
48✔
1386
        xml.raiseError(QTR("<member> does not begin with <name>"));
×
1387
        return { };
1388
    }
1389
    map.insert(QSL("name"), xml.readElementText());
42✔
1390
    xml.skipCurrentElement();
24✔
1391
    return map;
1392
}
6✔
1393

1394
} // namespace doxlee
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc