diff --git a/src/plugins/clangcodemodel/clangdlocatorfilters.cpp b/src/plugins/clangcodemodel/clangdlocatorfilters.cpp index ebd04c538b3..a7700d942af 100644 --- a/src/plugins/clangcodemodel/clangdlocatorfilters.cpp +++ b/src/plugins/clangcodemodel/clangdlocatorfilters.cpp @@ -209,46 +209,54 @@ private: m_content = TextEditor::TextDocument::currentTextDocument()->plainText(); } - LocatorFilterEntry generateLocatorEntry(const DocumentSymbol &info, - const LocatorFilterEntry &parent) override - { - LocatorFilterEntry entry; - entry.filter = this; - entry.displayName = ClangdClient::displayNameFromDocumentSymbol( - static_cast(info.kind()), info.name(), - info.detail().value_or(QString())); - entry.internalData = QVariant::fromValue(info); - const Position pos = info.range().start(); - entry.linkForEditor = {m_currentFilePath, pos.line() + 1, pos.character()}; - 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? - entry.displayIcon = LanguageClient::symbolIcon(info.kind()); - - return entry; - } - // Filter out declarations for which a definition is also present. QList matchesFor(QFutureInterface &future, const QString &entry) override { - QList allMatches - = DocumentLocatorFilter::matchesFor(future, entry); - QHash> possibleDuplicates; - for (const LocatorFilterEntry &e : std::as_const(allMatches)) - possibleDuplicates[e.displayName + e.extraInfo] << e; + struct Entry + { + LocatorFilterEntry entry; + DocumentSymbol symbol; + }; + QList docEntries; + + const auto docSymbolGenerator = [&](const DocumentSymbol &info, + const LocatorFilterEntry &parent) { + LocatorFilterEntry entry; + entry.filter = this; + entry.displayName = ClangdClient::displayNameFromDocumentSymbol( + static_cast(info.kind()), info.name(), + info.detail().value_or(QString())); + entry.internalData = QVariant::fromValue(info); + entry.linkForEditor = linkForDocSymbol(info); + 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? + entry.displayIcon = LanguageClient::symbolIcon(info.kind()); + docEntries.append({entry, info}); + return entry; + }; + + QList allMatches = matchesForImpl(future, entry, docSymbolGenerator); + if (docEntries.isEmpty()) + return allMatches; // SymbolInformation case + + QTC_CHECK(docEntries.size() == allMatches.size()); + QHash> possibleDuplicates; + for (const Entry &e : std::as_const(docEntries)) + possibleDuplicates[e.entry.displayName + e.entry.extraInfo] << e; const QTextDocument doc(m_content); for (auto it = possibleDuplicates.cbegin(); it != possibleDuplicates.cend(); ++it) { - const QList &duplicates = it.value(); + const QList &duplicates = it.value(); if (duplicates.size() == 1) continue; - QList declarations; - QList definitions; - for (const LocatorFilterEntry &candidate : duplicates) { - const auto symbol = qvariant_cast(candidate.internalData); + QList declarations; + QList definitions; + for (const Entry &candidate : duplicates) { + const DocumentSymbol symbol = candidate.symbol; const SymbolKind kind = static_cast(symbol.kind()); if (kind != SymbolKind::Class && kind != SymbolKind::Function) break; @@ -273,14 +281,14 @@ private: } if (definitions.size() == 1 && declarations.size() + definitions.size() == duplicates.size()) { - for (const LocatorFilterEntry &decl : std::as_const(declarations)) { - Utils::erase(allMatches, [&decl](const LocatorFilterEntry &e) { - return e.internalData == decl.internalData; + for (const Entry &decl : std::as_const(declarations)) { + Utils::erase(docEntries, [&decl](const Entry &e) { + return e.symbol == decl.symbol; }); } } } - return allMatches; + return Utils::transform(docEntries, [](const Entry &entry) { return entry.entry; }); } QString m_content; diff --git a/src/plugins/languageclient/locatorfilter.cpp b/src/plugins/languageclient/locatorfilter.cpp index 1b5b64d528c..ba4cc105abc 100644 --- a/src/plugins/languageclient/locatorfilter.cpp +++ b/src/plugins/languageclient/locatorfilter.cpp @@ -98,69 +98,31 @@ static LocatorFilterEntry generateLocatorEntry(const SymbolInformation &info, return entry; } -LocatorFilterEntry DocumentLocatorFilter::generateLocatorEntry(const SymbolInformation &info) +QList DocumentLocatorFilter::entriesForSymbolsInfo( + const QList &infoList, const QRegularExpression ®exp) { QTC_ASSERT(m_pathMapper, return {}); - return LanguageClient::generateLocatorEntry(info, this, m_pathMapper); -} - -QList DocumentLocatorFilter::generateLocatorEntries( - const SymbolInformation &info, const QRegularExpression ®exp, - const LocatorFilterEntry &parent) -{ - Q_UNUSED(parent) - if (regexp.match(info.name()).hasMatch()) - return {generateLocatorEntry(info)}; - return {}; -} - -LocatorFilterEntry DocumentLocatorFilter::generateLocatorEntry(const DocumentSymbol &info, - const LocatorFilterEntry &parent) -{ - Q_UNUSED(parent) - LocatorFilterEntry entry; - entry.filter = this; - entry.displayName = info.name(); - if (std::optional detail = info.detail()) - entry.extraInfo = detail.value_or(QString()); - entry.displayIcon = symbolIcon(info.kind()); - const Position &pos = info.range().start(); - entry.linkForEditor = {m_currentFilePath, pos.line() + 1, pos.character()}; - return entry; -} - -QList DocumentLocatorFilter::generateLocatorEntries( - const DocumentSymbol &info, const QRegularExpression ®exp, - const LocatorFilterEntry &parent) -{ QList entries; - const QList children = info.children().value_or(QList()); - const bool hasMatch = regexp.match(info.name()).hasMatch(); - LocatorFilterEntry entry; - if (hasMatch || !children.isEmpty()) - entry = generateLocatorEntry(info, parent); - if (hasMatch) - entries << entry; - for (const DocumentSymbol &child : children) - entries << generateLocatorEntries(child, regexp, entry); + for (const SymbolInformation &info : infoList) { + if (regexp.match(info.name()).hasMatch()) + entries << LanguageClient::generateLocatorEntry(info, this, m_pathMapper); + } return entries; } -template -QList DocumentLocatorFilter::generateEntries(const QList &list, - const QString &filter) +QList DocumentLocatorFilter::entriesForDocSymbols( + const QList &infoList, const QRegularExpression ®exp, + const DocSymbolGenerator &docSymbolGenerator, const LocatorFilterEntry &parent) { QList entries; - FuzzyMatcher::CaseSensitivity caseSensitivity - = ILocatorFilter::caseSensitivity(filter) == Qt::CaseSensitive - ? FuzzyMatcher::CaseSensitivity::CaseSensitive - : FuzzyMatcher::CaseSensitivity::CaseInsensitive; - const QRegularExpression regexp = FuzzyMatcher::createRegExp(filter, caseSensitivity); - if (!regexp.isValid()) - return entries; - - for (const T &item : list) - entries << generateLocatorEntries(item, regexp, {}); + for (const DocumentSymbol &info : infoList) { + const QList children = info.children().value_or(QList()); + const bool hasMatch = regexp.match(info.name()).hasMatch(); + const LocatorFilterEntry entry = hasMatch ? docSymbolGenerator(info, parent) : parent; + if (hasMatch) + entries << entry; + entries << entriesForDocSymbols(children, regexp, docSymbolGenerator, entry); + } return entries; } @@ -177,6 +139,39 @@ void DocumentLocatorFilter::prepareSearch(const QString &/*entry*/) QList DocumentLocatorFilter::matchesFor( QFutureInterface &future, const QString &entry) { + const auto docSymbolGenerator = [this](const DocumentSymbol &info, + const LocatorFilterEntry &parent) { + Q_UNUSED(parent) + LocatorFilterEntry entry; + entry.filter = this; + entry.displayName = info.name(); + if (std::optional detail = info.detail()) + entry.extraInfo = detail.value_or(QString()); + entry.displayIcon = symbolIcon(info.kind()); + entry.linkForEditor = linkForDocSymbol(info); + return entry; + }; + return matchesForImpl(future, entry, docSymbolGenerator); +} + +Utils::Link DocumentLocatorFilter::linkForDocSymbol(const DocumentSymbol &info) const +{ + const Position &pos = info.range().start(); + return {m_currentFilePath, pos.line() + 1, pos.character()}; +} + +QList DocumentLocatorFilter::matchesForImpl( + QFutureInterface &future, const QString &entry, + const DocSymbolGenerator &docSymbolGenerator) +{ + const FuzzyMatcher::CaseSensitivity caseSensitivity + = ILocatorFilter::caseSensitivity(entry) == Qt::CaseSensitive + ? FuzzyMatcher::CaseSensitivity::CaseSensitive + : FuzzyMatcher::CaseSensitivity::CaseInsensitive; + const QRegularExpression regExp = FuzzyMatcher::createRegExp(entry, caseSensitivity); + if (!regExp.isValid()) + return {}; + QMutexLocker locker(&m_mutex); if (!m_symbolCache) return {}; @@ -195,9 +190,9 @@ QList DocumentLocatorFilter::matchesFor( QTC_ASSERT(m_currentSymbols.has_value(), return {}); if (auto list = std::get_if>(&*m_currentSymbols)) - return generateEntries(*list, entry); + return entriesForDocSymbols(*list, regExp, docSymbolGenerator); else if (auto list = std::get_if>(&*m_currentSymbols)) - return generateEntries(*list, entry); + return entriesForSymbolsInfo(*list, regExp); return {}; } diff --git a/src/plugins/languageclient/locatorfilter.h b/src/plugins/languageclient/locatorfilter.h index 769fd39ba69..1ac354ed357 100644 --- a/src/plugins/languageclient/locatorfilter.h +++ b/src/plugins/languageclient/locatorfilter.h @@ -36,31 +36,29 @@ signals: protected: void forceUse() { m_forced = true; } - QPointer m_symbolCache; - LanguageServerProtocol::DocumentUri m_currentUri; Utils::FilePath m_currentFilePath; + using DocSymbolGenerator = std::function; + + Utils::Link linkForDocSymbol(const LanguageServerProtocol::DocumentSymbol &info) const; + QList matchesForImpl( + QFutureInterface &future, const QString &entry, + const DocSymbolGenerator &docSymbolGenerator); + private: void updateCurrentClient(); void updateSymbols(const LanguageServerProtocol::DocumentUri &uri, const LanguageServerProtocol::DocumentSymbolsResult &symbols); void resetSymbols(); - template - QList generateEntries(const QList &list, const QString &filter); - QList generateLocatorEntries( - const LanguageServerProtocol::SymbolInformation &info, - const QRegularExpression ®exp, - const Core::LocatorFilterEntry &parent); - QList generateLocatorEntries( - const LanguageServerProtocol::DocumentSymbol &info, - const QRegularExpression ®exp, - const Core::LocatorFilterEntry &parent); - virtual Core::LocatorFilterEntry generateLocatorEntry( - const LanguageServerProtocol::DocumentSymbol &info, - const Core::LocatorFilterEntry &parent); - virtual Core::LocatorFilterEntry generateLocatorEntry( - const LanguageServerProtocol::SymbolInformation &info); + QList entriesForSymbolsInfo( + const QList &infoList, + const QRegularExpression ®exp); + QList entriesForDocSymbols( + const QList &infoList, + const QRegularExpression ®exp, const DocSymbolGenerator &docSymbolGenerator, + const Core::LocatorFilterEntry &parent = {}); QMutex m_mutex; QMetaObject::Connection m_updateSymbolsConnection; @@ -68,6 +66,8 @@ private: std::optional m_currentSymbols; LanguageServerProtocol::DocumentUri::PathMapper m_pathMapper; bool m_forced = false; + QPointer m_symbolCache; + LanguageServerProtocol::DocumentUri m_currentUri; }; class LANGUAGECLIENT_EXPORT WorkspaceLocatorFilter : public Core::ILocatorFilter