aboutsummaryrefslogtreecommitdiffstats
path: root/src/qmlcompiler/qqmljsutils.cpp
diff options
context:
space:
mode:
authorSami Shalayel <sami.shalayel@qt.io>2024-08-26 16:59:42 +0200
committerSami Shalayel <sami.shalayel@qt.io>2024-09-10 12:01:33 +0200
commit36a447a4112d3ed8f1588f8ddd17fe521aeee494 (patch)
treec97df2212f3fe1ddf4691af5379eb17d45354e8e /src/qmlcompiler/qqmljsutils.cpp
parentb1ff6073a7247c921e20cd98b2e3297e7368681b (diff)
add util to map .qml from source to build folder
Add a helper method qmlSourcePathFromBuildPath in the QQmlJSUtils static class that maps QML files from the build folder to their source folder, and vice-versa. Uses a heuristic for QML modules that do not use "prefer" qmldirs for each folder that contains QML files. It will be used in a later commit to translate build folder paths, encountered during "go to definiton" in qmlls, to source folder paths. Pick-to: 6.8 6.7 Task-number: QTBUG-127661 Change-Id: I81f4b75a008d773835affb622af7f964b753e5ac Reviewed-by: Semih Yavuz <semih.yavuz@qt.io>
Diffstat (limited to 'src/qmlcompiler/qqmljsutils.cpp')
-rw-r--r--src/qmlcompiler/qqmljsutils.cpp93
1 files changed, 93 insertions, 0 deletions
diff --git a/src/qmlcompiler/qqmljsutils.cpp b/src/qmlcompiler/qqmljsutils.cpp
index fcf56d4b96..f40d4932ca 100644
--- a/src/qmlcompiler/qqmljsutils.cpp
+++ b/src/qmlcompiler/qqmljsutils.cpp
@@ -280,5 +280,98 @@ QStringList QQmlJSUtils::resourceFilesFromBuildFolders(const QStringList &buildF
return result;
}
+enum FilterType {
+ LocalFileFilter,
+ ResourceFileFilter
+};
+
+/*!
+\internal
+Obtain a QML module qrc entry from its qmldir entry.
+
+Contains a heuristic for QML modules without nested-qml-module-with-prefer-feature
+that tries to find a parent directory that contains a qmldir entry in the qrc.
+*/
+static QQmlJSResourceFileMapper::Entry
+qmlModuleEntryFromBuildPath(const QQmlJSResourceFileMapper *mapper,
+ const QString &pathInBuildFolder, FilterType type)
+{
+ const QString cleanPath = QDir::cleanPath(pathInBuildFolder);
+ QStringView directoryPath = cleanPath;
+
+ while (!directoryPath.isEmpty()) {
+ const qsizetype lastSlashIndex = directoryPath.lastIndexOf(u'/');
+ if (lastSlashIndex == -1)
+ return {};
+
+ directoryPath.truncate(lastSlashIndex);
+ const QString qmldirPath = u"%1/qmldir"_s.arg(directoryPath);
+ const QQmlJSResourceFileMapper::Filter qmldirFilter = type == LocalFileFilter
+ ? QQmlJSResourceFileMapper::localFileFilter(qmldirPath)
+ : QQmlJSResourceFileMapper::resourceFileFilter(qmldirPath);
+
+ QQmlJSResourceFileMapper::Entry result = mapper->entry(qmldirFilter);
+ if (result.isValid()) {
+ result.resourcePath.chop(std::char_traits<char>::length("/qmldir"));
+ result.filePath.chop(std::char_traits<char>::length("/qmldir"));
+ return result;
+ }
+ }
+ return {};
+}
+
+/*!
+\internal
+Obtains the source folder path from a build folder QML file path via the passed \c mapper.
+
+This works on proper QML modules when using the nested-qml-module-with-prefer-feature
+from 6.8 and uses a heuristic when the qmldir with the prefer entry is missing.
+*/
+QString QQmlJSUtils::qmlSourcePathFromBuildPath(const QQmlJSResourceFileMapper *mapper,
+ const QString &pathInBuildFolder)
+{
+ if (!mapper)
+ return pathInBuildFolder;
+
+ const auto qmlModuleEntry =
+ qmlModuleEntryFromBuildPath(mapper, pathInBuildFolder, LocalFileFilter);
+ if (!qmlModuleEntry.isValid())
+ return pathInBuildFolder;
+ const QString qrcPath = qmlModuleEntry.resourcePath
+ + QStringView(pathInBuildFolder).sliced(qmlModuleEntry.filePath.size());
+
+ const auto entry = mapper->entry(QQmlJSResourceFileMapper::resourceFileFilter(qrcPath));
+ return entry.isValid()? entry.filePath : pathInBuildFolder;
+}
+
+/*!
+\internal
+Obtains the source folder path from a build folder QML file path via the passed \c mapper, see also
+\l QQmlJSUtils::qmlSourcePathFromBuildPath.
+*/
+QString QQmlJSUtils::qmlBuildPathFromSourcePath(const QQmlJSResourceFileMapper *mapper,
+ const QString &pathInSourceFolder)
+{
+ if (!mapper)
+ return pathInSourceFolder;
+
+ const QString qrcPath =
+ mapper->entry(QQmlJSResourceFileMapper::localFileFilter(pathInSourceFolder))
+ .resourcePath;
+
+ if (qrcPath.isEmpty())
+ return pathInSourceFolder;
+
+ const auto moduleBuildEntry =
+ qmlModuleEntryFromBuildPath(mapper, qrcPath, ResourceFileFilter);
+
+ if (!moduleBuildEntry.isValid())
+ return pathInSourceFolder;
+
+ const auto qrcFolderPath = qrcPath.first(qrcPath.lastIndexOf(u'/')); // drop the filename
+
+ return moduleBuildEntry.filePath + qrcFolderPath.sliced(moduleBuildEntry.resourcePath.size())
+ + pathInSourceFolder.sliced(pathInSourceFolder.lastIndexOf(u'/'));
+}
QT_END_NAMESPACE