Utils: Allow FilePaths to be compared case-sensitively

... and make use of that when renaming.

Fixes: QTCREATORBUG-30846
Change-Id: Id06a6df5db13325d17dcd69270604e754d7dee2a
Reviewed-by: hjk <hjk@qt.io>
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
This commit is contained in:
Christian Kandeler
2024-06-06 14:21:13 +02:00
parent dc2317ebb8
commit 73191bce0c
5 changed files with 29 additions and 9 deletions

View File

@@ -293,6 +293,26 @@ QString FilePath::toString() const
return scheme() + "://" + encodedHost() + pathView(); 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. 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) 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 FilePath::equals(first, second, first.caseSensitivity());
return false;
return first.pathView().compare(second.pathView(), first.caseSensitivity()) == 0
&& first.host() == second.host()
&& first.scheme() == second.scheme();
} }
QTCREATOR_UTILS_EXPORT bool operator!=(const FilePath &first, const FilePath &second) QTCREATOR_UTILS_EXPORT bool operator!=(const FilePath &first, const FilePath &second)

View File

@@ -268,6 +268,8 @@ public:
// FIXME: Avoid. See toSettings, toVariant, toUserOutput, toFSPathString, path, nativePath. // FIXME: Avoid. See toSettings, toVariant, toUserOutput, toFSPathString, path, nativePath.
QString toString() const; QString toString() const;
bool equalsCaseSensitive(const FilePath &other) const;
private: private:
// These are needed. // These are needed.
QTCREATOR_UTILS_EXPORT friend bool operator==(const FilePath &first, const FilePath &second); 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); 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. // Implementation details. May change.
friend class ::tst_fileutils; friend class ::tst_fileutils;
void setPath(QStringView path); void setPath(QStringView path);

View File

@@ -174,7 +174,7 @@ void FileUtils::removeFiles(const FilePaths &filePaths, bool deleteFromFS)
bool FileUtils::renameFile(const FilePath &orgFilePath, const FilePath &newFilePath, bool FileUtils::renameFile(const FilePath &orgFilePath, const FilePath &newFilePath,
HandleIncludeGuards handleGuards) HandleIncludeGuards handleGuards)
{ {
if (orgFilePath == newFilePath) if (orgFilePath.equalsCaseSensitive(newFilePath))
return false; return false;
const FilePath dir = orgFilePath.absolutePath(); const FilePath dir = orgFilePath.absolutePath();

View File

@@ -3877,7 +3877,7 @@ ProjectExplorerPlugin::renameFile(Node *node, const QString &newFileName)
const FilePath newFilePath = FilePath::fromString(newFileName); const FilePath newFilePath = FilePath::fromString(newFileName);
if (oldFilePath == newFilePath) if (oldFilePath.equalsCaseSensitive(newFilePath))
return {}; return {};
const HandleIncludeGuards handleGuards = canTryToRenameIncludeGuards(node); const HandleIncludeGuards handleGuards = canTryToRenameIncludeGuards(node);

View File

@@ -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 // 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. // and offer to rename them as well.
if (orgFilePath != newFilePath && orgFilePath.suffix() == newFilePath.suffix()) { if (!orgFilePath.equalsCaseSensitive(newFilePath)
&& orgFilePath.suffix() == newFilePath.suffix()) {
const QList<Node *> candidateNodes = ProjectTree::siblingsWithSameBaseName(node); const QList<Node *> candidateNodes = ProjectTree::siblingsWithSameBaseName(node);
if (!candidateNodes.isEmpty()) { if (!candidateNodes.isEmpty()) {
QStringList fileNames = transform<QStringList>(candidateNodes, [](const Node *n) { QStringList fileNames = transform<QStringList>(candidateNodes, [](const Node *n) {