forked from qt-creator/qt-creator
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:
@@ -148,7 +148,8 @@ class LocatorMatcherPrivate;
|
||||
enum class MatcherType {
|
||||
AllSymbols,
|
||||
Classes,
|
||||
Functions
|
||||
Functions,
|
||||
CurrentDocumentSymbols
|
||||
};
|
||||
|
||||
class CORE_EXPORT LocatorMatcher final : public QObject
|
||||
|
@@ -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;
|
||||
});
|
||||
|
@@ -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 ¤tFileName)
|
||||
{
|
||||
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 ¤tFileName)
|
||||
{
|
||||
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);
|
||||
|
@@ -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
|
||||
{
|
||||
|
@@ -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()
|
||||
|
@@ -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()
|
||||
|
Reference in New Issue
Block a user