diff options
author | Semih Yavuz <semih.yavuz@qt.io> | 2024-04-30 12:43:11 +0200 |
---|---|---|
committer | Semih Yavuz <semih.yavuz@qt.io> | 2024-05-07 13:35:56 +0200 |
commit | 04751e1cf86647554d69c014c2c423f3c6c89ead (patch) | |
tree | 406c87d2fd4f0d0426683e216234ee4596bd1a4e /tests | |
parent | dcd948c0bbbef9bd9f01d6b401f466aaaa14ad84 (diff) |
qmlls: Add range support for semantic highlighting
Clients might ask only a range of the text document to be highlighted.
Then, we should perform highlighting for that particular range.
Introduce an optional data member m_range in the highlighting visitor.
If m_range has value, then highlight the current item only by checking
if it is overlapping with the requested range.
Task-number: QTBUG-120000
Change-Id: I635765d3d8831f7717edb96331db414f3813308f
Reviewed-by: Sami Shalayel <sami.shalayel@qt.io>
Diffstat (limited to 'tests')
-rw-r--r-- | tests/auto/qmlls/modules/tst_qmlls_modules.cpp | 100 | ||||
-rw-r--r-- | tests/auto/qmlls/modules/tst_qmlls_modules.h | 2 | ||||
-rw-r--r-- | tests/auto/qmlls/utils/tst_qmlls_highlighting.cpp | 28 | ||||
-rw-r--r-- | tests/auto/qmlls/utils/tst_qmlls_highlighting.h | 3 |
4 files changed, 107 insertions, 26 deletions
diff --git a/tests/auto/qmlls/modules/tst_qmlls_modules.cpp b/tests/auto/qmlls/modules/tst_qmlls_modules.cpp index 717b61cc28..6b9eb87d7d 100644 --- a/tests/auto/qmlls/modules/tst_qmlls_modules.cpp +++ b/tests/auto/qmlls/modules/tst_qmlls_modules.cpp @@ -1495,6 +1495,31 @@ void tst_qmlls_modules::quickFixes() QTRY_VERIFY_WITH_TIMEOUT(codeActionOk, 5000); } +static QQmlJS::Dom::DomItem fileObject(const QString &filePath) +{ + QFile f(filePath); + DomItem file; + if (!f.open(QIODevice::ReadOnly)) + return file; + QString code = f.readAll(); + QQmlJS::Dom::DomCreationOptions options; + options.setFlag(QQmlJS::Dom::DomCreationOption::WithScriptExpressions); + options.setFlag(QQmlJS::Dom::DomCreationOption::WithSemanticAnalysis); + options.setFlag(QQmlJS::Dom::DomCreationOption::WithRecovery); + + QStringList dirs = {QLibraryInfo::path(QLibraryInfo::Qml2ImportsPath)}; + auto envPtr = QQmlJS::Dom::DomEnvironment::create(dirs, + QQmlJS::Dom::DomEnvironment::Option::SingleThreaded + | QQmlJS::Dom::DomEnvironment::Option::NoDependencies, options); + envPtr->loadBuiltins(); + envPtr->loadFile(QQmlJS::Dom::FileToLoad::fromMemory(envPtr, filePath, code), + [&file](QQmlJS::Dom::Path, const QQmlJS::Dom::DomItem &, const QQmlJS::Dom::DomItem &newIt) { + file = newIt.fileObject(); + }); + envPtr->loadPendingDependencies(); + return file; +}; + void tst_qmlls_modules::semanticHighlightingFull_data() { QTest::addColumn<QString>("filePath"); @@ -1504,39 +1529,63 @@ void tst_qmlls_modules::semanticHighlightingFull_data() void tst_qmlls_modules::semanticHighlightingFull() { QFETCH(QString, filePath); + const auto item = fileObject(testFile(filePath)); + Highlights highlights; + const auto expectedData = highlights.collectTokens(item, std::nullopt); - const auto fileObject = [](const QString &filePath){ - QFile f(filePath); - DomItem file; - if (!f.open(QIODevice::ReadOnly)) - return file; - QString code = f.readAll(); - QQmlJS::Dom::DomCreationOptions options; - options.setFlag(QQmlJS::Dom::DomCreationOption::WithScriptExpressions); - options.setFlag(QQmlJS::Dom::DomCreationOption::WithSemanticAnalysis); - options.setFlag(QQmlJS::Dom::DomCreationOption::WithRecovery); - - QStringList dirs = {QLibraryInfo::path(QLibraryInfo::Qml2ImportsPath)}; - auto envPtr = QQmlJS::Dom::DomEnvironment::create(dirs, - QQmlJS::Dom::DomEnvironment::Option::SingleThreaded - | QQmlJS::Dom::DomEnvironment::Option::NoDependencies, options); - envPtr->loadBuiltins(); - envPtr->loadFile(QQmlJS::Dom::FileToLoad::fromMemory(envPtr, filePath, code), - [&file](QQmlJS::Dom::Path, const QQmlJS::Dom::DomItem &, const QQmlJS::Dom::DomItem &newIt) { - file = newIt.fileObject(); - }); - envPtr->loadPendingDependencies(); - return file; + const auto uri = openFile(filePath); + QVERIFY(uri); + QLspSpecification::SemanticTokensParams params; + params.textDocument.uri = *uri; + std::shared_ptr<bool> didFinish = std::make_shared<bool>(false); + const auto cleanup = [didFinish]() { *didFinish = true; }; + + auto &&responseHandler = [&](auto res) { + QScopeGuard callAtExit(cleanup); + const auto *const result = std::get_if<QLspSpecification::SemanticTokens>(&res); + QVERIFY(result); + QList<int> data = result->data; + QCOMPARE(data.size(), expectedData.size()); + QCOMPARE(data, expectedData); }; + auto &&errorHandler = [&](auto &error) { + QScopeGuard callAtExit(cleanup); + ProtocolBase::defaultResponseErrorHandler(error); + QVERIFY2(false, "error occurred on full semantic tokens"); + }; + + m_protocol->requestSemanticTokens(params, std::move(responseHandler), std::move(errorHandler)); + QTRY_VERIFY_WITH_TIMEOUT(*didFinish, 10000); +} + +void tst_qmlls_modules::semanticHighlightingRange_data() +{ + QTest::addColumn<QString>("filePath"); + QTest::addColumn<QLspSpecification::Range>("range"); + QTest::addRow("bigfile") << u"highlighting/bigFile.qml"_s + << QLspSpecification::Range{ { 6, 0 }, { 15, 0 } }; +} + +void tst_qmlls_modules::semanticHighlightingRange() +{ + QFETCH(QString, filePath); + QFETCH(QLspSpecification::Range, range); + const auto item = fileObject(testFile(filePath)); Highlights highlights; - const auto expectedData = highlights.collectTokens(item); + const auto qmlFile = item.as<QQmlJS::Dom::QmlFile>(); + const auto code = qmlFile->code(); + const int startOffset = int(QQmlLSUtils::textOffsetFrom(code, range.start.line, range.end.character)); + const int endOffset = int(QQmlLSUtils::textOffsetFrom(code, range.end.line, range.end.character)); + const auto expectedData = highlights.collectTokens(item, HighlightsRange{startOffset, endOffset}); const auto uri = openFile(filePath); QVERIFY(uri); - QLspSpecification::SemanticTokensParams params; + QLspSpecification::SemanticTokensRangeParams params; params.textDocument.uri = *uri; + params.range = range; + std::shared_ptr<bool> didFinish = std::make_shared<bool>(false); const auto cleanup = [didFinish]() { *didFinish = true; }; @@ -1555,7 +1604,8 @@ void tst_qmlls_modules::semanticHighlightingFull() QVERIFY2(false, "error occurred on full semantic tokens"); }; - m_protocol->requestSemanticTokens(params, std::move(responseHandler), std::move(errorHandler)); + m_protocol->requestSemanticTokensRange(params, std::move(responseHandler), + std::move(errorHandler)); QTRY_VERIFY_WITH_TIMEOUT(*didFinish, 10000); } diff --git a/tests/auto/qmlls/modules/tst_qmlls_modules.h b/tests/auto/qmlls/modules/tst_qmlls_modules.h index 5ffbce6c5b..aa6263ccc6 100644 --- a/tests/auto/qmlls/modules/tst_qmlls_modules.h +++ b/tests/auto/qmlls/modules/tst_qmlls_modules.h @@ -71,6 +71,8 @@ private slots: void checkQuickSnippets(); void semanticHighlightingFull_data(); void semanticHighlightingFull(); + void semanticHighlightingRange_data(); + void semanticHighlightingRange(); private: QProcess m_server; diff --git a/tests/auto/qmlls/utils/tst_qmlls_highlighting.cpp b/tests/auto/qmlls/utils/tst_qmlls_highlighting.cpp index 203f8a8390..fe5d83c53d 100644 --- a/tests/auto/qmlls/utils/tst_qmlls_highlighting.cpp +++ b/tests/auto/qmlls/utils/tst_qmlls_highlighting.cpp @@ -501,7 +501,7 @@ void tst_qmlls_highlighting::highlights() QFETCH(Token, expectedHighlightedToken); Highlights h; - HighlightingVisitor hv(h); + HighlightingVisitor hv(h, std::nullopt); fileItem.visitTree(QQmlJS::Dom::Path(), hv, VisitOption::Default, emptyChildrenVisitor, emptyChildrenVisitor); @@ -513,4 +513,30 @@ void tst_qmlls_highlighting::highlights() QCOMPARE(highlights.value(expectedHighlightedToken.offset), expectedHighlightedToken); } +void tst_qmlls_highlighting::rangeOverlapsWithSourceLocation_data() +{ + QTest::addColumn<QQmlJS::SourceLocation>("sourceLocation"); + QTest::addColumn<HighlightsRange>("range"); + QTest::addColumn<bool>("overlaps"); + + QTest::addRow("sl-inside-range") + << QQmlJS::SourceLocation(5, 1, 1, 1) << HighlightsRange{ 0, 100 } << true; + QTest::addRow("sl-exceeds-rightBoundRange") + << QQmlJS::SourceLocation(5, 1000, 1, 1) << HighlightsRange{ 0, 100 } << true; + QTest::addRow("sl-exceeds-leftRightBoundRange") + << QQmlJS::SourceLocation(5, 1000, 1, 1) << HighlightsRange{ 8, 100 } << true; + QTest::addRow("sl-exceeds-leftBoundRange") + << QQmlJS::SourceLocation(5, 100, 1, 1) << HighlightsRange{ 8, 1000 } << true; + QTest::addRow("no-overlaps") << QQmlJS::SourceLocation(5, 100, 1, 1) + << HighlightsRange{ 8000, 100000 } << false; +} + +void tst_qmlls_highlighting::rangeOverlapsWithSourceLocation() +{ + QFETCH(QQmlJS::SourceLocation, sourceLocation); + QFETCH(HighlightsRange, range); + QFETCH(bool, overlaps); + QVERIFY(overlaps == HighlightingUtils::rangeOverlapsWithSourceLocation(sourceLocation, range)); +} + QTEST_MAIN(tst_qmlls_highlighting) diff --git a/tests/auto/qmlls/utils/tst_qmlls_highlighting.h b/tests/auto/qmlls/utils/tst_qmlls_highlighting.h index 7e6c6431ac..f9d2b24afe 100644 --- a/tests/auto/qmlls/utils/tst_qmlls_highlighting.h +++ b/tests/auto/qmlls/utils/tst_qmlls_highlighting.h @@ -22,6 +22,9 @@ private slots: void highlights_data(); void highlights(); + void rangeOverlapsWithSourceLocation_data(); + void rangeOverlapsWithSourceLocation(); + private: QString m_highlightingDataDir; }; |