aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins
diff options
context:
space:
mode:
authorDavid Schulz <[email protected]>2023-06-23 13:32:35 +0200
committerDavid Schulz <[email protected]>2023-06-28 12:33:51 +0000
commit520264999af1ac56693c9720e0aeb2e032749d5d (patch)
tree39c7c03601c7510ba887c8061a80e2bfad0ab901 /src/plugins
parenta6e57425699f233d670c59d16bc247dfb08c028a (diff)
ClangCodeModel: fix crash on followSymbol
Big files are loaded in chunks inside a QEventLoop. If follow symbol is triggered via mouse and opens such a big file and the mouse is moved while loading that file ClangdFollowSymbol got deleted while opening the file in ClangdClient::followSymbol. Instead of the hard deletion just cancel that follow symbol operation and make sure done is emitted afterwards. The handling of that done signal takes care of the deletion of that follow symbol operation. Change-Id: Iba4ad6abb541186c2f26506f82fe1bc582818fca Reviewed-by: <[email protected]> Reviewed-by: Christian Kandeler <[email protected]>
Diffstat (limited to 'src/plugins')
-rw-r--r--src/plugins/clangcodemodel/clangdclient.cpp22
-rw-r--r--src/plugins/clangcodemodel/clangdclient.h6
-rw-r--r--src/plugins/clangcodemodel/clangdfollowsymbol.cpp31
-rw-r--r--src/plugins/clangcodemodel/clangdfollowsymbol.h1
-rw-r--r--src/plugins/clangcodemodel/test/clangdtests.cpp32
-rw-r--r--src/plugins/clangcodemodel/test/clangdtests.h1
6 files changed, 77 insertions, 16 deletions
diff --git a/src/plugins/clangcodemodel/clangdclient.cpp b/src/plugins/clangcodemodel/clangdclient.cpp
index 24e1c2d18f4..898f0ab535e 100644
--- a/src/plugins/clangcodemodel/clangdclient.cpp
+++ b/src/plugins/clangcodemodel/clangdclient.cpp
@@ -977,6 +977,12 @@ MessageId ClangdClient::requestSymbolInfo(const Utils::FilePath &filePath, const
return symReq.id();
}
+#ifdef WITH_TESTS
+ClangdFollowSymbol *ClangdClient::currentFollowSymbolOperation()
+{
+ return d->followSymbol;
+}
+#endif
void ClangdClient::followSymbol(TextDocument *document,
const QTextCursor &cursor,
@@ -989,8 +995,8 @@ void ClangdClient::followSymbol(TextDocument *document,
{
QTC_ASSERT(documentOpen(document), openDocument(document));
- delete d->followSymbol;
- d->followSymbol = nullptr;
+ if (d->followSymbol)
+ d->followSymbol->cancel();
const QTextCursor adjustedCursor = d->adjustedCursor(cursor, document);
if (followTo == FollowTo::SymbolDef && !resolveTarget) {
@@ -1000,12 +1006,14 @@ void ClangdClient::followSymbol(TextDocument *document,
qCDebug(clangdLog) << "follow symbol requested" << document->filePath()
<< adjustedCursor.blockNumber() << adjustedCursor.positionInBlock();
- d->followSymbol = new ClangdFollowSymbol(this, adjustedCursor, editorWidget, document, callback,
- followTo, openInSplit);
- connect(d->followSymbol, &ClangdFollowSymbol::done, this, [this] {
- d->followSymbol->deleteLater();
- d->followSymbol = nullptr;
+ auto clangdFollowSymbol = new ClangdFollowSymbol(this, adjustedCursor, editorWidget, document,
+ callback, followTo, openInSplit);
+ connect(clangdFollowSymbol, &ClangdFollowSymbol::done, this, [this, clangdFollowSymbol] {
+ clangdFollowSymbol->deleteLater();
+ if (clangdFollowSymbol == d->followSymbol)
+ d->followSymbol = nullptr;
});
+ d->followSymbol = clangdFollowSymbol;
}
void ClangdClient::switchDeclDef(TextDocument *document, const QTextCursor &cursor,
diff --git a/src/plugins/clangcodemodel/clangdclient.h b/src/plugins/clangcodemodel/clangdclient.h
index 27ec66a3017..2b354eaa2cc 100644
--- a/src/plugins/clangcodemodel/clangdclient.h
+++ b/src/plugins/clangcodemodel/clangdclient.h
@@ -37,6 +37,8 @@ void setupClangdConfigFile();
enum class FollowTo { SymbolDef, SymbolType };
+class ClangdFollowSymbol;
+
class ClangdClient : public LanguageClient::Client
{
Q_OBJECT
@@ -117,6 +119,10 @@ public:
const LanguageServerProtocol::Position &position,
const SymbolInfoHandler &handler);
+#ifdef WITH_TESTS
+ ClangdFollowSymbol *currentFollowSymbolOperation();
+#endif
+
signals:
void indexingFinished();
void foundReferences(const Utils::SearchResultItems &items);
diff --git a/src/plugins/clangcodemodel/clangdfollowsymbol.cpp b/src/plugins/clangcodemodel/clangdfollowsymbol.cpp
index 757ad4bf2e8..730a3fdd375 100644
--- a/src/plugins/clangcodemodel/clangdfollowsymbol.cpp
+++ b/src/plugins/clangcodemodel/clangdfollowsymbol.cpp
@@ -90,6 +90,7 @@ public:
void closeTempDocuments();
bool addOpenFile(const FilePath &filePath);
bool defLinkIsAmbiguous() const;
+ void cancel();
ClangdFollowSymbol * const q;
ClangdClient * const client;
@@ -169,18 +170,17 @@ ClangdFollowSymbol::ClangdFollowSymbol(ClangdClient *client, const QTextCursor &
ClangdFollowSymbol::~ClangdFollowSymbol()
{
- d->closeTempDocuments();
- if (d->virtualFuncAssistProcessor)
- d->virtualFuncAssistProcessor->resetData(false);
- for (const MessageId &id : std::as_const(d->pendingSymbolInfoRequests))
- d->client->cancelRequest(id);
- for (const MessageId &id : std::as_const(d->pendingGotoImplRequests))
- d->client->cancelRequest(id);
- for (const MessageId &id : std::as_const(d->pendingGotoDefRequests))
- d->client->cancelRequest(id);
+ d->cancel();
delete d;
}
+void ClangdFollowSymbol::cancel()
+{
+ d->cancel();
+ clear();
+ emitDone();
+}
+
void ClangdFollowSymbol::clear()
{
d->openedFiles.clear();
@@ -221,6 +221,19 @@ bool ClangdFollowSymbol::Private::defLinkIsAmbiguous() const
return true;
}
+void ClangdFollowSymbol::Private::cancel()
+{
+ closeTempDocuments();
+ if (virtualFuncAssistProcessor)
+ virtualFuncAssistProcessor->resetData(false);
+ for (const MessageId &id : std::as_const(pendingSymbolInfoRequests))
+ client->cancelRequest(id);
+ for (const MessageId &id : std::as_const(pendingGotoImplRequests))
+ client->cancelRequest(id);
+ for (const MessageId &id : std::as_const(pendingGotoDefRequests))
+ client->cancelRequest(id);
+}
+
bool ClangdFollowSymbol::Private::addOpenFile(const FilePath &filePath)
{
return openedFiles.insert(filePath).second;
diff --git a/src/plugins/clangcodemodel/clangdfollowsymbol.h b/src/plugins/clangcodemodel/clangdfollowsymbol.h
index 791f2f1a99a..33cef520d88 100644
--- a/src/plugins/clangcodemodel/clangdfollowsymbol.h
+++ b/src/plugins/clangcodemodel/clangdfollowsymbol.h
@@ -28,6 +28,7 @@ public:
TextEditor::TextDocument *document, const Utils::LinkHandler &callback,
FollowTo followTo, bool openInSplit);
~ClangdFollowSymbol();
+ void cancel();
void clear();
signals:
diff --git a/src/plugins/clangcodemodel/test/clangdtests.cpp b/src/plugins/clangcodemodel/test/clangdtests.cpp
index 5a52a207853..ceaf25787e8 100644
--- a/src/plugins/clangcodemodel/test/clangdtests.cpp
+++ b/src/plugins/clangcodemodel/test/clangdtests.cpp
@@ -4,6 +4,7 @@
#include "clangdtests.h"
#include "../clangdclient.h"
+#include "../clangdfollowsymbol.h"
#include "../clangmodelmanagersupport.h"
#include <coreplugin/editormanager/editormanager.h>
@@ -428,6 +429,37 @@ void ClangdTestFollowSymbol::test()
QCOMPARE(actualLink.targetColumn + 1, targetColumn);
}
+// Make sure it is safe to call follow symbol in a follow symbol handler. Since follow symbol
+// potentially opens a file that gets loaded in chunks which handles user events inbetween
+// the chunks we can potentially call a follow symbol while currently handling another one.
+void ClangdTestFollowSymbol::testFollowSymbolInHandler()
+{
+ TextEditor::TextDocument *const doc = document("header.h");
+ QVERIFY(doc);
+ QTimer timer;
+ timer.setSingleShot(true);
+ QEventLoop loop;
+ QTextCursor cursor(doc->document());
+ const int pos = Text::positionInText(doc->document(), 48, 9);
+ cursor.setPosition(pos);
+ QObject::connect(&timer, &QTimer::timeout, &loop, &QEventLoop::quit);
+
+ bool deleted = false;
+
+ const auto handler = [&](const Link &) {
+ client()->followSymbol(doc, cursor, nullptr, [&](const Link &) { loop.quit(); }, true,
+ FollowTo::SymbolDef, false);
+ QVERIFY(!deleted);
+ };
+
+ client()->followSymbol(doc, cursor, nullptr, handler, true, FollowTo::SymbolDef, false);
+ QVERIFY(client()->currentFollowSymbolOperation());
+ connect(client()->currentFollowSymbolOperation(), &QObject::destroyed, [&] { deleted = true; });
+ timer.start(10000);
+ loop.exec();
+ QVERIFY(timer.isActive());
+ timer.stop();
+}
ClangdTestLocalReferences::ClangdTestLocalReferences()
{
diff --git a/src/plugins/clangcodemodel/test/clangdtests.h b/src/plugins/clangcodemodel/test/clangdtests.h
index 90f4eca45af..92bf4efe90c 100644
--- a/src/plugins/clangcodemodel/test/clangdtests.h
+++ b/src/plugins/clangcodemodel/test/clangdtests.h
@@ -86,6 +86,7 @@ public:
private slots:
void test_data();
void test();
+ void testFollowSymbolInHandler();
};
class ClangdTestLocalReferences : public ClangdTest