CppEditor: Adapt include locations when renaming ui files

Fixes: QTCREATORBUG-14259
Change-Id: I5e8209338b531f0e65d85b423053bd19a8b47652
Reviewed-by: <github-actions-qt-creator@cristianadam.eu>
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
This commit is contained in:
Christian Kandeler
2022-10-19 13:09:57 +02:00
parent 7092d8da22
commit 8608386c36
3 changed files with 55 additions and 9 deletions

View File

@@ -784,15 +784,31 @@ QSet<QString> Snapshot::allIncludesForDocument(const QString &fileName) const
return result; return result;
} }
QList<Snapshot::IncludeLocation> Snapshot::includeLocationsOfDocument(const QString &fileName) const QList<Snapshot::IncludeLocation> 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<IncludeLocation> result; QList<IncludeLocation> result;
for (const_iterator cit = begin(), citEnd = end(); cit != citEnd; ++cit) { for (const_iterator cit = begin(), citEnd = end(); cit != citEnd; ++cit) {
const Document::Ptr doc = cit.value(); const Document::Ptr doc = cit.value();
const QList<Document::Include> includeFiles = doc->resolvedIncludes(); const QList<Document::Include> includeFiles = doc->resolvedIncludes();
bool foundMatch = false;
for (const Document::Include &includeFile : includeFiles) { for (const Document::Include &includeFile : includeFiles) {
if (includeFile.resolvedFileName() == fileName) if (isMatch(includeFile)) {
foundMatch = true;
result.push_back({doc, includeFile.line()}); 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; return result;

View File

@@ -409,7 +409,8 @@ public:
const QString &fileName) const; const QString &fileName) const;
QSet<QString> allIncludesForDocument(const QString &fileName) const; QSet<QString> allIncludesForDocument(const QString &fileName) const;
QList<IncludeLocation> includeLocationsOfDocument(const QString &fileName) const;
QList<IncludeLocation> includeLocationsOfDocument(const QString &fileNameOrPath) const;
Utils::FilePaths filesDependingOn(const Utils::FilePath &fileName) const; Utils::FilePaths filesDependingOn(const Utils::FilePath &fileName) const;
Utils::FilePaths filesDependingOn(const QString &fileName) const Utils::FilePaths filesDependingOn(const QString &fileName) const

View File

@@ -47,6 +47,7 @@
#include <projectexplorer/projectexplorer.h> #include <projectexplorer/projectexplorer.h>
#include <projectexplorer/projectexplorerconstants.h> #include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/projectmacro.h> #include <projectexplorer/projectmacro.h>
#include <projectexplorer/projectnodes.h>
#include <projectexplorer/projecttree.h> #include <projectexplorer/projecttree.h>
#include <projectexplorer/session.h> #include <projectexplorer/session.h>
#include <projectexplorer/target.h> #include <projectexplorer/target.h>
@@ -1562,18 +1563,46 @@ void CppModelManager::renameIncludes(const Utils::FilePath &oldFilePath,
const TextEditor::RefactoringChanges changes; 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<Snapshot::IncludeLocation> locations = snapshot().includeLocationsOfDocument( const QList<Snapshot::IncludeLocation> locations = snapshot().includeLocationsOfDocument(
oldFilePath.toString()); isUiFile ? oldFileName : oldFilePath.toString());
for (const Snapshot::IncludeLocation &loc : locations) { for (const Snapshot::IncludeLocation &loc : locations) {
TextEditor::RefactoringFilePtr file = changes.file( const auto filePath = FilePath::fromString(loc.first->fileName());
Utils::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 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) { if (replaceStart > -1) {
Utils::ChangeSet changeSet; Utils::ChangeSet changeSet;
changeSet.replace(block.position() + replaceStart, changeSet.replace(block.position() + replaceStart,
block.position() + replaceStart + oldFilePath.fileName().length(), block.position() + replaceStart + oldFileName.length(),
newFilePath.fileName()); newFileName);
file->setChangeSet(changeSet); file->setChangeSet(changeSet);
file->apply(); file->apply();
} }