CppLocatorFilter: Introduce cpp matchers

Change-Id: I7a9d3713a941c46ea8412a26743cdfcfa5791892
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: <github-actions-qt-creator@cristianadam.eu>
Reviewed-by: Christian Kandeler <christian.kandeler@qt.io>
This commit is contained in:
Jarek Kobus
2023-04-03 20:48:08 +02:00
parent 2eba3584a1
commit 3b76420e0f
4 changed files with 165 additions and 1 deletions

View File

@@ -85,6 +85,7 @@
#include <utils/algorithm.h>
#include <utils/fileutils.h>
#include <utils/fsengine/fileiconprovider.h>
#include <utils/futuresynchronizer.h>
#include <utils/hostosinfo.h>
#include <utils/macroexpander.h>
#include <utils/mimeutils.h>
@@ -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;

View File

@@ -5,7 +5,10 @@
#include <extensionsystem/iplugin.h>
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();

View File

@@ -4,17 +4,165 @@
#include "cpplocatorfilter.h"
#include "cppeditorconstants.h"
#include "cppeditorplugin.h"
#include "cppeditortr.h"
#include "cpplocatordata.h"
#include <utils/algorithm.h>
#include <utils/asynctask.h>
#include <QRegularExpression>
using namespace Core;
using namespace Utils;
namespace CppEditor {
using EntryFromIndex = std::function<LocatorFilterEntry(const IndexItem::Ptr &)>;
void matchesFor(QPromise<LocatorMatcherTask::OutputData> &promise, const QString &entry,
IndexItem::ItemType wantedType, const EntryFromIndex &converter)
{
QList<LocatorFilterEntry> 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<LocatorFilterEntry>()));
}
LocatorMatcherTask locatorMatcher(IndexItem::ItemType type, const EntryFromIndex &converter)
{
using namespace Tasking;
TreeStorage<LocatorMatcherTask::Storage> storage;
const auto onSetup = [=](AsyncTask<LocatorMatcherTask::OutputData> &async) {
async.setFutureSynchronizer(Internal::CppEditorPlugin::futureSynchronizer());
async.setConcurrentCallData(matchesFor, storage->input, type, converter);
};
const auto onDone = [storage](const AsyncTask<LocatorMatcherTask::OutputData> &async) {
if (async.isResultAvailable())
storage->output = async.result();
};
return {Async<LocatorMatcherTask::OutputData>(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);

View File

@@ -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