From 8608386c3668169a4065f6313918469713ff649f Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Wed, 19 Oct 2022 13:09:57 +0200 Subject: [PATCH] CppEditor: Adapt include locations when renaming ui files Fixes: QTCREATORBUG-14259 Change-Id: I5e8209338b531f0e65d85b423053bd19a8b47652 Reviewed-by: Reviewed-by: Christian Stenger --- src/libs/cplusplus/CppDocument.cpp | 20 +++++++++-- src/libs/cplusplus/CppDocument.h | 3 +- src/plugins/cppeditor/cppmodelmanager.cpp | 41 +++++++++++++++++++---- 3 files changed, 55 insertions(+), 9 deletions(-) diff --git a/src/libs/cplusplus/CppDocument.cpp b/src/libs/cplusplus/CppDocument.cpp index a121594c8e1..12ce8ea0cd3 100644 --- a/src/libs/cplusplus/CppDocument.cpp +++ b/src/libs/cplusplus/CppDocument.cpp @@ -784,15 +784,31 @@ QSet Snapshot::allIncludesForDocument(const QString &fileName) const return result; } -QList Snapshot::includeLocationsOfDocument(const QString &fileName) const +QList Snapshot::includeLocationsOfDocument( + const QString &fileNameOrPath) const { + const bool matchFullPath = Utils::FilePath::fromString(fileNameOrPath).isAbsolutePath(); + const auto isMatch = [&](const Document::Include &include) { + if (matchFullPath) + return include.resolvedFileName() == fileNameOrPath; + return Utils::FilePath::fromString(include.resolvedFileName()).fileName() == fileNameOrPath; + }; QList result; for (const_iterator cit = begin(), citEnd = end(); cit != citEnd; ++cit) { const Document::Ptr doc = cit.value(); const QList includeFiles = doc->resolvedIncludes(); + bool foundMatch = false; for (const Document::Include &includeFile : includeFiles) { - if (includeFile.resolvedFileName() == fileName) + if (isMatch(includeFile)) { + foundMatch = true; result.push_back({doc, includeFile.line()}); + } + } + if (!matchFullPath && !foundMatch) { + for (const auto &includeFile : cit.value()->unresolvedIncludes()) { + if (includeFile.unresolvedFileName() == fileNameOrPath) + result.push_back({doc, includeFile.line()}); + } } } return result; diff --git a/src/libs/cplusplus/CppDocument.h b/src/libs/cplusplus/CppDocument.h index 4cc76a66c9c..c3ee363f261 100644 --- a/src/libs/cplusplus/CppDocument.h +++ b/src/libs/cplusplus/CppDocument.h @@ -409,7 +409,8 @@ public: const QString &fileName) const; QSet allIncludesForDocument(const QString &fileName) const; - QList includeLocationsOfDocument(const QString &fileName) const; + + QList includeLocationsOfDocument(const QString &fileNameOrPath) const; Utils::FilePaths filesDependingOn(const Utils::FilePath &fileName) const; Utils::FilePaths filesDependingOn(const QString &fileName) const diff --git a/src/plugins/cppeditor/cppmodelmanager.cpp b/src/plugins/cppeditor/cppmodelmanager.cpp index da8fdb53f62..49e42e3eb5f 100644 --- a/src/plugins/cppeditor/cppmodelmanager.cpp +++ b/src/plugins/cppeditor/cppmodelmanager.cpp @@ -47,6 +47,7 @@ #include #include #include +#include #include #include #include @@ -1562,18 +1563,46 @@ void CppModelManager::renameIncludes(const Utils::FilePath &oldFilePath, const TextEditor::RefactoringChanges changes; + QString oldFileName = oldFilePath.fileName(); + QString newFileName = newFilePath.fileName(); + const bool isUiFile = oldFilePath.suffix() == "ui" && newFilePath.suffix() == "ui"; + if (isUiFile) { + oldFileName = "ui_" + oldFilePath.baseName() + ".h"; + newFileName = "ui_" + newFilePath.baseName() + ".h"; + } + static const auto getProductNode = [](const FilePath &filePath) -> const Node * { + const Node * const fileNode = ProjectTree::nodeForFile(filePath); + if (!fileNode) + return nullptr; + const ProjectNode *productNode = fileNode->parentProjectNode(); + while (productNode && !productNode->isProduct()) + productNode = productNode->parentProjectNode(); + if (!productNode) + productNode = fileNode->getProject()->rootProjectNode(); + return productNode; + }; + const Node * const productNodeForUiFile = isUiFile ? getProductNode(oldFilePath) : nullptr; + if (isUiFile && !productNodeForUiFile) + return; + const QList locations = snapshot().includeLocationsOfDocument( - oldFilePath.toString()); + isUiFile ? oldFileName : oldFilePath.toString()); for (const Snapshot::IncludeLocation &loc : locations) { - TextEditor::RefactoringFilePtr file = changes.file( - Utils::FilePath::fromString(loc.first->fileName())); + const auto filePath = FilePath::fromString(loc.first->fileName()); + + // Larger projects can easily have more than one ui file with the same name. + // Replace only if ui file and including source file belong to the same product. + if (isUiFile && getProductNode(filePath) != productNodeForUiFile) + continue; + + TextEditor::RefactoringFilePtr file = changes.file(filePath); const QTextBlock &block = file->document()->findBlockByNumber(loc.second - 1); - const int replaceStart = block.text().indexOf(oldFilePath.fileName()); + const int replaceStart = block.text().indexOf(oldFileName); if (replaceStart > -1) { Utils::ChangeSet changeSet; changeSet.replace(block.position() + replaceStart, - block.position() + replaceStart + oldFilePath.fileName().length(), - newFilePath.fileName()); + block.position() + replaceStart + oldFileName.length(), + newFileName); file->setChangeSet(changeSet); file->apply(); }