From 0996f18b252504ccc2db94b16c751835e3b9be8e Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Mon, 26 Mar 2018 13:52:17 +0200 Subject: Fix CONFIG+=qtquickcompiler with umlauts in the file path Instead of replacing every character that is not allowed in C++ identifiers with an underscore (which in turn could lead to collissions), replace it with the hexadecimal value of the offending character's unicode value. In addition we must use the complete suffix when mapping Foo.qml to Foo_qml.cpp. Task-number: QTBUG-68608 Started-by: Erik Verbruggen Change-Id: I7e2153f0e6671b37dcaee4efb9aaae1d9b230f0c Reviewed-by: Ulf Hermann --- tests/auto/qml/qmlcachegen/qmlcachegen.pro | 3 ++ tests/auto/qml/qmlcachegen/trickypaths.qrc | 2 + tests/auto/qml/qmlcachegen/trickypaths_umlaut.qrc | 5 ++ tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp | 22 +++++++-- tests/auto/qml/qmlcachegen/umlaut.qml | 4 ++ .../qmlcachegen/versionStyleSuffix-1.2-core-yc.qml | 4 ++ .../qmlcachegen/versionStyleSuffix-1.2-more.qml | 4 ++ tools/qmlcachegen/generateloader.cpp | 54 +++++++++++++++++++--- 8 files changed, 88 insertions(+), 10 deletions(-) create mode 100644 tests/auto/qml/qmlcachegen/trickypaths_umlaut.qrc create mode 100644 tests/auto/qml/qmlcachegen/umlaut.qml create mode 100644 tests/auto/qml/qmlcachegen/versionStyleSuffix-1.2-core-yc.qml create mode 100644 tests/auto/qml/qmlcachegen/versionStyleSuffix-1.2-more.qml diff --git a/tests/auto/qml/qmlcachegen/qmlcachegen.pro b/tests/auto/qml/qmlcachegen/qmlcachegen.pro index 40de4548a7..6dee2a0454 100644 --- a/tests/auto/qml/qmlcachegen/qmlcachegen.pro +++ b/tests/auto/qml/qmlcachegen/qmlcachegen.pro @@ -16,4 +16,7 @@ RESOURCES += jsimport.qml script.js library.js RESOURCES += Enums.qml +# QTBUG-46375 +!win32: RESOURCES += trickypaths_umlaut.qrc + QT += core-private qml-private testlib diff --git a/tests/auto/qml/qmlcachegen/trickypaths.qrc b/tests/auto/qml/qmlcachegen/trickypaths.qrc index 271cf6571e..57977ccf6d 100644 --- a/tests/auto/qml/qmlcachegen/trickypaths.qrc +++ b/tests/auto/qml/qmlcachegen/trickypaths.qrc @@ -1,5 +1,7 @@ trickypaths.qml +versionStyleSuffix-1.2-core-yc.qml +versionStyleSuffix-1.2-more.qml diff --git a/tests/auto/qml/qmlcachegen/trickypaths_umlaut.qrc b/tests/auto/qml/qmlcachegen/trickypaths_umlaut.qrc new file mode 100644 index 0000000000..9ca889d692 --- /dev/null +++ b/tests/auto/qml/qmlcachegen/trickypaths_umlaut.qrc @@ -0,0 +1,5 @@ + + +umlaut.qml + + diff --git a/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp b/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp index 3b7d268f7b..6dc54a323e 100644 --- a/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp +++ b/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp @@ -53,6 +53,7 @@ private slots: void workerScripts(); + void trickyPaths_data(); void trickyPaths(); void scriptImport(); @@ -408,13 +409,26 @@ void tst_qmlcachegen::functionExpressions() QCOMPARE(obj->property("h_connections_handler_called").toBool(), true); } +void tst_qmlcachegen::trickyPaths_data() +{ + QTest::addColumn("filePath"); + QTest::newRow("path with spaces") << QStringLiteral(":/directory with spaces/file name with spaces.qml"); + QTest::newRow("version style suffix 1") << QStringLiteral(":/directory with spaces/versionStyleSuffix-1.2-core-yc.qml"); + QTest::newRow("version style suffix 2") << QStringLiteral(":/directory with spaces/versionStyleSuffix-1.2-more.qml"); + + // QTBUG-46375 +#if !defined(Q_OS_WIN) + QTest::newRow("path with umlaut") << QStringLiteral(":/Bäh.qml"); +#endif +} + void tst_qmlcachegen::trickyPaths() { - QString pathWithSpaces(QStringLiteral(":/directory with spaces/file name with spaces.qml")); - QVERIFY2(QFile::exists(pathWithSpaces), qPrintable(pathWithSpaces)); - QCOMPARE(QFileInfo(pathWithSpaces).size(), 0); + QFETCH(QString, filePath); + QVERIFY2(QFile::exists(filePath), qPrintable(filePath)); + QCOMPARE(QFileInfo(filePath).size(), 0); QQmlEngine engine; - QQmlComponent component(&engine, QUrl("qrc" + pathWithSpaces)); + QQmlComponent component(&engine, QUrl("qrc" + filePath)); QScopedPointer obj(component.create()); QVERIFY(!obj.isNull()); QCOMPARE(obj->property("success").toInt(), 42); diff --git a/tests/auto/qml/qmlcachegen/umlaut.qml b/tests/auto/qml/qmlcachegen/umlaut.qml new file mode 100644 index 0000000000..0836808dc2 --- /dev/null +++ b/tests/auto/qml/qmlcachegen/umlaut.qml @@ -0,0 +1,4 @@ +import QtQml 2.0 +QtObject { + property int success: 42 +} diff --git a/tests/auto/qml/qmlcachegen/versionStyleSuffix-1.2-core-yc.qml b/tests/auto/qml/qmlcachegen/versionStyleSuffix-1.2-core-yc.qml new file mode 100644 index 0000000000..0836808dc2 --- /dev/null +++ b/tests/auto/qml/qmlcachegen/versionStyleSuffix-1.2-core-yc.qml @@ -0,0 +1,4 @@ +import QtQml 2.0 +QtObject { + property int success: 42 +} diff --git a/tests/auto/qml/qmlcachegen/versionStyleSuffix-1.2-more.qml b/tests/auto/qml/qmlcachegen/versionStyleSuffix-1.2-more.qml new file mode 100644 index 0000000000..0836808dc2 --- /dev/null +++ b/tests/auto/qml/qmlcachegen/versionStyleSuffix-1.2-more.qml @@ -0,0 +1,4 @@ +import QtQml 2.0 +QtObject { + property int success: 42 +} diff --git a/tools/qmlcachegen/generateloader.cpp b/tools/qmlcachegen/generateloader.cpp index 96528a9477..178a109791 100644 --- a/tools/qmlcachegen/generateloader.cpp +++ b/tools/qmlcachegen/generateloader.cpp @@ -35,6 +35,52 @@ #include #include +/*! + * \internal + * Mangles \a str to be a unique C++ identifier. Characters that are invalid for C++ identifiers + * are replaced by the pattern \c _0x_ where is the hexadecimal unicode + * representation of the character. As identifiers with leading underscores followed by either + * another underscore or a capital letter are reserved in C++, we also escape those, by escaping + * the first underscore, using the above method. + * + * \note + * Although C++11 allows for non-ascii (unicode) characters to be used in identifiers, + * many compilers forgot to read the spec and do not implement this. Some also do not + * implement C99 identifiers, because that is \e {at the implementation's discretion}. So, + * we are stuck with plain old boring identifiers. + */ +QString mangledIdentifier(const QString &str) +{ + Q_ASSERT(!str.isEmpty()); + + QString mangled; + mangled.reserve(str.size()); + + int i = 0; + if (str.startsWith(QLatin1Char('_')) && str.size() > 1) { + QChar ch = str.at(1); + if (ch == QLatin1Char('_') + || (ch >= QLatin1Char('A') && ch <= QLatin1Char('Z'))) { + mangled += QLatin1String("_0x5f_"); + ++i; + } + } + + for (int ei = str.length(); i != ei; ++i) { + auto c = str.at(i).unicode(); + if ((c >= QLatin1Char('0') && c <= QLatin1Char('9')) + || (c >= QLatin1Char('a') && c <= QLatin1Char('z')) + || (c >= QLatin1Char('A') && c <= QLatin1Char('Z')) + || c == QLatin1Char('_')) { + mangled += c; + } else { + mangled += QLatin1String("_0x") + QString::number(c, 16) + QLatin1Char('_'); + } + } + + return mangled; +} + QString symbolNamespaceForPath(const QString &relativePath) { QFileInfo fi(relativePath); @@ -47,12 +93,8 @@ QString symbolNamespaceForPath(const QString &relativePath) } symbol += fi.baseName(); symbol += QLatin1Char('_'); - symbol += fi.suffix(); - symbol.replace(QLatin1Char('.'), QLatin1Char('_')); - symbol.replace(QLatin1Char('+'), QLatin1Char('_')); - symbol.replace(QLatin1Char('-'), QLatin1Char('_')); - symbol.replace(QLatin1Char(' '), QLatin1Char('_')); - return symbol; + symbol += fi.completeSuffix(); + return mangledIdentifier(symbol); } struct VirtualDirectoryEntry -- cgit v1.2.3