Clang: Fix processing documents if multiple are opened at once

Reproducable with
 1. $ ./qtcreator a.cpp b.cpp
 2. Switch to a.cpp => no highlighting

Because ClangEditorDocumentProcessor does asynchronous processing, the
backend might receive a DocumentsOpenedMessage where the document is not
the current editor (happens for a.cpp in the example). When switching to
that document, the initial jobs were not processed as the document was
not dirty.

Address this case by also checking for documents that have a revision of
1 and are not dirty. Unify adding the annotations jobs to ensure that
not more than needed are run.

Change-Id: I14030260842f97d58280235e763c8d7490705f8d
Reviewed-by: Ivan Donchevskii <ivan.donchevskii@qt.io>
This commit is contained in:
Nikolai Kosjar
2018-06-05 13:05:47 +02:00
parent b30926cea4
commit cbd4d05423
3 changed files with 38 additions and 19 deletions

View File

@@ -61,7 +61,7 @@ ClangCodeModelServer::ClangCodeModelServer()
QObject::connect(&updateAnnotationsTimer,
&QTimer::timeout,
[this]() {
processJobsForDirtyAndVisibleDocuments();
processJobsForVisibleDocuments();
});
updateVisibleButNotCurrentDocumentsTimer.setSingleShot(true);
@@ -180,7 +180,7 @@ void ClangCodeModelServer::projectPartsUpdated(const ProjectPartsUpdatedMessage
resetDocuments(toDocumentResetInfos(affectedDocuments));
processJobsForDirtyAndVisibleDocuments();
processJobsForVisibleDocuments();
} catch (const std::exception &exception) {
qWarning() << "Error in ClangCodeModelServer::projectPartsUpdated:" << exception.what();
}
@@ -373,20 +373,30 @@ bool ClangCodeModelServer::isTimerRunningForTestOnly() const
return updateAnnotationsTimer.isActive();
}
void ClangCodeModelServer::processJobsForDirtyAndVisibleDocuments()
void ClangCodeModelServer::processJobsForVisibleDocuments()
{
processJobsForDirtyCurrentDocument();
processJobsForCurrentDocument();
processTimerForVisibleButNotCurrentDocuments();
}
void ClangCodeModelServer::processJobsForDirtyCurrentDocument()
void ClangCodeModelServer::processJobsForCurrentDocument()
{
auto currentDirtyDocuments = documents.filtered([](const Document &document) {
return document.isDirty() && document.isUsedByCurrentEditor();
auto currentDocuments = documents.filtered([](const Document &document) {
return document.isUsedByCurrentEditor()
&& (document.isDirty() || document.documentRevision() == 1);
});
QTC_CHECK(currentDirtyDocuments.size() <= 1);
QTC_CHECK(currentDocuments.size() <= 1);
addAndRunUpdateJobs(currentDirtyDocuments);
addAndRunUpdateJobs(currentDocuments);
}
static void addUpdateAnnotationsJobsAndProcess(DocumentProcessor &processor)
{
processor.addJob(JobRequest::Type::UpdateAnnotations,
PreferredTranslationUnit::PreviouslyParsed);
processor.addJob(JobRequest::Type::UpdateExtraAnnotations,
PreferredTranslationUnit::RecentlyParsed);
processor.process();
}
void ClangCodeModelServer::addAndRunUpdateJobs(std::vector<Document> documents)
@@ -395,11 +405,7 @@ void ClangCodeModelServer::addAndRunUpdateJobs(std::vector<Document> documents)
DocumentProcessor processor = documentProcessors().processor(document);
// Run the regular edit-reparse-job
processor.addJob(JobRequest::Type::UpdateAnnotations,
PreferredTranslationUnit::PreviouslyParsed);
processor.addJob(JobRequest::Type::UpdateExtraAnnotations,
PreferredTranslationUnit::RecentlyParsed);
processor.process();
addUpdateAnnotationsJobsAndProcess(processor);
// If requested, run jobs to increase the responsiveness of the document
if (useSupportiveTranslationUnit() && document.isResponsivenessIncreaseNeeded()) {
@@ -478,9 +484,7 @@ void ClangCodeModelServer::processInitialJobsForDocuments(const std::vector<Docu
{
for (const auto &document : documents) {
DocumentProcessor processor = documentProcessors().processor(document);
processor.addJob(JobRequest::Type::UpdateAnnotations);
processor.addJob(JobRequest::Type::UpdateExtraAnnotations);
processor.process();
addUpdateAnnotationsJobsAndProcess(processor);
}
}

View File

@@ -84,8 +84,8 @@ public: // for tests
private:
void processInitialJobsForDocuments(const std::vector<Document> &documents);
void processJobsForDirtyAndVisibleDocuments();
void processJobsForDirtyCurrentDocument();
void processJobsForVisibleDocuments();
void processJobsForCurrentDocument();
void processTimerForVisibleButNotCurrentDocuments();
void processSuspendResumeJobs(const std::vector<Document> &documents);

View File

@@ -258,6 +258,21 @@ TEST_F(ClangCodeModelServerSlowTest, NoInitialAnnotationsForClosedDocument)
closeDocument(filePathA);
}
TEST_F(ClangCodeModelServerSlowTest, AnnotationsForInitiallyNotVisibleDocument)
{
const int expectedAnnotationsCount = 2;
updateProjectPart();
updateVisibilty(filePathA, filePathA);
expectAnnotations(expectedAnnotationsCount);
clangServer.documentsOpened( // Open document while another is still visible
DocumentsOpenedMessage({FileContainer(filePathB, projectPartId, Utf8String(), false, 1)},
filePathA, {filePathA}));
clangServer.unsavedFilesUpdated( // Invalidate added jobs
UnsavedFilesUpdatedMessage({FileContainer(Utf8StringLiteral("aFile"), Utf8String())}));
updateVisibilty(filePathB, filePathB);
}
TEST_F(ClangCodeModelServerSlowTest, NoAnnotationsForClosedDocument)
{
const int expectedAnnotationsCount = AnnotationJobsMultiplier; // Only for registration.