ClangCodeModel: Reimplement matchers()

Change-Id: I2d541e24347aa47ec41f88cd7d18004dee7197cf
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Christian Kandeler <christian.kandeler@qt.io>
Reviewed-by: <github-actions-qt-creator@cristianadam.eu>
This commit is contained in:
Jarek Kobus
2023-04-17 21:04:20 +02:00
parent 5a341e087f
commit eb41e98b00
2 changed files with 129 additions and 1 deletions

View File

@@ -12,12 +12,15 @@
#include <cppeditor/cpplocatorfilter.h>
#include <cppeditor/cppmodelmanager.h>
#include <cppeditor/indexitem.h>
#include <extensionsystem/pluginmanager.h>
#include <languageclient/currentdocumentsymbolsrequesttask.h>
#include <languageclient/languageclientmanager.h>
#include <languageclient/languageclientutils.h>
#include <languageclient/locatorfilter.h>
#include <projectexplorer/projectmanager.h>
#include <utils/link.h>
#include <utils/algorithm.h>
#include <utils/asynctask.h>
#include <utils/link.h>
#include <QHash>
@@ -25,6 +28,7 @@ using namespace Core;
using namespace LanguageClient;
using namespace LanguageServerProtocol;
using namespace ProjectExplorer;
using namespace TextEditor;
using namespace Utils;
namespace ClangCodeModel {
@@ -212,6 +216,7 @@ LocatorMatcherTasks ClangFunctionsFilter::matchers()
ClangModelManagerSupport::clientsForOpenProjects(), MaxResultCount);
}
// TODO: Remove this class, it's used only internally by ClangdCurrentDocumentFilter
class LspCurrentDocumentFilter : public DocumentLocatorFilter
{
public:
@@ -341,6 +346,128 @@ ClangdCurrentDocumentFilter::ClangdCurrentDocumentFilter() : d(new Private)
ClangdCurrentDocumentFilter::~ClangdCurrentDocumentFilter() { delete d; }
static void filterCurrentResults(QPromise<void> &promise, const LocatorStorage &storage,
const CurrentDocumentSymbolsData &currentSymbolsData,
const QString &contents)
{
Q_UNUSED(promise)
struct Entry
{
LocatorFilterEntry entry;
DocumentSymbol symbol;
};
QList<Entry> docEntries;
const auto docSymbolModifier = [&docEntries](LocatorFilterEntry &entry,
const DocumentSymbol &info,
const LocatorFilterEntry &parent) {
entry.displayName = ClangdClient::displayNameFromDocumentSymbol(
static_cast<SymbolKind>(info.kind()), info.name(),
info.detail().value_or(QString()));
entry.extraInfo = parent.extraInfo;
if (!entry.extraInfo.isEmpty())
entry.extraInfo.append("::");
entry.extraInfo.append(parent.displayName);
// TODO: Can we extend clangd to send visibility information?
docEntries.append({entry, info});
return entry;
};
// TODO: Pass promise into currentSymbols
const LocatorFilterEntries allMatches = LanguageClient::currentDocumentSymbols(storage.input(),
currentSymbolsData, docSymbolModifier);
if (docEntries.isEmpty()) {
storage.reportOutput(allMatches);
return; // SymbolInformation case
}
QTC_CHECK(docEntries.size() == allMatches.size());
QHash<QString, QList<Entry>> possibleDuplicates;
for (const Entry &e : std::as_const(docEntries))
possibleDuplicates[e.entry.displayName + e.entry.extraInfo] << e;
const QTextDocument doc(contents);
for (auto it = possibleDuplicates.cbegin(); it != possibleDuplicates.cend(); ++it) {
const QList<Entry> &duplicates = it.value();
if (duplicates.size() == 1)
continue;
QList<Entry> declarations;
QList<Entry> definitions;
for (const Entry &candidate : duplicates) {
const DocumentSymbol symbol = candidate.symbol;
const SymbolKind kind = static_cast<SymbolKind>(symbol.kind());
if (kind != SymbolKind::Class && kind != SymbolKind::Function)
break;
const Range range = symbol.range();
const Range selectionRange = symbol.selectionRange();
if (kind == SymbolKind::Class) {
if (range.end() == selectionRange.end())
declarations << candidate;
else
definitions << candidate;
continue;
}
const int startPos = selectionRange.end().toPositionInDocument(&doc);
const int endPos = range.end().toPositionInDocument(&doc);
const QString functionBody = contents.mid(startPos, endPos - startPos);
// Hacky, but I don't see anything better.
if (functionBody.contains('{') && functionBody.contains('}'))
definitions << candidate;
else
declarations << candidate;
}
if (definitions.size() == 1
&& declarations.size() + definitions.size() == duplicates.size()) {
for (const Entry &decl : std::as_const(declarations)) {
Utils::erase(docEntries, [&decl](const Entry &e) {
return e.symbol == decl.symbol;
});
}
}
}
storage.reportOutput(Utils::transform(docEntries,
[](const Entry &entry) { return entry.entry; }));
}
LocatorMatcherTask currentDocumentMatcher()
{
using namespace Tasking;
TreeStorage<LocatorStorage> storage;
TreeStorage<CurrentDocumentSymbolsData> resultStorage;
const auto onQuerySetup = [=](CurrentDocumentSymbolsRequestTask &request) {
Q_UNUSED(request)
};
const auto onQueryDone = [resultStorage](const CurrentDocumentSymbolsRequestTask &request) {
*resultStorage = request.currentDocumentSymbolsData();
};
const auto onFilterSetup = [=](AsyncTask<void> &async) {
async.setFutureSynchronizer(ExtensionSystem::PluginManager::futureSynchronizer());
async.setConcurrentCallData(filterCurrentResults, *storage, *resultStorage,
TextDocument::currentTextDocument()->plainText());
};
const Group root {
Storage(resultStorage),
CurrentDocumentSymbolsRequest(onQuerySetup, onQueryDone),
Async<void>(onFilterSetup)
};
return {root, storage};
}
LocatorMatcherTasks ClangdCurrentDocumentFilter::matchers()
{
const auto doc = TextDocument::currentTextDocument();
QTC_ASSERT(doc, return {});
if (const ClangdClient *client = ClangModelManagerSupport::clientForFile(doc->filePath());
client && client->reachable()) {
return {currentDocumentMatcher()};
}
return CppEditor::cppMatchers(MatcherType::CurrentDocumentSymbols);
}
void ClangdCurrentDocumentFilter::prepareSearch(const QString &entry)
{
const auto doc = TextEditor::TextDocument::currentTextDocument();

View File

@@ -54,6 +54,7 @@ public:
~ClangdCurrentDocumentFilter() override;
private:
Core::LocatorMatcherTasks matchers() final;
void prepareSearch(const QString &entry) override;
QList<Core::LocatorFilterEntry> matchesFor(QFutureInterface<Core::LocatorFilterEntry> &future,
const QString &entry) override;