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 {
|
enum class MatcherType {
|
||||||
AllSymbols,
|
AllSymbols,
|
||||||
Classes,
|
Classes,
|
||||||
Functions
|
Functions,
|
||||||
|
CurrentDocumentSymbols
|
||||||
};
|
};
|
||||||
|
|
||||||
class CORE_EXPORT LocatorMatcher final : public QObject
|
class CORE_EXPORT LocatorMatcher final : public QObject
|
||||||
|
@@ -180,7 +180,7 @@ QList<IndexItem::Ptr> CppCurrentDocumentFilter::itemsOfCurrentDocument()
|
|||||||
const Snapshot snapshot = m_modelManager->snapshot();
|
const Snapshot snapshot = m_modelManager->snapshot();
|
||||||
if (const Document::Ptr thisDocument = snapshot.document(m_currentFileName)) {
|
if (const Document::Ptr thisDocument = snapshot.document(m_currentFileName)) {
|
||||||
IndexItem::Ptr rootNode = search(thisDocument);
|
IndexItem::Ptr rootNode = search(thisDocument);
|
||||||
rootNode->visitAllChildren([&](const IndexItem::Ptr &info) -> IndexItem::VisitorResult {
|
rootNode->visitAllChildren([&](const IndexItem::Ptr &info) {
|
||||||
m_itemsOfCurrentDoc.append(info);
|
m_itemsOfCurrentDoc.append(info);
|
||||||
return IndexItem::Recurse;
|
return IndexItem::Recurse;
|
||||||
});
|
});
|
||||||
|
@@ -7,13 +7,19 @@
|
|||||||
#include "cppeditorplugin.h"
|
#include "cppeditorplugin.h"
|
||||||
#include "cppeditortr.h"
|
#include "cppeditortr.h"
|
||||||
#include "cpplocatordata.h"
|
#include "cpplocatordata.h"
|
||||||
|
#include "cppmodelmanager.h"
|
||||||
|
|
||||||
|
#include <coreplugin/editormanager/editormanager.h>
|
||||||
|
#include <coreplugin/editormanager/ieditor.h>
|
||||||
|
|
||||||
#include <utils/algorithm.h>
|
#include <utils/algorithm.h>
|
||||||
#include <utils/asynctask.h>
|
#include <utils/asynctask.h>
|
||||||
|
#include <utils/fuzzymatcher.h>
|
||||||
|
|
||||||
#include <QRegularExpression>
|
#include <QRegularExpression>
|
||||||
|
|
||||||
using namespace Core;
|
using namespace Core;
|
||||||
|
using namespace CPlusPlus;
|
||||||
using namespace Utils;
|
using namespace Utils;
|
||||||
|
|
||||||
namespace CppEditor {
|
namespace CppEditor {
|
||||||
@@ -163,6 +169,152 @@ LocatorMatcherTask cppFunctionMatcher()
|
|||||||
return locatorMatcher(IndexItem::Function, converter);
|
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()
|
CppLocatorFilter::CppLocatorFilter()
|
||||||
{
|
{
|
||||||
setId(Constants::LOCATOR_FILTER_ID);
|
setId(Constants::LOCATOR_FILTER_ID);
|
||||||
|
@@ -13,6 +13,7 @@ namespace CppEditor {
|
|||||||
Core::LocatorMatcherTask CPPEDITOR_EXPORT cppAllSymbolsMatcher();
|
Core::LocatorMatcherTask CPPEDITOR_EXPORT cppAllSymbolsMatcher();
|
||||||
Core::LocatorMatcherTask CPPEDITOR_EXPORT cppClassMatcher();
|
Core::LocatorMatcherTask CPPEDITOR_EXPORT cppClassMatcher();
|
||||||
Core::LocatorMatcherTask CPPEDITOR_EXPORT cppFunctionMatcher();
|
Core::LocatorMatcherTask CPPEDITOR_EXPORT cppFunctionMatcher();
|
||||||
|
Core::LocatorMatcherTask CPPEDITOR_EXPORT cppCurrentDocumentMatcher();
|
||||||
|
|
||||||
class CPPEDITOR_EXPORT CppLocatorFilter : public Core::ILocatorFilter
|
class CPPEDITOR_EXPORT CppLocatorFilter : public Core::ILocatorFilter
|
||||||
{
|
{
|
||||||
|
@@ -77,6 +77,7 @@ class CppCurrentDocumentFilterTestCase
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CppCurrentDocumentFilterTestCase(const FilePath &filePath,
|
CppCurrentDocumentFilterTestCase(const FilePath &filePath,
|
||||||
|
const QList<LocatorMatcherTask> &matchers,
|
||||||
const ResultDataList &expectedResults,
|
const ResultDataList &expectedResults,
|
||||||
const QString &searchText = QString())
|
const QString &searchText = QString())
|
||||||
: BasicLocatorFilterTest(CppModelManager::instance()->currentDocumentFilter())
|
: BasicLocatorFilterTest(CppModelManager::instance()->currentDocumentFilter())
|
||||||
@@ -85,7 +86,16 @@ public:
|
|||||||
QVERIFY(succeededSoFar());
|
QVERIFY(succeededSoFar());
|
||||||
QVERIFY(!m_filePath.isEmpty());
|
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) {
|
if (debug) {
|
||||||
ResultData::printFilterEntries(expectedResults, "Expected:");
|
ResultData::printFilterEntries(expectedResults, "Expected:");
|
||||||
ResultData::printFilterEntries(results, "Results:");
|
ResultData::printFilterEntries(results, "Results:");
|
||||||
@@ -371,7 +381,10 @@ void LocatorFilterTest::testCurrentDocumentFilter()
|
|||||||
ResultData("main()", ""),
|
ResultData("main()", ""),
|
||||||
};
|
};
|
||||||
|
|
||||||
CppCurrentDocumentFilterTestCase(testFile, expectedResults);
|
CppCurrentDocumentFilterTestCase(testFile, {}, expectedResults);
|
||||||
|
CppCurrentDocumentFilterTestCase(testFile,
|
||||||
|
LocatorMatcher::matchers(MatcherType::CurrentDocumentSymbols),
|
||||||
|
expectedResults);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LocatorFilterTest::testCurrentDocumentHighlighting()
|
void LocatorFilterTest::testCurrentDocumentHighlighting()
|
||||||
@@ -395,7 +408,10 @@ void LocatorFilterTest::testCurrentDocumentHighlighting()
|
|||||||
|
|
||||||
Tests::VerifyCleanCppModelManager verify;
|
Tests::VerifyCleanCppModelManager verify;
|
||||||
|
|
||||||
CppCurrentDocumentFilterTestCase(testFile, expectedResults, searchText);
|
CppCurrentDocumentFilterTestCase(testFile, {}, expectedResults, searchText);
|
||||||
|
CppCurrentDocumentFilterTestCase(testFile,
|
||||||
|
LocatorMatcher::matchers(MatcherType::CurrentDocumentSymbols),
|
||||||
|
expectedResults, searchText);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LocatorFilterTest::testFunctionsFilterHighlighting()
|
void LocatorFilterTest::testFunctionsFilterHighlighting()
|
||||||
|
@@ -903,6 +903,8 @@ void CppModelManager::initCppTools()
|
|||||||
[] { return QList{CppEditor::cppClassMatcher()}; });
|
[] { return QList{CppEditor::cppClassMatcher()}; });
|
||||||
LocatorMatcher::addMatcherCreator(MatcherType::Functions,
|
LocatorMatcher::addMatcherCreator(MatcherType::Functions,
|
||||||
[] { return QList{CppEditor::cppFunctionMatcher()}; });
|
[] { return QList{CppEditor::cppFunctionMatcher()}; });
|
||||||
|
LocatorMatcher::addMatcherCreator(MatcherType::CurrentDocumentSymbols,
|
||||||
|
[] { return QList{CppEditor::cppCurrentDocumentMatcher()}; });
|
||||||
}
|
}
|
||||||
|
|
||||||
CppModelManager::CppModelManager()
|
CppModelManager::CppModelManager()
|
||||||
|
Reference in New Issue
Block a user