diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/plugins/clangcodemodel/clangdclient.cpp | 12 | ||||
-rw-r--r-- | src/plugins/clangcodemodel/test/clangdtests.cpp | 23 | ||||
-rw-r--r-- | src/plugins/coreplugin/editormanager/editormanager.h | 4 | ||||
-rw-r--r-- | src/plugins/cppeditor/CMakeLists.txt | 2 | ||||
-rw-r--r-- | src/plugins/cppeditor/cppeditor.qbs | 1 | ||||
-rw-r--r-- | src/plugins/cppeditor/cppeditor_dependencies.pri | 1 | ||||
-rw-r--r-- | src/plugins/cppeditor/cppeditorplugin.h | 10 | ||||
-rw-r--r-- | src/plugins/cppeditor/cppeditortestcase.cpp | 13 | ||||
-rw-r--r-- | src/plugins/cppeditor/cppeditortestcase.h | 5 | ||||
-rw-r--r-- | src/plugins/cppeditor/cppquickfix_test.cpp | 4 | ||||
-rw-r--r-- | src/plugins/cppeditor/cppuseselections_test.cpp | 13 | ||||
-rw-r--r-- | src/plugins/cppeditor/followsymbol_switchmethoddecldef_test.cpp | 121 | ||||
-rw-r--r-- | src/plugins/cpptools/cpptoolstestcase.cpp | 11 | ||||
-rw-r--r-- | src/plugins/cpptools/cpptoolstestcase.h | 19 | ||||
-rw-r--r-- | src/plugins/projectexplorer/project.h | 4 | ||||
-rw-r--r-- | src/plugins/texteditor/texteditor.cpp | 4 |
16 files changed, 207 insertions, 40 deletions
diff --git a/src/plugins/clangcodemodel/clangdclient.cpp b/src/plugins/clangcodemodel/clangdclient.cpp index b168045395..d1ec86393e 100644 --- a/src/plugins/clangcodemodel/clangdclient.cpp +++ b/src/plugins/clangcodemodel/clangdclient.cpp @@ -36,6 +36,7 @@ #include <cpptools/cppvirtualfunctionassistprovider.h> #include <cpptools/cppvirtualfunctionproposalitem.h> #include <languageclient/languageclientinterface.h> +#include <projectexplorer/project.h> #include <projectexplorer/projecttree.h> #include <projectexplorer/session.h> #include <texteditor/basefilefind.h> @@ -513,11 +514,14 @@ ClangdClient::ClangdClient(Project *project, const Utils::FilePath &jsonDbDir) setLocatorsEnabled(false); setProgressTitleForToken(indexingToken(), tr("Parsing C/C++ Files (clangd)")); setCurrentProject(project); - connect(this, &Client::workDone, this, [this](const ProgressToken &token) { + connect(this, &Client::workDone, this, [this, project](const ProgressToken &token) { const QString * const val = Utils::get_if<QString>(&token); if (val && *val == indexingToken()) { d->isFullyIndexed = true; emit indexingFinished(); +#ifdef WITH_TESTS + emit project->indexingFinished("Indexer.Clangd"); +#endif } }); @@ -848,6 +852,8 @@ void ClangdClient::followSymbol( return; } + qCDebug(clangdLog) << "follow symbol requested" << document->filePath() + << cursor.blockNumber() << cursor.positionInBlock(); d->followSymbolData.emplace(this, ++d->nextFollowSymbolId, cursor, editorWidget, DocumentUri::fromFilePath(document->filePath()), std::move(callback), openInSplit); @@ -856,6 +862,7 @@ void ClangdClient::followSymbol( // AST node corresponding to the cursor position, so we can find out whether // we have to look for overrides. const auto gotoDefCallback = [this, id = d->followSymbolData->id](const Utils::Link &link) { + qCDebug(clangdLog) << "received go to definition response"; if (!link.hasValidTarget()) { d->followSymbolData.reset(); return; @@ -872,6 +879,7 @@ void ClangdClient::followSymbol( Range(cursor))); astRequest.setResponseCallback([this, id = d->followSymbolData->id]( const AstRequest::Response &response) { + qCDebug(clangdLog) << "received ast response"; if (!d->followSymbolData || d->followSymbolData->id != id) return; const auto result = response.result(); @@ -891,6 +899,8 @@ void ClangdClient::Private::handleGotoDefinitionResult() QTC_ASSERT(followSymbolData->defLink.hasValidTarget(), return); QTC_ASSERT(followSymbolData->cursorNode.isValid(), return); + qCDebug(clangdLog) << "handling go to definition result"; + // No dis-ambiguation necessary. Call back with the link and finish. if (!followSymbolData->cursorNode.isMemberFunctionCall() && !followSymbolData->cursorNode.isPureVirtualDeclaration()) { diff --git a/src/plugins/clangcodemodel/test/clangdtests.cpp b/src/plugins/clangcodemodel/test/clangdtests.cpp index 4c109c888a..d0b0cf97bc 100644 --- a/src/plugins/clangcodemodel/test/clangdtests.cpp +++ b/src/plugins/clangcodemodel/test/clangdtests.cpp @@ -49,6 +49,7 @@ using namespace CPlusPlus; using namespace Core; +using namespace CppTools::Tests; using namespace ProjectExplorer; namespace ClangCodeModel { @@ -67,20 +68,6 @@ void ClangdTests::initTestCase() settings->setUseClangd(true); } -template <typename Signal> static bool waitForSignalOrTimeout( - const typename QtPrivate::FunctionPointer<Signal>::Object *sender, Signal signal) -{ - QTimer timer; - timer.setSingleShot(true); - timer.setInterval(timeOutInMs()); - QEventLoop loop; - QObject::connect(&timer, &QTimer::timeout, &loop, &QEventLoop::quit); - QObject::connect(sender, signal, &loop, &QEventLoop::quit); - timer.start(); - loop.exec(); - return timer.isActive(); -} - // 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. @@ -110,7 +97,7 @@ void ClangdTests::testFindReferences() ClangdClient *client = modelManagerSupport->clientForProject(openProjectResult.project()); if (!client) { QVERIFY(waitForSignalOrTimeout(modelManagerSupport, - &ClangModelManagerSupport::createdClient)); + &ClangModelManagerSupport::createdClient, timeOutInMs())); client = modelManagerSupport->clientForProject(openProjectResult.project()); } QVERIFY(client); @@ -119,7 +106,7 @@ void ClangdTests::testFindReferences() // Wait until the client is fully initialized, i.e. it's completed the handshake // with the server. if (!client->reachable()) - QVERIFY(waitForSignalOrTimeout(client, &ClangdClient::initialized)); + QVERIFY(waitForSignalOrTimeout(client, &ClangdClient::initialized, timeOutInMs())); QVERIFY(client->reachable()); // The kind of AST support we need was introduced in LLVM 13. @@ -128,7 +115,7 @@ void ClangdTests::testFindReferences() // Wait for index to build. if (!client->isFullyIndexed()) - QVERIFY(waitForSignalOrTimeout(client, &ClangdClient::indexingFinished)); + QVERIFY(waitForSignalOrTimeout(client, &ClangdClient::indexingFinished, timeOutInMs())); QVERIFY(client->isFullyIndexed()); // Open cpp documents. @@ -167,7 +154,7 @@ void ClangdTests::testFindReferences() cursor.setPosition((pos)); \ searchResults.clear(); \ client->findUsages((doc), cursor, {}); \ - QVERIFY(waitForSignalOrTimeout(client, &ClangdClient::findUsagesDone)); \ + QVERIFY(waitForSignalOrTimeout(client, &ClangdClient::findUsagesDone, timeOutInMs())); \ } while (false) #define EXPECT_RESULT(index, lne, col, type) \ diff --git a/src/plugins/coreplugin/editormanager/editormanager.h b/src/plugins/coreplugin/editormanager/editormanager.h index 1bea80ceca..aadb89483b 100644 --- a/src/plugins/coreplugin/editormanager/editormanager.h +++ b/src/plugins/coreplugin/editormanager/editormanager.h @@ -192,6 +192,10 @@ signals: void autoSaved(); void currentEditorAboutToChange(Core::IEditor *editor); +#ifdef WITH_TESTS + void linkOpened(); +#endif + public slots: static void saveDocument(); static void saveDocumentAs(); diff --git a/src/plugins/cppeditor/CMakeLists.txt b/src/plugins/cppeditor/CMakeLists.txt index 72d83ef26d..4b4bdd4c15 100644 --- a/src/plugins/cppeditor/CMakeLists.txt +++ b/src/plugins/cppeditor/CMakeLists.txt @@ -1,7 +1,7 @@ add_qtc_plugin(CppEditor DEFINES CPPEDITOR_LIBRARY PLUGIN_DEPENDS Core CppTools ProjectExplorer TextEditor - PLUGIN_TEST_DEPENDS QmakeProjectManager + PLUGIN_TEST_DEPENDS QbsProjectManager QmakeProjectManager SOURCES cppautocompleter.cpp cppautocompleter.h cppcodemodelinspectordialog.cpp cppcodemodelinspectordialog.h cppcodemodelinspectordialog.ui diff --git a/src/plugins/cppeditor/cppeditor.qbs b/src/plugins/cppeditor/cppeditor.qbs index de9b4d3101..a6c27c30c5 100644 --- a/src/plugins/cppeditor/cppeditor.qbs +++ b/src/plugins/cppeditor/cppeditor.qbs @@ -17,6 +17,7 @@ QtcPlugin { pluginTestDepends: [ "QmakeProjectManager", + "QbsProjectManager", ] files: [ diff --git a/src/plugins/cppeditor/cppeditor_dependencies.pri b/src/plugins/cppeditor/cppeditor_dependencies.pri index c9a690b079..a17c907490 100644 --- a/src/plugins/cppeditor/cppeditor_dependencies.pri +++ b/src/plugins/cppeditor/cppeditor_dependencies.pri @@ -9,4 +9,5 @@ QTC_PLUGIN_DEPENDS += \ cpptools \ projectexplorer QTC_TEST_DEPENDS += \ + qbsprojectmanager \ qmakeprojectmanager diff --git a/src/plugins/cppeditor/cppeditorplugin.h b/src/plugins/cppeditor/cppeditorplugin.h index 523c8e46a5..74a50ad406 100644 --- a/src/plugins/cppeditor/cppeditorplugin.h +++ b/src/plugins/cppeditor/cppeditorplugin.h @@ -27,6 +27,10 @@ #include <extensionsystem/iplugin.h> +#ifdef WITH_TESTS +namespace ProjectExplorer { class Kit; } +#endif + namespace CppEditor { namespace Internal { @@ -49,6 +53,10 @@ public: CppQuickFixAssistProvider *quickFixProvider() const; +#ifdef WITH_TESTS + ProjectExplorer::Kit *m_testKit = nullptr; +#endif + signals: void outlineSortingChanged(bool sort); void typeHierarchyRequested(); @@ -67,6 +75,8 @@ private: QVector<QObject *> createTestObjects() const override; private slots: + void initTestCase(); + // The following tests expect that no projects are loaded on start-up. void test_SwitchMethodDeclarationDefinition_data(); void test_SwitchMethodDeclarationDefinition(); diff --git a/src/plugins/cppeditor/cppeditortestcase.cpp b/src/plugins/cppeditor/cppeditortestcase.cpp index 027523a02d..b9aaae023a 100644 --- a/src/plugins/cppeditor/cppeditortestcase.cpp +++ b/src/plugins/cppeditor/cppeditortestcase.cpp @@ -28,9 +28,12 @@ #include "cppeditor.h" #include "cppeditorwidget.h" #include "cppeditordocument.h" +#include "cppeditorplugin.h" #include <coreplugin/editormanager/editormanager.h> +#include <cpptools/cppcodemodelsettings.h> #include <cpptools/cppsemanticinfo.h> +#include <cpptools/cpptoolsreuse.h> #include <cplusplus/CppDocument.h> #include <QDir> @@ -74,12 +77,20 @@ bool TestDocument::hasCursorMarker() const { return m_cursorPosition != -1; } bool TestDocument::hasAnchorMarker() const { return m_anchorPosition != -1; } TestCase::TestCase(bool runGarbageCollector) - : CppTools::Tests::TestCase(runGarbageCollector) + : CppTools::Tests::TestCase(runGarbageCollector), + m_prevUseClangd(CppTools::codeModelSettings()->useClangd()) { } TestCase::~TestCase() { + CppTools::codeModelSettings()->setUseClangd(m_prevUseClangd); +} + +void TestCase::setUseClangd() +{ + if (CppEditorPlugin::instance()->m_testKit) + CppTools::codeModelSettings()->setUseClangd(true); } bool TestCase::openCppEditor(const QString &fileName, CppEditor **editor, CppEditorWidget **editorWidget) diff --git a/src/plugins/cppeditor/cppeditortestcase.h b/src/plugins/cppeditor/cppeditortestcase.h index 6eb9821bdd..519b7cbafd 100644 --- a/src/plugins/cppeditor/cppeditortestcase.h +++ b/src/plugins/cppeditor/cppeditortestcase.h @@ -62,12 +62,17 @@ public: TestCase(bool runGarbageCollector = true); ~TestCase(); + void setUseClangd(); + static bool openCppEditor(const QString &fileName, CppEditor **editor, CppEditorWidget **editorWidget = 0); static CPlusPlus::Document::Ptr waitForRehighlightedSemanticDocument( CppEditorWidget *editorWidget); + +private: + const bool m_prevUseClangd; }; } // namespace Tests diff --git a/src/plugins/cppeditor/cppquickfix_test.cpp b/src/plugins/cppeditor/cppquickfix_test.cpp index 849201d8a5..35f35a3cc3 100644 --- a/src/plugins/cppeditor/cppquickfix_test.cpp +++ b/src/plugins/cppeditor/cppquickfix_test.cpp @@ -7185,7 +7185,7 @@ void CppEditorPlugin::test_quickfix_ExtractFunction_data() "}\n" "void NS::C::f(NS::C &c)\n" "{\n" - " @{start}C *c = &c;@{end}\n" + " @{start}C *c2 = &c;@{end}\n" "}\n") << _("namespace NS {\n" "class C {\n" @@ -7197,7 +7197,7 @@ void CppEditorPlugin::test_quickfix_ExtractFunction_data() "}\n" "inline void NS::C::extracted(NS::C &c)\n" "{\n" - " C *c = &c;\n" + " C *c2 = &c;\n" "}\n" "\n" "void NS::C::f(NS::C &c)\n" diff --git a/src/plugins/cppeditor/cppuseselections_test.cpp b/src/plugins/cppeditor/cppuseselections_test.cpp index 10d6927434..1bf53c3799 100644 --- a/src/plugins/cppeditor/cppuseselections_test.cpp +++ b/src/plugins/cppeditor/cppuseselections_test.cpp @@ -28,6 +28,8 @@ #include "cppeditorplugin.h" #include "cppeditortestcase.h" +#include <cpptools/cppmodelmanager.h> + #include <QElapsedTimer> #include <QtTest> @@ -100,11 +102,18 @@ UseSelectionsTestCase::UseSelectionsTestCase(TestDocument &testFile, bool hasTimedOut; const SelectionList selections = waitForUseSelections(&hasTimedOut); - QEXPECT_FAIL("non-local use as macro argument - argument expanded 1", "TODO", Abort); + const bool clangCodeModel = CppTools::CppModelManager::instance()->isClangCodeModelActive(); + if (clangCodeModel) { + QEXPECT_FAIL("local use as macro argument - argument eaten", "fails with CCM, find out why", + Abort); + } else { + QEXPECT_FAIL("non-local use as macro argument - argument expanded 1", "TODO", Abort); + } QVERIFY(!hasTimedOut); // foreach (const Selection &selection, selections) // qDebug() << QTest::toString(selection); - QEXPECT_FAIL("non-local use as macro argument - argument expanded 2", "TODO", Abort); + if (!clangCodeModel) + QEXPECT_FAIL("non-local use as macro argument - argument expanded 2", "TODO", Abort); QCOMPARE(selections, expectedSelections); } diff --git a/src/plugins/cppeditor/followsymbol_switchmethoddecldef_test.cpp b/src/plugins/cppeditor/followsymbol_switchmethoddecldef_test.cpp index 5cf1e31d29..e6c871f4cd 100644 --- a/src/plugins/cppeditor/followsymbol_switchmethoddecldef_test.cpp +++ b/src/plugins/cppeditor/followsymbol_switchmethoddecldef_test.cpp @@ -28,13 +28,18 @@ #include "cppeditorplugin.h" #include "cppeditortestcase.h" +#include <cpptools/cppcodemodelsettings.h> #include <cpptools/cppelementevaluator.h> #include <cpptools/cppfollowsymbolundercursor.h> #include <cpptools/cppvirtualfunctionassistprovider.h> #include <cpptools/cppvirtualfunctionproposalitem.h> +#include <cpptools/cpptoolsreuse.h> #include <cpptools/cpptoolstestcase.h> #include <cpptools/cppmodelmanager.h> +#include <projectexplorer/kitmanager.h> +#include <projectexplorer/projectexplorer.h> + #include <texteditor/codeassist/genericproposalmodel.h> #include <texteditor/codeassist/iassistprocessor.h> #include <texteditor/codeassist/iassistproposal.h> @@ -76,6 +81,7 @@ using namespace CPlusPlus; using namespace CppTools; using namespace TextEditor; using namespace Core; +using namespace ProjectExplorer; class OverrideItem { public: @@ -267,6 +273,8 @@ F2TestCase::F2TestCase(CppEditorAction action, { QVERIFY(succeededSoFar()); + setUseClangd(); + // Check if there are initial and target position markers TestDocumentPtr initialTestFile = testFileWithInitialCursorMarker(testFiles); QVERIFY2(initialTestFile, @@ -275,13 +283,68 @@ F2TestCase::F2TestCase(CppEditorAction action, QVERIFY2(targetTestFile, "No test file with target cursor marker is provided."); + const QString curTestName = QLatin1String(QTest::currentTestFunction()); + const QString tag = QLatin1String(QTest::currentDataTag()); + const bool useClangd = CppTools::codeModelSettings()->useClangd(); + if (useClangd) { + if (curTestName == "test_FollowSymbolUnderCursor_virtualFunctionCall" + || curTestName == "test_FollowSymbolUnderCursor_virtualFunctionCall_multipleDocuments") { + QSKIP("TODO: Add test infrastructure for this"); + } + if (curTestName == "test_FollowSymbolUnderCursor_QObject_connect" + || curTestName == "test_FollowSymbolUnderCursor_QObject_oldStyleConnect") { + QSKIP("TODO: Implement fall-back"); + } + if (curTestName == "test_FollowSymbolUnderCursor_classOperator" && tag == "backward") + QSKIP("clangd goes to operator name first"); + if (tag.toLower().contains("fuzzy")) + QSKIP("fuzzy matching is not supposed to work with clangd"); // TODO: Implement fallback as we do with libclang + if (tag == "baseClassFunctionIntroducedByUsingDeclaration") + QSKIP("clangd points to the using declaration"); + if (tag == "classDestructor") + QSKIP("clangd wants the cursor before the ~ character"); + if (curTestName == "test_FollowSymbolUnderCursor_classOperator_inOp") + QSKIP("clangd goes to operator name first"); + if (tag == "fromFunctionBody" || tag == "fromReturnType" + || tag == "conversionOperatorDecl2Def") { + QSKIP("TODO: explicit decl/def switch not yet supported with clangd"); + } + } + // Write files to disk CppTools::Tests::TemporaryDir temporaryDir; QVERIFY(temporaryDir.isValid()); + QString projectFileContent = "CppApplication { files: ["; foreach (TestDocumentPtr testFile, testFiles) { QVERIFY(testFile->baseDirectory().isEmpty()); testFile->setBaseDirectory(temporaryDir.path()); QVERIFY(testFile->writeToDisk()); + projectFileContent += QString::fromLatin1("\"%1\",").arg(testFile->filePath()); + } + projectFileContent += "]}\n"; + + class ProjectCloser { + public: + void setProject(Project *p) { m_p = p; } + ~ProjectCloser() { if (m_p) ProjectExplorerPlugin::unloadProject(m_p); } + private: + Project * m_p = nullptr; + } projectCloser; + + if (useClangd) { + TestDocument projectFile(projectFileContent.toUtf8(), "project.qbs"); + projectFile.setBaseDirectory(temporaryDir.path()); + QVERIFY(projectFile.writeToDisk()); + const auto openProjectResult = ProjectExplorerPlugin::openProject(projectFile.filePath()); + QVERIFY2(openProjectResult && openProjectResult.project(), + qPrintable(openProjectResult.errorMessage())); + projectCloser.setProject(openProjectResult.project()); + openProjectResult.project()->configureAsExampleProject( + CppEditorPlugin::instance()->m_testKit); + + // Wait until project is fully indexed. + QVERIFY(CppTools::Tests::waitForSignalOrTimeout(openProjectResult.project(), + &Project::indexingFinished, CppTools::Tests::clangdIndexingTimeout())); } // Update Code Model @@ -294,7 +357,8 @@ F2TestCase::F2TestCase(CppEditorAction action, foreach (TestDocumentPtr testFile, testFiles) { QVERIFY(openCppEditor(testFile->filePath(), &testFile->m_editor, &testFile->m_editorWidget)); - closeEditorAtEndOfTestCase(testFile->m_editor); + if (!useClangd) // Editors get closed when unloading project. + closeEditorAtEndOfTestCase(testFile->m_editor); // Wait until the indexer processed the just opened file. // The file is "Full Checked" since it is in the working copy now, @@ -303,13 +367,16 @@ F2TestCase::F2TestCase(CppEditorAction action, const Document::Ptr document = waitForFileInGlobalSnapshot(testFile->filePath()); QVERIFY(document); if (document->checkMode() == Document::FullCheck) { + if (!document->diagnosticMessages().isEmpty()) + qDebug() << document->diagnosticMessages().first().text(); QVERIFY(document->diagnosticMessages().isEmpty()); break; } } // Rehighlight - waitForRehighlightedSemanticDocument(testFile->m_editorWidget); + if (!useClangd) + waitForRehighlightedSemanticDocument(testFile->m_editorWidget); } // Activate editor of initial test file @@ -329,14 +396,8 @@ F2TestCase::F2TestCase(CppEditorAction action, FollowSymbolInterface &delegate = CppModelManager::instance()->followSymbolInterface(); auto* builtinFollowSymbol = dynamic_cast<FollowSymbolUnderCursor *>(&delegate); if (!builtinFollowSymbol) { - if (filePaths.size() > 1) - QSKIP("Clang FollowSymbol does not currently support multiple files (except cpp+header)"); - const QString curTestName = QLatin1String(QTest::currentTestFunction()); - if (curTestName == "test_FollowSymbolUnderCursor_QObject_connect" - || curTestName == "test_FollowSymbolUnderCursor_virtualFunctionCall" - || curTestName == "test_FollowSymbolUnderCursor_QTCREATORBUG7903") { + if (curTestName == "test_FollowSymbolUnderCursor_QTCREATORBUG7903") QSKIP((curTestName + " is not supported by Clang FollowSymbol").toLatin1()); - } widget->openLinkUnderCursor(); break; @@ -358,14 +419,24 @@ F2TestCase::F2TestCase(CppEditorAction action, break; } case SwitchBetweenMethodDeclarationDefinitionAction: - CppEditorPlugin::instance()->switchDeclarationDefinition(); + if (CppTools::codeModelSettings()->useClangd()) + initialTestFile->m_editorWidget->openLinkUnderCursor(); + else + CppEditorPlugin::instance()->switchDeclarationDefinition(); break; default: QFAIL("Unknown test action"); break; } - QCoreApplication::processEvents(); + if (useClangd) { + QEXPECT_FAIL("infiniteLoopLocalTypedef_QTCREATORBUG-11999", + "clangd bug: Go to definition does not return", Abort); + QVERIFY(CppTools::Tests::waitForSignalOrTimeout(EditorManager::instance(), + &EditorManager::linkOpened, 10000)); + } else { + QCoreApplication::processEvents(); + } // Compare IEditor *currentEditor = EditorManager::currentEditor(); @@ -379,8 +450,11 @@ F2TestCase::F2TestCase(CppEditorAction action, // qDebug() << "Expected line:" << expectedLine; // qDebug() << "Expected column:" << expectedColumn; - QEXPECT_FAIL("globalVarFromEnum", "Contributor works on a fix.", Abort); - QEXPECT_FAIL("matchFunctionSignature_Follow_5", "foo(int) resolved as CallAST", Abort); + if (!CppTools::codeModelSettings()->useClangd()) { + QEXPECT_FAIL("globalVarFromEnum", "Contributor works on a fix.", Abort); + QEXPECT_FAIL("matchFunctionSignature_Follow_5", "foo(int) resolved as CallAST", Abort); + } + QCOMPARE(currentTextEditor->currentLine(), expectedLine); QCOMPARE(currentTextEditor->currentColumn(), expectedColumn); @@ -421,6 +495,25 @@ Q_DECLARE_METATYPE(QList<CppEditor::Internal::TestDocumentPtr>) namespace CppEditor { namespace Internal { +void CppEditorPlugin::initTestCase() +{ + const auto settings = CppTools::codeModelSettings(); + const QString clangdFromEnv = qEnvironmentVariable("QTC_CLANGD"); + if (clangdFromEnv.isEmpty()) + return; + settings->setClangdFilePath(Utils::FilePath::fromString(clangdFromEnv)); + const auto clangd = settings->clangdFilePath(); + if (clangd.isEmpty() || !clangd.exists()) + return; + + // Find suitable kit. + m_testKit = Utils::findOr(KitManager::kits(), nullptr, [](const Kit *k) { + return k->isValid(); + }); + if (!m_testKit) + QSKIP("This test requires at least one kit to be present"); +} + void CppEditorPlugin::test_SwitchMethodDeclarationDefinition_data() { QTest::addColumn<QByteArray>("header"); @@ -576,7 +669,6 @@ void CppEditorPlugin::test_SwitchMethodDeclarationDefinition_data() "int OtherClass::var;\n" "namespace NS {\n" "int OtherClass::var;\n" - "float Test::var;\n" "int Test::$var;\n" "}\n"); @@ -1276,7 +1368,6 @@ void CppEditorPlugin::test_FollowSymbolUnderCursor_multipleDocuments_data() "int OtherClass::var;\n" "namespace NS {\n" "int OtherClass::var;\n" - "float Test::var;\n" "int Test::$var;\n" "}\n", "file.cpp")}; } diff --git a/src/plugins/cpptools/cpptoolstestcase.cpp b/src/plugins/cpptools/cpptoolstestcase.cpp index 8a714b7df7..c80a4a7cff 100644 --- a/src/plugins/cpptools/cpptoolstestcase.cpp +++ b/src/plugins/cpptools/cpptoolstestcase.cpp @@ -44,6 +44,7 @@ #include <cplusplus/CppDocument.h> #include <utils/executeondestruction.h> #include <utils/fileutils.h> +#include <utils/hostosinfo.h> #include <utils/temporarydirectory.h> #include <QtTest> @@ -421,5 +422,15 @@ bool VerifyCleanCppModelManager::isClean(bool testOnlyForCleanedProjects) #undef RETURN_FALSE_IF_NOT +int clangdIndexingTimeout() +{ + const QByteArray timeoutAsByteArray = qgetenv("QTC_CLANGD_INDEXING_TIMEOUT"); + bool isConversionOk = false; + const int intervalAsInt = timeoutAsByteArray.toInt(&isConversionOk); + if (!isConversionOk) + return Utils::HostOsInfo::isWindowsHost() ? 20000 : 10000; + return intervalAsInt; +} + } // namespace Tests } // namespace CppTools diff --git a/src/plugins/cpptools/cpptoolstestcase.h b/src/plugins/cpptools/cpptoolstestcase.h index aaa94f1e07..08ae5b7c70 100644 --- a/src/plugins/cpptools/cpptoolstestcase.h +++ b/src/plugins/cpptools/cpptoolstestcase.h @@ -30,7 +30,9 @@ #include <cplusplus/CppDocument.h> #include <utils/temporarydirectory.h> +#include <QEventLoop> #include <QStringList> +#include <QTimer> namespace CPlusPlus { class Document; @@ -54,6 +56,23 @@ class ProjectInfo; namespace Tests { +int CPPTOOLS_EXPORT clangdIndexingTimeout(); + +template <typename Signal> inline bool waitForSignalOrTimeout( + const typename QtPrivate::FunctionPointer<Signal>::Object *sender, Signal signal, + int timeoutInMs) +{ + QTimer timer; + timer.setSingleShot(true); + timer.setInterval(timeoutInMs); + QEventLoop loop; + QObject::connect(&timer, &QTimer::timeout, &loop, &QEventLoop::quit); + QObject::connect(sender, signal, &loop, &QEventLoop::quit); + timer.start(); + loop.exec(); + return timer.isActive(); +} + class CPPTOOLS_EXPORT TestDocument { public: diff --git a/src/plugins/projectexplorer/project.h b/src/plugins/projectexplorer/project.h index 31cb6e12b9..fd550b5eab 100644 --- a/src/plugins/projectexplorer/project.h +++ b/src/plugins/projectexplorer/project.h @@ -212,6 +212,10 @@ signals: void rootProjectDirectoryChanged(); +#ifdef WITH_TESTS + void indexingFinished(Utils::Id indexer); +#endif + protected: virtual RestoreResult fromMap(const QVariantMap &map, QString *errorMessage); void createTargetFromMap(const QVariantMap &map, int index); diff --git a/src/plugins/texteditor/texteditor.cpp b/src/plugins/texteditor/texteditor.cpp index 033dd2a58a..69d11f2747 100644 --- a/src/plugins/texteditor/texteditor.cpp +++ b/src/plugins/texteditor/texteditor.cpp @@ -6257,6 +6257,10 @@ void TextEditorWidget::findLinkAt(const QTextCursor &cursor, bool TextEditorWidget::openLink(const Utils::Link &link, bool inNextSplit) { +#ifdef WITH_TESTS + struct Signaller { ~Signaller() { emit EditorManager::instance()->linkOpened(); } } s; +#endif + if (!link.hasValidTarget()) return false; |