ClangCodeModel: Do not try to rename macros and namespaces with clangd

Unfortunately, clangd refuses to rename macros and namespaces.
Fall back to our old two-stage "find + replace" approach for macros
(which clangd can find just fine) and employ the built-in code model for
namespaces (as they don't get indexed at all by clangd).

Change-Id: I08b1088ff4de9220427e089ef0700dbf2a944081
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: <github-actions-qt-creator@cristianadam.eu>
This commit is contained in:
Christian Kandeler
2023-04-03 14:12:39 +02:00
parent 6ad3531b15
commit 0319542937
4 changed files with 51 additions and 15 deletions

View File

@@ -508,22 +508,57 @@ void ClangdClient::closeExtraFile(const Utils::FilePath &filePath)
SendDocUpdates::Ignore); SendDocUpdates::Ignore);
} }
void ClangdClient::findUsages(TextDocument *document, const QTextCursor &cursor, void ClangdClient::findUsages(const CppEditor::CursorInEditor &cursor,
const std::optional<QString> &replacement, const std::optional<QString> &replacement,
const std::function<void()> &renameCallback) const std::function<void()> &renameCallback)
{ {
// Quick check: Are we even on anything searchable? // Quick check: Are we even on anything searchable?
const QTextCursor adjustedCursor = d->adjustedCursor(cursor, document); const QTextCursor adjustedCursor = d->adjustedCursor(cursor.cursor(), cursor.textDocument());
const QString searchTerm = d->searchTermFromCursor(adjustedCursor); const QString searchTerm = d->searchTermFromCursor(adjustedCursor);
if (searchTerm.isEmpty()) if (searchTerm.isEmpty())
return; return;
if (replacement && versionNumber() >= QVersionNumber(16) if (replacement && versionNumber() >= QVersionNumber(16)
&& Utils::qtcEnvironmentVariable("QTC_CLANGD_RENAMING") != "0") { && Utils::qtcEnvironmentVariable("QTC_CLANGD_RENAMING") != "0") {
symbolSupport().renameSymbol(document, adjustedCursor, *replacement, renameCallback,
CppEditor::preferLowerCaseFileNames()); // If we have up-to-date highlighting data, we can prevent giving clangd
// macros or namespaces to rename, which it can't cope with.
// TODO: Fix this upstream for macros; see https://github.com/clangd/clangd/issues/729.
bool useClangdForRenaming = true;
const auto highlightingData = d->highlightingData.constFind(cursor.textDocument());
if (highlightingData != d->highlightingData.end()
&& highlightingData->previousTokens.second == documentVersion(cursor.filePath())) {
const auto candidate = std::lower_bound(
highlightingData->previousTokens.first.cbegin(),
highlightingData->previousTokens.first.cend(),
cursor.cursor().position(),
[&cursor](const ExpandedSemanticToken &token, int pos) {
const int startPos = Utils::Text::positionInText(
cursor.textDocument()->document(), token.line, token.column);
return startPos + token.length < pos;
});
if (candidate != highlightingData->previousTokens.first.cend()) {
const int startPos = Utils::Text::positionInText(
cursor.textDocument()->document(), candidate->line, candidate->column);
if (startPos <= cursor.cursor().position()) {
if (candidate->type == "namespace") {
CppEditor::CppModelManager::globalRename(
cursor, *replacement, renameCallback,
CppEditor::CppModelManager::Backend::Builtin);
return; return;
} }
if (candidate->type == "macro")
useClangdForRenaming = false;
}
}
}
if (useClangdForRenaming) {
symbolSupport().renameSymbol(cursor.textDocument(), adjustedCursor, *replacement,
renameCallback, CppEditor::preferLowerCaseFileNames());
return;
}
}
const bool categorize = CppEditor::codeModelSettings()->categorizeFindReferences(); const bool categorize = CppEditor::codeModelSettings()->categorizeFindReferences();
@@ -531,14 +566,15 @@ void ClangdClient::findUsages(TextDocument *document, const QTextCursor &cursor,
if (searchTerm != "operator" && Utils::allOf(searchTerm, [](const QChar &c) { if (searchTerm != "operator" && Utils::allOf(searchTerm, [](const QChar &c) {
return c.isLetterOrNumber() || c == '_'; return c.isLetterOrNumber() || c == '_';
})) { })) {
d->findUsages(document, adjustedCursor, searchTerm, replacement, renameCallback, categorize); d->findUsages(cursor.textDocument(), adjustedCursor, searchTerm, replacement,
renameCallback, categorize);
return; return;
} }
// Otherwise get the proper spelling of the search term from clang, so we can put it into the // Otherwise get the proper spelling of the search term from clang, so we can put it into the
// search widget. // search widget.
const auto symbolInfoHandler = [this, doc = QPointer(document), adjustedCursor, replacement, const auto symbolInfoHandler = [this, doc = QPointer(cursor.textDocument()), adjustedCursor,
renameCallback, categorize] replacement, renameCallback, categorize]
(const QString &name, const QString &, const MessageId &) { (const QString &name, const QString &, const MessageId &) {
if (!doc) if (!doc)
return; return;
@@ -546,7 +582,8 @@ void ClangdClient::findUsages(TextDocument *document, const QTextCursor &cursor,
return; return;
d->findUsages(doc.data(), adjustedCursor, name, replacement, renameCallback, categorize); d->findUsages(doc.data(), adjustedCursor, name, replacement, renameCallback, categorize);
}; };
requestSymbolInfo(document->filePath(), Range(adjustedCursor).start(), symbolInfoHandler); requestSymbolInfo(cursor.textDocument()->filePath(), Range(adjustedCursor).start(),
symbolInfoHandler);
} }
void ClangdClient::checkUnused(const Utils::Link &link, Core::SearchResult *search, void ClangdClient::checkUnused(const Utils::Link &link, Core::SearchResult *search,

View File

@@ -53,7 +53,7 @@ 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(const CppEditor::CursorInEditor &cursor,
const std::optional<QString> &replacement, const std::optional<QString> &replacement,
const std::function<void()> &renameCallback); const std::function<void()> &renameCallback);
void checkUnused(const Utils::Link &link, Core::SearchResult *search, void checkUnused(const Utils::Link &link, Core::SearchResult *search,

View File

@@ -320,7 +320,7 @@ void ClangModelManagerSupport::globalRename(const CppEditor::CursorInEditor &cur
client && client->isFullyIndexed()) { client && client->isFullyIndexed()) {
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(), replacement, callback); client->findUsages(cursor, replacement, callback);
return; return;
} }
CppModelManager::globalRename(cursor, replacement, callback, CppModelManager::Backend::Builtin); CppModelManager::globalRename(cursor, replacement, callback, CppModelManager::Backend::Builtin);
@@ -332,8 +332,7 @@ void ClangModelManagerSupport::findUsages(const CppEditor::CursorInEditor &curso
client && client->isFullyIndexed()) { client && client->isFullyIndexed()) {
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, {}, {});
return; return;
} }
CppModelManager::findUsages(cursor, CppModelManager::Backend::Builtin); CppModelManager::findUsages(cursor, CppModelManager::Backend::Builtin);

View File

@@ -294,7 +294,7 @@ void ClangdTestFindReferences::test()
QVERIFY(doc); QVERIFY(doc);
QTextCursor cursor(doc->document()); QTextCursor cursor(doc->document());
cursor.setPosition(pos); cursor.setPosition(pos);
client()->findUsages(doc, cursor, {}, {}); client()->findUsages(CppEditor::CursorInEditor(cursor, doc->filePath(), nullptr, doc), {}, {});
QVERIFY(waitForSignalOrTimeout(client(), &ClangdClient::findUsagesDone, timeOutInMs())); QVERIFY(waitForSignalOrTimeout(client(), &ClangdClient::findUsagesDone, timeOutInMs()));
QCOMPARE(m_actualResults.size(), expectedResults.size()); QCOMPARE(m_actualResults.size(), expectedResults.size());