forked from qt-creator/qt-creator
ClangCodeModel: Get search term for "Find References" from clangd
QTextCursor's understanding of a "word" does not always correspond to what will actually be searched for (e.g. "operator+"). By doing a symbol info request first, we make sure that the string displayed to the user in the search widget is really what clangd is searching for. Change-Id: I8be6e6122e5ed76334c4e6fc5b41debed96b6a40 Reviewed-by: Christian Stenger <christian.stenger@qt.io>
This commit is contained in:
@@ -682,6 +682,8 @@ public:
|
|||||||
Private(ClangdClient *q, Project *project)
|
Private(ClangdClient *q, Project *project)
|
||||||
: q(q), settings(CppTools::ClangdProjectSettings(project).settings()) {}
|
: q(q), settings(CppTools::ClangdProjectSettings(project).settings()) {}
|
||||||
|
|
||||||
|
void findUsages(TextEditor::TextDocument *document, const QTextCursor &cursor,
|
||||||
|
const QString &searchTerm, const Utils::optional<QString> &replacement);
|
||||||
void handleFindUsagesResult(quint64 key, const QList<Location> &locations);
|
void handleFindUsagesResult(quint64 key, const QList<Location> &locations);
|
||||||
static void handleRenameRequest(const SearchResult *search,
|
static void handleRenameRequest(const SearchResult *search,
|
||||||
const ReplacementData &replacementData,
|
const ReplacementData &replacementData,
|
||||||
@@ -868,69 +870,31 @@ void ClangdClient::closeExtraFile(const Utils::FilePath &filePath)
|
|||||||
void ClangdClient::findUsages(TextEditor::TextDocument *document, const QTextCursor &cursor,
|
void ClangdClient::findUsages(TextEditor::TextDocument *document, const QTextCursor &cursor,
|
||||||
const Utils::optional<QString> &replacement)
|
const Utils::optional<QString> &replacement)
|
||||||
{
|
{
|
||||||
// TODO: This will be wrong for e.g. operators. Use a Symbol info request to get the real symbol string.
|
// Quick check: Are we even on anything searchable?
|
||||||
const QString searchTerm = d->searchTermFromCursor(cursor);
|
if (d->searchTermFromCursor(cursor).isEmpty())
|
||||||
if (searchTerm.isEmpty())
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ReferencesData refData;
|
// Get the proper spelling of the search term from clang, so we can put it into the
|
||||||
refData.key = d->nextJobId++;
|
// search widget.
|
||||||
if (replacement) {
|
const TextDocumentIdentifier docId(DocumentUri::fromFilePath(document->filePath()));
|
||||||
ReplacementData replacementData;
|
const TextDocumentPositionParams params(docId, Range(cursor).start());
|
||||||
replacementData.oldSymbolName = searchTerm;
|
SymbolInfoRequest symReq(params);
|
||||||
replacementData.newSymbolName = *replacement;
|
symReq.setResponseCallback([this, doc = QPointer(document), cursor, replacement]
|
||||||
if (replacementData.newSymbolName.isEmpty())
|
(const SymbolInfoRequest::Response &response) {
|
||||||
replacementData.newSymbolName = replacementData.oldSymbolName;
|
if (!doc)
|
||||||
refData.replacementData = replacementData;
|
|
||||||
}
|
|
||||||
refData.search = SearchResultWindow::instance()->startNewSearch(
|
|
||||||
tr("C++ Usages:"),
|
|
||||||
{},
|
|
||||||
searchTerm,
|
|
||||||
replacement ? SearchResultWindow::SearchAndReplace : SearchResultWindow::SearchOnly,
|
|
||||||
SearchResultWindow::PreserveCaseDisabled,
|
|
||||||
"CppEditor");
|
|
||||||
if (refData.categorize)
|
|
||||||
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) {
|
|
||||||
Core::EditorManager::openEditorAtSearchResult(item);
|
|
||||||
});
|
|
||||||
SearchResultWindow::instance()->popup(IOutputPane::ModeSwitch | IOutputPane::WithFocus);
|
|
||||||
d->runningFindUsages.insert(refData.key, refData);
|
|
||||||
|
|
||||||
const Utils::optional<MessageId> requestId = symbolSupport().findUsages(
|
|
||||||
document, cursor, [this, key = refData.key](const QList<Location> &locations) {
|
|
||||||
d->handleFindUsagesResult(key, locations);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!requestId) {
|
|
||||||
d->finishSearch(refData, false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
connect(refData.search, &SearchResult::cancelled, this, [this, requestId, key = refData.key] {
|
|
||||||
const auto refData = d->runningFindUsages.find(key);
|
|
||||||
if (refData == d->runningFindUsages.end())
|
|
||||||
return;
|
return;
|
||||||
cancelRequest(*requestId);
|
const auto result = response.result();
|
||||||
refData->canceled = true;
|
if (!result)
|
||||||
refData->search->disconnect(this);
|
return;
|
||||||
d->finishSearch(*refData, true);
|
const auto list = Utils::get_if<QList<SymbolDetails>>(&result.value());
|
||||||
|
if (!list || list->isEmpty())
|
||||||
|
return;
|
||||||
|
const SymbolDetails &sd = list->first();
|
||||||
|
if (sd.name().isEmpty())
|
||||||
|
return;
|
||||||
|
d->findUsages(doc.data(), cursor, sd.name(), replacement);
|
||||||
});
|
});
|
||||||
|
sendContent(symReq);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClangdClient::enableTesting() { d->isTesting = true; }
|
void ClangdClient::enableTesting() { d->isTesting = true; }
|
||||||
@@ -971,6 +935,71 @@ QVersionNumber ClangdClient::versionNumber() const
|
|||||||
|
|
||||||
CppTools::ClangdSettings::Data ClangdClient::settingsData() const { return d->settings; }
|
CppTools::ClangdSettings::Data ClangdClient::settingsData() const { return d->settings; }
|
||||||
|
|
||||||
|
void ClangdClient::Private::findUsages(TextEditor::TextDocument *document,
|
||||||
|
const QTextCursor &cursor, const QString &searchTerm,
|
||||||
|
const Utils::optional<QString> &replacement)
|
||||||
|
{
|
||||||
|
ReferencesData refData;
|
||||||
|
refData.key = nextJobId++;
|
||||||
|
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(
|
||||||
|
tr("C++ Usages:"),
|
||||||
|
{},
|
||||||
|
searchTerm,
|
||||||
|
replacement ? SearchResultWindow::SearchAndReplace : SearchResultWindow::SearchOnly,
|
||||||
|
SearchResultWindow::PreserveCaseDisabled,
|
||||||
|
"CppEditor");
|
||||||
|
if (refData.categorize)
|
||||||
|
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) {
|
||||||
|
Core::EditorManager::openEditorAtSearchResult(item);
|
||||||
|
});
|
||||||
|
SearchResultWindow::instance()->popup(IOutputPane::ModeSwitch | IOutputPane::WithFocus);
|
||||||
|
runningFindUsages.insert(refData.key, refData);
|
||||||
|
|
||||||
|
const Utils::optional<MessageId> requestId = q->symbolSupport().findUsages(
|
||||||
|
document, cursor, [this, key = refData.key](const QList<Location> &locations) {
|
||||||
|
handleFindUsagesResult(key, locations);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!requestId) {
|
||||||
|
finishSearch(refData, false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
QObject::connect(refData.search, &SearchResult::cancelled, q, [this, requestId, key = refData.key] {
|
||||||
|
const auto refData = runningFindUsages.find(key);
|
||||||
|
if (refData == runningFindUsages.end())
|
||||||
|
return;
|
||||||
|
q->cancelRequest(*requestId);
|
||||||
|
refData->canceled = true;
|
||||||
|
refData->search->disconnect(q);
|
||||||
|
finishSearch(*refData, true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
void ClangdClient::Private::handleFindUsagesResult(quint64 key, const QList<Location> &locations)
|
void ClangdClient::Private::handleFindUsagesResult(quint64 key, const QList<Location> &locations)
|
||||||
{
|
{
|
||||||
const auto refData = runningFindUsages.find(key);
|
const auto refData = runningFindUsages.find(key);
|
||||||
|
|||||||
Reference in New Issue
Block a user