/**************************************************************************** ** ** Copyright (C) 2021 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qt Creator. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ****************************************************************************/ #include "clangdtests.h" #include "clangautomationutils.h" #include "clangbatchfileprocessor.h" #include "../clangdclient.h" #include "../clangmodelmanagersupport.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace CPlusPlus; using namespace Core; using namespace CppTools::Tests; using namespace ProjectExplorer; using namespace TextEditor; namespace ClangCodeModel { namespace Internal { namespace Tests { using Range = std::tuple; } // namespace Tests } // namespace Internal } // namespace ClangCodeModel Q_DECLARE_METATYPE(ClangCodeModel::Internal::Tests::Range) namespace ClangCodeModel { namespace Internal { namespace Tests { ClangdTest::~ClangdTest() { if (m_project) ProjectExplorerPlugin::unloadProject(m_project); delete m_projectDir; } Utils::FilePath ClangdTest::filePath(const QString &fileName) const { return Utils::FilePath::fromString(m_projectDir->absolutePath(fileName.toLocal8Bit())); } void ClangdTest::initTestCase() { const QString clangdFromEnv = qEnvironmentVariable("QTC_CLANGD"); if (!clangdFromEnv.isEmpty()) CppTools::ClangdSettings::setClangdFilePath(Utils::FilePath::fromString(clangdFromEnv)); const auto clangd = CppTools::ClangdSettings::instance().clangdFilePath(); if (clangd.isEmpty() || !clangd.exists()) QSKIP("clangd binary not found"); CppTools::ClangdSettings::setUseClangd(true); // Find suitable kit. m_kit = Utils::findOr(KitManager::kits(), nullptr, [](const Kit *k) { return k->isValid() && QtSupport::QtKitAspect::qtVersion(k); }); if (!m_kit) QSKIP("The test requires at least one valid kit with a valid Qt"); // Copy project out of qrc file, open it, and set up target. m_projectDir = new TemporaryCopiedDir(qrcPath(QFileInfo(m_projectFileName) .baseName().toLocal8Bit())); QVERIFY(m_projectDir->isValid()); const auto openProjectResult = ProjectExplorerPlugin::openProject( Utils::FilePath::fromString(m_projectDir->absolutePath(m_projectFileName.toUtf8()))); QVERIFY2(openProjectResult, qPrintable(openProjectResult.errorMessage())); m_project = openProjectResult.project(); m_project->configureAsExampleProject(m_kit); // Setting up the project should result in a clangd client being created. // Wait until that has happened. const auto modelManagerSupport = ClangModelManagerSupport::instance(); m_client = modelManagerSupport->clientForProject(openProjectResult.project()); if (!m_client) { QVERIFY(waitForSignalOrTimeout(modelManagerSupport, &ClangModelManagerSupport::createdClient, timeOutInMs())); m_client = modelManagerSupport->clientForProject(m_project); } QVERIFY(m_client); m_client->enableTesting(); // Wait until the client is fully initialized, i.e. it's completed the handshake // with the server. if (!m_client->reachable()) QVERIFY(waitForSignalOrTimeout(m_client, &ClangdClient::initialized, timeOutInMs())); QVERIFY(m_client->reachable()); // The kind of AST support we need was introduced in LLVM 13. if (m_minVersion != -1 && m_client->versionNumber() < QVersionNumber(m_minVersion)) QSKIP("clangd is too old"); // Wait for index to build. if (!m_client->isFullyIndexed()) { QVERIFY(waitForSignalOrTimeout(m_client, &ClangdClient::indexingFinished, clangdIndexingTimeout())); } QVERIFY(m_client->isFullyIndexed()); // Open cpp documents. for (const QString &sourceFileName : qAsConst(m_sourceFileNames)) { const auto sourceFilePath = Utils::FilePath::fromString( m_projectDir->absolutePath(sourceFileName.toLocal8Bit())); QVERIFY2(sourceFilePath.exists(), qPrintable(sourceFilePath.toUserOutput())); IEditor * const editor = EditorManager::openEditor(sourceFilePath); QVERIFY(editor); const auto doc = qobject_cast(editor->document()); QVERIFY(doc); QVERIFY(m_client->documentForFilePath(sourceFilePath) == doc); m_sourceDocuments.insert(sourceFileName, doc); } } ClangdTestFindReferences::ClangdTestFindReferences() { setProjectFileName("find-usages.pro"); setSourceFileNames({"defs.h", "main.cpp"}); setMinimumVersion(13); } void ClangdTestFindReferences::initTestCase() { ClangdTest::initTestCase(); CppTools::codeModelSettings()->setCategorizeFindReferences(true); connect(client(), &ClangdClient::foundReferences, this, [this](const QList &results) { if (results.isEmpty()) return; if (results.first().path().first().endsWith("defs.h")) m_actualResults = results + m_actualResults; // Guarantee expected file order. else m_actualResults += results; }); } void ClangdTestFindReferences::test_data() { QTest::addColumn("fileName"); QTest::addColumn("pos"); using ItemList = QList; QTest::addColumn("expectedResults"); static const auto makeItem = [](int line, int column, Usage::Type type) { SearchResultItem item; item.setMainRange(line, column, 0); item.setUserData(int(type)); return item; }; QTest::newRow("struct member") << "defs.h" << 55 << ItemList{ makeItem(2, 17, Usage::Type::Read), makeItem(3, 15, Usage::Type::Declaration), makeItem(6, 17, Usage::Type::WritableRef), makeItem(8, 11, Usage::Type::WritableRef), makeItem(9, 13, Usage::Type::WritableRef), makeItem(10, 12, Usage::Type::WritableRef), makeItem(11, 13, Usage::Type::WritableRef), makeItem(12, 14, Usage::Type::WritableRef), makeItem(13, 26, Usage::Type::WritableRef), makeItem(14, 23, Usage::Type::Read), makeItem(15, 14, Usage::Type::Read), makeItem(16, 24, Usage::Type::WritableRef), makeItem(17, 15, Usage::Type::WritableRef), makeItem(18, 22, Usage::Type::Read), makeItem(19, 12, Usage::Type::WritableRef), makeItem(20, 12, Usage::Type::Read), makeItem(21, 13, Usage::Type::WritableRef), makeItem(22, 13, Usage::Type::Read), makeItem(23, 12, Usage::Type::Read), makeItem(42, 20, Usage::Type::Read), makeItem(44, 15, Usage::Type::Read), makeItem(47, 15, Usage::Type::Write), makeItem(50, 11, Usage::Type::Read), makeItem(51, 11, Usage::Type::Write), makeItem(52, 9, Usage::Type::Write), makeItem(53, 7, Usage::Type::Write), makeItem(56, 7, Usage::Type::Write), makeItem(56, 25, Usage::Type::Other), makeItem(58, 13, Usage::Type::Read), makeItem(58, 25, Usage::Type::Read), makeItem(59, 7, Usage::Type::Write), makeItem(59, 24, Usage::Type::Read)}; QTest::newRow("constructor member initialization") << "defs.h" << 68 << ItemList{ makeItem(2, 10, Usage::Type::Write), makeItem(4, 8, Usage::Type::Declaration)}; QTest::newRow("direct member initialization") << "defs.h" << 101 << ItemList{ makeItem(5, 21, Usage::Type::Initialization), makeItem(45, 16, Usage::Type::Read)}; // FIXME: The override gets reported twice. clangd bug? QTest::newRow("pure virtual declaration") << "defs.h" << 420 << ItemList{ makeItem(17, 17, Usage::Type::Declaration), makeItem(21, 9, Usage::Type::Declaration), makeItem(21, 9, Usage::Type::Declaration)}; QTest::newRow("pointer variable") << "main.cpp" << 52 << ItemList{ makeItem(6, 10, Usage::Type::Initialization), makeItem(8, 4, Usage::Type::Write), makeItem(10, 4, Usage::Type::Write), makeItem(24, 5, Usage::Type::Write), makeItem(25, 11, Usage::Type::WritableRef), makeItem(26, 11, Usage::Type::Read), makeItem(27, 10, Usage::Type::WritableRef), makeItem(28, 10, Usage::Type::Read), makeItem(29, 11, Usage::Type::Read), makeItem(30, 15, Usage::Type::WritableRef), makeItem(31, 22, Usage::Type::Read)}; QTest::newRow("struct variable") << "main.cpp" << 39 << ItemList{ makeItem(5, 7, Usage::Type::Declaration), makeItem(6, 15, Usage::Type::WritableRef), makeItem(8, 9, Usage::Type::WritableRef), makeItem(9, 11, Usage::Type::WritableRef), makeItem(11, 4, Usage::Type::Write), makeItem(11, 11, Usage::Type::WritableRef), makeItem(12, 12, Usage::Type::WritableRef), makeItem(13, 6, Usage::Type::Write), makeItem(14, 21, Usage::Type::Read), makeItem(15, 4, Usage::Type::Write), makeItem(15, 12, Usage::Type::Read), makeItem(16, 22, Usage::Type::WritableRef), makeItem(17, 13, Usage::Type::WritableRef), makeItem(18, 20, Usage::Type::Read), makeItem(19, 10, Usage::Type::WritableRef), makeItem(20, 10, Usage::Type::Read), makeItem(21, 11, Usage::Type::WritableRef), makeItem(22, 11, Usage::Type::Read), makeItem(23, 10, Usage::Type::Read), makeItem(32, 4, Usage::Type::Write), makeItem(33, 23, Usage::Type::WritableRef), makeItem(34, 23, Usage::Type::Read), makeItem(35, 15, Usage::Type::WritableRef), makeItem(36, 22, Usage::Type::WritableRef), makeItem(37, 4, Usage::Type::Read), makeItem(38, 4, Usage::Type::WritableRef), makeItem(39, 6, Usage::Type::WritableRef), makeItem(40, 4, Usage::Type::Read), makeItem(41, 4, Usage::Type::WritableRef), makeItem(42, 4, Usage::Type::Read), makeItem(42, 18, Usage::Type::Read), makeItem(43, 11, Usage::Type::Write), makeItem(54, 4, Usage::Type::Other), makeItem(55, 4, Usage::Type::Other)}; // Some of these are conceptually questionable, as S is a type and thus we cannot "read from" // or "write to" it. But it probably matches the intuitive user expectation. QTest::newRow("struct type") << "defs.h" << 7 << ItemList{ makeItem(1, 7, Usage::Type::Declaration), makeItem(2, 4, Usage::Type::Declaration), makeItem(20, 19, Usage::Type::Other), makeItem(10, 9, Usage::Type::WritableRef), makeItem(12, 4, Usage::Type::Write), makeItem(44, 12, Usage::Type::Read), makeItem(45, 13, Usage::Type::Read), makeItem(47, 12, Usage::Type::Write), makeItem(50, 8, Usage::Type::Read), makeItem(51, 8, Usage::Type::Write), makeItem(52, 6, Usage::Type::Write), makeItem(53, 4, Usage::Type::Write), makeItem(56, 4, Usage::Type::Write), makeItem(56, 22, Usage::Type::Other), makeItem(58, 10, Usage::Type::Read), makeItem(58, 22, Usage::Type::Read), makeItem(59, 4, Usage::Type::Write), makeItem(59, 21, Usage::Type::Read)}; QTest::newRow("subclass") << "defs.h" << 450 << ItemList{ makeItem(20, 7, Usage::Type::Declaration), makeItem(5, 4, Usage::Type::Other), makeItem(13, 21, Usage::Type::Other), makeItem(32, 8, Usage::Type::Other)}; QTest::newRow("array variable") << "main.cpp" << 1134 << ItemList{ makeItem(57, 8, Usage::Type::Declaration), makeItem(58, 4, Usage::Type::Write), makeItem(59, 15, Usage::Type::Read)}; } // The main point here is to test our access type categorization. // We do not try to stress-test clangd's "Find References" functionality; such tests belong // into LLVM. void ClangdTestFindReferences::test() { QFETCH(QString, fileName); QFETCH(int, pos); QFETCH(QList, expectedResults); TextEditor::TextDocument * const doc = document(fileName); QVERIFY(doc); QTextCursor cursor(doc->document()); cursor.setPosition(pos); client()->findUsages(doc, cursor, {}); QVERIFY(waitForSignalOrTimeout(client(), &ClangdClient::findUsagesDone, timeOutInMs())); QCOMPARE(m_actualResults.size(), expectedResults.size()); for (int i = 0; i < m_actualResults.size(); ++i) { const SearchResultItem &curActual = m_actualResults.at(i); const SearchResultItem &curExpected = expectedResults.at(i); QCOMPARE(curActual.mainRange().begin.line, curExpected.mainRange().begin.line); QCOMPARE(curActual.mainRange().begin.column, curExpected.mainRange().begin.column); QCOMPARE(curActual.userData(), curExpected.userData()); } } ClangdTestFollowSymbol::ClangdTestFollowSymbol() { setProjectFileName("follow-symbol.pro"); setSourceFileNames({"main.cpp", "header.h"}); setMinimumVersion(12); } void ClangdTestFollowSymbol::test_data() { QTest::addColumn("sourceFile"); QTest::addColumn("sourceLine"); QTest::addColumn("sourceColumn"); QTest::addColumn("targetFile"); QTest::addColumn("targetLine"); QTest::addColumn("targetColumn"); QTest::newRow("on namespace") << "main.cpp" << 27 << 1 << "header.h" << 28 << 11; QTest::newRow("class ref") << "main.cpp" << 27 << 9 << "header.h" << 34 << 7; QTest::newRow("forward decl (same file)") << "header.h" << 32 << 7 << "header.h" << 34 << 7; QTest::newRow("forward decl (different file") << "header.h" << 48 << 9 << "main.cpp" << 54 << 7; QTest::newRow("class definition (same file)") << "header.h" << 34 << 7 << "header.h" << 32 << 7; QTest::newRow("class definition (different file)") << "main.cpp" << 54 << 7 << "header.h" << 48 << 7; QTest::newRow("constructor decl") << "header.h" << 36 << 5 << "main.cpp" << 27 << 14; QTest::newRow("constructor definition") << "main.cpp" << 27 << 14 << "header.h" << 36 << 5; QTest::newRow("member ref") << "main.cpp" << 39 << 10 << "header.h" << 38 << 18; QTest::newRow("union member ref") << "main.cpp" << 91 << 20 << "main.cpp" << 86 << 13; QTest::newRow("member decl") << "header.h" << 38 << 18 << "header.h" << 38 << 18; QTest::newRow("function ref") << "main.cpp" << 66 << 12 << "main.cpp" << 35 << 5; QTest::newRow("member function ref") << "main.cpp" << 42 << 12 << "main.cpp" << 49 << 21; QTest::newRow("function with no def ref") << "main.cpp" << 43 << 5 << "header.h" << 59 << 5; QTest::newRow("function def") << "main.cpp" << 35 << 5 << "header.h" << 52 << 5; QTest::newRow("member function def") << "main.cpp" << 49 << 21 << "header.h" << 43 << 9; QTest::newRow("member function decl") << "header.h" << 43 << 9 << "main.cpp" << 49 << 21; QTest::newRow("include") << "main.cpp" << 25 << 13 << "header.h" << 1 << 1; QTest::newRow("local var") << "main.cpp" << 39 << 6 << "main.cpp" << 36 << 9; QTest::newRow("alias") << "main.cpp" << 36 << 5 << "main.cpp" << 33 << 7; QTest::newRow("static var") << "main.cpp" << 40 << 27 << "header.h" << 30 << 7; QTest::newRow("member function ref (other class)") << "main.cpp" << 62 << 39 << "cursor.cpp" << 104 << 22; QTest::newRow("macro ref") << "main.cpp" << 66 << 43 << "header.h" << 27 << 9; QTest::newRow("on namespace 2") << "main.cpp" << 27 << 3 << "header.h" << 28 << 11; QTest::newRow("after namespace") << "main.cpp" << 27 << 7 << "header.h" << 28 << 11; QTest::newRow("operator def") << "main.cpp" << 76 << 13 << "main.cpp" << 72 << 9; QTest::newRow("operator def 2") << "main.cpp" << 80 << 15 << "main.cpp" << 73 << 10; QTest::newRow("operator decl") << "main.cpp" << 72 << 12 << "main.cpp" << 76 << 10; QTest::newRow("operator decl 2") << "main.cpp" << 73 << 12 << "main.cpp" << 80 << 11; } void ClangdTestFollowSymbol::test() { QFETCH(QString, sourceFile); QFETCH(int, sourceLine); QFETCH(int, sourceColumn); QFETCH(QString, targetFile); QFETCH(int, targetLine); QFETCH(int, targetColumn); TextEditor::TextDocument * const doc = document(sourceFile); QVERIFY(doc); QTimer timer; timer.setSingleShot(true); QEventLoop loop; QObject::connect(&timer, &QTimer::timeout, &loop, &QEventLoop::quit); Utils::Link actualLink; const auto handler = [&actualLink, &loop](const Utils::Link &l) { actualLink = l; loop.quit(); }; QTextCursor cursor(doc->document()); const int pos = Utils::Text::positionInText(doc->document(), sourceLine, sourceColumn); cursor.setPosition(pos); client()->followSymbol(doc, cursor, nullptr, handler, true, false); timer.start(10000); loop.exec(); QVERIFY(timer.isActive()); timer.stop(); QCOMPARE(actualLink.targetFilePath, filePath(targetFile)); QEXPECT_FAIL("union member ref", "FIXME: clangd points to union", Abort); QCOMPARE(actualLink.targetLine, targetLine); QCOMPARE(actualLink.targetColumn + 1, targetColumn); } ClangdTestLocalReferences::ClangdTestLocalReferences() { setProjectFileName("local-references.pro"); setSourceFileNames({"references.cpp"}); setMinimumVersion(13); } // We currently only support local variables, but if and when clangd implements // the linkedEditingRange request, we can change the expected values for // the file-scope test cases from empty ranges to the actual locations. void ClangdTestLocalReferences::test_data() { QTest::addColumn("sourceLine"); QTest::addColumn("sourceColumn"); QTest::addColumn>("expectedRanges"); QTest::newRow("cursor not on identifier") << 3 << 5 << QList(); QTest::newRow("local variable, one use") << 3 << 9 << QList{{3, 9, 3}}; QTest::newRow("local variable, two uses") << 10 << 9 << QList{{10, 9, 3}, {11, 12, 3}}; QTest::newRow("class name") << 16 << 7 << QList() /* QList{{16, 7, 3}, {19, 5, 3}} */; QTest::newRow("namespace") << 24 << 11 << QList() /* QList{{24, 11, 1}, {25, 11, 1}, {26, 1, 1}} */; QTest::newRow("class name via using") << 30 << 21 << QList() /* QList{{30, 21, 3}, {31, 10, 3}} */; QTest::newRow("forward-declared class") << 35 << 7 << QList() /* QList{{35, 7, 3}, {36, 14, 3}} */; QTest::newRow("class name and new expression") << 40 << 7 << QList() /* QList{{40, 7, 3}, {43, 9, 3}} */; QTest::newRow("instantiated template object") << 52 << 19 << QList{{52, 19, 3}, {53, 5, 3}}; QTest::newRow("variable in template") << 62 << 13 << QList() /* QList{{62, 13, 3}, {63, 11, 3}} */; QTest::newRow("member in template") << 67 << 7 << QList() /* QList{{64, 16, 3}, {67, 7, 3}} */; QTest::newRow("template type") << 58 << 19 << QList() /* QList{{58, 19, 1}, {60, 5, 1}, {67, 5, 1}} */; QTest::newRow("template parameter member access") << 76 << 9 << QList(); QTest::newRow("constructor as type") << 82 << 5 << QList() /* QList{{81, 8, 3}, {82, 5, 3}, {83, 6, 3}} */; QTest::newRow("freestanding overloads") << 88 << 5 << QList() /* QList{{88, 5, 3}, {89, 5, 3}} */; QTest::newRow("member function overloads") << 94 << 9 << QList() /* QList{{94, 9, 3}, {95, 9, 3}} */; QTest::newRow("function and function template") << 100 << 26 << QList() /* QList{{100, 26, 3}, {101, 5, 3}} */; QTest::newRow("function and function template as member") << 106 << 30 << QList() /* QList{{106, 30, 3}, {107, 9, 3}} */; QTest::newRow("enum type") << 112 << 6 << QList() /* QList{{112, 6, 2}, {113, 8, 2}} */; QTest::newRow("captured lambda var") << 122 << 15 << QList{{122, 15, 3}, {122, 33, 3}}; QTest::newRow("lambda initializer") << 122 << 19 << QList{{121, 19, 3}, {122, 19, 3}}; QTest::newRow("template specialization") << 127 << 25 << QList() /* QList{{127, 5, 3}, {128, 25, 3}, {129, 18, 3}} */; QTest::newRow("dependent name") << 133 << 34 << QList() /* QList{{133, 34, 3} */; QTest::newRow("function call and definition") << 140 << 5 << QList() /* QList{{140, 5, 3}, {142, 25, 3}} */; QTest::newRow("object-like macro") << 147 << 9 << QList() /* QList{{147, 9, 3}, {150, 12, 3}} */; QTest::newRow("function-like macro") << 155 << 9 << QList() /* QList{{155, 9, 3}, {158, 12, 3}} */; QTest::newRow("argument to function-like macro") << 156 << 27 << QList{{156, 27, 3}, {158, 16, 3}}; QTest::newRow("overloaded bracket operator argument") << 172 << 7 << QList{{171, 7, 1}, {172, 7, 1}, {172, 12, 1}, {173, 7, 1}, {173, 10, 1}}; QTest::newRow("overloaded call operator second argument") << 173 << 10 << QList{{171, 7, 1}, {172, 7, 1}, {172, 12, 1}, {173, 7, 1}, {173, 10, 1}}; QTest::newRow("overloaded operators arguments from outside") << 171 << 7 << QList{{171, 7, 1}, {172, 7, 1}, {172, 12, 1}, {173, 7, 1}, {173, 10, 1}}; } void ClangdTestLocalReferences::test() { QFETCH(int, sourceLine); QFETCH(int, sourceColumn); QFETCH(QList, expectedRanges); TextEditor::TextDocument * const doc = document("references.cpp"); QVERIFY(doc); QTimer timer; timer.setSingleShot(true); QEventLoop loop; QObject::connect(&timer, &QTimer::timeout, &loop, &QEventLoop::quit); QList actualRanges; const auto handler = [&actualRanges, &loop](const QString &symbol, const ClangBackEnd::SourceLocationsContainer &container, int) { for (const ClangBackEnd::SourceLocationContainer &c : container.m_sourceLocationContainers) { actualRanges << Range(c.line, c.column, symbol.length()); } loop.quit(); }; QTextCursor cursor(doc->document()); const int pos = Utils::Text::positionInText(doc->document(), sourceLine, sourceColumn); cursor.setPosition(pos); client()->findLocalUsages(doc, cursor, std::move(handler)); timer.start(10000); loop.exec(); QEXPECT_FAIL("cursor not on identifier", "clangd bug: go to definition does not return", Abort); QEXPECT_FAIL("template parameter member access", "clangd bug: go to definition does not return", Abort); QVERIFY(timer.isActive()); timer.stop(); QCOMPARE(actualRanges, expectedRanges); } // This tests our help item construction, not the actual tooltip contents. Those come // pre-formatted from clangd. ClangdTestTooltips::ClangdTestTooltips() { setProjectFileName("tooltips.pro"); setSourceFileNames({"tooltips.cpp"}); setMinimumVersion(13); } void ClangdTestTooltips::test_data() { QTest::addColumn("line"); QTest::addColumn("column"); QTest::addColumn("expectedIds"); QTest::addColumn("expectedMark"); QTest::addColumn("expectedCategory"); QTest::newRow("LocalParameterVariableConstRefCustomType") << 12 << 12 << QStringList("Foo") << QString("Foo") << int(HelpItem::ClassOrNamespace); QTest::newRow("LocalNonParameterVariableConstRefCustomType") << 14 << 5 << QStringList("Foo") << QString("Foo") << int(HelpItem::ClassOrNamespace); QTest::newRow("MemberVariableBuiltinType") << 12 << 16 << QStringList() << QString() << int(HelpItem::Unknown); QTest::newRow("MemberFunctionCall") << 21 << 9 << QStringList{"Bar::mem", "mem"} << QString("mem()") << int(HelpItem::Function); QTest::newRow("TemplateFunctionCall") << 30 << 5 << QStringList{"t"} << QString("t(int)") << int(HelpItem::Function); QTest::newRow("Enum") << 49 << 12 << QStringList{"EnumType"} << QString("EnumType") << int(HelpItem::Enum); QTest::newRow("Enumerator") << 49 << 22 << QStringList{"Custom"} << QString("EnumType") << int(HelpItem::Enum); QTest::newRow("TemplateTypeFromParameter") << 55 << 25 << QStringList{"Baz"} << QString("Baz") << int(HelpItem::ClassOrNamespace); QTest::newRow("TemplateTypeFromNonParameter") << 56 << 19 << QStringList{"Baz"} << QString("Baz") << int(HelpItem::ClassOrNamespace); QTest::newRow("IncludeDirective") << 59 << 11 << QStringList{"tooltipinfo.h"} << QString("tooltipinfo.h") << int(HelpItem::Brief); QTest::newRow("MacroUse") << 66 << 5 << QStringList{"MACRO_FROM_MAINFILE"} << QString("MACRO_FROM_MAINFILE") << int(HelpItem::Macro); QTest::newRow("TypeNameIntroducedByUsingDirectiveQualified") << 77 << 5 << QStringList{"N::Muu", "Muu"} << QString("Muu") << int(HelpItem::ClassOrNamespace); QTest::newRow("TypeNameIntroducedByUsingDirectiveResolvedAndQualified") << 82 << 5 << QStringList{"N::Muu", "Muu"} << QString("Muu") << int(HelpItem::ClassOrNamespace); QTest::newRow("TypeNameIntroducedByUsingDeclarationQualified") << 87 << 5 << QStringList{"N::Muu", "Muu"} << QString("Muu") << int(HelpItem::ClassOrNamespace); QTest::newRow("Namespace") << 106 << 11 << QStringList{"X"} << QString("X") << int(HelpItem::ClassOrNamespace); QTest::newRow("NamespaceQualified") << 107 << 11 << QStringList{"X::Y", "Y"} << QString("Y") << int(HelpItem::ClassOrNamespace); QTest::newRow("TypeName_ResolveTypeDef") << 122 << 5 << QStringList{"PtrFromTypeDef"} << QString("PtrFromTypeDef") << int(HelpItem::Typedef); QTest::newRow("TypeName_ResolveAlias") << 123 << 5 << QStringList{"PtrFromTypeAlias"} << QString("PtrFromTypeAlias") << int(HelpItem::Typedef); QTest::newRow("TypeName_ResolveTemplateTypeAlias") << 124 << 5 << QStringList{"PtrFromTemplateTypeAlias"} << QString("PtrFromTemplateTypeAlias") << int(HelpItem::Typedef); QTest::newRow("TemplateClassReference") << 134 << 5 << QStringList{"Zii"} << QString("Zii") << int(HelpItem::ClassOrNamespace); QTest::newRow("TemplateClassQualified") << 135 << 5 << QStringList{"U::Yii", "Yii"} << QString("Yii") << int(HelpItem::ClassOrNamespace); QTest::newRow("ResolveNamespaceAliasForType") << 144 << 8 << QStringList{"A::X", "X"} << QString("X") << int(HelpItem::ClassOrNamespace); QTest::newRow("ResolveNamespaceAlias") << 144 << 5 << QStringList{"B"} << QString("B") << int(HelpItem::ClassOrNamespace); QTest::newRow("QualificationForTemplateClassInClassInNamespace") << 153 << 16 << QStringList{"N::Outer::Inner", "Outer::Inner", "Inner"} << QString("Inner") << int(HelpItem::ClassOrNamespace); QTest::newRow("Function") << 165 << 5 << QStringList{"f"} << QString("f()") << int(HelpItem::Function); QTest::newRow("Function_QualifiedName") << 166 << 8 << QStringList{"R::f", "f"} << QString("f()") << int(HelpItem::Function); QTest::newRow("FunctionWithParameter") << 167 << 5 << QStringList{"f"} << QString("f(int)") << int(HelpItem::Function); QTest::newRow("FunctionWithDefaultValue") << 168 << 5 << QStringList{"z"} << QString("z(int)") << int(HelpItem::Function); QTest::newRow("PointerToPointerToClass") << 200 << 12 << QStringList{"Nuu"} << QString("Nuu") << int(HelpItem::ClassOrNamespace); QTest::newRow("AutoTypeEnum") << 177 << 10 << QStringList{"EnumType"} << QString("EnumType") << int(HelpItem::Enum); QTest::newRow("AutoTypeClass") << 178 << 10 << QStringList{"Bar"} << QString("Bar") << int(HelpItem::ClassOrNamespace); QTest::newRow("AutoTypeTemplate") << 179 << 10 << QStringList{"Zii"} << QString("Zii") << int(HelpItem::ClassOrNamespace); QTest::newRow("Function_DefaultConstructor") << 193 << 5 << QStringList{"Con"} << QString("Con") << int(HelpItem::ClassOrNamespace); QTest::newRow("Function_ExplicitDefaultConstructor") << 194 << 5 << QStringList{"ExplicitCon"} << QString("ExplicitCon") << int(HelpItem::ClassOrNamespace); QTest::newRow("Function_CustomConstructor") << 195 << 5 << QStringList{"ExplicitCon"} << QString("ExplicitCon") << int(HelpItem::ClassOrNamespace); } void ClangdTestTooltips::test() { QFETCH(int, line); QFETCH(int, column); QFETCH(QStringList, expectedIds); QFETCH(QString, expectedMark); QFETCH(int, expectedCategory); TextEditor::TextDocument * const doc = document("tooltips.cpp"); QVERIFY(doc); const auto editor = qobject_cast(EditorManager::currentEditor()); QVERIFY(editor); QCOMPARE(editor->document(), doc); QVERIFY(editor->editorWidget()); if (client()->versionNumber() < QVersionNumber(14) && QLatin1String(QTest::currentDataTag()) == QLatin1String("IncludeDirective")) { QSKIP("FIXME: clangd sends empty or no hover data for includes"); } QTimer timer; timer.setSingleShot(true); QEventLoop loop; QObject::connect(&timer, &QTimer::timeout, &loop, &QEventLoop::quit); HelpItem helpItem; const auto handler = [&helpItem, &loop](const HelpItem &h) { helpItem = h; loop.quit(); }; connect(client(), &ClangdClient::helpItemGathered, handler); QTextCursor cursor(doc->document()); const int pos = Utils::Text::positionInText(doc->document(), line, column); cursor.setPosition(pos); editor->editorWidget()->processTooltipRequest(cursor); timer.start(10000); loop.exec(); QVERIFY(timer.isActive()); timer.stop(); QEXPECT_FAIL("TypeName_ResolveTemplateTypeAlias", "typedef already resolved in AST", Abort); QCOMPARE(int(helpItem.category()), expectedCategory); QEXPECT_FAIL("TemplateClassQualified", "Additional look-up needed?", Abort); QCOMPARE(helpItem.helpIds(), expectedIds); QCOMPARE(helpItem.docMark(), expectedMark); } ClangdTestHighlighting::ClangdTestHighlighting() { setProjectFileName("highlighting.pro"); setSourceFileNames({"highlighting.cpp"}); setMinimumVersion(13); } void ClangdTestHighlighting::initTestCase() { ClangdTest::initTestCase(); QTimer timer; timer.setSingleShot(true); QEventLoop loop; QObject::connect(&timer, &QTimer::timeout, &loop, &QEventLoop::quit); const auto handler = [this, &loop](const TextEditor::HighlightingResults &results) { m_results = results; loop.quit(); }; connect(client(), &ClangdClient::highlightingResultsReady, handler); timer.start(10000); loop.exec(); QVERIFY(timer.isActive()); QVERIFY(!m_results.isEmpty()); } void ClangdTestHighlighting::test_data() { QTest::addColumn("firstLine"); QTest::addColumn("startColumn"); QTest::addColumn("lastLine"); QTest::addColumn("endColumn"); QTest::addColumn>("expectedStyles"); QTest::addColumn("expectedKind"); QTest::newRow("string literal") << 1 << 24 << 1 << 34 << QList{C_STRING} << 0; QTest::newRow("UTF-8 string literal") << 2 << 24 << 2 << 36 << QList{C_STRING} << 0; QTest::newRow("raw string literal") << 3 << 24 << 4 << 9 << QList{C_STRING} << 0; QTest::newRow("character literal") << 5 << 24 << 5 << 27 << QList{C_STRING} << 0; QTest::newRow("integer literal") << 23 << 24 << 23 << 25 << QList{C_NUMBER} << 0; QTest::newRow("float literal") << 24 << 24 << 24 << 28 << QList{C_NUMBER} << 0; QTest::newRow("function definition") << 45 << 5 << 45 << 13 << QList{C_FUNCTION, C_FUNCTION_DEFINITION, C_DECLARATION} << 0; QTest::newRow("member function definition") << 52 << 10 << 52 << 24 << QList{C_FUNCTION, C_FUNCTION_DEFINITION, C_DECLARATION} << 0; QTest::newRow("virtual member function definition outside of class body") << 586 << 17 << 586 << 32 << QList{C_VIRTUAL_METHOD, C_FUNCTION_DEFINITION, C_DECLARATION} << 0; QTest::newRow("virtual member function definition inside class body") << 589 << 16 << 589 << 41 << QList{C_VIRTUAL_METHOD, C_FUNCTION_DEFINITION, C_DECLARATION} << 0; QTest::newRow("function declaration") << 55 << 5 << 55 << 24 << QList{C_FUNCTION, C_DECLARATION} << 0; QTest::newRow("member function declaration") << 59 << 10 << 59 << 24 << QList{C_FUNCTION, C_DECLARATION} << 0; QTest::newRow("member function call") << 104 << 9 << 104 << 32 << QList{C_FUNCTION} << 0; QTest::newRow("function call") << 64 << 5 << 64 << 13 << QList{C_FUNCTION} << 0; QTest::newRow("type conversion function (struct)") << 68 << 14 << 68 << 17 << QList{C_TYPE, C_OPERATOR, C_DECLARATION} << 0; QTest::newRow("type conversion function (built-in)") << 69 << 14 << 69 << 17 << QList{C_PRIMITIVE_TYPE, C_OPERATOR, C_DECLARATION} << 0; QTest::newRow("type reference") << 74 << 5 << 74 << 8 << QList{C_TYPE} << 0; QTest::newRow("local variable declaration") << 79 << 9 << 79 << 12 << QList{C_LOCAL, C_DECLARATION} << 0; QTest::newRow("local variable reference") << 81 << 5 << 81 << 8 << QList{C_LOCAL} << 0; QTest::newRow("function parameter declaration") << 84 << 41 << 84 << 44 << QList{C_PARAMETER, C_DECLARATION} << 0; QTest::newRow("function parameter reference") << 86 << 5 << 86 << 8 << QList{C_PARAMETER} << 0; QTest::newRow("member declaration") << 90 << 9 << 90 << 20 << QList{C_FIELD, C_DECLARATION} << 0; QTest::newRow("member reference") << 94 << 9 << 94 << 20 << QList{C_FIELD} << 0; QTest::newRow("static member function declaration") << 110 << 10 << 110 << 22 << QList{C_FUNCTION, C_DECLARATION} << 0; QTest::newRow("static member function call") << 114 << 15 << 114 << 27 << QList{C_FUNCTION} << 0; QTest::newRow("enum declaration") << 118 << 6 << 118 << 17 << QList{C_TYPE, C_ENUMERATION, C_DECLARATION} << 0; QTest::newRow("enumerator declaration") << 120 << 5 << 120 << 15 << QList{C_ENUMERATION, C_DECLARATION} << 0; QTest::newRow("enum in variable declaration") << 125 << 5 << 125 << 16 << QList{C_TYPE, C_ENUMERATION} << 0; QTest::newRow("enum variable declaration") << 125 << 17 << 125 << 28 << QList{C_LOCAL, C_DECLARATION} << 0; QTest::newRow("enum variable reference") << 127 << 5 << 127 << 16 << QList{C_LOCAL} << 0; QTest::newRow("enumerator reference") << 127 << 19 << 127 << 29 << QList{C_ENUMERATION} << 0; QTest::newRow("forward declaration") << 130 << 7 << 130 << 23 << QList{C_TYPE, C_DECLARATION} << 0; QTest::newRow("constructor declaration") << 134 << 5 << 134 << 10 << QList{C_FUNCTION, C_DECLARATION} << 0; QTest::newRow("destructor declaration") << 135 << 6 << 135 << 11 << QList{C_FUNCTION, C_DECLARATION} << 0; QTest::newRow("reference to forward-declared class") << 138 << 1 << 138 << 17 << QList{C_TYPE} << 0; QTest::newRow("class in variable declaration") << 140 << 5 << 140 << 10 << QList{C_TYPE} << 0; QTest::newRow("class variable declaration") << 140 << 11 << 140 << 31 << QList{C_LOCAL, C_DECLARATION} << 0; QTest::newRow("union declaration") << 145 << 7 << 145 << 12 << QList{C_TYPE, C_DECLARATION} << 0; QTest::newRow("union in global variable declaration") << 150 << 1 << 150 << 6 << QList{C_TYPE} << 0; QTest::newRow("global variable declaration") << 150 << 7 << 150 << 32 << QList{C_GLOBAL, C_DECLARATION} << 0; QTest::newRow("struct declaration") << 50 << 8 << 50 << 11 << QList{C_TYPE, C_DECLARATION} << 0; QTest::newRow("namespace declaration") << 160 << 11 << 160 << 20 << QList{C_TYPE, C_DECLARATION} << 0; QTest::newRow("namespace alias declaration") << 164 << 11 << 164 << 25 << QList{C_TYPE, C_DECLARATION} << 0; QTest::newRow("struct in namespaced using declaration") << 165 << 18 << 165 << 35 << QList{C_TYPE} << 0; QTest::newRow("namespace reference") << 166 << 1 << 166 << 10 << QList{C_TYPE} << 0; QTest::newRow("namespaced struct in global variable declaration") << 166 << 12 << 166 << 29 << QList{C_TYPE} << 0; QTest::newRow("virtual function declaration") << 170 << 18 << 170 << 33 << QList{C_VIRTUAL_METHOD, C_DECLARATION} << 0; QTest::newRow("virtual function call via pointer") << 192 << 33 << 192 << 48 << QList{C_VIRTUAL_METHOD} << 0; QTest::newRow("final virtual function call via pointer") << 202 << 38 << 202 << 58 << QList{C_VIRTUAL_METHOD} << 0; QTest::newRow("non-final virtual function call via pointer") << 207 << 41 << 207 << 61 << QList{C_VIRTUAL_METHOD} << 0; QTest::newRow("operator+ declaration") << 220 << 18 << 220 << 19 << QList{C_PUNCTUATION, C_OPERATOR, C_OVERLOADED_OPERATOR, C_DECLARATION} << 0; QTest::newRow("operator+ call") << 224 << 36 << 224 << 37 << QList{C_PUNCTUATION, C_OPERATOR, C_OVERLOADED_OPERATOR} << 0; QTest::newRow("operator+= call") << 226 << 24 << 226 << 26 << QList{C_PUNCTUATION, C_OPERATOR, C_OVERLOADED_OPERATOR} << 0; QTest::newRow("operator* member declaration") << 604 << 18 << 604 << 19 << QList{C_PUNCTUATION, C_OPERATOR, C_OVERLOADED_OPERATOR, C_DECLARATION} << 0; QTest::newRow("operator* non-member declaration") << 607 << 14 << 607 << 15 << QList{C_PUNCTUATION, C_OPERATOR, C_OVERLOADED_OPERATOR, C_DECLARATION} << 0; QTest::newRow("operator* member call") << 613 << 7 << 613 << 8 << QList{C_PUNCTUATION, C_OPERATOR, C_OVERLOADED_OPERATOR} << 0; QTest::newRow("operator* non-member call") << 614 << 7 << 614 << 8 << QList{C_PUNCTUATION, C_OPERATOR, C_OVERLOADED_OPERATOR} << 0; QTest::newRow("operator<<= member declaration") << 618 << 19 << 618 << 22 << QList{C_PUNCTUATION, C_OPERATOR, C_OVERLOADED_OPERATOR, C_DECLARATION} << 0; QTest::newRow("operator<<= call") << 629 << 12 << 629 << 15 << QList{C_PUNCTUATION, C_OPERATOR, C_OVERLOADED_OPERATOR} << 0; QTest::newRow("integer literal 2") << 629 << 16 << 629 << 17 << QList{C_NUMBER} << 0; QTest::newRow("operator(int) member declaration (opening paren") << 619 << 19 << 619 << 20 << QList{C_PUNCTUATION, C_OPERATOR, C_OVERLOADED_OPERATOR, C_DECLARATION} << 0; QTest::newRow("operator(int) member declaration (closing paren") << 619 << 20 << 619 << 21 << QList{C_PUNCTUATION, C_OPERATOR, C_OVERLOADED_OPERATOR, C_DECLARATION} << 0; QTest::newRow("operator(int) call (opening parenthesis)") << 632 << 12 << 632 << 13 << QList{C_PUNCTUATION, C_OPERATOR, C_OVERLOADED_OPERATOR} << 0; QTest::newRow("operator(int) call (argument)") << 632 << 13 << 632 << 14 << QList{C_NUMBER} << 0; QTest::newRow("operator(int) call (closing parenthesis)") << 632 << 14 << 632 << 15 << QList{C_PUNCTUATION, C_OPERATOR, C_OVERLOADED_OPERATOR} << 0; QTest::newRow("operator[] member declaration (opening bracket") << 620 << 18 << 620 << 19 << QList{C_PUNCTUATION, C_OPERATOR, C_OVERLOADED_OPERATOR, C_DECLARATION} << 0; QTest::newRow("operator[] member declaration (closing bracket") << 620 << 20 << 620 << 21 << QList{C_PUNCTUATION, C_OPERATOR, C_OVERLOADED_OPERATOR, C_DECLARATION} << 0; QTest::newRow("operator[] call (opening bracket)") << 633 << 12 << 633 << 13 << QList{C_PUNCTUATION, C_OPERATOR, C_OVERLOADED_OPERATOR} << 0; QTest::newRow("operator[] call (argument)") << 633 << 13 << 633 << 14 << QList{C_NUMBER} << 0; QTest::newRow("operator[] call (closing bracket)") << 633 << 14 << 633 << 15 << QList{C_PUNCTUATION, C_OPERATOR, C_OVERLOADED_OPERATOR} << 0; QTest::newRow("operator new member declaration") << 621 << 20 << 621 << 23 << QList{C_KEYWORD, C_OPERATOR, C_OVERLOADED_OPERATOR, C_DECLARATION} << 0; QTest::newRow("operator new member call") << 635 << 22 << 635 << 25 << QList{C_KEYWORD, C_OPERATOR, C_OVERLOADED_OPERATOR} << 0; QTest::newRow("operator delete member declaration") << 622 << 19 << 622 << 25 << QList{C_KEYWORD, C_OPERATOR, C_OVERLOADED_OPERATOR, C_DECLARATION} << 0; QTest::newRow("operator delete member call") << 636 << 5 << 636 << 11 << QList{C_KEYWORD, C_OPERATOR, C_OVERLOADED_OPERATOR} << 0; QTest::newRow("var after operator delete member call") << 636 << 12 << 636 << 19 << QList{C_LOCAL} << 0; QTest::newRow("operator new[] member declaration (keyword)") << 623 << 20 << 623 << 23 << QList{C_KEYWORD, C_OPERATOR, C_OVERLOADED_OPERATOR, C_DECLARATION} << 0; QTest::newRow("operator new[] member declaration (opening bracket)") << 623 << 23 << 623 << 24 << QList{C_PUNCTUATION, C_OPERATOR, C_OVERLOADED_OPERATOR, C_DECLARATION} << 0; QTest::newRow("operator new[] member declaration (closing bracket)") << 623 << 24 << 623 << 25 << QList{C_PUNCTUATION, C_OPERATOR, C_OVERLOADED_OPERATOR, C_DECLARATION} << 0; QTest::newRow("operator new[] member call (keyword") << 637 << 19 << 637 << 22 << QList{C_KEYWORD, C_OPERATOR, C_OVERLOADED_OPERATOR} << 0; QTest::newRow("operator new[] member call (type argument)") << 637 << 23 << 637 << 28 << QList{C_TYPE} << 0; QTest::newRow("operator new[] member call (opening bracket)") << 637 << 28 << 637 << 29 << QList{C_PUNCTUATION, C_OPERATOR, C_OVERLOADED_OPERATOR} << 0; QTest::newRow("operator new[] member call (size argument)") << 637 << 29 << 637 << 31 << QList{C_NUMBER} << 0; QTest::newRow("operator new[] member call (closing bracket)") << 637 << 31 << 637 << 32 << QList{C_PUNCTUATION, C_OPERATOR, C_OVERLOADED_OPERATOR} << 0; QTest::newRow("operator delete[] member declaration (keyword)") << 624 << 19 << 624 << 25 << QList{C_KEYWORD, C_OPERATOR, C_OVERLOADED_OPERATOR, C_DECLARATION} << 0; QTest::newRow("operator delete[] member declaration (opening bracket)") << 624 << 25 << 624 << 26 << QList{C_PUNCTUATION, C_OPERATOR, C_OVERLOADED_OPERATOR, C_DECLARATION} << 0; QTest::newRow("operator delete[] member declaration (closing bracket)") << 624 << 26 << 624 << 27 << QList{C_PUNCTUATION, C_OPERATOR, C_OVERLOADED_OPERATOR, C_DECLARATION} << 0; QTest::newRow("operator delete[] member call (keyword") << 638 << 5 << 638 << 11 << QList{C_KEYWORD, C_OPERATOR, C_OVERLOADED_OPERATOR} << 0; QTest::newRow("operator delete[] member call (opening bracket)") << 638 << 12 << 638 << 13 << QList{C_PUNCTUATION, C_OPERATOR, C_OVERLOADED_OPERATOR} << 0; QTest::newRow("operator delete[] member call (closing bracket)") << 638 << 13 << 638 << 14 << QList{C_PUNCTUATION, C_OPERATOR, C_OVERLOADED_OPERATOR} << 0; QTest::newRow("operator new built-in call") << 634 << 14 << 634 << 17 << QList{C_KEYWORD, C_OPERATOR} << 0; QTest::newRow("operator() member declaration (opening paren") << 654 << 20 << 654 << 21 << QList{C_PUNCTUATION, C_OPERATOR, C_OVERLOADED_OPERATOR, C_DECLARATION} << 0; QTest::newRow("operator() member declaration (closing paren") << 654 << 21 << 654 << 22 << QList{C_PUNCTUATION, C_OPERATOR, C_OVERLOADED_OPERATOR, C_DECLARATION} << 0; QTest::newRow("operator() call (opening parenthesis)") << 662 << 11 << 662 << 12 << QList{C_PUNCTUATION, C_OPERATOR, C_OVERLOADED_OPERATOR} << 0; QTest::newRow("operator() call (closing parenthesis)") << 662 << 12 << 662 << 13 << QList{C_PUNCTUATION, C_OPERATOR, C_OVERLOADED_OPERATOR} << 0; QTest::newRow("operator* member declaration (2)") << 655 << 17 << 655 << 18 << QList{C_PUNCTUATION, C_OPERATOR, C_OVERLOADED_OPERATOR, C_DECLARATION} << 0; QTest::newRow("operator* member call (2)") << 663 << 5 << 663 << 6 << QList{C_PUNCTUATION, C_OPERATOR, C_OVERLOADED_OPERATOR} << 0; QTest::newRow("operator= member declaration") << 656 << 20 << 656 << 21 << QList{C_PUNCTUATION, C_OPERATOR, C_OVERLOADED_OPERATOR, C_DECLARATION} << 0; QTest::newRow("operator= call") << 664 << 12 << 664 << 13 << QList{C_PUNCTUATION, C_OPERATOR, C_OVERLOADED_OPERATOR} << 0; QTest::newRow("ternary operator (question mark)") << 668 << 18 << 668 << 19 << QList{C_PUNCTUATION, C_OPERATOR} << int(CppTools::SemanticHighlighter::TernaryIf); QTest::newRow("ternary operator (colon)") << 668 << 23 << 668 << 24 << QList{C_PUNCTUATION, C_OPERATOR} << int(CppTools::SemanticHighlighter::TernaryElse); QTest::newRow("opening angle bracket in function template declaration") << 247 << 10 << 247 << 11 << QList{C_PUNCTUATION} << int(CppTools::SemanticHighlighter::AngleBracketOpen); QTest::newRow("closing angle bracket in function template declaration") << 247 << 18 << 247 << 19 << QList{C_PUNCTUATION} << int(CppTools::SemanticHighlighter::AngleBracketClose); QTest::newRow("opening angle bracket in class template declaration") << 261 << 10 << 261 << 11 << QList{C_PUNCTUATION} << int(CppTools::SemanticHighlighter::AngleBracketOpen); QTest::newRow("closing angle bracket in class template declaration") << 261 << 18 << 261 << 19 << QList{C_PUNCTUATION} << int(CppTools::SemanticHighlighter::AngleBracketClose); QTest::newRow("macro definition") << 231 << 9 << 231 << 31 << QList{C_PREPROCESSOR, C_DECLARATION} << 0; QTest::newRow("function-like macro definition") << 232 << 9 << 232 << 24 << QList{C_PREPROCESSOR, C_DECLARATION} << 0; QTest::newRow("function-like macro call") << 236 << 5 << 236 << 20 << QList{C_PREPROCESSOR} << 0; QTest::newRow("function-like macro call argument 1") << 236 << 21 << 236 << 22 << QList{C_NUMBER} << 0; QTest::newRow("function-like macro call argument 2") << 236 << 24 << 236 << 25 << QList{C_NUMBER} << 0; QTest::newRow("function template call") << 254 << 5 << 254 << 21 << QList{C_FUNCTION} << 0; QTest::newRow("template type parameter") << 265 << 17 << 265 << 38 << QList{C_TYPE, C_DECLARATION} << 0; QTest::newRow("template parameter default argument") << 265 << 41 << 265 << 44 << QList{C_TYPE} << 0; QTest::newRow("template non-type parameter") << 265 << 50 << 265 << 74 << QList{C_LOCAL, C_DECLARATION} << 0; QTest::newRow("template non-type parameter default argument") << 265 << 77 << 265 << 78 << QList{C_NUMBER} << 0; QTest::newRow("template template parameter") << 265 << 103 << 265 << 128 << QList{C_TYPE, C_DECLARATION} << 0; QTest::newRow("template template parameter default argument") << 265 << 131 << 265 << 142 << QList{C_TYPE} << 0; QTest::newRow("outer opening angle bracket in nested template declaration") << 265 << 10 << 265 << 11 << QList{C_PUNCTUATION} << int(CppTools::SemanticHighlighter::AngleBracketOpen); QTest::newRow("inner opening angle bracket in nested template declaration") << 265 << 89 << 265 << 90 << QList{C_PUNCTUATION} << int(CppTools::SemanticHighlighter::AngleBracketOpen); QTest::newRow("inner closing angle bracket in nested template declaration") << 265 << 95 << 265 << 96 << QList{C_PUNCTUATION} << int(CppTools::SemanticHighlighter::AngleBracketClose); QTest::newRow("outer closing angle bracket in nested template declaration") << 265 << 142 << 265 << 143 << QList{C_PUNCTUATION} << int(CppTools::SemanticHighlighter::AngleBracketClose); QTest::newRow("function template declaration") << 266 << 6 << 266 << 22 << QList{C_FUNCTION, C_FUNCTION_DEFINITION, C_DECLARATION} << 0; QTest::newRow("template type parameter reference") << 268 << 5 << 268 << 26 << QList{C_TYPE} << 0; QTest::newRow("local var declaration of template parameter type") << 268 << 27 << 268 << 57 << QList{C_LOCAL, C_DECLARATION} << 0; QTest::newRow("reference to non-type template parameter") << 269 << 46 << 269 << 70 << QList{C_LOCAL} << 0; QTest::newRow("local var declaration initialized with non-type template parameter") << 269 << 10 << 269 << 43 << QList{C_LOCAL, C_DECLARATION} << 0; QTest::newRow("template template parameter reference") << 270 << 5 << 270 << 30 << QList{C_TYPE} << 0; QTest::newRow("template type parameter reference in template instantiation") << 270 << 31 << 270 << 52 << QList{C_TYPE} << 0; QTest::newRow("local var declaration of template template parameter type") << 270 << 54 << 270 << 88 << QList{C_LOCAL, C_DECLARATION} << 0; QTest::newRow("local variable declaration as argument to function-like macro call") << 302 << 18 << 302 << 23 << QList{C_LOCAL, C_DECLARATION} << 0; QTest::newRow("local variable as argument to function-like macro call") << 302 << 25 << 302 << 34 << QList{C_LOCAL} << 0; QTest::newRow("class member as argument to function-like macro call") << 310 << 29 << 310 << 38 << QList{C_FIELD} << 0; QTest::newRow("enum declaration with underlying type") << 316 << 6 << 316 << 21 << QList{C_TYPE, C_ENUMERATION, C_DECLARATION} << 0; QTest::newRow("type in static_cast") << 328 << 23 << 328 << 33 << QList{C_TYPE} << 0; QTest::newRow("opening angle bracket in static_cast") << 328 << 16 << 328 << 17 << QList{C_PUNCTUATION} << int(CppTools::SemanticHighlighter::AngleBracketOpen); QTest::newRow("closing angle bracket in static_cast") << 328 << 39 << 328 << 40 << QList{C_PUNCTUATION} << int(CppTools::SemanticHighlighter::AngleBracketClose); QTest::newRow("type in reinterpret_cast") << 329 << 28 << 329 << 38 << QList{C_TYPE} << 0; QTest::newRow("integer alias declaration") << 333 << 7 << 333 << 25 << QList{C_TYPE, C_DECLARATION} << 0; QTest::newRow("integer alias in declaration") << 341 << 5 << 341 << 17 << QList{C_TYPE} << 0; QTest::newRow("recursive integer alias in declaration") << 342 << 5 << 342 << 23 << QList{C_TYPE} << 0; QTest::newRow("integer typedef in declaration") << 343 << 5 << 343 << 19 << QList{C_TYPE} << 0; QTest::newRow("call to function pointer alias") << 344 << 5 << 344 << 13 << QList{C_TYPE} << 0; QTest::newRow("friend class declaration") << 350 << 18 << 350 << 27 << QList{C_TYPE} << 0; QTest::newRow("friend class reference") << 351 << 34 << 351 << 43 << QList{C_TYPE} << 0; QTest::newRow("function parameter of friend class type") << 351 << 45 << 351 << 50 << QList{C_PARAMETER, C_DECLARATION} << 0; QTest::newRow("constructor member initialization") << 358 << 9 << 358 << 15 << QList{C_FIELD} << 0; QTest::newRow("call to function template") << 372 << 5 << 372 << 25 << QList{C_FUNCTION} << 0; QTest::newRow("class template declaration") << 377 << 7 << 377 << 20 << QList{C_TYPE, C_DECLARATION} << 0; QTest::newRow("class template instantiation (name)") << 384 << 5 << 384 << 18 << QList{C_TYPE} << 0; QTest::newRow("class template instantiation (opening angle bracket)") << 384 << 18 << 384 << 19 << QList{C_PUNCTUATION} << int(CppTools::SemanticHighlighter::AngleBracketOpen); QTest::newRow("class template instantiation (closing angle bracket)") << 384 << 22 << 384 << 23 << QList{C_PUNCTUATION} << int(CppTools::SemanticHighlighter::AngleBracketClose); QTest::newRow("namespace in declaration") << 413 << 4 << 413 << 26 << QList{C_TYPE} << 0; QTest::newRow("namespaced class in declaration") << 413 << 28 << 413 << 41 << QList{C_TYPE} << 0; QTest::newRow("class as template argument in declaration") << 413 << 42 << 413 << 52 << QList{C_TYPE} << 0; QTest::newRow("local variable declaration of template instance type") << 413 << 54 << 413 << 77 << QList{C_LOCAL, C_DECLARATION} << 0; QTest::newRow("local typedef declaration") << 418 << 17 << 418 << 35 << QList{C_TYPE, C_DECLARATION} << 0; QTest::newRow("local typedef in variable declaration") << 419 << 5 << 419 << 23 << QList{C_TYPE} << 0; QTest::newRow("non-const reference argument") << 455 << 31 << 455 << 32 << QList{C_LOCAL, C_OUTPUT_ARGUMENT} << 0; QTest::newRow("const reference argument") << 464 << 28 << 464 << 29 << QList{C_LOCAL} << 0; QTest::newRow("rvalue reference argument") << 473 << 48 << 473 << 49 << QList{C_LOCAL} << 0; QTest::newRow("non-const pointer argument") << 482 << 29 << 482 << 30 << QList{C_LOCAL, C_OUTPUT_ARGUMENT} << 0; QTest::newRow("pointer to const argument") << 490 << 28 << 490 << 29 << QList{C_LOCAL} << 0; QTest::newRow("const pointer argument") << 491 << 26 << 491 << 27 << QList{C_LOCAL, C_OUTPUT_ARGUMENT} << 0; QTest::newRow("non-const reference via member function call as output argument (object)") << 580 << 29 << 580 << 30 << QList{C_LOCAL, C_OUTPUT_ARGUMENT} << 0; QTest::newRow("non-const reference via member function call as output argument (function)") << 580 << 31 << 580 << 37 << QList{C_FUNCTION, C_OUTPUT_ARGUMENT} << 0; QTest::newRow("value argument") << 501 << 57 << 501 << 58 << QList{C_LOCAL} << 0; QTest::newRow("non-const ref argument as second arg") << 501 << 61 << 501 << 62 << QList{C_LOCAL, C_OUTPUT_ARGUMENT} << 0; QTest::newRow("non-const ref argument from function parameter") << 506 << 31 << 506 << 40 << QList{C_PARAMETER, C_OUTPUT_ARGUMENT} << 0; QTest::newRow("non-const pointer argument expression") << 513 << 30 << 513 << 31 << QList{C_LOCAL, C_OUTPUT_ARGUMENT} << 0; QTest::newRow("non-const ref argument from qualified member (object)") << 525 << 31 << 525 << 39 << QList{C_LOCAL, C_OUTPUT_ARGUMENT} << 0; QTest::newRow("non-const ref argument from qualified member (member)") << 525 << 40 << 525 << 46 << QList{C_FIELD, C_OUTPUT_ARGUMENT} << 0; QTest::newRow("non-const ref argument to constructor") << 540 << 47 << 540 << 55 << QList{C_LOCAL, C_OUTPUT_ARGUMENT} << 0; QTest::newRow("non-const ref argument to member initialization") << 546 << 15 << 546 << 18 << QList{C_PARAMETER, C_OUTPUT_ARGUMENT} << 0; QTest::newRow("typedef as underlying type in enum declaration") << 424 << 21 << 424 << 39 << QList{C_TYPE} << 0; QTest::newRow("argument to user-defined subscript operator") << 434 << 12 << 434 << 17 << QList{C_PARAMETER} << 0; QTest::newRow("partial class template specialization") << 553 << 25 << 553 << 28 << QList{C_TYPE, C_DECLARATION} << 0; QTest::newRow("using declaration for function") << 556 << 10 << 556 << 13 << QList{C_FUNCTION} << 0; QTest::newRow("variable in operator() call") << 566 << 7 << 566 << 10 << QList{C_PARAMETER} << 0; QTest::newRow("using declaration for function template") << 584 << 10 << 584 << 16 << QList{C_FUNCTION} << 0; QTest::newRow("Q_PROPERTY (macro name)") << 599 << 5 << 599 << 15 << QList{C_PREPROCESSOR} << 0; QTest::newRow("Q_PROPERTY (property name)") << 599 << 52 << 599 << 56 << QList{C_FIELD} << 0; QTest::newRow("Q_PROPERTY (getter)") << 599 << 62 << 599 << 69 << QList{C_FUNCTION} << 0; QTest::newRow("Q_PROPERTY (notifier)") << 599 << 91 << 599 << 102 << QList{C_FUNCTION} << 0; QTest::newRow("Q_PROPERTY (type)") << 600 << 22 << 600 << 29 << QList{C_TYPE} << 0; QTest::newRow("multi-line Q_PROPERTY (macro name)") << 704 << 5 << 704 << 15 << QList{C_PREPROCESSOR} << 0; QTest::newRow("multi-line Q_PROPERTY (property name)") << 718 << 13 << 718 << 17 << QList{C_FIELD} << 0; QTest::newRow("multi-line Q_PROPERTY (getter)") << 722 << 13 << 722 << 20 << QList{C_FUNCTION} << 0; QTest::newRow("multi-line Q_PROPERTY (notifier)") << 730 << 13 << 730 << 24 << QList{C_FUNCTION} << 0; QTest::newRow("old-style signal (macro)") << 672 << 5 << 672 << 11 << QList{C_PREPROCESSOR} << 0; QTest::newRow("old-style signal (signal)") << 672 << 12 << 672 << 21 << QList{C_FUNCTION} << 0; QTest::newRow("old-style signal (signal parameter)") << 672 << 22 << 672 << 29 << QList{C_TYPE} << 0; QTest::newRow("old-style slot (macro)") << 673 << 5 << 673 << 9 << QList{C_PREPROCESSOR} << 0; QTest::newRow("old-style slot (slot)") << 673 << 10 << 673 << 19 << QList{C_FUNCTION} << 0; QTest::newRow("old-style slot (slot parameter)") << 673 << 20 << 673 << 27 << QList{C_TYPE} << 0; QTest::newRow("old-style signal with complex parameter (macro)") << 674 << 5 << 674 << 11 << QList{C_PREPROCESSOR} << 0; QTest::newRow("old-style signal with complex parameter (signal)") << 674 << 12 << 674 << 21 << QList{C_FUNCTION} << 0; QTest::newRow("old-style signal with complex parameter (signal parameter part 1)") << 674 << 22 << 674 << 29 << QList{C_TYPE} << 0; QTest::newRow("old-style signal with complex parameter (signal parameter part 2)") << 674 << 32 << 674 << 37 << QList{C_TYPE} << 0; QTest::newRow("old-style signal with complex parameter (signal parameter part 3)") << 674 << 39 << 674 << 46 << QList{C_TYPE} << 0; QTest::newRow("constructor parameter") << 681 << 64 << 681 << 88 << QList{C_PARAMETER, C_DECLARATION} << 0; QTest::newRow("non-const ref argument to constructor (2)") << 686 << 42 << 686 << 45 << QList{C_LOCAL, C_OUTPUT_ARGUMENT} << 0; QTest::newRow("local variable captured by lambda") << 442 << 24 << 442 << 27 << QList{C_LOCAL} << 0; QTest::newRow("static protected member") << 693 << 16 << 693 << 30 << QList{C_FIELD, C_DECLARATION} << 0; QTest::newRow("static private member") << 696 << 16 << 696 << 28 << QList{C_FIELD, C_DECLARATION} << 0; QTest::newRow("alias template declaration (opening angle bracket)") << 700 << 10 << 700 << 11 << QList{C_PUNCTUATION} << int(CppTools::SemanticHighlighter::AngleBracketOpen); QTest::newRow("alias template declaration (closing angle bracket)") << 700 << 16 << 700 << 17 << QList{C_PUNCTUATION} << int(CppTools::SemanticHighlighter::AngleBracketClose); QTest::newRow("alias template declaration (new type)") << 700 << 24 << 700 << 28 << QList{C_TYPE, C_DECLARATION} << 0; QTest::newRow("alias template declaration (base type)") << 700 << 31 << 700 << 32 << QList{C_TYPE} << 0; QTest::newRow("alias template declaration (base type opening angle bracket)") << 700 << 32 << 700 << 33 << QList{C_PUNCTUATION} << int(CppTools::SemanticHighlighter::AngleBracketOpen); QTest::newRow("alias template declaration (base type closing angle bracket)") << 700 << 37 << 700 << 38 << QList{C_PUNCTUATION} << int(CppTools::SemanticHighlighter::AngleBracketClose); QTest::newRow("alias template instantiation (type)") << 701 << 1 << 701 << 5 << QList{C_TYPE} << 0; QTest::newRow("alias template instantiation (opening angle bracket)") << 701 << 5 << 701 << 6 << QList{C_PUNCTUATION} << int(CppTools::SemanticHighlighter::AngleBracketOpen); QTest::newRow("alias template instantiation (closing angle bracket)") << 701 << 7 << 701 << 8 << QList{C_PUNCTUATION} << int(CppTools::SemanticHighlighter::AngleBracketClose); QTest::newRow("function template specialization (opening angle bracket 1)") << 802 << 9 << 802 << 10 << QList{C_PUNCTUATION} << int(CppTools::SemanticHighlighter::AngleBracketOpen); QTest::newRow("function template specialization (closing angle bracket 1)") << 802 << 10 << 802 << 11 << QList{C_PUNCTUATION} << int(CppTools::SemanticHighlighter::AngleBracketClose); QTest::newRow("function template specialization (function name)") << 802 << 17 << 802 << 29 << QList{C_FUNCTION, C_FUNCTION_DEFINITION, C_DECLARATION} << 0; QTest::newRow("function template specialization (opening angle bracket 2)") << 802 << 29 << 802 << 30 << QList{C_PUNCTUATION} << int(CppTools::SemanticHighlighter::AngleBracketOpen); QTest::newRow("function template specialization (closing angle bracket 2)") << 802 << 33 << 802 << 34 << QList{C_PUNCTUATION} << int(CppTools::SemanticHighlighter::AngleBracketClose); QTest::newRow("class template specialization (opening angle bracket 1)") << 804 << 9 << 804 << 10 << QList{C_PUNCTUATION} << int(CppTools::SemanticHighlighter::AngleBracketOpen); QTest::newRow("class template specialization (closing angle bracket 1)") << 804 << 10 << 804 << 11 << QList{C_PUNCTUATION} << int(CppTools::SemanticHighlighter::AngleBracketClose); QTest::newRow("class template specialization (class name)") << 804 << 18 << 804 << 21 << QList{C_TYPE, C_DECLARATION} << 0; QTest::newRow("class template specialization (opening angle bracket 2)") << 804 << 21 << 804 << 22 << QList{C_PUNCTUATION} << int(CppTools::SemanticHighlighter::AngleBracketOpen); QTest::newRow("class template specialization (closing angle bracket 2)") << 804 << 25 << 804 << 26 << QList{C_PUNCTUATION} << int(CppTools::SemanticHighlighter::AngleBracketClose); QTest::newRow("structured binding (var 1)") << 737 << 17 << 737 << 18 << QList{C_LOCAL, C_DECLARATION} << 0; QTest::newRow("structured binding (var 2)") << 737 << 20 << 737 << 21 << QList{C_LOCAL, C_DECLARATION} << 0; QTest::newRow("local var via indirect macro") << 746 << 20 << 746 << 30 << QList{C_LOCAL} << 0; QTest::newRow("global variable in multi-dimensional array") << 752 << 13 << 752 << 23 << QList{C_GLOBAL} << 0; QTest::newRow("reference to global variable") << 764 << 5 << 764 << 14 << QList{C_GLOBAL} << 0; QTest::newRow("nested template instantiation (namespace 1)") << 773 << 8 << 773 << 11 << QList{C_TYPE} << 0; QTest::newRow("nested template instantiation (type 1)") << 773 << 13 << 773 << 19 << QList{C_TYPE} << 0; QTest::newRow("nested template instantiation (opening angle bracket 1)") << 773 << 19 << 773 << 20 << QList{C_PUNCTUATION} << int(CppTools::SemanticHighlighter::AngleBracketOpen); QTest::newRow("nested template instantiation (namespace 2)") << 773 << 20 << 773 << 23 << QList{C_TYPE} << 0; QTest::newRow("nested template instantiation (type 2)") << 773 << 25 << 773 << 29 << QList{C_TYPE} << 0; QTest::newRow("nested template instantiation (opening angle bracket 2)") << 773 << 29 << 773 << 30 << QList{C_PUNCTUATION} << int(CppTools::SemanticHighlighter::AngleBracketOpen); QTest::newRow("nested template instantiation (closing angle bracket 1)") << 773 << 38 << 773 << 39 << QList{C_PUNCTUATION} << int(CppTools::SemanticHighlighter::AngleBracketClose); QTest::newRow("nested template instantiation (closing angle bracket 2)") << 773 << 39 << 773 << 40 << QList{C_PUNCTUATION} << int(CppTools::SemanticHighlighter::AngleBracketClose); QTest::newRow("nested template instantiation (variable)") << 773 << 41 << 773 << 43 << QList{C_GLOBAL, C_DECLARATION} << 0; QTest::newRow("doubly nested template instantiation (opening angle bracket 1)") << 806 << 12 << 806 << 13 << QList{C_PUNCTUATION} << int(CppTools::SemanticHighlighter::AngleBracketOpen); QTest::newRow("doubly nested template instantiation (opening angle bracket 2)") << 806 << 24 << 806 << 25 << QList{C_PUNCTUATION} << int(CppTools::SemanticHighlighter::AngleBracketOpen); QTest::newRow("doubly nested template instantiation (opening angle bracket 3)") << 806 << 36 << 806 << 37 << QList{C_PUNCTUATION} << int(CppTools::SemanticHighlighter::AngleBracketOpen); QTest::newRow("doubly nested template instantiation (closing angle bracket 1)") << 806 << 40 << 806 << 41 << QList{C_PUNCTUATION} << int(CppTools::SemanticHighlighter::AngleBracketClose); QTest::newRow("doubly nested template instantiation (closing angle bracket 2)") << 806 << 41 << 806 << 42 << QList{C_PUNCTUATION} << int(CppTools::SemanticHighlighter::AngleBracketClose); QTest::newRow("doubly nested template instantiation (closing angle bracket 3)") << 806 << 42 << 806 << 43 << QList{C_PUNCTUATION} << int(CppTools::SemanticHighlighter::AngleBracketClose); QTest::newRow("triply nested template instantiation with spacing (opening angle bracket 1)") << 808 << 13 << 808 << 14 << QList{C_PUNCTUATION} << int(CppTools::SemanticHighlighter::AngleBracketOpen); QTest::newRow("triply nested template instantiation with spacing (opening angle bracket 2)") << 808 << 27 << 808 << 28 << QList{C_PUNCTUATION} << int(CppTools::SemanticHighlighter::AngleBracketOpen); QTest::newRow("triply nested template instantiation with spacing (opening angle bracket 3)") << 808 << 39 << 808 << 40 << QList{C_PUNCTUATION} << int(CppTools::SemanticHighlighter::AngleBracketOpen); QTest::newRow("triply nested template instantiation with spacing (opening angle bracket 4)") << 809 << 12 << 809 << 13 << QList{C_PUNCTUATION} << int(CppTools::SemanticHighlighter::AngleBracketOpen); QTest::newRow("triply nested template instantiation with spacing (closing angle bracket 1)") << 810 << 1 << 810 << 2 << QList{C_PUNCTUATION} << int(CppTools::SemanticHighlighter::AngleBracketClose); QTest::newRow("triply nested template instantiation with spacing (closing angle bracket 2)") << 810 << 2 << 810 << 3 << QList{C_PUNCTUATION} << int(CppTools::SemanticHighlighter::AngleBracketClose); QTest::newRow("triply nested template instantiation with spacing (closing angle bracket 3)") << 811 << 2 << 811 << 3 << QList{C_PUNCTUATION} << int(CppTools::SemanticHighlighter::AngleBracketClose); QTest::newRow("triply nested template instantiation with spacing (closing angle bracket 4)") << 812 << 3 << 812 << 4 << QList{C_PUNCTUATION} << int(CppTools::SemanticHighlighter::AngleBracketClose); QTest::newRow("cyrillic string") << 792 << 24 << 792 << 27 << QList{C_STRING} << 0; QTest::newRow("macro in struct") << 795 << 9 << 795 << 14 << QList{C_PREPROCESSOR, C_DECLARATION} << 0; QTest::newRow("#ifdef'ed out code") << 800 << 1 << 800 << 17 << QList{C_DISABLED_CODE} << 0; } void ClangdTestHighlighting::test() { QFETCH(int, firstLine); QFETCH(int, startColumn); QFETCH(int, lastLine); QFETCH(int, endColumn); QFETCH(QList, expectedStyles); QFETCH(int, expectedKind); const TextEditor::TextDocument * const doc = document("highlighting.cpp"); QVERIFY(doc); const int startPos = Utils::Text::positionInText(doc->document(), firstLine, startColumn); const int endPos = Utils::Text::positionInText(doc->document(), lastLine, endColumn); const auto lessThan = [=](const TextEditor::HighlightingResult &r, int) { return Utils::Text::positionInText(doc->document(), r.line, r.column) < startPos; }; const auto findResults = [=] { TextEditor::HighlightingResults results; auto it = std::lower_bound(m_results.cbegin(), m_results.cend(), 0, lessThan); if (it == m_results.cend()) return results; while (it != m_results.cend()) { const int resultEndPos = Utils::Text::positionInText(doc->document(), it->line, it->column) + it->length; if (resultEndPos > endPos) break; results << *it++; } return results; }; const TextEditor::HighlightingResults results = findResults(); QEXPECT_FAIL("typedef as underlying type in enum declaration", "FIXME: clangd does not report this symbol", Abort); QEXPECT_FAIL("Q_PROPERTY (property name)", "FIXME: How to do this?", Abort); QEXPECT_FAIL("Q_PROPERTY (getter)", "FIXME: How to do this?", Abort); QEXPECT_FAIL("Q_PROPERTY (notifier)", "FIXME: How to do this?", Abort); QEXPECT_FAIL("Q_PROPERTY (type)", "FIXME: How to do this?", Abort); QEXPECT_FAIL("multi-line Q_PROPERTY (property name)", "FIXME: How to do this?", Abort); QEXPECT_FAIL("multi-line Q_PROPERTY (getter)", "FIXME: How to do this?", Abort); QEXPECT_FAIL("multi-line Q_PROPERTY (notifier)", "FIXME: How to do this?", Abort); QEXPECT_FAIL("old-style signal (signal)", "check if and how we want to support this", Abort); QEXPECT_FAIL("old-style signal (signal parameter)", "check if and how we want to support this", Abort); QEXPECT_FAIL("old-style slot (slot)", "check if and how we want to support this", Abort); QEXPECT_FAIL("old-style slot (slot parameter)", "check if and how we want to support this", Abort); QEXPECT_FAIL("old-style signal with complex parameter (signal)", "check if and how we want to support this", Abort); QEXPECT_FAIL("old-style signal with complex parameter (signal parameter part 1)", "check if and how we want to support this", Abort); QEXPECT_FAIL("old-style signal with complex parameter (signal parameter part 2)", "check if and how we want to support this", Abort); QEXPECT_FAIL("old-style signal with complex parameter (signal parameter part 3)", "check if and how we want to support this", Abort); QEXPECT_FAIL("alias template instantiation (type)", "FIXME: clangd doesn't report this", Abort); QEXPECT_FAIL("alias template instantiation (opening angle bracket)", "FIXME: This construct does not appear in the AST", Abort); QEXPECT_FAIL("alias template instantiation (closing angle bracket)", "FIXME: This construct does not appear in the AST", Abort); QEXPECT_FAIL("function template specialization (opening angle bracket 1)", "specialization appears as a normal function in the AST", Abort); QEXPECT_FAIL("function template specialization (closing angle bracket 1)", "specialization appears as a normal function in the AST", Abort); QEXPECT_FAIL("function template specialization (opening angle bracket 2)", "specialization appears as a normal function in the AST", Abort); QEXPECT_FAIL("function template specialization (closing angle bracket 2)", "specialization appears as a normal function in the AST", Abort); QCOMPARE(results.length(), 1); const TextEditor::HighlightingResult result = results.first(); QCOMPARE(result.line, firstLine); QCOMPARE(result.column, startColumn); QCOMPARE(result.length, endPos - startPos); QList actualStyles; if (result.useTextSyles) { actualStyles << result.textStyles.mainStyle; for (const TextEditor::TextStyle s : result.textStyles.mixinStyles) actualStyles << s; } if (client()->versionNumber() < QVersionNumber(14)) { QEXPECT_FAIL("final virtual function call via pointer", "clangd < 14 does not send virtual modifier", Continue); QEXPECT_FAIL("virtual member function definition outside of class body", "clangd < 14 does not send virtual modifier", Continue); QEXPECT_FAIL("virtual function call via pointer", "clangd < 14 does not send virtual modifier", Continue); QEXPECT_FAIL("non-final virtual function call via pointer", "clangd < 14 does not send virtual modifier", Continue); } QEXPECT_FAIL("template non-type parameter", "FIXME: clangd reports non-type template parameters at \"typeParameter\"", Continue); QEXPECT_FAIL("reference to non-type template parameter", "FIXME: clangd reports non-type template parameters at \"typeParameter\"", Continue); QEXPECT_FAIL("non-const reference via member function call as output argument (function)", "Without punctuation and comment tokens from clangd, it's not possible " "to highlight entire expressions. But do we really want this? What about nested " "calls where the inner arguments are const?", Continue); QCOMPARE(actualStyles, expectedStyles); QCOMPARE(result.kind, expectedKind); } } // namespace Tests } // namespace Internal } // namespace ClangCodeModel