Skip to content

Commit 3175b47

Browse files
committed
refactor(generator): migrate typesystem parser to QXmlStreamReader
- drop the legacy QtXml reader/handler stack in favor of `QXmlStreamReader` - rewrite the typesystem Handler to drive the stream reader directly and wrap `QXmlStreamAttributes` - update attribute helpers and error reporting to match the new streaming API - open typesystem files with QText mode and surface parse failures via `ReportHandler`
1 parent f4769f1 commit 3175b47

File tree

1 file changed

+106
-54
lines changed

1 file changed

+106
-54
lines changed

generator/typesystem.cpp

Lines changed: 106 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -48,25 +48,11 @@
4848

4949
#include <memory>
5050

51-
#include <QtXml>
51+
#include <QFile>
52+
#include <QTextStream>
53+
#include <QXmlStreamReader>
5254
#include <qcompilerdetection.h> // Q_FALLTHROUGH
5355

54-
/* This file needs to be rewritten as documented here:
55-
*
56-
* See: https://doc.qt.io/qt-6/xml-changes-qt6.html
57-
*
58-
* The rewrite may be backward compatible to Qt4.3 APIs because the base
59-
* facilites (QXmlStreamReader) used to relace the 'SAX' parser were apparently
60-
* available then. Use of Xml5Compat is a work round until such a rewrite has
61-
* been done.
62-
*/
63-
#if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
64-
# if defined(__GNUC__)
65-
# pragma GCC warning "Qt6: implement Qt6 compatible XML reading"
66-
# endif
67-
# include <QtCore5Compat/QXmlDefaultHandler>
68-
#endif
69-
7056
QString strings_Object = QLatin1String("Object");
7157
QString strings_String = QLatin1String("String");
7258
QString strings_Thread = QLatin1String("Thread");
@@ -150,9 +136,48 @@ class StackElement
150136
} value;
151137
};
152138

153-
class Handler : public QXmlDefaultHandler
139+
class Handler
154140
{
155141
public:
142+
class Attributes
143+
{
144+
public:
145+
Attributes() = default;
146+
explicit Attributes(const QXmlStreamAttributes &attributes)
147+
: m_attributes(attributes) {}
148+
149+
int length() const { return m_attributes.size(); }
150+
151+
QString localName(int index) const
152+
{
153+
return m_attributes.at(index).name().toString();
154+
}
155+
156+
QString value(int index) const
157+
{
158+
return m_attributes.at(index).value().toString();
159+
}
160+
161+
QString value(const QString &qualifiedName) const
162+
{
163+
return m_attributes.hasAttribute(qualifiedName)
164+
? m_attributes.value(qualifiedName).toString()
165+
: QString();
166+
}
167+
168+
int index(const QString &qualifiedName) const
169+
{
170+
for (int i = 0; i < m_attributes.size(); ++i) {
171+
if (m_attributes.at(i).name().toString() == qualifiedName)
172+
return i;
173+
}
174+
return -1;
175+
}
176+
177+
private:
178+
QXmlStreamAttributes m_attributes;
179+
};
180+
156181
Handler(TypeDatabase *database, unsigned int qtVersion, bool generate)
157182
: m_database(database)
158183
, m_generate(generate ? TypeEntry::GenerateAll : TypeEntry::GenerateForSubclass)
@@ -197,25 +222,23 @@ class Handler : public QXmlDefaultHandler
197222
tagNames["reference-count"] = StackElement::ReferenceCount;
198223
}
199224

225+
bool parse(QXmlStreamReader &reader);
200226
bool startDocument() { m_nestingLevel = 0; m_disabledLevel = -1; return true; }
201227
bool startElement(const QString &namespaceURI, const QString &localName,
202-
const QString &qName, const QXmlAttributes &atts);
228+
const QString &qName, const Attributes &atts);
203229
bool endElement(const QString &namespaceURI, const QString &localName, const QString &qName);
204230

205231
QString errorString() const { return m_error; }
206-
bool error(const QXmlParseException &exception);
207-
bool fatalError(const QXmlParseException &exception);
208-
bool warning(const QXmlParseException &exception);
209232

210233
bool characters(const QString &ch);
211234

212235
private:
213-
void fetchAttributeValues(const QString &name, const QXmlAttributes &atts,
236+
void fetchAttributeValues(const QString &name, const Attributes &atts,
214237
QHash<QString, QString> *acceptedAttributes);
215238

216-
bool importFileElement(const QXmlAttributes &atts);
239+
bool importFileElement(const Attributes &atts);
217240
bool convertBoolean(const QString &, const QString &, bool);
218-
bool qtVersionMatches(const QXmlAttributes& atts, bool& ok);
241+
bool qtVersionMatches(const Attributes& atts, bool& ok);
219242

220243
TypeDatabase *m_database;
221244
StackElement* current;
@@ -237,31 +260,55 @@ class Handler : public QXmlDefaultHandler
237260
int m_disabledLevel{}; // if this is != 0, elements should be ignored
238261
};
239262

240-
bool Handler::error(const QXmlParseException &e)
263+
bool Handler::parse(QXmlStreamReader &reader)
241264
{
242-
qWarning() << "Error: line=" << e.lineNumber()
243-
<< ", column=" << e.columnNumber()
244-
<< ", message=" << e.message() << "\n";
245-
return false;
246-
}
265+
if (!startDocument())
266+
return false;
247267

248-
bool Handler::fatalError(const QXmlParseException &e)
249-
{
250-
qWarning() << "Fatal error: line=" << e.lineNumber()
251-
<< ", column=" << e.columnNumber()
252-
<< ", message=" << e.message() << "\n";
253-
return false;
254-
}
268+
while (!reader.atEnd()) {
269+
const auto token = reader.readNext();
270+
switch (token) {
271+
case QXmlStreamReader::StartElement: {
272+
Attributes attributes(reader.attributes());
273+
if (!startElement(reader.namespaceUri().toString(),
274+
reader.name().toString(),
275+
reader.qualifiedName().toString(),
276+
attributes)) {
277+
return false;
278+
}
279+
break;
280+
}
281+
case QXmlStreamReader::EndElement:
282+
if (!endElement(reader.namespaceUri().toString(),
283+
reader.name().toString(),
284+
reader.qualifiedName().toString())) {
285+
return false;
286+
}
287+
break;
288+
case QXmlStreamReader::Characters:
289+
case QXmlStreamReader::EntityReference:
290+
if (!characters(reader.text().toString())) {
291+
return false;
292+
}
293+
break;
294+
default:
295+
break;
296+
}
297+
}
255298

256-
bool Handler::warning(const QXmlParseException &e)
257-
{
258-
qWarning() << "Warning: line=" << e.lineNumber()
259-
<< ", column=" << e.columnNumber()
260-
<< ", message=" << e.message() << "\n";
261-
return false;
299+
if (reader.hasError()) {
300+
m_error = QStringLiteral("Parse error at line %1, column %2: %3")
301+
.arg(reader.lineNumber())
302+
.arg(reader.columnNumber())
303+
.arg(reader.errorString());
304+
qWarning() << m_error;
305+
return false;
306+
}
307+
308+
return true;
262309
}
263310

264-
void Handler::fetchAttributeValues(const QString &name, const QXmlAttributes &atts,
311+
void Handler::fetchAttributeValues(const QString &name, const Attributes &atts,
265312
QHash<QString, QString> *acceptedAttributes)
266313
{
267314
Q_ASSERT(acceptedAttributes != 0);
@@ -358,6 +405,9 @@ bool Handler::endElement(const QString &, const QString &localName, const QStrin
358405

359406
bool Handler::characters(const QString &ch)
360407
{
408+
if (!current)
409+
return true;
410+
361411
if(current->type == StackElement::Template){
362412
current->value.templateEntry->addCode(ch);
363413
return true;
@@ -398,7 +448,7 @@ bool Handler::characters(const QString &ch)
398448
return true;
399449
}
400450

401-
bool Handler::importFileElement(const QXmlAttributes &atts)
451+
bool Handler::importFileElement(const Attributes &atts)
402452
{
403453
QString fileName = atts.value("name");
404454
if(fileName.isEmpty()){
@@ -470,7 +520,7 @@ bool Handler::convertBoolean(const QString &_value, const QString &attributeName
470520
}
471521
}
472522

473-
bool Handler::qtVersionMatches(const QXmlAttributes& atts, bool& ok)
523+
bool Handler::qtVersionMatches(const Attributes& atts, bool& ok)
474524
{
475525
ok = true;
476526
int beforeIndex = atts.index("before-version");
@@ -501,7 +551,7 @@ bool Handler::qtVersionMatches(const QXmlAttributes& atts, bool& ok)
501551
}
502552

503553
bool Handler::startElement(const QString &, const QString &n,
504-
const QString &, const QXmlAttributes &atts)
554+
const QString &, const Attributes &atts)
505555
{
506556
QString tagName = n.toLower();
507557
m_nestingLevel++;
@@ -1601,17 +1651,19 @@ bool TypeDatabase::parseFile(const QString &filename, unsigned int qtVersion, bo
16011651
QFile file(filename);
16021652

16031653
Q_ASSERT(file.exists());
1604-
QXmlInputSource source(&file);
1654+
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
1655+
ReportHandler::warning(QString::fromLatin1("Could not open typesystem file: '%1'").arg(filename));
1656+
return false;
1657+
}
16051658

16061659
int count = m_entries.size();
16071660

1608-
QXmlSimpleReader reader;
16091661
Handler handler(this, qtVersion, generate);
1662+
QXmlStreamReader reader(&file);
16101663

1611-
reader.setContentHandler(&handler);
1612-
reader.setErrorHandler(&handler);
1613-
1614-
bool ok = reader.parse(&source, false);
1664+
bool ok = handler.parse(reader);
1665+
if (!ok && !handler.errorString().isEmpty())
1666+
ReportHandler::warning(handler.errorString());
16151667

16161668
int newCount = m_entries.size();
16171669

0 commit comments

Comments
 (0)