diff options
Diffstat (limited to 'tests/auto')
14 files changed, 362 insertions, 24 deletions
diff --git a/tests/auto/qmlls/modules/tst_qmlls_modules.cpp b/tests/auto/qmlls/modules/tst_qmlls_modules.cpp index 7ad4b4447e..533fccfe62 100644 --- a/tests/auto/qmlls/modules/tst_qmlls_modules.cpp +++ b/tests/auto/qmlls/modules/tst_qmlls_modules.cpp @@ -1945,8 +1945,8 @@ void tst_qmlls_modules::semanticHighlightingFull() { QFETCH(QString, filePath); const auto item = fileObject(testFile(filePath)); - QmlHighlighting::HighlightsContainer highlights; - const auto expectedData = QmlHighlighting::Utils::collectTokens(item, std::nullopt); + QmlHighlighting::HighlightsContainer highlights = QmlHighlighting::Utils::visitTokens(item, std::nullopt); + const auto expectedData = QmlHighlighting::Utils::encodeSemanticTokens(highlights); const auto uri = openFile(filePath); QVERIFY(uri); @@ -1988,13 +1988,13 @@ void tst_qmlls_modules::semanticHighlightingRange() QFETCH(QLspSpecification::Range, range); const auto item = fileObject(testFile(filePath)); - QmlHighlighting::HighlightsContainer highlights; 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 = QmlHighlighting::Utils::collectTokens( + QmlHighlighting::HighlightsContainer highlights = QmlHighlighting::Utils::visitTokens( item, QmlHighlighting::HighlightsRange{ startOffset, endOffset }); + const auto expectedData = QmlHighlighting::Utils::encodeSemanticTokens(highlights); const auto uri = openFile(filePath); QVERIFY(uri); @@ -2039,8 +2039,12 @@ void tst_qmlls_modules::semanticHighlightingDelta() const auto fileItem = fileObject(testFile(filePath)); const auto deltaFileItem = fileObject(testFile(deltaFilePath)); - auto fullDocumentSemanticTokensData = QmlHighlighting::Utils::collectTokens(fileItem, std::nullopt); - auto editedDocumentSemanticTokensData = QmlHighlighting::Utils::collectTokens(deltaFileItem, std::nullopt); + const auto fullDocumentSemanticTokens = QmlHighlighting::Utils::visitTokens(fileItem, std::nullopt); + const auto editedDocumentSemanticTokens = QmlHighlighting::Utils::visitTokens(deltaFileItem, std::nullopt); + auto fullDocumentSemanticTokensData = + QmlHighlighting::Utils::encodeSemanticTokens(fullDocumentSemanticTokens); + auto editedDocumentSemanticTokensData = + QmlHighlighting::Utils::encodeSemanticTokens(editedDocumentSemanticTokens); const auto expectedEdits = QmlHighlighting::Utils::computeDiff( fullDocumentSemanticTokensData, editedDocumentSemanticTokensData); diff --git a/tests/auto/qmlls/utils/data/highlights/highlightsShift.qml b/tests/auto/qmlls/utils/data/highlights/highlightsShift.qml new file mode 100644 index 0000000000..df4ffc69da --- /dev/null +++ b/tests/auto/qmlls/utils/data/highlights/highlightsShift.qml @@ -0,0 +1,8 @@ +import QtQuick +Item { + width: 100 + Rectangle { + width: 100 + height: 100 + } +} diff --git a/tests/auto/qmlls/utils/data/highlights/highlightsShift_consoleLog.qml b/tests/auto/qmlls/utils/data/highlights/highlightsShift_consoleLog.qml new file mode 100644 index 0000000000..b717634689 --- /dev/null +++ b/tests/auto/qmlls/utils/data/highlights/highlightsShift_consoleLog.qml @@ -0,0 +1,8 @@ +import QtQuick + +HasEnumAndAttachedType { + property var enumValue: 1 + Component.onCompleted: { + console.log(enumValue) + } +} diff --git a/tests/auto/qmlls/utils/data/highlights/highlightsShift_withComments.qml b/tests/auto/qmlls/utils/data/highlights/highlightsShift_withComments.qml new file mode 100644 index 0000000000..fddac941f6 --- /dev/null +++ b/tests/auto/qmlls/utils/data/highlights/highlightsShift_withComments.qml @@ -0,0 +1,11 @@ +import QtQuick + +HasEnumAndAttachedType { + property var enumValue: 1 + Component.onCompleted: { + console.log(enumValue) + } +} + +// This is a comment line +// Another comment line
\ No newline at end of file diff --git a/tests/auto/qmlls/utils/data/highlights/invalid/highlightsShift_consoleLog_del.qml b/tests/auto/qmlls/utils/data/highlights/invalid/highlightsShift_consoleLog_del.qml new file mode 100644 index 0000000000..63ace4b663 --- /dev/null +++ b/tests/auto/qmlls/utils/data/highlights/invalid/highlightsShift_consoleLog_del.qml @@ -0,0 +1,8 @@ +import QtQuick + +HasEnumAndAttachedType { + property var enumValue: 1 + Component.onCompleted: + console.log(enumValue) + } +} diff --git a/tests/auto/qmlls/utils/data/highlights/invalid/highlightsShift_del1.qml b/tests/auto/qmlls/utils/data/highlights/invalid/highlightsShift_del1.qml new file mode 100644 index 0000000000..ee722b9ce7 --- /dev/null +++ b/tests/auto/qmlls/utils/data/highlights/invalid/highlightsShift_del1.qml @@ -0,0 +1,8 @@ +imQuick +Item { + width: 100 + Rectangle { + width: 100 + height: 100 + } +} diff --git a/tests/auto/qmlls/utils/data/highlights/invalid/highlightsShift_del2.qml b/tests/auto/qmlls/utils/data/highlights/invalid/highlightsShift_del2.qml new file mode 100644 index 0000000000..c81451e306 --- /dev/null +++ b/tests/auto/qmlls/utils/data/highlights/invalid/highlightsShift_del2.qml @@ -0,0 +1,8 @@ +import QtQuick +Ite + width: 100 + Rectangle { + width: 100 + height: 100 + } +} diff --git a/tests/auto/qmlls/utils/data/highlights/invalid/highlightsShift_del3.qml b/tests/auto/qmlls/utils/data/highlights/invalid/highlightsShift_del3.qml new file mode 100644 index 0000000000..7e93d458d3 --- /dev/null +++ b/tests/auto/qmlls/utils/data/highlights/invalid/highlightsShift_del3.qml @@ -0,0 +1,8 @@ + QtQuick +Item { + width: 100 + Rectangle { + width: 100 + height: 100 + } +} diff --git a/tests/auto/qmlls/utils/data/highlights/invalid/highlightsShift_del4.qml b/tests/auto/qmlls/utils/data/highlights/invalid/highlightsShift_del4.qml new file mode 100644 index 0000000000..8e8e7f0475 --- /dev/null +++ b/tests/auto/qmlls/utils/data/highlights/invalid/highlightsShift_del4.qml @@ -0,0 +1,6 @@ +import QtQuick +Item { + width: 100 + Rectangle { + +} diff --git a/tests/auto/qmlls/utils/data/highlights/invalid/highlightsShift_del5.qml b/tests/auto/qmlls/utils/data/highlights/invalid/highlightsShift_del5.qml new file mode 100644 index 0000000000..9cf4c3804a --- /dev/null +++ b/tests/auto/qmlls/utils/data/highlights/invalid/highlightsShift_del5.qml @@ -0,0 +1,7 @@ +import QtQuick +Item { + width: 100 + Rectangle +height: 100 + } +} diff --git a/tests/auto/qmlls/utils/data/highlights/invalid/highlightsShift_del6.qml b/tests/auto/qmlls/utils/data/highlights/invalid/highlightsShift_del6.qml new file mode 100644 index 0000000000..5437541542 --- /dev/null +++ b/tests/auto/qmlls/utils/data/highlights/invalid/highlightsShift_del6.qml @@ -0,0 +1,6 @@ +import QtQuick +Item { + width: 100th: 100 + height: 100 + } +} diff --git a/tests/auto/qmlls/utils/data/highlights/invalid/highlightsShift_withComments_del.qml b/tests/auto/qmlls/utils/data/highlights/invalid/highlightsShift_withComments_del.qml new file mode 100644 index 0000000000..4bccec2ebe --- /dev/null +++ b/tests/auto/qmlls/utils/data/highlights/invalid/highlightsShift_withComments_del.qml @@ -0,0 +1,5 @@ +import QtQuick + + +// This is a comment line +// Another comment line
\ No newline at end of file diff --git a/tests/auto/qmlls/utils/tst_qmlls_highlighting.cpp b/tests/auto/qmlls/utils/tst_qmlls_highlighting.cpp index 6dae204bb0..49fe4e8c87 100644 --- a/tests/auto/qmlls/utils/tst_qmlls_highlighting.cpp +++ b/tests/auto/qmlls/utils/tst_qmlls_highlighting.cpp @@ -991,28 +991,28 @@ void tst_qmlls_highlighting::computeDiff() } } -void tst_qmlls_highlighting::enumCrash() +static QQmlJS::Dom::DomItem fileObject(const QString &filePath) { using namespace QQmlJS::Dom; - const auto fileObject = [](const QString &filePath) { - QFile f(filePath); - DomItem file; - if (!f.open(QIODevice::ReadOnly | QIODevice::Text)) - return file; - QString code = f.readAll(); - - QStringList dirs = { QLibraryInfo::path(QLibraryInfo::Qml2ImportsPath) }; - auto envPtr = DomEnvironment::create( - dirs, QQmlJS::Dom::DomEnvironment::Option::SingleThreaded, Extended); - envPtr->loadBuiltins(); - envPtr->loadFile(FileToLoad::fromMemory(envPtr, filePath, code), - [&file](Path, const DomItem &, const DomItem &newIt) { - file = newIt.fileObject(); - }); - envPtr->loadPendingDependencies(); + QFile f(filePath); + DomItem file; + if (!f.open(QIODevice::ReadOnly | QIODevice::Text)) return file; - }; + QString code = f.readAll(); + + QStringList dirs = { QLibraryInfo::path(QLibraryInfo::Qml2ImportsPath) }; + auto envPtr = DomEnvironment::create(dirs, QQmlJS::Dom::DomEnvironment::Option::SingleThreaded, + Extended); + envPtr->loadBuiltins(); + envPtr->loadFile( + FileToLoad::fromMemory(envPtr, filePath, code), + [&file](Path, const DomItem &, const DomItem &newIt) { file = newIt.fileObject(); }); + envPtr->loadPendingDependencies(); + return file; +}; +void tst_qmlls_highlighting::enumCrash() +{ const auto filePath = m_highlightingDataDir + "/enums_qtbug.qml"; const auto fileItem = fileObject(filePath); @@ -1021,4 +1021,253 @@ void tst_qmlls_highlighting::enumCrash() QVERIFY(!highlights.isEmpty()); } +void tst_qmlls_highlighting::shiftHighlights_data() +{ + QTest::addColumn<QmlHighlighting::HighlightsContainer>("lastValidHighlights"); + QTest::addColumn<QString>("lastValidCode"); + QTest::addColumn<QString>("currentCode"); + QTest::addColumn<QmlHighlighting::HighlightsContainer>("expectedHighlights"); + + const auto filePath = m_highlightingDataDir + "/highlightsShift.qml"; + const auto fileItem = fileObject(filePath); + const auto originalHighlights = QmlHighlighting::Utils::visitTokens(fileItem, std::nullopt); + const QString lastValidCode = fileItem.ownerAs<QQmlJS::Dom::QmlFile>()->code(); + + const auto editedCode = [&](const QString &file) -> QString { + const auto editedPath = m_highlightingDataDir + file; + QFile editedFile(editedPath); + if (!editedFile.open(QIODevice::ReadOnly | QIODevice::Text)) + return QString(); + return editedFile.readAll(); + }; + + // delete port Qt from import QtQuick + // Expect highlights are the same as the originals except Item token. + { + const QString currentCode = editedCode("/invalid/highlightsShift_del1.qml"); + + QmlHighlighting::HighlightsContainer expectedHighlights = originalHighlights; + expectedHighlights.remove(0); + expectedHighlights.remove(7); + const auto im = QQmlJS::SourceLocation(0, 2, 1, 1); // 'im' location + expectedHighlights[im.offset] = + HighlightToken(im, QmlHighlightKind::QmlKeyword, QmlHighlightModifier::None); + const auto quick = QQmlJS::SourceLocation(3, 5, 1, 3); // 'Quick' location + expectedHighlights[quick.offset] = + HighlightToken(quick, QmlHighlightKind::QmlImportId, QmlHighlightModifier::None); + + QTest::addRow("modify-line-without-lineshift-from-lhs-rhs") + << originalHighlights << lastValidCode << currentCode << expectedHighlights; + } + // modify Item { into Ite + // Expect highlights are the same as the originals except Item token. + { + const QString currentCode = editedCode("/invalid/highlightsShift_del2.qml"); + + QmlHighlighting::HighlightsContainer expectedHighlights = originalHighlights; + const auto itemNewLoc = QQmlJS::SourceLocation(15, 3, 2, 1); // 'Ite' location + expectedHighlights[itemNewLoc.offset] = + HighlightToken(itemNewLoc, QmlHighlightKind::QmlType, QmlHighlightModifier::None); + + QTest::addRow("modify-line-without-lineshift-from-rhs") + << originalHighlights << lastValidCode << currentCode << expectedHighlights; + } + // delete "import" from import QtQuick + // Expect highlights are the same as the originals QtQuick token should shift. + // and import should be gone. + { + const QString currentCode = editedCode("/invalid/highlightsShift_del3.qml"); + + QmlHighlighting::HighlightsContainer expectedHighlights = originalHighlights; + // remove import QtQuick + expectedHighlights.remove(0); + expectedHighlights.remove(7); + // insert QtQuick + const auto qtquickNewLoc = QQmlJS::SourceLocation(1, 7, 1, 2); + expectedHighlights[qtquickNewLoc.offset] = HighlightToken( + qtquickNewLoc, QmlHighlightKind::QmlImportId, QmlHighlightModifier::None); + + QTest::addRow("modify-line-without-lineshift-from-lhs") + << originalHighlights << lastValidCode << currentCode << expectedHighlights; + } + + // delete inner content of Rectangle, leave it in invalid state + { + const QString currentCode = editedCode("/invalid/highlightsShift_del4.qml"); + + QmlHighlighting::HighlightsContainer expectedHighlights = originalHighlights; + // remove Rectangle content tokens + expectedHighlights.remove(61); // width + expectedHighlights.remove(68); // 100 + expectedHighlights.remove(80); // height + expectedHighlights.remove(88); // 100 + + QTest::addRow("delete-multiline-no-shift") + << originalHighlights << lastValidCode << currentCode << expectedHighlights; + } + // delete width content of Rectangle, height should line shift up + { + const QString currentCode = editedCode("/invalid/highlightsShift_del5.qml"); + + QmlHighlighting::HighlightsContainer expectedHighlights = originalHighlights; + // remove Rectangle content tokens + expectedHighlights.remove(61); // width + expectedHighlights.remove(68); // 100 + + // height should line shift up, and shifts column + auto heightToken = expectedHighlights.take(80); + expectedHighlights.remove(80); + heightToken.loc.startLine = 5; + heightToken.loc.startColumn = 1; + heightToken.loc.offset = 51; + expectedHighlights[heightToken.loc.offset] = heightToken; + + auto numberToken = expectedHighlights.take(88); + expectedHighlights.remove(88); + numberToken.loc.startLine = 5; + numberToken.loc.startColumn = 9; + numberToken.loc.offset = 59; + expectedHighlights[numberToken.loc.offset] = numberToken; + QTest::addRow("delete-multiline-line-column-shift") + << originalHighlights << lastValidCode << currentCode << expectedHighlights; + } + // delete width content of Rectangle, height should line shift up, Rectangle should be erased + // th: 100 part of width should line up and start at the end of upper line + { + const QString currentCode = editedCode("/invalid/highlightsShift_del6.qml"); + + QmlHighlighting::HighlightsContainer expectedHighlights = originalHighlights; + // remove Rectangle content tokens + expectedHighlights.remove(41); // Rectangle + + // width + auto widthToken = expectedHighlights.take(61); + expectedHighlights.remove(61); + widthToken.loc.startLine = 3; + widthToken.loc.startColumn = 15; + widthToken.loc.offset = 36; + widthToken.loc.length = 2; // th part remained + expectedHighlights[widthToken.loc.offset] = widthToken; + // 100 + auto numberToken = expectedHighlights.take(68); + expectedHighlights.remove(68); + numberToken.loc.startLine = 3; + numberToken.loc.startColumn = 19; + numberToken.loc.offset = 40; + expectedHighlights[numberToken.loc.offset] = numberToken; + // height should line shift up + auto heightToken = expectedHighlights.take(80); + expectedHighlights.remove(80); + heightToken.loc.startLine = 4; + heightToken.loc.startColumn = 9; + heightToken.loc.offset = 52; + expectedHighlights[heightToken.loc.offset] = heightToken; + + auto heightNumber = expectedHighlights.take(88); + expectedHighlights.remove(88); + heightNumber.loc.startLine = 4; + heightNumber.loc.startColumn = 17; + heightNumber.loc.offset = 60; + expectedHighlights[heightNumber.loc.offset] = heightNumber; + + QTest::addRow("delete-multiline-line-column-shift-2") + << originalHighlights << lastValidCode << currentCode << expectedHighlights; + } + { // manual testing find: console.log(element) + const auto filePath = m_highlightingDataDir + "/highlightsShift_consoleLog.qml"; + const auto fileItem = fileObject(filePath); + const auto highlights = QmlHighlighting::Utils::visitTokens(fileItem, std::nullopt); + const QString validCode = fileItem.ownerAs<QQmlJS::Dom::QmlFile>()->code(); + const QString currentCode = editedCode("/invalid/highlightsShift_consoleLog_del.qml"); + + QmlHighlighting::HighlightsContainer expectedHighlights = highlights; + // console + auto consoleToken = expectedHighlights.take(108); + expectedHighlights.remove(108); + consoleToken.loc.offset = 107; + expectedHighlights[consoleToken.loc.offset] = consoleToken; + // log + auto logToken = expectedHighlights.take(116); + expectedHighlights.remove(116); + logToken.loc.offset = 115; + expectedHighlights[logToken.loc.offset] = logToken; + // enumValue + auto enumValueToken = expectedHighlights.take(120); + expectedHighlights.remove(120); + enumValueToken.loc.offset = 119; + expectedHighlights[enumValueToken.loc.offset] = enumValueToken; + + QTest::addRow("delete-shift-console-log") + << highlights << validCode << currentCode << expectedHighlights; + } + { // manual testing find: comments after deletion + const auto filePath = m_highlightingDataDir + "/highlightsShift_withComments.qml"; + const auto fileItem = fileObject(filePath); + const auto highlights = QmlHighlighting::Utils::visitTokens(fileItem, std::nullopt); + const QString validCode = fileItem.ownerAs<QQmlJS::Dom::QmlFile>()->code(); + const QString currentCode = editedCode("/invalid/highlightsShift_withComments_del.qml"); + + QmlHighlighting::HighlightsContainer expectedHighlights; + // import + expectedHighlights[0] = highlights[0]; + // QtQuick + expectedHighlights[7] = highlights[7]; + // commentline 1 + auto commentLine1 = QmlHighlighting::HighlightToken( + QQmlJS::SourceLocation(17, 25, 4, 1), + QmlHighlightKind::Comment, QmlHighlightModifier::None); + expectedHighlights[commentLine1.loc.offset] = commentLine1; + // commentline 2 + auto commentLine2 = QmlHighlighting::HighlightToken( + QQmlJS::SourceLocation(43, 23, 5, 1), + QmlHighlightKind::Comment, QmlHighlightModifier::None); + expectedHighlights[commentLine2.loc.offset] = commentLine2; + + QTest::addRow("delete-shift-comments-after-deletion") + << highlights << validCode << currentCode << expectedHighlights; + } +} + +void tst_qmlls_highlighting::shiftHighlights() +{ + QFETCH(QmlHighlighting::HighlightsContainer, lastValidHighlights); + QFETCH(QString, lastValidCode); + QFETCH(QString, currentCode); + QFETCH(QmlHighlighting::HighlightsContainer, expectedHighlights); + + HighlightsContainer actualHighlights = + QmlHighlighting::Utils::shiftHighlights(lastValidHighlights, lastValidCode, currentCode); + [&] { + const auto actualEncoded = QmlHighlighting::Utils::encodeSemanticTokens( + actualHighlights, QmlHighlighting::HighlightingMode::Default); + const auto expectedEncoded = QmlHighlighting::Utils::encodeSemanticTokens( + expectedHighlights, QmlHighlighting::HighlightingMode::Default); + QCOMPARE(actualEncoded, expectedEncoded); + }(); + + if (QTest::currentTestFailed()) { + auto [actual, expected] = + std::mismatch(actualHighlights.begin(), actualHighlights.end(), + expectedHighlights.begin(), expectedHighlights.end()); + + if (actual != actualHighlights.end() && expected != expectedHighlights.end()) { + + const auto msg = [](const QString &title, int actualValue, int expectedValue) { + return QString("%1 : [Actual %2, Expected %3]") + .arg(title) + .arg(actualValue) + .arg(expectedValue); + }; + qDebug() << msg("Offset", actual->loc.offset, expected->loc.offset); + qDebug() << msg("Length", actual->loc.length, expected->loc.length); + qDebug() << msg("StartLine", actual->loc.startLine, expected->loc.startLine); + qDebug() << msg("StartColumn", actual->loc.startColumn, expected->loc.startColumn); + qDebug() << msg("Kind", static_cast<int>(actual->kind), + static_cast<int>(expected->kind)); + qDebug() << msg("Modifiers", static_cast<int>(actual->modifiers), + static_cast<int>(expected->modifiers)); + } + } +} + 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 42a0344a65..f7dc03ac00 100644 --- a/tests/auto/qmlls/utils/tst_qmlls_highlighting.h +++ b/tests/auto/qmlls/utils/tst_qmlls_highlighting.h @@ -32,6 +32,8 @@ private slots: void computeDiff(); void enumCrash(); + void shiftHighlights_data(); + void shiftHighlights(); private: QString m_highlightingDataDir; |
