forked from qt-creator/qt-creator
Clang: Fix delayed reparse of dirty and visible but not current documents
1. Open document foo.h
2. Create a split and open foo.cpp (#including "foo.h")
3. Edit foo.h (e.g. by introducing a syntax error, so that foo.cpp will
indicate header errors in the toolbar or as info bar)
=> Actual: foo.cpp will be reparsed immediately.
Expected: foo.cpp should be reparsed after a delay.
This saves resources (cpu time) and minimizes poping up of the header
info bar while editing header files in splits.
Regression introduced by
commit 380d756a03
Clang: Hook up supportive translation unit on first edit
Change-Id: Ib5fd90e49415dfc3aefacab7cd627b0e1937f5fc
Reviewed-by: David Schulz <david.schulz@qt.io>
This commit is contained in:
@@ -50,6 +50,8 @@
|
|||||||
#include <updatetranslationunitsforeditormessage.h>
|
#include <updatetranslationunitsforeditormessage.h>
|
||||||
#include <updatevisibletranslationunitsmessage.h>
|
#include <updatevisibletranslationunitsmessage.h>
|
||||||
|
|
||||||
|
#include <utils/qtcassert.h>
|
||||||
|
|
||||||
#include <QCoreApplication>
|
#include <QCoreApplication>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
|
||||||
@@ -57,16 +59,21 @@ namespace ClangBackEnd {
|
|||||||
|
|
||||||
ClangCodeModelServer::ClangCodeModelServer()
|
ClangCodeModelServer::ClangCodeModelServer()
|
||||||
: documents(projects, unsavedFiles)
|
: documents(projects, unsavedFiles)
|
||||||
, updateDocumentAnnotationsTimeOutInMs(1500)
|
|
||||||
{
|
{
|
||||||
updateDocumentAnnotationsTimer.setSingleShot(true);
|
updateDocumentAnnotationsTimer.setSingleShot(true);
|
||||||
|
|
||||||
QObject::connect(&updateDocumentAnnotationsTimer,
|
QObject::connect(&updateDocumentAnnotationsTimer,
|
||||||
&QTimer::timeout,
|
&QTimer::timeout,
|
||||||
[this]() {
|
[this]() {
|
||||||
processJobsForDirtyAndVisibleDocuments();
|
processJobsForDirtyAndVisibleDocuments();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
updateVisibleButNotCurrentDocumentsTimer.setSingleShot(true);
|
||||||
|
QObject::connect(&updateVisibleButNotCurrentDocumentsTimer,
|
||||||
|
&QTimer::timeout,
|
||||||
|
[this]() {
|
||||||
|
processJobsForDirtyAndVisibleButNotCurrentDocuments();
|
||||||
|
});
|
||||||
|
|
||||||
QObject::connect(documents.clangFileSystemWatcher(),
|
QObject::connect(documents.clangFileSystemWatcher(),
|
||||||
&ClangFileSystemWatcher::fileChanged,
|
&ClangFileSystemWatcher::fileChanged,
|
||||||
[this](const Utf8String &filePath) {
|
[this](const Utf8String &filePath) {
|
||||||
@@ -265,16 +272,44 @@ bool ClangCodeModelServer::isTimerRunningForTestOnly() const
|
|||||||
|
|
||||||
void ClangCodeModelServer::processJobsForDirtyAndVisibleDocuments()
|
void ClangCodeModelServer::processJobsForDirtyAndVisibleDocuments()
|
||||||
{
|
{
|
||||||
for (const auto &document : documents.documents()) {
|
processJobsForDirtyCurrentDocument();
|
||||||
if (document.isNeedingReparse() && document.isVisibleInEditor()) {
|
processTimerForVisibleButNotCurrentDocuments();
|
||||||
DocumentProcessor processor = documentProcessors().processor(document);
|
}
|
||||||
processor.addJob(createJobRequest(document,
|
|
||||||
JobRequest::Type::UpdateDocumentAnnotations,
|
|
||||||
PreferredTranslationUnit::PreviouslyParsed));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
documentProcessors().process();
|
void ClangCodeModelServer::processJobsForDirtyCurrentDocument()
|
||||||
|
{
|
||||||
|
const auto currentDirtyDocuments = documents.filtered([](const Document &document) {
|
||||||
|
return document.isNeedingReparse() && document.isUsedByCurrentEditor();
|
||||||
|
});
|
||||||
|
QTC_CHECK(currentDirtyDocuments.size() <= 1);
|
||||||
|
|
||||||
|
addAndRunUpdateJobs(currentDirtyDocuments);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClangCodeModelServer::addAndRunUpdateJobs(const std::vector<Document> &documents)
|
||||||
|
{
|
||||||
|
for (const auto &document : documents) {
|
||||||
|
DocumentProcessor processor = documentProcessors().processor(document);
|
||||||
|
processor.addJob(createJobRequest(document,
|
||||||
|
JobRequest::Type::UpdateDocumentAnnotations,
|
||||||
|
PreferredTranslationUnit::PreviouslyParsed));
|
||||||
|
processor.process();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClangCodeModelServer::processTimerForVisibleButNotCurrentDocuments()
|
||||||
|
{
|
||||||
|
if (documents.dirtyAndVisibleButNotCurrentDocuments().empty()) {
|
||||||
|
updateVisibleButNotCurrentDocumentsTimer.stop();
|
||||||
|
} else {
|
||||||
|
updateVisibleButNotCurrentDocumentsTimer.start(
|
||||||
|
updateVisibleButNotCurrentDocumentsTimeOutInMs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClangCodeModelServer::processJobsForDirtyAndVisibleButNotCurrentDocuments()
|
||||||
|
{
|
||||||
|
addAndRunUpdateJobs(documents.dirtyAndVisibleButNotCurrentDocuments());
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClangCodeModelServer::processInitialJobsForDocuments(const std::vector<Document> &documents)
|
void ClangCodeModelServer::processInitialJobsForDocuments(const std::vector<Document> &documents)
|
||||||
@@ -332,6 +367,11 @@ void ClangCodeModelServer::setUpdateDocumentAnnotationsTimeOutInMsForTestsOnly(i
|
|||||||
updateDocumentAnnotationsTimeOutInMs = value;
|
updateDocumentAnnotationsTimeOutInMs = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ClangCodeModelServer::setUpdateVisibleButNotCurrentDocumentsTimeOutInMsForTestsOnly(int value)
|
||||||
|
{
|
||||||
|
updateVisibleButNotCurrentDocumentsTimeOutInMs = value;
|
||||||
|
}
|
||||||
|
|
||||||
DocumentProcessors &ClangCodeModelServer::documentProcessors()
|
DocumentProcessors &ClangCodeModelServer::documentProcessors()
|
||||||
{
|
{
|
||||||
if (!documentProcessors_) {
|
if (!documentProcessors_) {
|
||||||
|
@@ -65,16 +65,22 @@ public: // for tests
|
|||||||
int queueSizeForTestsOnly();
|
int queueSizeForTestsOnly();
|
||||||
bool isTimerRunningForTestOnly() const;
|
bool isTimerRunningForTestOnly() const;
|
||||||
void setUpdateDocumentAnnotationsTimeOutInMsForTestsOnly(int value);
|
void setUpdateDocumentAnnotationsTimeOutInMsForTestsOnly(int value);
|
||||||
|
void setUpdateVisibleButNotCurrentDocumentsTimeOutInMsForTestsOnly(int value);
|
||||||
DocumentProcessors &documentProcessors();
|
DocumentProcessors &documentProcessors();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void startDocumentAnnotationsTimerIfFileIsNotOpenAsDocument(const Utf8String &filePath);
|
void startDocumentAnnotationsTimerIfFileIsNotOpenAsDocument(const Utf8String &filePath);
|
||||||
void addJobRequestsForDirtyAndVisibleDocuments();
|
|
||||||
void processJobsForDirtyAndVisibleDocuments();
|
|
||||||
void processInitialJobsForDocuments(const std::vector<Document> &documents);
|
void processInitialJobsForDocuments(const std::vector<Document> &documents);
|
||||||
void startInitializingSupportiveTranslationUnits(const std::vector<Document> &documents);
|
void startInitializingSupportiveTranslationUnits(const std::vector<Document> &documents);
|
||||||
|
|
||||||
|
void processJobsForDirtyAndVisibleDocuments();
|
||||||
|
void processJobsForDirtyCurrentDocument();
|
||||||
|
void processTimerForVisibleButNotCurrentDocuments();
|
||||||
|
void processJobsForDirtyAndVisibleButNotCurrentDocuments();
|
||||||
|
|
||||||
|
void addAndRunUpdateJobs(const std::vector<Document> &documents);
|
||||||
|
|
||||||
JobRequest createJobRequest(const Document &document,
|
JobRequest createJobRequest(const Document &document,
|
||||||
JobRequest::Type type,
|
JobRequest::Type type,
|
||||||
PreferredTranslationUnit preferredTranslationUnit
|
PreferredTranslationUnit preferredTranslationUnit
|
||||||
@@ -88,7 +94,10 @@ private:
|
|||||||
QScopedPointer<DocumentProcessors> documentProcessors_; // Delayed initialization
|
QScopedPointer<DocumentProcessors> documentProcessors_; // Delayed initialization
|
||||||
|
|
||||||
QTimer updateDocumentAnnotationsTimer;
|
QTimer updateDocumentAnnotationsTimer;
|
||||||
int updateDocumentAnnotationsTimeOutInMs;
|
int updateDocumentAnnotationsTimeOutInMs = 1500;
|
||||||
|
|
||||||
|
QTimer updateVisibleButNotCurrentDocumentsTimer;
|
||||||
|
int updateVisibleButNotCurrentDocumentsTimeOutInMs = 2000;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ClangBackEnd
|
} // namespace ClangBackEnd
|
||||||
|
@@ -33,6 +33,8 @@
|
|||||||
#include <skippedsourceranges.h>
|
#include <skippedsourceranges.h>
|
||||||
#include <unsavedfiles.h>
|
#include <unsavedfiles.h>
|
||||||
|
|
||||||
|
#include <utils/algorithm.h>
|
||||||
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
@@ -143,6 +145,20 @@ const std::vector<Document> &Documents::documents() const
|
|||||||
return documents_;
|
return documents_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const std::vector<Document> Documents::filtered(const IsMatchingDocument &isMatchingDocument) const
|
||||||
|
{
|
||||||
|
return Utils::filtered(documents_, isMatchingDocument);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Document> Documents::dirtyAndVisibleButNotCurrentDocuments() const
|
||||||
|
{
|
||||||
|
return filtered([](const Document &document) {
|
||||||
|
return document.isNeedingReparse()
|
||||||
|
&& document.isVisibleInEditor()
|
||||||
|
&& !document.isUsedByCurrentEditor();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
UnsavedFiles Documents::unsavedFiles() const
|
UnsavedFiles Documents::unsavedFiles() const
|
||||||
{
|
{
|
||||||
return unsavedFiles_;
|
return unsavedFiles_;
|
||||||
|
@@ -32,6 +32,7 @@
|
|||||||
|
|
||||||
#include <QVector>
|
#include <QVector>
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace ClangBackEnd {
|
namespace ClangBackEnd {
|
||||||
@@ -57,6 +58,9 @@ public:
|
|||||||
bool hasDocumentWithFilePath(const Utf8String &filePath) const;
|
bool hasDocumentWithFilePath(const Utf8String &filePath) const;
|
||||||
|
|
||||||
const std::vector<Document> &documents() const;
|
const std::vector<Document> &documents() const;
|
||||||
|
using IsMatchingDocument = std::function<bool(const Document &document)>;
|
||||||
|
const std::vector<Document> filtered(const IsMatchingDocument &isMatchingDocument) const;
|
||||||
|
std::vector<Document> dirtyAndVisibleButNotCurrentDocuments() const;
|
||||||
|
|
||||||
UnsavedFiles unsavedFiles() const;
|
UnsavedFiles unsavedFiles() const;
|
||||||
|
|
||||||
|
@@ -289,6 +289,42 @@ TEST_F(Documents, HasNotDocument)
|
|||||||
ASSERT_FALSE(documents.hasDocument(filePath, projectPartId));
|
ASSERT_FALSE(documents.hasDocument(filePath, projectPartId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(Documents, FilteredPositive)
|
||||||
|
{
|
||||||
|
documents.create({{filePath, projectPartId}});
|
||||||
|
const auto isMatchingFilePath = [this](const Document &document) {
|
||||||
|
return document.filePath() == filePath;
|
||||||
|
};
|
||||||
|
|
||||||
|
const bool hasMatches = !documents.filtered(isMatchingFilePath).empty();
|
||||||
|
|
||||||
|
ASSERT_TRUE(hasMatches);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(Documents, FilteredNegative)
|
||||||
|
{
|
||||||
|
documents.create({{filePath, projectPartId}});
|
||||||
|
const auto isMatchingNothing = [](const Document &) {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
const bool hasMatches = !documents.filtered(isMatchingNothing).empty();
|
||||||
|
|
||||||
|
ASSERT_FALSE(hasMatches);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(Documents, DirtyAndVisibleButNotCurrentDocuments)
|
||||||
|
{
|
||||||
|
documents.create({{filePath, projectPartId}});
|
||||||
|
documents.updateDocumentsWithChangedDependency(filePath);
|
||||||
|
documents.setVisibleInEditors({filePath});
|
||||||
|
documents.setUsedByCurrentEditor(Utf8String());
|
||||||
|
|
||||||
|
const bool hasMatches = !documents.dirtyAndVisibleButNotCurrentDocuments().empty();
|
||||||
|
|
||||||
|
ASSERT_TRUE(hasMatches);
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(Documents, isUsedByCurrentEditor)
|
TEST_F(Documents, isUsedByCurrentEditor)
|
||||||
{
|
{
|
||||||
documents.create({fileContainer});
|
documents.create({fileContainer});
|
||||||
|
@@ -375,6 +375,7 @@ void ClangClangCodeModelServer::SetUp()
|
|||||||
{
|
{
|
||||||
clangServer.setClient(&mockClangCodeModelClient);
|
clangServer.setClient(&mockClangCodeModelClient);
|
||||||
clangServer.setUpdateDocumentAnnotationsTimeOutInMsForTestsOnly(0);
|
clangServer.setUpdateDocumentAnnotationsTimeOutInMsForTestsOnly(0);
|
||||||
|
clangServer.setUpdateVisibleButNotCurrentDocumentsTimeOutInMsForTestsOnly(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClangClangCodeModelServer::TearDown()
|
void ClangClangCodeModelServer::TearDown()
|
||||||
|
Reference in New Issue
Block a user