From 73191bce0ce0db76dff29c0ad317a6e908848138 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Thu, 6 Jun 2024 14:21:13 +0200 Subject: [PATCH] Utils: Allow FilePaths to be compared case-sensitively ... and make use of that when renaming. Fixes: QTCREATORBUG-30846 Change-Id: Id06a6df5db13325d17dcd69270604e754d7dee2a Reviewed-by: hjk Reviewed-by: Christian Stenger --- src/libs/utils/filepath.cpp | 27 ++++++++++++++----- src/libs/utils/filepath.h | 4 +++ src/plugins/coreplugin/fileutils.cpp | 2 +- .../projectexplorer/projectexplorer.cpp | 2 +- src/plugins/projectexplorer/projectmodels.cpp | 3 ++- 5 files changed, 29 insertions(+), 9 deletions(-) diff --git a/src/libs/utils/filepath.cpp b/src/libs/utils/filepath.cpp index c631034eba2..c4d77a29efc 100644 --- a/src/libs/utils/filepath.cpp +++ b/src/libs/utils/filepath.cpp @@ -293,6 +293,26 @@ QString FilePath::toString() const return scheme() + "://" + encodedHost() + pathView(); } +bool FilePath::equals(const FilePath &first, const FilePath &second, Qt::CaseSensitivity cs) +{ + if (first.m_hash != 0 && second.m_hash != 0 && first.m_hash != second.m_hash) + return false; + + return first.pathView().compare(second.pathView(), cs) == 0 + && first.host() == second.host() + && first.scheme() == second.scheme(); +} + +/*! + * Returns true if the two file paths compare equal case-sensitively. + * This is relevant on semi-case sensitive systems like Windows with NTFS. + * @see QTCREATORBUG-30846 + */ +bool FilePath::equalsCaseSensitive(const FilePath &other) const +{ + return equals(*this, other, Qt::CaseSensitive); +} + /*! Returns a QString for passing on to QString based APIs. @@ -2354,12 +2374,7 @@ DeviceFileHooks &DeviceFileHooks::instance() QTCREATOR_UTILS_EXPORT bool operator==(const FilePath &first, const FilePath &second) { - if (first.m_hash != 0 && second.m_hash != 0 && first.m_hash != second.m_hash) - return false; - - return first.pathView().compare(second.pathView(), first.caseSensitivity()) == 0 - && first.host() == second.host() - && first.scheme() == second.scheme(); + return FilePath::equals(first, second, first.caseSensitivity()); } QTCREATOR_UTILS_EXPORT bool operator!=(const FilePath &first, const FilePath &second) diff --git a/src/libs/utils/filepath.h b/src/libs/utils/filepath.h index cb975248ec2..e742bf1a0de 100644 --- a/src/libs/utils/filepath.h +++ b/src/libs/utils/filepath.h @@ -268,6 +268,8 @@ public: // FIXME: Avoid. See toSettings, toVariant, toUserOutput, toFSPathString, path, nativePath. QString toString() const; + bool equalsCaseSensitive(const FilePath &other) const; + private: // These are needed. QTCREATOR_UTILS_EXPORT friend bool operator==(const FilePath &first, const FilePath &second); @@ -282,6 +284,8 @@ private: QTCREATOR_UTILS_EXPORT friend QDebug operator<<(QDebug dbg, const FilePath &c); + static bool equals(const FilePath &first, const FilePath &second, Qt::CaseSensitivity cs); + // Implementation details. May change. friend class ::tst_fileutils; void setPath(QStringView path); diff --git a/src/plugins/coreplugin/fileutils.cpp b/src/plugins/coreplugin/fileutils.cpp index f7c7d4a759c..e05375393da 100644 --- a/src/plugins/coreplugin/fileutils.cpp +++ b/src/plugins/coreplugin/fileutils.cpp @@ -174,7 +174,7 @@ void FileUtils::removeFiles(const FilePaths &filePaths, bool deleteFromFS) bool FileUtils::renameFile(const FilePath &orgFilePath, const FilePath &newFilePath, HandleIncludeGuards handleGuards) { - if (orgFilePath == newFilePath) + if (orgFilePath.equalsCaseSensitive(newFilePath)) return false; const FilePath dir = orgFilePath.absolutePath(); diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp index b9da6f33a87..d4c5717ce3d 100644 --- a/src/plugins/projectexplorer/projectexplorer.cpp +++ b/src/plugins/projectexplorer/projectexplorer.cpp @@ -3877,7 +3877,7 @@ ProjectExplorerPlugin::renameFile(Node *node, const QString &newFileName) const FilePath newFilePath = FilePath::fromString(newFileName); - if (oldFilePath == newFilePath) + if (oldFilePath.equalsCaseSensitive(newFilePath)) return {}; const HandleIncludeGuards handleGuards = canTryToRenameIncludeGuards(node); diff --git a/src/plugins/projectexplorer/projectmodels.cpp b/src/plugins/projectexplorer/projectmodels.cpp index 484bc5a0192..5f5aa0150e1 100644 --- a/src/plugins/projectexplorer/projectmodels.cpp +++ b/src/plugins/projectexplorer/projectmodels.cpp @@ -291,7 +291,8 @@ bool FlatModel::setData(const QModelIndex &index, const QVariant &value, int rol // The base name of the file was changed. Go look for other files with the same base name // and offer to rename them as well. - if (orgFilePath != newFilePath && orgFilePath.suffix() == newFilePath.suffix()) { + if (!orgFilePath.equalsCaseSensitive(newFilePath) + && orgFilePath.suffix() == newFilePath.suffix()) { const QList candidateNodes = ProjectTree::siblingsWithSameBaseName(node); if (!candidateNodes.isEmpty()) { QStringList fileNames = transform(candidateNodes, [](const Node *n) {