diff options
author | Fabian Kosmale <fabian.kosmale@qt.io> | 2022-10-20 13:33:26 +0200 |
---|---|---|
committer | Fabian Kosmale <fabian.kosmale@qt.io> | 2023-01-25 14:51:30 +0100 |
commit | 58e55b68d9c43d2b4d0a8dfb3e0497a814cc61a7 (patch) | |
tree | 40f75e771693d48dd0b479c460ac2716883e45d6 /src | |
parent | cfb690f87a8483539816f12199908dde4a59584d (diff) |
QQmlImport: Handle file selectors in qmldir
With file selectors, a type can exist in the same version under
different paths. Detect this case, canonicalize the filename to the
selector free version, and rely on the engine to resolve a URL to the
correct file.
Fixes: QTBUG-107797
Change-Id: I0f74fd37936abfa08547fb439bfa5264e6ca4787
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
(cherry picked from commit 9bfb27be010940ca735ca7dd67a092a03289e27c)
Reviewed-by: Sami Shalayel <sami.shalayel@qt.io>
Diffstat (limited to 'src')
-rw-r--r-- | src/qml/qml/qqmlimport.cpp | 60 |
1 files changed, 60 insertions, 0 deletions
diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp index 611ff42681..5e60f9fb95 100644 --- a/src/qml/qml/qqmlimport.cpp +++ b/src/qml/qml/qqmlimport.cpp @@ -1169,6 +1169,26 @@ QString QQmlImportsPrivate::resolvedUri(const QString &dir_arg, QQmlImportDataba return stableRelativePath; } +/* removes all file selector occurrences in path + firstPlus is the position of the initial '+' in the path + which we always have as we check for '+' to decide whether + we need to do some work at all +*/ +static QString pathWithoutFileSelectors(QString path, // we want a copy of path + qsizetype firstPlus) +{ + do { + Q_ASSERT(path.at(firstPlus) == u'+'); + const auto eos = path.size(); + qsizetype terminatingSlashPos = firstPlus + 1; + while (terminatingSlashPos != eos && path.at(terminatingSlashPos) != u'/') + ++terminatingSlashPos; + path.remove(firstPlus, terminatingSlashPos - firstPlus + 1); + firstPlus = path.indexOf(u'+', firstPlus); + } while (firstPlus != -1); + return path; +} + /*! \internal @@ -1215,10 +1235,42 @@ QTypeRevision QQmlImportsPrivate::matchingQmldirVersion( typedef QQmlDirComponents::const_iterator ConstIterator; const QQmlDirComponents &components = qmldir.components(); + QMultiHash<QString, ConstIterator> baseFileName2ConflictingComponents; + ConstIterator cend = components.constEnd(); for (ConstIterator cit = components.constBegin(); cit != cend; ++cit) { for (ConstIterator cit2 = components.constBegin(); cit2 != cit; ++cit2) { if (cit2->typeName == cit->typeName && cit2->version == cit->version) { + // ugly heuristic to deal with file selectors + const auto comp2PotentialFileSelectorPos = cit2->fileName.indexOf(u'+'); + const bool comp2MightHaveFileSelector = comp2PotentialFileSelectorPos != -1; + /* If we detect conflicting paths, we check if they agree when we remove anything looking like a + file selector. + We need to create copies of the filenames, otherwise QString::replace would modify the + existing file-names + */ + QString compFileName1 = cit->fileName; + QString compFileName2 = cit2->fileName; + if (auto fileSelectorPos1 = compFileName1.indexOf(u'+'); fileSelectorPos1 != -1) { + // existing entry was file selector entry, fix it up + // it could also be the case that _both_ are using file selectors + QString baseName = comp2MightHaveFileSelector ? pathWithoutFileSelectors(compFileName2, + comp2PotentialFileSelectorPos) + : compFileName2; + if (pathWithoutFileSelectors(compFileName1, fileSelectorPos1) == baseName) { + baseFileName2ConflictingComponents.insert(baseName, cit); + baseFileName2ConflictingComponents.insert(baseName, cit2); + continue; + } + // fall through to error case + } else if (comp2MightHaveFileSelector) { + // new entry contains file selector (and we now that cit did not) + if (pathWithoutFileSelectors(compFileName2, comp2PotentialFileSelectorPos) == compFileName1) { + baseFileName2ConflictingComponents.insert(compFileName1, cit2); + continue; + } + // fall through to error case + } // This entry clashes with a predecessor QQmlError error; error.setDescription(QQmlImportDatabase::tr("\"%1\" version %2.%3 is defined more than once in module \"%4\"") @@ -1232,6 +1284,14 @@ QTypeRevision QQmlImportsPrivate::matchingQmldirVersion( addVersion(cit->version); } + // ensure that all components point to the actual base URL, and let the file selectors resolve them correctly during URL resolution + for (auto keyIt = baseFileName2ConflictingComponents.keyBegin(); keyIt != baseFileName2ConflictingComponents.keyEnd(); ++keyIt) { + const QString& baseFileName = *keyIt; + const auto conflictingComponents = baseFileName2ConflictingComponents.values(baseFileName); + for (ConstIterator component: conflictingComponents) + component->fileName = baseFileName; + } + typedef QList<QQmlDirParser::Script>::const_iterator SConstIterator; const QQmlDirScripts &scripts = qmldir.scripts(); |