Skip to content

Commit 25fdb58

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 25fdb58

File tree

1 file changed

+107
-54
lines changed

1 file changed

+107
-54
lines changed

generator/typesystem.cpp

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

4949
#include <memory>
5050

51-
#include <QtXml>
51+
#include <QDebug>
52+
#include <QFile>
53+
#include <QTextStream>
54+
#include <QXmlStreamReader>
5255
#include <qcompilerdetection.h> // Q_FALLTHROUGH
5356

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-
7057
QString strings_Object = QLatin1String("Object");
7158
QString strings_String = QLatin1String("String");
7259
QString strings_Thread = QLatin1String("Thread");
@@ -150,9 +137,48 @@ class StackElement
150137
} value;
151138
};
152139

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

226+
bool parse(QXmlStreamReader &reader);
200227
bool startDocument() { m_nestingLevel = 0; m_disabledLevel = -1; return true; }
201228
bool startElement(const QString &namespaceURI, const QString &localName,
202-
const QString &qName, const QXmlAttributes &atts);
229+
const QString &qName, const Attributes &atts);
203230
bool endElement(const QString &namespaceURI, const QString &localName, const QString &qName);
204231

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

210234
bool characters(const QString &ch);
211235

212236
private:
213-
void fetchAttributeValues(const QString &name, const QXmlAttributes &atts,
237+
void fetchAttributeValues(const QString &name, const Attributes &atts,
214238
QHash<QString, QString> *acceptedAttributes);
215239

216-
bool importFileElement(const QXmlAttributes &atts);
240+
bool importFileElement(const Attributes &atts);
217241
bool convertBoolean(const QString &, const QString &, bool);
218-
bool qtVersionMatches(const QXmlAttributes& atts, bool& ok);
242+
bool qtVersionMatches(const Attributes& atts, bool& ok);
219243

220244
TypeDatabase *m_database;
221245
StackElement* current;
@@ -237,31 +261,55 @@ class Handler : public QXmlDefaultHandler
237261
int m_disabledLevel{}; // if this is != 0, elements should be ignored
238262
};
239263

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

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-
}
269+
while (!reader.atEnd()) {
270+
const auto token = reader.readNext();
271+
switch (token) {
272+
case QXmlStreamReader::StartElement: {
273+
Attributes attributes(reader.attributes());
274+
if (!startElement(reader.namespaceUri().toString(),
275+
reader.name().toString(),
276+
reader.qualifiedName().toString(),
277+
attributes)) {
278+
return false;
279+
}
280+
break;
281+
}
282+
case QXmlStreamReader::EndElement:
283+
if (!endElement(reader.namespaceUri().toString(),
284+
reader.name().toString(),
285+
reader.qualifiedName().toString())) {
286+
return false;
287+
}
288+
break;
289+
case QXmlStreamReader::Characters:
290+
case QXmlStreamReader::EntityReference:
291+
if (!characters(reader.text().toString())) {
292+
return false;
293+
}
294+
break;
295+
default:
296+
break;
297+
}
298+
}
255299

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;
300+
if (reader.hasError()) {
301+
m_error = QStringLiteral("Parse error at line %1, column %2: %3")
302+
.arg(reader.lineNumber())
303+
.arg(reader.columnNumber())
304+
.arg(reader.errorString());
305+
qWarning() << m_error;
306+
return false;
307+
}
308+
309+
return true;
262310
}
263311

264-
void Handler::fetchAttributeValues(const QString &name, const QXmlAttributes &atts,
312+
void Handler::fetchAttributeValues(const QString &name, const Attributes &atts,
265313
QHash<QString, QString> *acceptedAttributes)
266314
{
267315
Q_ASSERT(acceptedAttributes != 0);
@@ -358,6 +406,9 @@ bool Handler::endElement(const QString &, const QString &localName, const QStrin
358406

359407
bool Handler::characters(const QString &ch)
360408
{
409+
if (!current)
410+
return true;
411+
361412
if(current->type == StackElement::Template){
362413
current->value.templateEntry->addCode(ch);
363414
return true;
@@ -398,7 +449,7 @@ bool Handler::characters(const QString &ch)
398449
return true;
399450
}
400451

401-
bool Handler::importFileElement(const QXmlAttributes &atts)
452+
bool Handler::importFileElement(const Attributes &atts)
402453
{
403454
QString fileName = atts.value("name");
404455
if(fileName.isEmpty()){
@@ -470,7 +521,7 @@ bool Handler::convertBoolean(const QString &_value, const QString &attributeName
470521
}
471522
}
472523

473-
bool Handler::qtVersionMatches(const QXmlAttributes& atts, bool& ok)
524+
bool Handler::qtVersionMatches(const Attributes& atts, bool& ok)
474525
{
475526
ok = true;
476527
int beforeIndex = atts.index("before-version");
@@ -501,7 +552,7 @@ bool Handler::qtVersionMatches(const QXmlAttributes& atts, bool& ok)
501552
}
502553

503554
bool Handler::startElement(const QString &, const QString &n,
504-
const QString &, const QXmlAttributes &atts)
555+
const QString &, const Attributes &atts)
505556
{
506557
QString tagName = n.toLower();
507558
m_nestingLevel++;
@@ -1601,17 +1652,19 @@ bool TypeDatabase::parseFile(const QString &filename, unsigned int qtVersion, bo
16011652
QFile file(filename);
16021653

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

16061660
int count = m_entries.size();
16071661

1608-
QXmlSimpleReader reader;
16091662
Handler handler(this, qtVersion, generate);
1663+
QXmlStreamReader reader(&file);
16101664

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

16161669
int newCount = m_entries.size();
16171670

0 commit comments

Comments
 (0)