ClangCodeModel: Force clangd restart on external changes

Neither we nor clangd can afford to watch all source files, which means
that after e.g. a branch switch we can easily end up in an inconsistent
state.
We alleviate this problem by restarting clangd if at least one open file
was changed externally.

Change-Id: I7e0d14835e3afbd7a64c3233614f2161282dddc0
Reviewed-by: David Schulz <david.schulz@qt.io>
This commit is contained in:
Christian Kandeler
2021-09-03 17:14:54 +02:00
parent 847a03786c
commit d583dde17b
12 changed files with 166 additions and 1 deletions

View File

@@ -51,6 +51,7 @@
#include <QElapsedTimer>
#include <QEventLoop>
#include <QFile>
#include <QFileInfo>
#include <QPair>
#include <QScopedPointer>
@@ -1922,6 +1923,50 @@ AssistProposalItemInterface *ClangdTestCompletion::getItem(
return nullptr;
}
ClangdTestExternalChanges::ClangdTestExternalChanges()
{
setProjectFileName("completion.pro");
setSourceFileNames({"mainwindow.cpp", "main.cpp"});
}
void ClangdTestExternalChanges::test()
{
// Break a header file that is used, but not open in Creator.
// Neither we nor the server should notice, and no diagnostics should be shown for the
// source file that includes the now-broken header.
QFile header(project()->projectDirectory().toString() + "/mainwindow.h");
QVERIFY(header.open(QIODevice::WriteOnly));
header.write("blubb");
header.close();
ClangdClient * const oldClient = client();
QVERIFY(oldClient);
QVERIFY(!waitForSignalOrTimeout(ClangModelManagerSupport::instance(),
&ClangModelManagerSupport::createdClient, timeOutInMs()));
QCOMPARE(client(), oldClient);
const TextDocument * const curDoc = document("main.cpp");
QVERIFY(curDoc);
QVERIFY(curDoc->marks().isEmpty());
// Now trigger an external change in an open, but not currently visible file and
// verify that we get a new client and diagnostics in the current editor.
TextDocument * const docToChange = document("mainwindow.cpp");
docToChange->setSilentReload();
QFile otherSource(filePath("mainwindow.cpp").toString());
QVERIFY(otherSource.open(QIODevice::WriteOnly));
otherSource.write("blubb");
otherSource.close();
QVERIFY(waitForSignalOrTimeout(ClangModelManagerSupport::instance(),
&ClangModelManagerSupport::createdClient, timeOutInMs()));
ClangdClient * const newClient = ClangModelManagerSupport::instance()
->clientForFile(filePath("main.cpp"));
QVERIFY(newClient);
QVERIFY(newClient != oldClient);
newClient->enableTesting();
if (curDoc->marks().isEmpty())
QVERIFY(waitForSignalOrTimeout(newClient, &ClangdClient::textMarkCreated, timeOutInMs()));
}
} // namespace Tests
} // namespace Internal
} // namespace ClangCodeModel