CppLocatorFilter: Add cppCurrentDocumentMatcher()

Add also a test for it.

Change-Id: I324b1a2cbe89c0a1258dde93524689cb85e06737
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-11 16:03:41 +02:00
parent 0b5db8e558
commit 64f946445c
6 changed files with 178 additions and 6 deletions

View File

@@ -148,7 +148,8 @@ class LocatorMatcherPrivate;
enum class MatcherType {
AllSymbols,
Classes,
Functions
Functions,
CurrentDocumentSymbols
};
class CORE_EXPORT LocatorMatcher final : public QObject

View File

@@ -52,7 +52,7 @@ void CppCurrentDocumentFilter::makeAuxiliary()
}
QList<LocatorFilterEntry> CppCurrentDocumentFilter::matchesFor(
QFutureInterface<LocatorFilterEntry> &future, const QString & entry)
QFutureInterface<LocatorFilterEntry> &future, const QString &entry)
{
const QRegularExpression regexp = createRegExp(entry);
if (!regexp.isValid())
@@ -180,7 +180,7 @@ QList<IndexItem::Ptr> CppCurrentDocumentFilter::itemsOfCurrentDocument()
const Snapshot snapshot = m_modelManager->snapshot();
if (const Document::Ptr thisDocument = snapshot.document(m_currentFileName)) {
IndexItem::Ptr rootNode = search(thisDocument);
rootNode->visitAllChildren([&](const IndexItem::Ptr &info) -> IndexItem::VisitorResult {
rootNode->visitAllChildren([&](const IndexItem::Ptr &info) {
m_itemsOfCurrentDoc.append(info);
return IndexItem::Recurse;
});

View File

@@ -7,13 +7,19 @@
#include "cppeditorplugin.h"
#include "cppeditortr.h"
#include "cpplocatordata.h"
#include "cppmodelmanager.h"
#include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/editormanager/ieditor.h>
#include <utils/algorithm.h>
#include <utils/asynctask.h>
#include <utils/fuzzymatcher.h>
#include <QRegularExpression>
using namespace Core;
using namespace CPlusPlus;
using namespace Utils;
namespace CppEditor {
@@ -163,6 +169,152 @@ LocatorMatcherTask cppFunctionMatcher()
return locatorMatcher(IndexItem::Function, converter);
}
QList<IndexItem::Ptr> itemsOfCurrentDocument(const FilePath &currentFileName)
{
if (currentFileName.isEmpty())
return {};
QList<IndexItem::Ptr> results;
const Snapshot snapshot = CppModelManager::instance()->snapshot();
if (const Document::Ptr thisDocument = snapshot.document(currentFileName)) {
SearchSymbols search;
search.setSymbolsToSearchFor(SymbolSearcher::Declarations |
SymbolSearcher::Enums |
SymbolSearcher::Functions |
SymbolSearcher::Classes);
IndexItem::Ptr rootNode = search(thisDocument);
rootNode->visitAllChildren([&](const IndexItem::Ptr &info) {
results.append(info);
return IndexItem::Recurse;
});
}
return results;
}
LocatorFilterEntry::HighlightInfo highlightInfo(const QRegularExpressionMatch &match,
LocatorFilterEntry::HighlightInfo::DataType dataType)
{
const FuzzyMatcher::HighlightingPositions positions =
FuzzyMatcher::highlightingPositions(match);
return LocatorFilterEntry::HighlightInfo(positions.starts, positions.lengths, dataType);
}
void matchesForCurrentDocument(QPromise<LocatorMatcherTask::OutputData> &promise,
const QString &entry, const FilePath &currentFileName)
{
const QRegularExpression regexp = FuzzyMatcher::createRegExp(entry, Qt::CaseInsensitive, false);
if (!regexp.isValid())
return;
struct Entry
{
LocatorFilterEntry entry;
IndexItem::Ptr info;
};
QList<Entry> goodEntries;
QList<Entry> betterEntries;
const QList<IndexItem::Ptr> items = itemsOfCurrentDocument(currentFileName);
for (const IndexItem::Ptr &info : items) {
if (promise.isCanceled())
break;
QString matchString = info->symbolName();
if (info->type() == IndexItem::Declaration)
matchString = info->representDeclaration();
else if (info->type() == IndexItem::Function)
matchString += info->symbolType();
QRegularExpressionMatch match = regexp.match(matchString);
if (match.hasMatch()) {
const bool betterMatch = match.capturedStart() == 0;
QString name = matchString;
QString extraInfo = info->symbolScope();
if (info->type() == IndexItem::Function) {
if (info->unqualifiedNameAndScope(matchString, &name, &extraInfo)) {
name += info->symbolType();
match = regexp.match(name);
}
}
// TODO: Passing nullptr for filter -> accept won't work now. Replace with accept function.
LocatorFilterEntry filterEntry(nullptr, name);
filterEntry.displayIcon = info->icon();
filterEntry.linkForEditor = {info->filePath(), info->line(), info->column()};
filterEntry.extraInfo = extraInfo;
if (match.hasMatch()) {
filterEntry.highlightInfo = highlightInfo(match,
LocatorFilterEntry::HighlightInfo::DisplayName);
} else {
match = regexp.match(extraInfo);
filterEntry.highlightInfo =
highlightInfo(match, LocatorFilterEntry::HighlightInfo::ExtraInfo);
}
if (betterMatch)
betterEntries.append({filterEntry, info});
else
goodEntries.append({filterEntry, info});
}
}
// entries are unsorted by design!
betterEntries += goodEntries;
QHash<QString, QList<Entry>> possibleDuplicates;
for (const Entry &e : std::as_const(betterEntries))
possibleDuplicates[e.info->scopedSymbolName() + e.info->symbolType()] << e;
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 IndexItem::Ptr info = candidate.info;
if (info->type() != IndexItem::Function)
break;
if (info->isFunctionDefinition())
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(betterEntries, [&decl](const Entry &e) {
return e.info == decl.info;
});
}
}
}
promise.addResult(Utils::transform(betterEntries,
[](const Entry &entry) { return entry.entry; }));
}
FilePath currentFileName()
{
IEditor *currentEditor = EditorManager::currentEditor();
return currentEditor ? currentEditor->document()->filePath() : FilePath();
}
LocatorMatcherTask cppCurrentDocumentMatcher()
{
using namespace Tasking;
TreeStorage<LocatorMatcherTask::Storage> storage;
const auto onSetup = [=](AsyncTask<LocatorMatcherTask::OutputData> &async) {
async.setFutureSynchronizer(Internal::CppEditorPlugin::futureSynchronizer());
async.setConcurrentCallData(matchesForCurrentDocument, storage->input, currentFileName());
};
const auto onDone = [storage](const AsyncTask<LocatorMatcherTask::OutputData> &async) {
if (async.isResultAvailable())
storage->output = async.result();
};
return {Async<LocatorMatcherTask::OutputData>(onSetup, onDone, onDone), storage};
}
CppLocatorFilter::CppLocatorFilter()
{
setId(Constants::LOCATOR_FILTER_ID);

View File

@@ -13,6 +13,7 @@ namespace CppEditor {
Core::LocatorMatcherTask CPPEDITOR_EXPORT cppAllSymbolsMatcher();
Core::LocatorMatcherTask CPPEDITOR_EXPORT cppClassMatcher();
Core::LocatorMatcherTask CPPEDITOR_EXPORT cppFunctionMatcher();
Core::LocatorMatcherTask CPPEDITOR_EXPORT cppCurrentDocumentMatcher();
class CPPEDITOR_EXPORT CppLocatorFilter : public Core::ILocatorFilter
{

View File

@@ -77,6 +77,7 @@ class CppCurrentDocumentFilterTestCase
{
public:
CppCurrentDocumentFilterTestCase(const FilePath &filePath,
const QList<LocatorMatcherTask> &matchers,
const ResultDataList &expectedResults,
const QString &searchText = QString())
: BasicLocatorFilterTest(CppModelManager::instance()->currentDocumentFilter())
@@ -85,7 +86,16 @@ public:
QVERIFY(succeededSoFar());
QVERIFY(!m_filePath.isEmpty());
ResultDataList results = ResultData::fromFilterEntryList(matchesFor(searchText));
const auto runMatcher = [this, matchers, searchText] {
CppCurrentDocumentFilterTestCase::doBeforeLocatorRun();
const auto result = LocatorMatcher::runBlocking(matchers, searchText);
CppCurrentDocumentFilterTestCase::doAfterLocatorRun();
return result;
};
const QList<LocatorFilterEntry> entries = matchers.isEmpty() ? matchesFor(searchText)
: runMatcher();
ResultDataList results = ResultData::fromFilterEntryList(entries);
if (debug) {
ResultData::printFilterEntries(expectedResults, "Expected:");
ResultData::printFilterEntries(results, "Results:");
@@ -371,7 +381,10 @@ void LocatorFilterTest::testCurrentDocumentFilter()
ResultData("main()", ""),
};
CppCurrentDocumentFilterTestCase(testFile, expectedResults);
CppCurrentDocumentFilterTestCase(testFile, {}, expectedResults);
CppCurrentDocumentFilterTestCase(testFile,
LocatorMatcher::matchers(MatcherType::CurrentDocumentSymbols),
expectedResults);
}
void LocatorFilterTest::testCurrentDocumentHighlighting()
@@ -395,7 +408,10 @@ void LocatorFilterTest::testCurrentDocumentHighlighting()
Tests::VerifyCleanCppModelManager verify;
CppCurrentDocumentFilterTestCase(testFile, expectedResults, searchText);
CppCurrentDocumentFilterTestCase(testFile, {}, expectedResults, searchText);
CppCurrentDocumentFilterTestCase(testFile,
LocatorMatcher::matchers(MatcherType::CurrentDocumentSymbols),
expectedResults, searchText);
}
void LocatorFilterTest::testFunctionsFilterHighlighting()

View File

@@ -903,6 +903,8 @@ void CppModelManager::initCppTools()
[] { return QList{CppEditor::cppClassMatcher()}; });
LocatorMatcher::addMatcherCreator(MatcherType::Functions,
[] { return QList{CppEditor::cppFunctionMatcher()}; });
LocatorMatcher::addMatcherCreator(MatcherType::CurrentDocumentSymbols,
[] { return QList{CppEditor::cppCurrentDocumentMatcher()}; });
}
CppModelManager::CppModelManager()