From 3b76420e0f5055e55d24dd51d1f88a880392982c Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 3 Apr 2023 20:48:08 +0200 Subject: [PATCH] CppLocatorFilter: Introduce cpp matchers Change-Id: I7a9d3713a941c46ea8412a26743cdfcfa5791892 Reviewed-by: Qt CI Bot Reviewed-by: Reviewed-by: Christian Kandeler --- src/plugins/cppeditor/cppeditorplugin.cpp | 8 ++ src/plugins/cppeditor/cppeditorplugin.h | 6 +- src/plugins/cppeditor/cpplocatorfilter.cpp | 148 +++++++++++++++++++++ src/plugins/cppeditor/cpplocatorfilter.h | 4 + 4 files changed, 165 insertions(+), 1 deletion(-) diff --git a/src/plugins/cppeditor/cppeditorplugin.cpp b/src/plugins/cppeditor/cppeditorplugin.cpp index 2d4cabe726e..53d6ef55bda 100644 --- a/src/plugins/cppeditor/cppeditorplugin.cpp +++ b/src/plugins/cppeditor/cppeditorplugin.cpp @@ -85,6 +85,7 @@ #include #include #include +#include #include #include #include @@ -198,6 +199,7 @@ public: ClangdSettingsPage *m_clangdSettingsPage = nullptr; CppCodeStyleSettingsPage m_cppCodeStyleSettingsPage; CppProjectUpdaterFactory m_cppProjectUpdaterFactory; + FutureSynchronizer m_futureSynchronizer; }; static CppEditorPlugin *m_instance = nullptr; @@ -631,6 +633,12 @@ bool CppEditorPlugin::usePragmaOnce() return m_instance->d->m_fileSettings.headerPragmaOnce; } +FutureSynchronizer *CppEditorPlugin::futureSynchronizer() +{ + QTC_ASSERT(m_instance, return nullptr); + return &m_instance->d->m_futureSynchronizer; +} + const QStringList &CppEditorPlugin::headerSearchPaths() { return m_instance->d->m_fileSettings.headerSearchPaths; diff --git a/src/plugins/cppeditor/cppeditorplugin.h b/src/plugins/cppeditor/cppeditorplugin.h index c28ee16b1e1..b24bc927f65 100644 --- a/src/plugins/cppeditor/cppeditorplugin.h +++ b/src/plugins/cppeditor/cppeditorplugin.h @@ -5,7 +5,10 @@ #include -namespace Utils { class FilePath; } +namespace Utils { +class FilePath; +class FutureSynchronizer; +} namespace CppEditor { class CppCodeModelSettings; @@ -37,6 +40,7 @@ public: static Utils::FilePath licenseTemplatePath(); static QString licenseTemplate(); static bool usePragmaOnce(); + static Utils::FutureSynchronizer *futureSynchronizer(); void openDeclarationDefinitionInNextSplit(); void openTypeHierarchy(); diff --git a/src/plugins/cppeditor/cpplocatorfilter.cpp b/src/plugins/cppeditor/cpplocatorfilter.cpp index 541acb05154..671c2d205e6 100644 --- a/src/plugins/cppeditor/cpplocatorfilter.cpp +++ b/src/plugins/cppeditor/cpplocatorfilter.cpp @@ -4,17 +4,165 @@ #include "cpplocatorfilter.h" #include "cppeditorconstants.h" +#include "cppeditorplugin.h" #include "cppeditortr.h" #include "cpplocatordata.h" #include +#include #include using namespace Core; +using namespace Utils; namespace CppEditor { +using EntryFromIndex = std::function; + +void matchesFor(QPromise &promise, const QString &entry, + IndexItem::ItemType wantedType, const EntryFromIndex &converter) +{ + QList entries[int(ILocatorFilter::MatchLevel::Count)]; + const Qt::CaseSensitivity caseSensitivityForPrefix = ILocatorFilter::caseSensitivity(entry); + const QRegularExpression regexp = ILocatorFilter::createRegExp(entry); + if (!regexp.isValid()) + return; + + const bool hasColonColon = entry.contains("::"); + const QRegularExpression shortRegexp = hasColonColon + ? ILocatorFilter::createRegExp(entry.mid(entry.lastIndexOf("::") + 2)) : regexp; + CppLocatorData *locatorData = CppModelManager::instance()->locatorData(); + locatorData->filterAllFiles([&](const IndexItem::Ptr &info) { + if (promise.isCanceled()) + return IndexItem::Break; + const IndexItem::ItemType type = info->type(); + if (type & wantedType) { + const QString symbolName = info->symbolName(); + QString matchString = hasColonColon ? info->scopedSymbolName() : symbolName; + int matchOffset = hasColonColon ? matchString.size() - symbolName.size() : 0; + QRegularExpressionMatch match = regexp.match(matchString); + bool matchInParameterList = false; + if (!match.hasMatch() && (type == IndexItem::Function)) { + matchString += info->symbolType(); + match = regexp.match(matchString); + matchInParameterList = true; + } + + if (match.hasMatch()) { + LocatorFilterEntry filterEntry = converter(info); + + // Highlight the matched characters, therefore it may be necessary + // to update the match if the displayName is different from matchString + if (QStringView(matchString).mid(matchOffset) != filterEntry.displayName) { + match = shortRegexp.match(filterEntry.displayName); + matchOffset = 0; + } + filterEntry.highlightInfo = ILocatorFilter::highlightInfo(match); + if (matchInParameterList && filterEntry.highlightInfo.startsDisplay.isEmpty()) { + match = regexp.match(filterEntry.extraInfo); + filterEntry.highlightInfo = ILocatorFilter::highlightInfo( + match, LocatorFilterEntry::HighlightInfo::ExtraInfo); + } else if (matchOffset > 0) { + for (int &start : filterEntry.highlightInfo.startsDisplay) + start -= matchOffset; + } + + if (matchInParameterList) + entries[int(ILocatorFilter::MatchLevel::Normal)].append(filterEntry); + else if (filterEntry.displayName.startsWith(entry, caseSensitivityForPrefix)) + entries[int(ILocatorFilter::MatchLevel::Best)].append(filterEntry); + else if (filterEntry.displayName.contains(entry, caseSensitivityForPrefix)) + entries[int(ILocatorFilter::MatchLevel::Better)].append(filterEntry); + else + entries[int(ILocatorFilter::MatchLevel::Good)].append(filterEntry); + } + } + + if (info->type() & IndexItem::Enum) + return IndexItem::Continue; + return IndexItem::Recurse; + }); + + for (auto &entry : entries) { + if (entry.size() < 1000) + Utils::sort(entry, LocatorFilterEntry::compareLexigraphically); + } + + promise.addResult(std::accumulate(std::begin(entries), std::end(entries), + QList())); +} + +LocatorMatcherTask locatorMatcher(IndexItem::ItemType type, const EntryFromIndex &converter) +{ + using namespace Tasking; + + TreeStorage storage; + + const auto onSetup = [=](AsyncTask &async) { + async.setFutureSynchronizer(Internal::CppEditorPlugin::futureSynchronizer()); + async.setConcurrentCallData(matchesFor, storage->input, type, converter); + }; + const auto onDone = [storage](const AsyncTask &async) { + if (async.isResultAvailable()) + storage->output = async.result(); + }; + return {Async(onSetup, onDone, onDone), storage}; +} + +LocatorMatcherTask cppLocatorMatcher() +{ + const auto converter = [](const IndexItem::Ptr &info) { + // TODO: Passing nullptr for filter -> accept won't work now. Replace with accept function. + LocatorFilterEntry filterEntry(nullptr, info->scopedSymbolName()); + filterEntry.displayIcon = info->icon(); + filterEntry.linkForEditor = {info->filePath(), info->line(), info->column()}; + if (info->type() == IndexItem::Class || info->type() == IndexItem::Enum) + filterEntry.extraInfo = info->shortNativeFilePath(); + else + filterEntry.extraInfo = info->symbolType(); + return filterEntry; + }; + return locatorMatcher(IndexItem::All, converter); +} + +LocatorMatcherTask cppClassMatcher() +{ + const auto converter = [](const IndexItem::Ptr &info) { + // TODO: Passing nullptr for filter -> accept won't work now. Replace with accept function. + LocatorFilterEntry filterEntry(nullptr, info->symbolName()); + filterEntry.displayIcon = info->icon(); + filterEntry.linkForEditor = {info->filePath(), info->line(), info->column()}; + filterEntry.extraInfo = info->symbolScope().isEmpty() + ? info->shortNativeFilePath() + : info->symbolScope(); + filterEntry.filePath = info->filePath(); + return filterEntry; + }; + return locatorMatcher(IndexItem::Class, converter); +} + +LocatorMatcherTask cppFunctionMatcher() +{ + const auto converter = [](const IndexItem::Ptr &info) { + QString name = info->symbolName(); + QString extraInfo = info->symbolScope(); + info->unqualifiedNameAndScope(name, &name, &extraInfo); + if (extraInfo.isEmpty()) + extraInfo = info->shortNativeFilePath(); + else + extraInfo.append(" (" + info->filePath().fileName() + ')'); + // TODO: Passing nullptr for filter -> accept won't work now. Replace with accept function. + LocatorFilterEntry filterEntry(nullptr, name + info->symbolType()); + filterEntry.displayIcon = info->icon(); + filterEntry.linkForEditor = {info->filePath(), info->line(), info->column()}; + filterEntry.extraInfo = extraInfo; + + return filterEntry; + }; + return locatorMatcher(IndexItem::Function, converter); +} + CppLocatorFilter::CppLocatorFilter() { setId(Constants::LOCATOR_FILTER_ID); diff --git a/src/plugins/cppeditor/cpplocatorfilter.h b/src/plugins/cppeditor/cpplocatorfilter.h index 126853c313d..b484a9c7687 100644 --- a/src/plugins/cppeditor/cpplocatorfilter.h +++ b/src/plugins/cppeditor/cpplocatorfilter.h @@ -10,6 +10,10 @@ namespace CppEditor { +Core::LocatorMatcherTask CPPEDITOR_EXPORT cppLocatorMatcher(); +Core::LocatorMatcherTask CPPEDITOR_EXPORT cppClassMatcher(); +Core::LocatorMatcherTask CPPEDITOR_EXPORT cppFunctionMatcher(); + class CPPEDITOR_EXPORT CppLocatorFilter : public Core::ILocatorFilter { Q_OBJECT