ClangCodeModel: Implement global renaming via clangd

Note that we do not use the LSP rename functionality. We do "manual"
renaming the same way as in the built-in code model, but based on the
references found by clangd.

Change-Id: Ifa5597efe5c89c8f9204a4f5323bc755544696cf
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: David Schulz <david.schulz@qt.io>
This commit is contained in:
Christian Kandeler
2021-05-18 12:59:15 +02:00
parent 78274956d0
commit 12fd21a880
9 changed files with 186 additions and 77 deletions

View File

@@ -32,7 +32,12 @@
#include <cpptools/cppfindreferences.h> #include <cpptools/cppfindreferences.h>
#include <cpptools/cpptoolsreuse.h> #include <cpptools/cpptoolsreuse.h>
#include <languageclient/languageclientinterface.h> #include <languageclient/languageclientinterface.h>
#include <projectexplorer/projecttree.h>
#include <projectexplorer/session.h>
#include <texteditor/basefilefind.h>
#include <utils/algorithm.h>
#include <QCheckBox>
#include <QFile> #include <QFile>
#include <QHash> #include <QHash>
#include <QPointer> #include <QPointer>
@@ -42,6 +47,7 @@ using namespace CPlusPlus;
using namespace Core; using namespace Core;
using namespace LanguageClient; using namespace LanguageClient;
using namespace LanguageServerProtocol; using namespace LanguageServerProtocol;
using namespace ProjectExplorer;
namespace ClangCodeModel { namespace ClangCodeModel {
namespace Internal { namespace Internal {
@@ -296,15 +302,20 @@ public:
QString fileContent; QString fileContent;
AstNode ast; AstNode ast;
}; };
class ReplacementData {
public:
QString oldSymbolName;
QString newSymbolName;
QSet<Utils::FilePath> fileRenameCandidates;
};
class ReferencesData { class ReferencesData {
public: public:
void setCanceled() { search->setUserData(true); }
bool isCanceled() const { return search && search->userData().toBool(); }
QMap<DocumentUri, ReferencesFileData> fileData; QMap<DocumentUri, ReferencesFileData> fileData;
QList<MessageId> pendingAstRequests; QList<MessageId> pendingAstRequests;
QPointer<SearchResult> search; QPointer<SearchResult> search;
Utils::optional<ReplacementData> replacementData;
quint64 key; quint64 key;
bool canceled = false;
}; };
class ClangdClient::Private class ClangdClient::Private
@@ -313,9 +324,14 @@ public:
Private(ClangdClient *q) : q(q) {} Private(ClangdClient *q) : q(q) {}
void handleFindUsagesResult(quint64 key, const QList<Location> &locations); void handleFindUsagesResult(quint64 key, const QList<Location> &locations);
void addSearchResultsForFile(const ReferencesData &refData, const Utils::FilePath &file, static void handleRenameRequest(const SearchResult *search,
const ReplacementData &replacementData,
const QString &newSymbolName,
const QList<Core::SearchResultItem> &checkedItems,
bool preserveCase);
void addSearchResultsForFile(ReferencesData &refData, const Utils::FilePath &file,
const ReferencesFileData &fileData); const ReferencesFileData &fileData);
void reportAllSearchResultsAndFinish(const ReferencesData &data); void reportAllSearchResultsAndFinish(ReferencesData &data);
void finishSearch(const ReferencesData &refData, bool canceled); void finishSearch(const ReferencesData &refData, bool canceled);
ClangdClient * const q; ClangdClient * const q;
@@ -326,7 +342,7 @@ public:
bool isTesting = false; bool isTesting = false;
}; };
ClangdClient::ClangdClient(ProjectExplorer::Project *project, const Utils::FilePath &jsonDbDir) ClangdClient::ClangdClient(Project *project, const Utils::FilePath &jsonDbDir)
: Client(clientInterface(jsonDbDir)), d(new Private(this)) : Client(clientInterface(jsonDbDir)), d(new Private(this))
{ {
setName(tr("clangd")); setName(tr("clangd"));
@@ -355,7 +371,7 @@ ClangdClient::ClangdClient(ProjectExplorer::Project *project, const Utils::FileP
// Report all search results found so far. // Report all search results found so far.
for (quint64 key : d->runningFindUsages.keys()) for (quint64 key : d->runningFindUsages.keys())
d->reportAllSearchResultsAndFinish(d->runningFindUsages.value(key)); d->reportAllSearchResultsAndFinish(d->runningFindUsages[key]);
QTC_CHECK(d->runningFindUsages.isEmpty()); QTC_CHECK(d->runningFindUsages.isEmpty());
}); });
@@ -388,13 +404,9 @@ void ClangdClient::closeExtraFile(const Utils::FilePath &filePath)
TextDocumentIdentifier{DocumentUri::fromFilePath(filePath)}))); TextDocumentIdentifier{DocumentUri::fromFilePath(filePath)})));
} }
void ClangdClient::findUsages(TextEditor::TextDocument *document, const QTextCursor &cursor) void ClangdClient::findUsages(TextEditor::TextDocument *document, const QTextCursor &cursor,
const Utils::optional<QString> &replacement)
{ {
if (versionNumber() < QVersionNumber(13)) {
symbolSupport().findUsages(document, cursor);
return;
}
QTextCursor termCursor(cursor); QTextCursor termCursor(cursor);
termCursor.select(QTextCursor::WordUnderCursor); termCursor.select(QTextCursor::WordUnderCursor);
const QString searchTerm = termCursor.selectedText(); // TODO: This will be wrong for e.g. operators. Use a Symbol info request to get the real symbol string. const QString searchTerm = termCursor.selectedText(); // TODO: This will be wrong for e.g. operators. Use a Symbol info request to get the real symbol string.
@@ -402,19 +414,42 @@ void ClangdClient::findUsages(TextEditor::TextDocument *document, const QTextCur
return; return;
ReferencesData refData; ReferencesData refData;
refData.key = d->nextFindUsagesKey++;
if (replacement) {
ReplacementData replacementData;
replacementData.oldSymbolName = searchTerm;
replacementData.newSymbolName = *replacement;
if (replacementData.newSymbolName.isEmpty())
replacementData.newSymbolName = replacementData.oldSymbolName;
refData.replacementData = replacementData;
}
refData.search = SearchResultWindow::instance()->startNewSearch( refData.search = SearchResultWindow::instance()->startNewSearch(
tr("C++ Usages:"), tr("C++ Usages:"),
{}, {},
searchTerm, searchTerm,
SearchResultWindow::SearchOnly, replacement ? SearchResultWindow::SearchAndReplace : SearchResultWindow::SearchOnly,
SearchResultWindow::PreserveCaseDisabled, SearchResultWindow::PreserveCaseDisabled,
"CppEditor"); "CppEditor");
refData.search->setFilter(new CppTools::CppSearchResultFilter); refData.search->setFilter(new CppTools::CppSearchResultFilter);
if (refData.replacementData) {
refData.search->setTextToReplace(refData.replacementData->newSymbolName);
const auto renameFilesCheckBox = new QCheckBox;
renameFilesCheckBox->setVisible(false);
refData.search->setAdditionalReplaceWidget(renameFilesCheckBox);
const auto renameHandler =
[search = refData.search](const QString &newSymbolName,
const QList<SearchResultItem> &checkedItems,
bool preserveCase) {
const auto replacementData = search->userData().value<ReplacementData>();
Private::handleRenameRequest(search, replacementData, newSymbolName, checkedItems,
preserveCase);
};
connect(refData.search, &SearchResult::replaceButtonClicked, renameHandler);
}
connect(refData.search, &SearchResult::activated, [](const SearchResultItem& item) { connect(refData.search, &SearchResult::activated, [](const SearchResultItem& item) {
Core::EditorManager::openEditorAtSearchResult(item); Core::EditorManager::openEditorAtSearchResult(item);
}); });
SearchResultWindow::instance()->popup(IOutputPane::ModeSwitch | IOutputPane::WithFocus); SearchResultWindow::instance()->popup(IOutputPane::ModeSwitch | IOutputPane::WithFocus);
refData.key = d->nextFindUsagesKey++;
d->runningFindUsages.insert(refData.key, refData); d->runningFindUsages.insert(refData.key, refData);
const Utils::optional<MessageId> requestId = symbolSupport().findUsages( const Utils::optional<MessageId> requestId = symbolSupport().findUsages(
@@ -431,7 +466,7 @@ void ClangdClient::findUsages(TextEditor::TextDocument *document, const QTextCur
if (refData == d->runningFindUsages.end()) if (refData == d->runningFindUsages.end())
return; return;
cancelRequest(*requestId); cancelRequest(*requestId);
refData->setCanceled(); refData->canceled = true;
refData->search->disconnect(this); refData->search->disconnect(this);
d->finishSearch(*refData, true); d->finishSearch(*refData, true);
}); });
@@ -462,7 +497,7 @@ void ClangdClient::Private::handleFindUsagesResult(quint64 key, const QList<Loca
const auto refData = runningFindUsages.find(key); const auto refData = runningFindUsages.find(key);
if (refData == runningFindUsages.end()) if (refData == runningFindUsages.end())
return; return;
if (!refData->search || refData->isCanceled()) { if (!refData->search || refData->canceled) {
finishSearch(*refData, true); finishSearch(*refData, true);
return; return;
} }
@@ -478,7 +513,7 @@ void ClangdClient::Private::handleFindUsagesResult(quint64 key, const QList<Loca
const auto refData = runningFindUsages.find(key); const auto refData = runningFindUsages.find(key);
if (refData == runningFindUsages.end()) if (refData == runningFindUsages.end())
return; return;
refData->setCanceled(); refData->canceled = true;
refData->search->disconnect(q); refData->search->disconnect(q);
for (const MessageId &id : qAsConst(refData->pendingAstRequests)) for (const MessageId &id : qAsConst(refData->pendingAstRequests))
q->cancelRequest(id); q->cancelRequest(id);
@@ -499,7 +534,8 @@ void ClangdClient::Private::handleFindUsagesResult(quint64 key, const QList<Loca
} }
qCDebug(clangdLog) << "document count is" << refData->fileData.size(); qCDebug(clangdLog) << "document count is" << refData->fileData.size();
if (refData->fileData.size() > 15) { // TODO: If we need to keep this, make it configurable. if (refData->replacementData || q->versionNumber() < QVersionNumber(13)
|| refData->fileData.size() > 15) { // TODO: If we need to keep this, make it configurable.
qCDebug(clangdLog) << "skipping AST retrieval"; qCDebug(clangdLog) << "skipping AST retrieval";
reportAllSearchResultsAndFinish(*refData); reportAllSearchResultsAndFinish(*refData);
return; return;
@@ -520,7 +556,7 @@ void ClangdClient::Private::handleFindUsagesResult(quint64 key, const QList<Loca
const auto refData = runningFindUsages.find(key); const auto refData = runningFindUsages.find(key);
if (refData == runningFindUsages.end()) if (refData == runningFindUsages.end())
return; return;
if (!refData->search || refData->isCanceled()) if (!refData->search || refData->canceled)
return; return;
ReferencesFileData &data = refData->fileData[loc]; ReferencesFileData &data = refData->fileData[loc];
const auto result = response.result(); const auto result = response.result();
@@ -545,7 +581,33 @@ void ClangdClient::Private::handleFindUsagesResult(quint64 key, const QList<Loca
} }
} }
void ClangdClient::Private::addSearchResultsForFile(const ReferencesData &refData, void ClangdClient::Private::handleRenameRequest(const SearchResult *search,
const ReplacementData &replacementData,
const QString &newSymbolName,
const QList<SearchResultItem> &checkedItems,
bool preserveCase)
{
const QStringList fileNames = TextEditor::BaseFileFind::replaceAll(newSymbolName, checkedItems,
preserveCase);
if (!fileNames.isEmpty())
SearchResultWindow::instance()->hide();
const auto renameFilesCheckBox = qobject_cast<QCheckBox *>(search->additionalReplaceWidget());
QTC_ASSERT(renameFilesCheckBox, return);
if (!renameFilesCheckBox->isChecked())
return;
QVector<Node *> fileNodes;
for (const Utils::FilePath &file : replacementData.fileRenameCandidates) {
Node * const node = ProjectTree::nodeForFile(file);
if (node)
fileNodes << node;
}
if (!fileNodes.isEmpty())
CppTools::renameFilesForSymbol(replacementData.oldSymbolName, newSymbolName, fileNodes);
}
void ClangdClient::Private::addSearchResultsForFile(ReferencesData &refData,
const Utils::FilePath &file, const Utils::FilePath &file,
const ReferencesFileData &fileData) const ReferencesFileData &fileData)
{ {
@@ -563,6 +625,15 @@ void ClangdClient::Private::addSearchResultsForFile(const ReferencesData &refDat
item.setMainRange(SymbolSupport::convertRange(range)); item.setMainRange(SymbolSupport::convertRange(range));
item.setUseTextEditorFont(true); item.setUseTextEditorFont(true);
item.setLineText(rangeWithText.second); item.setLineText(rangeWithText.second);
if (refData.search->supportsReplace()) {
const bool fileInSession = SessionManager::projectForFile(file);
item.setSelectForReplacement(fileInSession);
if (fileInSession && file.toFileInfo().baseName().compare(
refData.replacementData->oldSymbolName,
Qt::CaseInsensitive) == 0) {
refData.replacementData->fileRenameCandidates << file; // TODO: We want to do this only for types. Use SymbolInformation once we have it.
}
}
items << item; items << item;
} }
if (isTesting) if (isTesting)
@@ -571,11 +642,11 @@ void ClangdClient::Private::addSearchResultsForFile(const ReferencesData &refDat
refData.search->addResults(items, SearchResult::AddOrdered); refData.search->addResults(items, SearchResult::AddOrdered);
} }
void ClangdClient::Private::reportAllSearchResultsAndFinish(const ReferencesData &refData) void ClangdClient::Private::reportAllSearchResultsAndFinish(ReferencesData &refData)
{ {
for (auto it = refData.fileData.begin(); it != refData.fileData.end(); ++it) for (auto it = refData.fileData.begin(); it != refData.fileData.end(); ++it)
addSearchResultsForFile(refData, it.key().toFilePath(), it.value()); addSearchResultsForFile(refData, it.key().toFilePath(), it.value());
finishSearch(refData, refData.isCanceled()); finishSearch(refData, refData.canceled);
} }
void ClangdClient::Private::finishSearch(const ReferencesData &refData, bool canceled) void ClangdClient::Private::finishSearch(const ReferencesData &refData, bool canceled)
@@ -585,9 +656,23 @@ void ClangdClient::Private::finishSearch(const ReferencesData &refData, bool can
} else if (refData.search) { } else if (refData.search) {
refData.search->finishSearch(canceled); refData.search->finishSearch(canceled);
refData.search->disconnect(q); refData.search->disconnect(q);
if (refData.replacementData) {
const auto renameCheckBox = qobject_cast<QCheckBox *>(
refData.search->additionalReplaceWidget());
QTC_CHECK(renameCheckBox);
const QSet<Utils::FilePath> files = refData.replacementData->fileRenameCandidates;
renameCheckBox->setText(tr("Re&name %n files", nullptr, files.size()));
const QStringList filesForUser = Utils::transform<QStringList>(files,
[](const Utils::FilePath &fp) { return fp.toUserOutput(); });
renameCheckBox->setToolTip(tr("Files:\n%1").arg(filesForUser.join('\n')));
renameCheckBox->setVisible(true);
refData.search->setUserData(QVariant::fromValue(*refData.replacementData));
}
} }
runningFindUsages.remove(refData.key); runningFindUsages.remove(refData.key);
} }
} // namespace Internal } // namespace Internal
} // namespace ClangCodeModel } // namespace ClangCodeModel
Q_DECLARE_METATYPE(ClangCodeModel::Internal::ReplacementData)

View File

@@ -26,6 +26,7 @@
#pragma once #pragma once
#include <languageclient/client.h> #include <languageclient/client.h>
#include <utils/optional.h>
#include <QVersionNumber> #include <QVersionNumber>
@@ -49,7 +50,8 @@ public:
void openExtraFile(const Utils::FilePath &filePath, const QString &content = {}); void openExtraFile(const Utils::FilePath &filePath, const QString &content = {});
void closeExtraFile(const Utils::FilePath &filePath); void closeExtraFile(const Utils::FilePath &filePath);
void findUsages(TextEditor::TextDocument *document, const QTextCursor &cursor); void findUsages(TextEditor::TextDocument *document, const QTextCursor &cursor,
const Utils::optional<QString> &replacement);
void enableTesting(); void enableTesting();

View File

@@ -86,6 +86,23 @@ void RefactoringEngine::startLocalRenaming(const CppTools::CursorInEditor &data,
m_watcher->setFuture(cursorFuture); m_watcher->setFuture(cursorFuture);
} }
void RefactoringEngine::globalRename(const CppTools::CursorInEditor &cursor,
CppTools::UsagesCallback &&callback,
const QString &replacement)
{
ProjectExplorer::Project * const project
= ProjectExplorer::SessionManager::projectForFile(cursor.filePath());
ClangdClient * const client = ClangModelManagerSupport::instance()->clientForProject(project);
if (!client || !client->isFullyIndexed()) {
CppTools::CppModelManager::builtinRefactoringEngine()
->globalRename(cursor, std::move(callback), replacement);
return;
}
QTC_ASSERT(client->documentOpen(cursor.textDocument()),
client->openDocument(cursor.textDocument()));
client->findUsages(cursor.textDocument(), cursor.cursor(), replacement);
}
void RefactoringEngine::findUsages(const CppTools::CursorInEditor &cursor, void RefactoringEngine::findUsages(const CppTools::CursorInEditor &cursor,
CppTools::UsagesCallback &&callback) const CppTools::UsagesCallback &&callback) const
{ {
@@ -99,7 +116,7 @@ void RefactoringEngine::findUsages(const CppTools::CursorInEditor &cursor,
} }
QTC_ASSERT(client->documentOpen(cursor.textDocument()), QTC_ASSERT(client->documentOpen(cursor.textDocument()),
client->openDocument(cursor.textDocument())); client->openDocument(cursor.textDocument()));
client->findUsages(cursor.textDocument(), cursor.cursor()); client->findUsages(cursor.textDocument(), cursor.cursor(), {});
} }
} // namespace Internal } // namespace Internal

View File

@@ -44,8 +44,8 @@ public:
void startLocalRenaming(const CppTools::CursorInEditor &data, void startLocalRenaming(const CppTools::CursorInEditor &data,
CppTools::ProjectPart *projectPart, CppTools::ProjectPart *projectPart,
RenameCallback &&renameSymbolsCallback) override; RenameCallback &&renameSymbolsCallback) override;
void globalRename(const CppTools::CursorInEditor &, CppTools::UsagesCallback &&, void globalRename(const CppTools::CursorInEditor &cursor, CppTools::UsagesCallback &&callback,
const QString &) override {} const QString &replacement) override;
void findUsages(const CppTools::CursorInEditor &cursor, void findUsages(const CppTools::CursorInEditor &cursor,
CppTools::UsagesCallback &&callback) const override; CppTools::UsagesCallback &&callback) const override;
void globalFollowSymbol(const CppTools::CursorInEditor &, void globalFollowSymbol(const CppTools::CursorInEditor &,

View File

@@ -168,7 +168,7 @@ void ClangdTests::testFindReferences()
QTextCursor cursor((doc)->document()); \ QTextCursor cursor((doc)->document()); \
cursor.setPosition((pos)); \ cursor.setPosition((pos)); \
searchResults.clear(); \ searchResults.clear(); \
client->findUsages((doc), cursor); \ client->findUsages((doc), cursor, {}); \
QVERIFY(waitForSignalOrTimeout(client, &ClangdClient::findUsagesDone)); \ QVERIFY(waitForSignalOrTimeout(client, &ClangdClient::findUsagesDone)); \
} while (false) } while (false)

View File

@@ -491,7 +491,8 @@ void CppEditorWidget::renameUsages(const QString &replacement, QTextCursor curso
{ {
if (cursor.isNull()) if (cursor.isNull())
cursor = textCursor(); cursor = textCursor();
CppTools::CursorInEditor cursorInEditor{cursor, textDocument()->filePath(), this}; CppTools::CursorInEditor cursorInEditor{cursor, textDocument()->filePath(), this,
textDocument()};
QPointer<CppEditorWidget> cppEditorWidget = this; QPointer<CppEditorWidget> cppEditorWidget = this;
d->m_modelManager->globalRename(cursorInEditor, d->m_modelManager->globalRename(cursorInEditor,
[=](const CppTools::Usages &usages) { [=](const CppTools::Usages &usages) {

View File

@@ -59,6 +59,8 @@ using namespace ProjectExplorer;
namespace CppTools { namespace CppTools {
namespace { static bool isAllLowerCase(const QString &text) { return text.toLower() == text; } }
SearchResultColor::Style colorStyleForUsageType(CPlusPlus::Usage::Type type) SearchResultColor::Style colorStyleForUsageType(CPlusPlus::Usage::Type type)
{ {
switch (type) { switch (type) {
@@ -75,6 +77,51 @@ SearchResultColor::Style colorStyleForUsageType(CPlusPlus::Usage::Type type)
return SearchResultColor::Style::Default; // For dumb compilers. return SearchResultColor::Style::Default; // For dumb compilers.
} }
void renameFilesForSymbol(const QString &oldSymbolName, const QString &newSymbolName,
const QVector<Node *> &files)
{
Internal::CppFileSettings settings;
settings.fromSettings(Core::ICore::settings());
const QStringList newPaths =
Utils::transform<QList>(files,
[&oldSymbolName, newSymbolName, &settings](const Node *node) -> QString {
const QFileInfo fi = node->filePath().toFileInfo();
const QString oldBaseName = fi.baseName();
QString newBaseName = newSymbolName;
// 1) new symbol lowercase: new base name lowercase
if (isAllLowerCase(newSymbolName)) {
newBaseName = newSymbolName;
// 2) old base name mixed case: new base name is verbatim symbol name
} else if (!isAllLowerCase(oldBaseName)) {
newBaseName = newSymbolName;
// 3) old base name lowercase, old symbol mixed case: new base name lowercase
} else if (!isAllLowerCase(oldSymbolName)) {
newBaseName = newSymbolName.toLower();
// 4) old base name lowercase, old symbol lowercase, new symbol mixed case:
// use the preferences setting for new base name case
} else if (settings.lowerCaseFiles) {
newBaseName = newSymbolName.toLower();
}
if (newBaseName == oldBaseName)
return QString();
return fi.absolutePath() + "/" + newBaseName + '.' + fi.completeSuffix();
});
for (int i = 0; i < files.size(); ++i) {
if (!newPaths.at(i).isEmpty()) {
Node *node = files.at(i);
ProjectExplorerPlugin::renameFile(node, newPaths.at(i));
}
}
}
QWidget *CppSearchResultFilter::createWidget() QWidget *CppSearchResultFilter::createWidget()
{ {
const auto widget = new QWidget; const auto widget = new QWidget;
@@ -469,11 +516,6 @@ void CppFindReferences::findAll_helper(SearchResult *search, CPlusPlus::Symbol *
connect(progress, &FutureProgress::clicked, search, &SearchResult::popup); connect(progress, &FutureProgress::clicked, search, &SearchResult::popup);
} }
static bool isAllLowerCase(const QString &text)
{
return text.toLower() == text;
}
void CppFindReferences::onReplaceButtonClicked(const QString &text, void CppFindReferences::onReplaceButtonClicked(const QString &text,
const QList<SearchResultItem> &items, const QList<SearchResultItem> &items,
bool preserveCase) bool preserveCase)
@@ -495,48 +537,7 @@ void CppFindReferences::onReplaceButtonClicked(const QString &text,
if (!renameFilesCheckBox || !renameFilesCheckBox->isChecked()) if (!renameFilesCheckBox || !renameFilesCheckBox->isChecked())
return; return;
CppFileSettings settings; renameFilesForSymbol(parameters.prettySymbolName, text, parameters.filesToRename);
settings.fromSettings(Core::ICore::settings());
const QStringList newPaths =
Utils::transform<QList>(parameters.filesToRename,
[&parameters, text, &settings](const Node *node) -> QString {
const QFileInfo fi = node->filePath().toFileInfo();
const QString oldSymbolName = parameters.prettySymbolName;
const QString oldBaseName = fi.baseName();
const QString newSymbolName = text;
QString newBaseName = newSymbolName;
// 1) new symbol lowercase: new base name lowercase
if (isAllLowerCase(newSymbolName)) {
newBaseName = newSymbolName;
// 2) old base name mixed case: new base name is verbatim symbol name
} else if (!isAllLowerCase(oldBaseName)) {
newBaseName = newSymbolName;
// 3) old base name lowercase, old symbol mixed case: new base name lowercase
} else if (!isAllLowerCase(oldSymbolName)) {
newBaseName = newSymbolName.toLower();
// 4) old base name lowercase, old symbol lowercase, new symbol mixed case:
// use the preferences setting for new base name case
} else if (settings.lowerCaseFiles) {
newBaseName = newSymbolName.toLower();
}
if (newBaseName == oldBaseName)
return QString();
return fi.absolutePath() + "/" + newBaseName + '.' + fi.completeSuffix();
});
for (int i = 0; i < parameters.filesToRename.size(); ++i) {
if (!newPaths.at(i).isEmpty()) {
Node *node = parameters.filesToRename.at(i);
ProjectExplorerPlugin::renameFile(node, newPaths.at(i));
}
}
} }
void CppFindReferences::searchAgain() void CppFindReferences::searchAgain()

View File

@@ -49,6 +49,9 @@ namespace CppTools {
class CppModelManager; class CppModelManager;
Core::SearchResultColor::Style CPPTOOLS_EXPORT colorStyleForUsageType(CPlusPlus::Usage::Type type); Core::SearchResultColor::Style CPPTOOLS_EXPORT colorStyleForUsageType(CPlusPlus::Usage::Type type);
void CPPTOOLS_EXPORT renameFilesForSymbol(const QString &oldSymbolName,
const QString &newSymbolName,
const QVector<ProjectExplorer::Node *> &files);
class CPPTOOLS_EXPORT CppSearchResultFilter : public Core::SearchResultFilter class CPPTOOLS_EXPORT CppSearchResultFilter : public Core::SearchResultFilter
{ {

View File

@@ -323,7 +323,7 @@ void CppModelManager::startLocalRenaming(const CursorInEditor &data,
void CppModelManager::globalRename(const CursorInEditor &data, UsagesCallback &&renameCallback, void CppModelManager::globalRename(const CursorInEditor &data, UsagesCallback &&renameCallback,
const QString &replacement) const QString &replacement)
{ {
RefactoringEngineInterface *engine = getRefactoringEngine(d->m_refactoringEngines); RefactoringEngineInterface *engine = getRefactoringEngine(d->m_refactoringEngines, false);
QTC_ASSERT(engine, return;); QTC_ASSERT(engine, return;);
engine->globalRename(data, std::move(renameCallback), replacement); engine->globalRename(data, std::move(renameCallback), replacement);
} }