summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/tools/clangbackend/ipcsource/clangbackend_global.h7
-rw-r--r--src/tools/clangbackend/ipcsource/clangbackendclangipc-source.pri6
-rw-r--r--src/tools/clangbackend/ipcsource/clangcodemodelserver.cpp14
-rw-r--r--src/tools/clangbackend/ipcsource/clangcodemodelserver.h1
-rw-r--r--src/tools/clangbackend/ipcsource/clangdocument.cpp15
-rw-r--r--src/tools/clangbackend/ipcsource/clangdocument.h3
-rw-r--r--src/tools/clangbackend/ipcsource/clangdocumentsuspenderresumer.cpp141
-rw-r--r--src/tools/clangbackend/ipcsource/clangdocumentsuspenderresumer.h62
-rw-r--r--src/tools/clangbackend/ipcsource/clangiasyncjob.cpp6
-rw-r--r--src/tools/clangbackend/ipcsource/clangjobqueue.cpp10
-rw-r--r--src/tools/clangbackend/ipcsource/clangjobrequest.cpp16
-rw-r--r--src/tools/clangbackend/ipcsource/clangjobrequest.h7
-rw-r--r--src/tools/clangbackend/ipcsource/clangresumedocumentjob.cpp54
-rw-r--r--src/tools/clangbackend/ipcsource/clangresumedocumentjob.h44
-rw-r--r--src/tools/clangbackend/ipcsource/clangsuspenddocumentjob.cpp73
-rw-r--r--src/tools/clangbackend/ipcsource/clangsuspenddocumentjob.h44
-rw-r--r--src/tools/clangbackend/ipcsource/clangtranslationunit.cpp13
-rw-r--r--src/tools/clangbackend/ipcsource/clangtranslationunit.h2
-rw-r--r--src/tools/clangbackend/ipcsource/clangupdatedocumentannotationsjob.cpp16
-rw-r--r--src/tools/clangbackend/ipcsource/clangupdatedocumentannotationsjob.h8
-rw-r--r--tests/unit/unittest/clangdocumentsuspenderresumer-test.cpp295
-rw-r--r--tests/unit/unittest/clangjobqueue-test.cpp22
-rw-r--r--tests/unit/unittest/clangresumedocumentjob-test.cpp92
-rw-r--r--tests/unit/unittest/clangsuspenddocumentjob-test.cpp73
-rw-r--r--tests/unit/unittest/data/empty1.cpp0
-rw-r--r--tests/unit/unittest/data/empty2.cpp0
-rw-r--r--tests/unit/unittest/data/empty3.cpp0
-rw-r--r--tests/unit/unittest/unittest.pro3
28 files changed, 1021 insertions, 6 deletions
diff --git a/src/tools/clangbackend/ipcsource/clangbackend_global.h b/src/tools/clangbackend/ipcsource/clangbackend_global.h
index 0dccaa87ad..d806afc98c 100644
--- a/src/tools/clangbackend/ipcsource/clangbackend_global.h
+++ b/src/tools/clangbackend/ipcsource/clangbackend_global.h
@@ -25,6 +25,8 @@
#pragma once
+#include <clang-c/Index.h>
+
namespace ClangBackEnd {
enum class PreferredTranslationUnit
@@ -34,4 +36,9 @@ enum class PreferredTranslationUnit
LastUninitialized,
};
+// CLANG-UPGRADE-CHECK: Remove IS_SUSPEND_SUPPORTED once we require clang >= 5.0
+#if defined(CINDEX_VERSION_HAS_BACKPORTED_SUSPEND) || CINDEX_VERSION_MINOR >= 41
+# define IS_SUSPEND_SUPPORTED
+#endif
+
} // namespace ClangBackEnd
diff --git a/src/tools/clangbackend/ipcsource/clangbackendclangipc-source.pri b/src/tools/clangbackend/ipcsource/clangbackendclangipc-source.pri
index 06be9be18d..877d63ca9c 100644
--- a/src/tools/clangbackend/ipcsource/clangbackendclangipc-source.pri
+++ b/src/tools/clangbackend/ipcsource/clangbackendclangipc-source.pri
@@ -12,6 +12,7 @@ HEADERS += \
$$PWD/clangdocumentprocessor.h \
$$PWD/clangdocumentprocessors.h \
$$PWD/clangdocuments.h \
+ $$PWD/clangdocumentsuspenderresumer.h \
$$PWD/clangexceptions.h \
$$PWD/clangfilepath.h \
$$PWD/clangfilesystemwatcher.h \
@@ -25,8 +26,10 @@ HEADERS += \
$$PWD/clangreparsesupportivetranslationunitjob.h \
$$PWD/clangrequestdocumentannotationsjob.h \
$$PWD/clangrequestreferencesjob.h \
+ $$PWD/clangresumedocumentjob.h \
$$PWD/clangstring.h \
$$PWD/clangsupportivetranslationunitinitializer.h \
+ $$PWD/clangsuspenddocumentjob.h \
$$PWD/clangtranslationunit.h \
$$PWD/clangtranslationunits.h \
$$PWD/clangtranslationunitupdater.h \
@@ -63,6 +66,7 @@ SOURCES += \
$$PWD/clangdocumentprocessor.cpp \
$$PWD/clangdocumentprocessors.cpp \
$$PWD/clangdocuments.cpp \
+ $$PWD/clangdocumentsuspenderresumer.cpp \
$$PWD/clangexceptions.cpp \
$$PWD/clangfilepath.cpp \
$$PWD/clangfilesystemwatcher.cpp \
@@ -72,10 +76,12 @@ SOURCES += \
$$PWD/clangjobrequest.cpp \
$$PWD/clangjobs.cpp \
$$PWD/clangparsesupportivetranslationunitjob.cpp \
+ $$PWD/clangresumedocumentjob.cpp \
$$PWD/clangreferencescollector.cpp \
$$PWD/clangreparsesupportivetranslationunitjob.cpp \
$$PWD/clangrequestdocumentannotationsjob.cpp \
$$PWD/clangrequestreferencesjob.cpp \
+ $$PWD/clangsuspenddocumentjob.cpp \
$$PWD/clangsupportivetranslationunitinitializer.cpp \
$$PWD/clangtranslationunit.cpp \
$$PWD/clangtranslationunits.cpp \
diff --git a/src/tools/clangbackend/ipcsource/clangcodemodelserver.cpp b/src/tools/clangbackend/ipcsource/clangcodemodelserver.cpp
index ffbf7fd94c..0e54fce5c3 100644
--- a/src/tools/clangbackend/ipcsource/clangcodemodelserver.cpp
+++ b/src/tools/clangbackend/ipcsource/clangcodemodelserver.cpp
@@ -26,6 +26,7 @@
#include "clangcodemodelserver.h"
#include "clangdocuments.h"
+#include "clangdocumentsuspenderresumer.h"
#include "clangfilesystemwatcher.h"
#include "clangtranslationunits.h"
#include "codecompleter.h"
@@ -89,6 +90,7 @@ void ClangCodeModelServer::registerTranslationUnitsForEditor(const ClangBackEnd:
unsavedFiles.createOrUpdate(message.fileContainers());
documents.setUsedByCurrentEditor(message.currentEditorFilePath());
documents.setVisibleInEditors(message.visibleEditorFilePaths());
+ processSuspendResumeJobs(documents.documents());
processInitialJobsForDocuments(createdDocuments);
} catch (const std::exception &exception) {
@@ -264,6 +266,8 @@ void ClangCodeModelServer::updateVisibleTranslationUnits(const UpdateVisibleTran
try {
documents.setUsedByCurrentEditor(message.currentEditorFilePath());
documents.setVisibleInEditors(message.visibleEditorFilePaths());
+ processSuspendResumeJobs(documents.documents());
+
updateDocumentAnnotationsTimer.start(0);
} catch (const std::exception &exception) {
qWarning() << "Error in ClangCodeModelServer::updateVisibleTranslationUnits:" << exception.what();
@@ -347,6 +351,16 @@ void ClangCodeModelServer::processJobsForDirtyAndVisibleButNotCurrentDocuments()
addAndRunUpdateJobs(documents.dirtyAndVisibleButNotCurrentDocuments());
}
+void ClangCodeModelServer::processSuspendResumeJobs(const std::vector<Document> &documents)
+{
+ const SuspendResumeJobs suspendResumeJobs = createSuspendResumeJobs(documents);
+ for (const SuspendResumeJobsEntry &entry : suspendResumeJobs) {
+ DocumentProcessor processor = documentProcessors().processor(entry.document);
+ processor.addJob(entry.jobRequestType, entry.preferredTranslationUnit);
+ processor.process();
+ }
+}
+
void ClangCodeModelServer::processInitialJobsForDocuments(const std::vector<Document> &documents)
{
for (const auto &document : documents) {
diff --git a/src/tools/clangbackend/ipcsource/clangcodemodelserver.h b/src/tools/clangbackend/ipcsource/clangcodemodelserver.h
index 70d99b5afa..d5fc33250b 100644
--- a/src/tools/clangbackend/ipcsource/clangcodemodelserver.h
+++ b/src/tools/clangbackend/ipcsource/clangcodemodelserver.h
@@ -77,6 +77,7 @@ private:
void processJobsForDirtyCurrentDocument();
void processTimerForVisibleButNotCurrentDocuments();
void processJobsForDirtyAndVisibleButNotCurrentDocuments();
+ void processSuspendResumeJobs(const std::vector<Document> &documents);
void addAndRunUpdateJobs(std::vector<Document> documents);
diff --git a/src/tools/clangbackend/ipcsource/clangdocument.cpp b/src/tools/clangbackend/ipcsource/clangdocument.cpp
index 933bf61276..a4f95d17b8 100644
--- a/src/tools/clangbackend/ipcsource/clangdocument.cpp
+++ b/src/tools/clangbackend/ipcsource/clangdocument.cpp
@@ -80,6 +80,7 @@ public:
bool isUsedByCurrentEditor = false;
bool isVisibleInEditor = false;
bool increaseResponsiveness = false;
+ bool isSuspended = false;
};
DocumentData::DocumentData(const Utf8String &filePath,
@@ -226,6 +227,20 @@ void Document::setResponsivenessIncreaseNeeded(bool responsivenessIncreaseNeeded
d->increaseResponsiveness = responsivenessIncreaseNeeded;
}
+bool Document::isSuspended() const
+{
+ checkIfNull();
+
+ return d->isSuspended;
+}
+
+void Document::setIsSuspended(bool isSuspended)
+{
+ checkIfNull();
+
+ d->isSuspended = isSuspended;
+}
+
bool Document::isUsedByCurrentEditor() const
{
checkIfNull();
diff --git a/src/tools/clangbackend/ipcsource/clangdocument.h b/src/tools/clangbackend/ipcsource/clangdocument.h
index 48dc32acee..260705c135 100644
--- a/src/tools/clangbackend/ipcsource/clangdocument.h
+++ b/src/tools/clangbackend/ipcsource/clangdocument.h
@@ -93,6 +93,9 @@ public:
bool isResponsivenessIncreaseNeeded() const;
void setResponsivenessIncreaseNeeded(bool responsivenessIncreaseNeeded);
+ bool isSuspended() const;
+ void setIsSuspended(bool isSuspended);
+
bool isUsedByCurrentEditor() const;
void setIsUsedByCurrentEditor(bool isUsedByCurrentEditor);
diff --git a/src/tools/clangbackend/ipcsource/clangdocumentsuspenderresumer.cpp b/src/tools/clangbackend/ipcsource/clangdocumentsuspenderresumer.cpp
new file mode 100644
index 0000000000..8edde48fd6
--- /dev/null
+++ b/src/tools/clangbackend/ipcsource/clangdocumentsuspenderresumer.cpp
@@ -0,0 +1,141 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "clangdocumentsuspenderresumer.h"
+
+#include "clangbackendipc_global.h"
+#include "clangdocumentprocessors.h"
+#include "clangdocuments.h"
+
+#include <utils/algorithm.h>
+
+#include <algorithm>
+
+namespace ClangBackEnd {
+
+constexpr int DefaultHotDocumentsSize = 7;
+
+void categorizeHotColdDocuments(int hotDocumentsSize,
+ const std::vector<Document> &inDocuments,
+ std::vector<Document> &hotDocuments,
+ std::vector<Document> &coldDocuments)
+{
+ // Sort documents, most recently used/visible at top
+ std::vector<Document> documents = inDocuments;
+ std::stable_sort(documents.begin(), documents.end(), [](const Document &a, const Document &b) {
+ return a.visibleTimePoint() > b.visibleTimePoint();
+ });
+
+ // Ensure that visible documents are always hot, otherwise not all visible
+ // documents will be resumed.
+ const auto isVisible = [](const Document &document) { return document.isVisibleInEditor(); };
+ const int visibleDocumentsSize = Utils::count(documents, isVisible);
+ hotDocumentsSize = std::max(hotDocumentsSize, visibleDocumentsSize);
+
+ if (documents.size() <= uint(hotDocumentsSize)) {
+ hotDocuments = documents;
+ coldDocuments.clear();
+ } else {
+ const auto firstColdIterator = documents.begin() + hotDocumentsSize;
+ hotDocuments = std::vector<Document>(documents.begin(), firstColdIterator);
+ coldDocuments = std::vector<Document>(firstColdIterator, documents.end());
+ }
+}
+
+#ifdef IS_SUSPEND_SUPPORTED
+static int hotDocumentsSize()
+{
+ static int hotDocuments = -1;
+ if (hotDocuments == -1) {
+ bool ok = false;
+ const int fromEnvironment = qEnvironmentVariableIntValue("QTC_CLANG_HOT_DOCUMENTS", &ok);
+ hotDocuments = ok && fromEnvironment >= 1 ? fromEnvironment : DefaultHotDocumentsSize;
+ }
+
+ return hotDocuments;
+}
+
+static SuspendResumeJobs createJobs(const Document &document, JobRequest::Type type)
+{
+ SuspendResumeJobs jobs;
+
+ jobs.append({document, type, PreferredTranslationUnit::RecentlyParsed});
+ if (document.isResponsivenessIncreased())
+ jobs.append({document, type, PreferredTranslationUnit::PreviouslyParsed});
+
+ return jobs;
+}
+
+static bool isFineDocument(const Document &document)
+{
+ return !document.isNull() && document.isIntact();
+}
+
+static bool isSuspendable(const Document &document)
+{
+ return isFineDocument(document)
+ && !document.isSuspended()
+ && !document.isVisibleInEditor();
+}
+
+static bool isResumable(const Document &document)
+{
+ return isFineDocument(document)
+ && document.isSuspended()
+ && document.isVisibleInEditor();
+}
+
+#endif // IS_SUSPEND_SUPPORTED
+
+SuspendResumeJobs createSuspendResumeJobs(const std::vector<Document> &documents,
+ int customHotDocumentSize)
+{
+ Q_UNUSED(documents);
+ Q_UNUSED(customHotDocumentSize);
+
+ SuspendResumeJobs jobs;
+
+#ifdef IS_SUSPEND_SUPPORTED
+ std::vector<Document> hotDocuments;
+ std::vector<Document> coldDocuments;
+
+ const int size = (customHotDocumentSize == -1) ? hotDocumentsSize() : customHotDocumentSize;
+ categorizeHotColdDocuments(size, documents, hotDocuments, coldDocuments);
+
+ // Cold documents should be suspended...
+ const std::vector<Document> toSuspend = Utils::filtered(coldDocuments, &isSuspendable);
+ for (const Document &document : toSuspend)
+ jobs += createJobs(document, JobRequest::Type::SuspendDocument);
+
+ // ...and hot documents that were suspended should be resumed
+ const std::vector<Document> toResume = Utils::filtered(hotDocuments, &isResumable);
+ for (const Document &document : toResume)
+ jobs += createJobs(document, JobRequest::Type::ResumeDocument);
+#endif // IS_SUSPEND_SUPPORTED
+
+ return jobs;
+}
+
+} // namespace ClangBackEnd
diff --git a/src/tools/clangbackend/ipcsource/clangdocumentsuspenderresumer.h b/src/tools/clangbackend/ipcsource/clangdocumentsuspenderresumer.h
new file mode 100644
index 0000000000..7e2bd8722d
--- /dev/null
+++ b/src/tools/clangbackend/ipcsource/clangdocumentsuspenderresumer.h
@@ -0,0 +1,62 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#pragma once
+
+#include "clangdocument.h"
+#include "clangjobrequest.h"
+
+#include <vector>
+
+namespace ClangBackEnd {
+
+class SuspendResumeJobsEntry {
+public:
+ SuspendResumeJobsEntry() = default;
+ SuspendResumeJobsEntry(const Document &document,
+ JobRequest::Type jobRequestType,
+ PreferredTranslationUnit preferredTranslationUnit)
+ : document(document)
+ , jobRequestType(jobRequestType)
+ , preferredTranslationUnit(preferredTranslationUnit)
+ {
+ }
+
+ Document document;
+ JobRequest::Type jobRequestType = JobRequest::Type::SuspendDocument;
+ PreferredTranslationUnit preferredTranslationUnit = PreferredTranslationUnit::RecentlyParsed;
+};
+using SuspendResumeJobs = QVector<SuspendResumeJobsEntry>;
+
+SuspendResumeJobs createSuspendResumeJobs(const std::vector<Document> &documents,
+ int customHotDocumentCounts = -1);
+
+// for tests
+void categorizeHotColdDocuments(int hotDocumentsSize,
+ const std::vector<Document> &inDocuments,
+ std::vector<Document> &hotDocuments,
+ std::vector<Document> &coldDocuments);
+
+} // namespace ClangBackEnd
diff --git a/src/tools/clangbackend/ipcsource/clangiasyncjob.cpp b/src/tools/clangbackend/ipcsource/clangiasyncjob.cpp
index 14de731eb6..db3aebfe8e 100644
--- a/src/tools/clangbackend/ipcsource/clangiasyncjob.cpp
+++ b/src/tools/clangbackend/ipcsource/clangiasyncjob.cpp
@@ -31,6 +31,8 @@
#include "clangreparsesupportivetranslationunitjob.h"
#include "clangrequestdocumentannotationsjob.h"
#include "clangrequestreferencesjob.h"
+#include "clangresumedocumentjob.h"
+#include "clangsuspenddocumentjob.h"
#include "clangupdatedocumentannotationsjob.h"
Q_LOGGING_CATEGORY(jobsLog, "qtc.clangbackend.jobs");
@@ -54,6 +56,10 @@ IAsyncJob *IAsyncJob::create(JobRequest::Type type)
return new RequestDocumentAnnotationsJob();
case JobRequest::Type::RequestReferences:
return new RequestReferencesJob();
+ case JobRequest::Type::SuspendDocument:
+ return new SuspendDocumentJob();
+ case JobRequest::Type::ResumeDocument:
+ return new ResumeDocumentJob();
}
return nullptr;
diff --git a/src/tools/clangbackend/ipcsource/clangjobqueue.cpp b/src/tools/clangbackend/ipcsource/clangjobqueue.cpp
index 7af76ce32d..8c9ace68e6 100644
--- a/src/tools/clangbackend/ipcsource/clangjobqueue.cpp
+++ b/src/tools/clangbackend/ipcsource/clangjobqueue.cpp
@@ -179,6 +179,16 @@ static bool passesPreconditions(const JobRequest &request, const Document &docum
using Condition = JobRequest::Condition;
const JobRequest::Conditions conditions = request.conditions;
+ if (conditions.testFlag(Condition::DocumentSuspended) && !document.isSuspended()) {
+ qCDebug(jobsLog) << "Not choosing due to unsuspended document:" << request;
+ return false;
+ }
+
+ if (conditions.testFlag(Condition::DocumentUnsuspended) && document.isSuspended()) {
+ qCDebug(jobsLog) << "Not choosing due to suspended document:" << request;
+ return false;
+ }
+
if (conditions.testFlag(Condition::DocumentVisible) && !document.isVisibleInEditor()) {
qCDebug(jobsLog) << "Not choosing due to invisble document:" << request;
return false;
diff --git a/src/tools/clangbackend/ipcsource/clangjobrequest.cpp b/src/tools/clangbackend/ipcsource/clangjobrequest.cpp
index c9162b2125..1f6bf17ee8 100644
--- a/src/tools/clangbackend/ipcsource/clangjobrequest.cpp
+++ b/src/tools/clangbackend/ipcsource/clangjobrequest.cpp
@@ -40,6 +40,8 @@ static const char *JobRequestTypeToText(JobRequest::Type type)
RETURN_TEXT_FOR_CASE(CompleteCode);
RETURN_TEXT_FOR_CASE(RequestDocumentAnnotations);
RETURN_TEXT_FOR_CASE(RequestReferences);
+ RETURN_TEXT_FOR_CASE(SuspendDocument);
+ RETURN_TEXT_FOR_CASE(ResumeDocument);
}
return "UnhandledJobRequestType";
@@ -121,7 +123,19 @@ JobRequest::ExpirationReasons JobRequest::expirationReasonsForType(Type type)
JobRequest::Conditions JobRequest::conditionsForType(JobRequest::Type type)
{
- Conditions conditions = Condition::DocumentVisible;
+ if (type == Type::SuspendDocument) {
+ return Conditions(Condition::DocumentUnsuspended)
+ | Conditions(Condition::DocumentNotVisible);
+ }
+
+ if (type == Type::ResumeDocument) {
+ return Conditions(Condition::DocumentSuspended)
+ | Conditions(Condition::DocumentVisible);
+ }
+
+ Conditions conditions = Conditions(Condition::DocumentUnsuspended)
+ | Conditions(Condition::DocumentVisible);
+
if (type == Type::RequestReferences)
conditions |= Condition::CurrentDocumentRevision;
diff --git a/src/tools/clangbackend/ipcsource/clangjobrequest.h b/src/tools/clangbackend/ipcsource/clangjobrequest.h
index b484dee7ce..b9bbf0a3be 100644
--- a/src/tools/clangbackend/ipcsource/clangjobrequest.h
+++ b/src/tools/clangbackend/ipcsource/clangjobrequest.h
@@ -53,13 +53,18 @@ public:
CompleteCode,
RequestDocumentAnnotations,
RequestReferences,
+
+ SuspendDocument,
+ ResumeDocument,
};
enum class Condition {
NoCondition = 1 << 0,
DocumentVisible = 1 << 1,
DocumentNotVisible = 1 << 2,
- CurrentDocumentRevision = 1 << 3,
+ DocumentSuspended = 1 << 3,
+ DocumentUnsuspended = 1 << 4,
+ CurrentDocumentRevision = 1 << 5,
};
Q_DECLARE_FLAGS(Conditions, Condition)
diff --git a/src/tools/clangbackend/ipcsource/clangresumedocumentjob.cpp b/src/tools/clangbackend/ipcsource/clangresumedocumentjob.cpp
new file mode 100644
index 0000000000..c628d4444a
--- /dev/null
+++ b/src/tools/clangbackend/ipcsource/clangresumedocumentjob.cpp
@@ -0,0 +1,54 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "clangresumedocumentjob.h"
+
+#include <utils/qtcassert.h>
+
+namespace ClangBackEnd {
+
+void ResumeDocumentJob::finalizeAsyncRun()
+{
+ if (context().isDocumentOpen()) {
+ if (QTC_GUARD(asyncResult().updateResult.hasReparsed()))
+ m_pinnedDocument.setIsSuspended(false);
+ }
+
+ UpdateDocumentAnnotationsJob::finalizeAsyncRun();
+}
+
+bool ResumeDocumentJob::isExpectedJobRequestType(const JobRequest &jobRequest) const
+{
+ return jobRequest.type == JobRequest::Type::ResumeDocument;
+}
+
+TranslationUnitUpdateInput ResumeDocumentJob::createUpdateInput(const Document &document) const
+{
+ TranslationUnitUpdateInput input = UpdateDocumentAnnotationsJob::createUpdateInput(document);
+ input.reparseNeeded = true;
+ return input;
+}
+
+} // namespace ClangBackEnd
diff --git a/src/tools/clangbackend/ipcsource/clangresumedocumentjob.h b/src/tools/clangbackend/ipcsource/clangresumedocumentjob.h
new file mode 100644
index 0000000000..aff8e780f7
--- /dev/null
+++ b/src/tools/clangbackend/ipcsource/clangresumedocumentjob.h
@@ -0,0 +1,44 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#pragma once
+
+#include "clangasyncjob.h"
+#include "clangdocument.h"
+#include "clangupdatedocumentannotationsjob.h"
+
+namespace ClangBackEnd {
+
+class ResumeDocumentJob : public UpdateDocumentAnnotationsJob
+{
+public:
+ void finalizeAsyncRun() override;
+
+private:
+ bool isExpectedJobRequestType(const JobRequest &jobRequest) const override;
+ TranslationUnitUpdateInput createUpdateInput(const Document &document) const override;
+};
+
+} // namespace ClangBackEnd
diff --git a/src/tools/clangbackend/ipcsource/clangsuspenddocumentjob.cpp b/src/tools/clangbackend/ipcsource/clangsuspenddocumentjob.cpp
new file mode 100644
index 0000000000..e3406fcf32
--- /dev/null
+++ b/src/tools/clangbackend/ipcsource/clangsuspenddocumentjob.cpp
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "clangsuspenddocumentjob.h"
+
+#include <clangbackendipc/clangbackendipcdebugutils.h>
+
+#include <utils/qtcassert.h>
+
+namespace ClangBackEnd {
+
+static bool runAsyncHelper(const TranslationUnit &translationUnit)
+{
+ TIME_SCOPE_DURATION("SuspendDocumentJobRunner");
+
+ return translationUnit.suspend();
+}
+
+IAsyncJob::AsyncPrepareResult SuspendDocumentJob::prepareAsyncRun()
+{
+ const JobRequest jobRequest = context().jobRequest;
+ QTC_ASSERT(jobRequest.type == JobRequest::Type::SuspendDocument, return AsyncPrepareResult());
+
+ try {
+ m_pinnedDocument = context().documentForJobRequest();
+ m_pinnedFileContainer = m_pinnedDocument.fileContainer();
+
+ TranslationUnit translationUnit
+ = m_pinnedDocument.translationUnit(jobRequest.preferredTranslationUnit);
+ setRunner([translationUnit]() {
+ return runAsyncHelper(translationUnit);
+ });
+ return AsyncPrepareResult{translationUnit.id()};
+
+ } catch (const std::exception &exception) {
+ qWarning() << "Error in SuspendDocumentJob::prepareAsyncRun:" << exception.what();
+ return AsyncPrepareResult();
+ }
+}
+
+void SuspendDocumentJob::finalizeAsyncRun()
+{
+ if (context().isDocumentOpen()) {
+ const bool suspendSucceeded = asyncResult();
+ if (QTC_GUARD(suspendSucceeded)) {
+ m_pinnedDocument.setIsSuspended(true);
+ }
+ }
+}
+
+} // namespace ClangBackEnd
diff --git a/src/tools/clangbackend/ipcsource/clangsuspenddocumentjob.h b/src/tools/clangbackend/ipcsource/clangsuspenddocumentjob.h
new file mode 100644
index 0000000000..16d5b52a1e
--- /dev/null
+++ b/src/tools/clangbackend/ipcsource/clangsuspenddocumentjob.h
@@ -0,0 +1,44 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#pragma once
+
+#include "clangasyncjob.h"
+#include "clangdocument.h"
+
+namespace ClangBackEnd {
+
+class SuspendDocumentJob : public AsyncJob<bool>
+{
+public:
+ AsyncPrepareResult prepareAsyncRun() override;
+ void finalizeAsyncRun() override;
+
+private:
+ Document m_pinnedDocument;
+ FileContainer m_pinnedFileContainer;
+};
+
+} // namespace ClangBackEnd
diff --git a/src/tools/clangbackend/ipcsource/clangtranslationunit.cpp b/src/tools/clangbackend/ipcsource/clangtranslationunit.cpp
index ca95c5f190..0bc0509a5e 100644
--- a/src/tools/clangbackend/ipcsource/clangtranslationunit.cpp
+++ b/src/tools/clangbackend/ipcsource/clangtranslationunit.cpp
@@ -25,6 +25,7 @@
#include "clangtranslationunit.h"
+#include "clangbackend_global.h"
#include "clangreferencescollector.h"
#include "clangtranslationunitupdater.h"
@@ -38,6 +39,8 @@
#include <sourcelocation.h>
#include <sourcerange.h>
+#include <utils/qtcassert.h>
+
namespace ClangBackEnd {
TranslationUnit::TranslationUnit(const Utf8String &id,
@@ -100,6 +103,16 @@ TranslationUnitUpdateResult TranslationUnit::reparse(
return updater.update(TranslationUnitUpdater::UpdateMode::ForceReparse);
}
+bool TranslationUnit::suspend() const
+{
+#ifdef IS_SUSPEND_SUPPORTED
+ return clang_suspendTranslationUnit(cxTranslationUnit());
+#else
+ QTC_CHECK(false && "clang_suspendTranslationUnit() not supported.");
+ return false;
+#endif
+}
+
TranslationUnit::CodeCompletionResult TranslationUnit::complete(
UnsavedFiles &unsavedFiles,
uint line,
diff --git a/src/tools/clangbackend/ipcsource/clangtranslationunit.h b/src/tools/clangbackend/ipcsource/clangtranslationunit.h
index 5e6d28736a..cc398e9a72 100644
--- a/src/tools/clangbackend/ipcsource/clangtranslationunit.h
+++ b/src/tools/clangbackend/ipcsource/clangtranslationunit.h
@@ -71,6 +71,8 @@ public:
CXIndex &cxIndex() const;
CXTranslationUnit &cxTranslationUnit() const;
+ bool suspend() const;
+
TranslationUnitUpdateResult update(const TranslationUnitUpdateInput &parseInput) const;
TranslationUnitUpdateResult parse(const TranslationUnitUpdateInput &parseInput) const;
TranslationUnitUpdateResult reparse(const TranslationUnitUpdateInput &parseInput) const;
diff --git a/src/tools/clangbackend/ipcsource/clangupdatedocumentannotationsjob.cpp b/src/tools/clangbackend/ipcsource/clangupdatedocumentannotationsjob.cpp
index fee622964d..b4b56fe534 100644
--- a/src/tools/clangbackend/ipcsource/clangupdatedocumentannotationsjob.cpp
+++ b/src/tools/clangbackend/ipcsource/clangupdatedocumentannotationsjob.cpp
@@ -56,8 +56,7 @@ static UpdateDocumentAnnotationsJob::AsyncResult runAsyncHelper(
IAsyncJob::AsyncPrepareResult UpdateDocumentAnnotationsJob::prepareAsyncRun()
{
const JobRequest jobRequest = context().jobRequest;
- QTC_ASSERT(jobRequest.type == JobRequest::Type::UpdateDocumentAnnotations,
- return AsyncPrepareResult());
+ QTC_ASSERT(isExpectedJobRequestType(jobRequest), return AsyncPrepareResult());
try {
m_pinnedDocument = context().documentForJobRequest();
@@ -65,7 +64,7 @@ IAsyncJob::AsyncPrepareResult UpdateDocumentAnnotationsJob::prepareAsyncRun()
const TranslationUnit translationUnit
= m_pinnedDocument.translationUnit(jobRequest.preferredTranslationUnit);
- const TranslationUnitUpdateInput updateInput = m_pinnedDocument.createUpdateInput();
+ const TranslationUnitUpdateInput updateInput = createUpdateInput(m_pinnedDocument);
setRunner([translationUnit, updateInput]() {
return runAsyncHelper(translationUnit, updateInput);
});
@@ -87,6 +86,17 @@ void UpdateDocumentAnnotationsJob::finalizeAsyncRun()
}
}
+bool UpdateDocumentAnnotationsJob::isExpectedJobRequestType(const JobRequest &jobRequest) const
+{
+ return jobRequest.type == JobRequest::Type::UpdateDocumentAnnotations;
+}
+
+TranslationUnitUpdateInput
+UpdateDocumentAnnotationsJob::createUpdateInput(const Document &document) const
+{
+ return document.createUpdateInput();
+}
+
void UpdateDocumentAnnotationsJob::incorporateUpdaterResult(const AsyncResult &result)
{
m_pinnedDocument.incorporateUpdaterResult(result.updateResult);
diff --git a/src/tools/clangbackend/ipcsource/clangupdatedocumentannotationsjob.h b/src/tools/clangbackend/ipcsource/clangupdatedocumentannotationsjob.h
index 00fe3be311..fdbe9068a6 100644
--- a/src/tools/clangbackend/ipcsource/clangupdatedocumentannotationsjob.h
+++ b/src/tools/clangbackend/ipcsource/clangupdatedocumentannotationsjob.h
@@ -53,12 +53,18 @@ public:
AsyncPrepareResult prepareAsyncRun() override;
void finalizeAsyncRun() override;
+protected:
+ virtual bool isExpectedJobRequestType(const JobRequest &jobRequest) const;
+ virtual TranslationUnitUpdateInput createUpdateInput(const Document &document) const;
+
private:
void incorporateUpdaterResult(const AsyncResult &result);
void sendAnnotations(const AsyncResult &result);
-private:
+protected:
Document m_pinnedDocument;
+
+private:
FileContainer m_pinnedFileContainer;
};
diff --git a/tests/unit/unittest/clangdocumentsuspenderresumer-test.cpp b/tests/unit/unittest/clangdocumentsuspenderresumer-test.cpp
new file mode 100644
index 0000000000..8ab78ebded
--- /dev/null
+++ b/tests/unit/unittest/clangdocumentsuspenderresumer-test.cpp
@@ -0,0 +1,295 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "googletest.h"
+
+#include "dummyclangipcclient.h"
+
+#include <clangclock.h>
+#include <clangdocument.h>
+#include <clangdocumentprocessors.h>
+#include <clangdocuments.h>
+#include <clangdocumentsuspenderresumer.h>
+#include <clangtranslationunits.h>
+#include <projects.h>
+#include <unsavedfiles.h>
+#include <utf8string.h>
+
+#include <utils/algorithm.h>
+
+#include <clang-c/Index.h>
+
+using ClangBackEnd::Clock;
+using ClangBackEnd::Document;
+using ClangBackEnd::JobRequest;
+using ClangBackEnd::PreferredTranslationUnit;
+using ClangBackEnd::SuspendResumeJobs;
+using ClangBackEnd::SuspendResumeJobsEntry;
+using ClangBackEnd::TimePoint;
+
+using testing::ContainerEq;
+using testing::ElementsAre;
+using testing::IsEmpty;
+
+namespace ClangBackEnd {
+
+bool operator==(const SuspendResumeJobsEntry &a, const SuspendResumeJobsEntry &b)
+{
+ return a.document == b.document
+ && a.jobRequestType == b.jobRequestType
+ && a.preferredTranslationUnit == b.preferredTranslationUnit;
+}
+
+} // ClangBackEnd
+
+namespace {
+
+class DocumentSuspenderResumer : public ::testing::Test
+{
+protected:
+ void SetUp() override;
+ Document getDocument(const Utf8String &filePath);
+ void categorizeDocuments(int hotDocumentsSize);
+ SuspendResumeJobs createSuspendResumeJobs(int hotDocumentsSize = -1);
+
+protected:
+ ClangBackEnd::ProjectParts projects;
+ ClangBackEnd::UnsavedFiles unsavedFiles;
+ ClangBackEnd::Documents documents{projects, unsavedFiles};
+ DummyIpcClient dummyIpcClient;
+ ClangBackEnd::DocumentProcessors documentProcessors{documents, unsavedFiles, projects,
+ dummyIpcClient};
+
+ const Utf8String projectPartId = Utf8StringLiteral("projectPartId");
+
+ const Utf8String filePath1 = Utf8StringLiteral(TESTDATA_DIR"/empty1.cpp");
+ const ClangBackEnd::FileContainer fileContainer1{filePath1, projectPartId, Utf8String(), true};
+
+ const Utf8String filePath2 = Utf8StringLiteral(TESTDATA_DIR"/empty2.cpp");
+ const ClangBackEnd::FileContainer fileContainer2{filePath2, projectPartId, Utf8String(), true};
+
+ const Utf8String filePath3 = Utf8StringLiteral(TESTDATA_DIR"/empty3.cpp");
+ const ClangBackEnd::FileContainer fileContainer3{filePath3, projectPartId, Utf8String(), true};
+
+ std::vector<Document> hotDocuments;
+ std::vector<Document> coldDocuments;
+};
+
+TEST_F(DocumentSuspenderResumer, CategorizeNoDocuments)
+{
+ categorizeDocuments(99);
+
+ ASSERT_THAT(hotDocuments, IsEmpty());
+ ASSERT_THAT(coldDocuments, IsEmpty());
+}
+
+TEST_F(DocumentSuspenderResumer, CategorizeSingleDocument)
+{
+ documents.create({fileContainer1});
+
+ categorizeDocuments(99);
+
+ ASSERT_THAT(hotDocuments, ElementsAre(getDocument(filePath1)));
+ ASSERT_THAT(coldDocuments, IsEmpty());
+}
+
+TEST_F(DocumentSuspenderResumer, CategorizeKeepsStableOrder)
+{
+ documents.create({fileContainer1, fileContainer2});
+
+ categorizeDocuments(99);
+
+ ASSERT_THAT(hotDocuments, ElementsAre(getDocument(filePath1),
+ getDocument(filePath2)));
+}
+
+TEST_F(DocumentSuspenderResumer, CategorizePutsLastVisibleToTopOfHotDocuments)
+{
+ documents.create({fileContainer1, fileContainer2});
+ documents.setVisibleInEditors({filePath1});
+ documents.setVisibleInEditors({filePath2});
+
+ categorizeDocuments(99);
+
+ ASSERT_THAT(hotDocuments, ElementsAre(getDocument(filePath2),
+ getDocument(filePath1)));
+}
+
+TEST_F(DocumentSuspenderResumer, CategorizeWithLessDocumentsThanWeCareFor)
+{
+ documents.create({fileContainer1});
+
+ categorizeDocuments(2);
+
+ ASSERT_THAT(hotDocuments, ElementsAre(getDocument(filePath1)));
+ ASSERT_THAT(coldDocuments, IsEmpty());
+}
+
+TEST_F(DocumentSuspenderResumer, CategorizeWithZeroHotDocuments)
+{
+ documents.create({fileContainer1});
+
+ categorizeDocuments(0);
+
+ ASSERT_THAT(hotDocuments, IsEmpty());
+ ASSERT_THAT(coldDocuments, ElementsAre(getDocument(filePath1)));
+}
+
+TEST_F(DocumentSuspenderResumer, CategorizeWithMoreVisibleDocumentsThanHotDocuments)
+{
+ const TimePoint timePoint = Clock::now();
+ Document document1 = documents.create({fileContainer1})[0];
+ document1.setIsVisibleInEditor(true, timePoint);
+ Document document2 = documents.create({fileContainer2})[0];
+ document2.setIsVisibleInEditor(true, timePoint);
+
+ categorizeDocuments(1);
+
+ ASSERT_THAT(hotDocuments, ElementsAre(getDocument(filePath1), getDocument(filePath2)));
+ ASSERT_THAT(coldDocuments, IsEmpty());
+}
+
+TEST_F(DocumentSuspenderResumer, CreateSuspendJobForInvisible)
+{
+ Document document = documents.create({fileContainer1})[0];
+ document.setIsSuspended(false);
+ document.setIsVisibleInEditor(false, Clock::now());
+ const SuspendResumeJobs expectedJobs = {
+ {document, JobRequest::Type::SuspendDocument, PreferredTranslationUnit::RecentlyParsed}
+ };
+
+ const SuspendResumeJobs jobs = createSuspendResumeJobs(/*hotDocumentsSize=*/ 0);
+
+ ASSERT_THAT(jobs, ContainerEq(expectedJobs));
+}
+
+TEST_F(DocumentSuspenderResumer, DoNotCreateSuspendJobForVisible)
+{
+ Document document = documents.create({fileContainer1})[0];
+ document.setIsSuspended(false);
+ document.setIsVisibleInEditor(true, Clock::now());
+
+ const SuspendResumeJobs jobs = createSuspendResumeJobs(/*hotDocumentsSize=*/ 0);
+
+ ASSERT_THAT(jobs, ContainerEq(SuspendResumeJobs()));
+}
+
+TEST_F(DocumentSuspenderResumer, CreateSuspendJobsForDocumentWithSupportiveTranslationUnit)
+{
+ Document document = documents.create({fileContainer1})[0];
+ document.setIsSuspended(false);
+ document.setIsVisibleInEditor(false, Clock::now());
+ document.translationUnits().createAndAppend(); // Add supportive translation unit
+ const SuspendResumeJobs expectedJobs = {
+ {document, JobRequest::Type::SuspendDocument, PreferredTranslationUnit::RecentlyParsed},
+ {document, JobRequest::Type::SuspendDocument, PreferredTranslationUnit::PreviouslyParsed},
+ };
+
+ const SuspendResumeJobs jobs = createSuspendResumeJobs(/*hotDocumentsSize=*/ 0);
+
+ ASSERT_THAT(jobs, ContainerEq(expectedJobs));
+}
+
+TEST_F(DocumentSuspenderResumer, CreateResumeJob)
+{
+ Document document = documents.create({fileContainer1})[0];
+ document.setIsSuspended(true);
+ document.setIsVisibleInEditor(true, Clock::now());
+ const SuspendResumeJobs expectedJobs = {
+ {document, JobRequest::Type::ResumeDocument, PreferredTranslationUnit::RecentlyParsed}
+ };
+
+ const SuspendResumeJobs jobs = createSuspendResumeJobs();
+
+ ASSERT_THAT(jobs, ContainerEq(expectedJobs));
+}
+
+TEST_F(DocumentSuspenderResumer, DoNotCreateResumeJobForInvisible)
+{
+ Document document = documents.create({fileContainer1})[0];
+ document.setIsSuspended(true);
+ document.setIsVisibleInEditor(false, Clock::now());
+
+ const SuspendResumeJobs jobs = createSuspendResumeJobs(/*hotDocumentsSize=*/ 0);
+
+ ASSERT_THAT(jobs, ContainerEq(SuspendResumeJobs()));
+}
+
+TEST_F(DocumentSuspenderResumer, CreateResumeJobsForDocumentWithSupportiveTranslationUnit)
+{
+ Document document = documents.create({fileContainer1})[0];
+ document.setIsSuspended(true);
+ document.setIsVisibleInEditor(true, Clock::now());
+ document.translationUnits().createAndAppend(); // Add supportive translation unit
+ const SuspendResumeJobs expectedJobs = {
+ {document, JobRequest::Type::ResumeDocument, PreferredTranslationUnit::RecentlyParsed},
+ {document, JobRequest::Type::ResumeDocument, PreferredTranslationUnit::PreviouslyParsed},
+ };
+
+ const SuspendResumeJobs jobs = createSuspendResumeJobs();
+
+ ASSERT_THAT(jobs, ContainerEq(expectedJobs));
+}
+
+TEST_F(DocumentSuspenderResumer, CreateSuspendAndResumeJobs)
+{
+ Document hotDocument = documents.create({fileContainer1})[0];
+ hotDocument.setIsSuspended(true);
+ Document coldDocument = documents.create({fileContainer2})[0];
+ coldDocument.setIsSuspended(false);
+ documents.setVisibleInEditors({filePath1});
+ const SuspendResumeJobs expectedJobs = {
+ {coldDocument, JobRequest::Type::SuspendDocument, PreferredTranslationUnit::RecentlyParsed},
+ {hotDocument, JobRequest::Type::ResumeDocument, PreferredTranslationUnit::RecentlyParsed},
+ };
+
+ const SuspendResumeJobs jobs = createSuspendResumeJobs(/*hotDocumentsSize=*/ 1);
+
+ ASSERT_THAT(jobs, ContainerEq(expectedJobs));
+}
+
+void DocumentSuspenderResumer::SetUp()
+{
+ projects.createOrUpdate({ClangBackEnd::ProjectPartContainer(projectPartId)});
+}
+
+ClangBackEnd::Document DocumentSuspenderResumer::getDocument(const Utf8String &filePath)
+{
+ return documents.document(filePath, projectPartId);
+}
+
+void DocumentSuspenderResumer::categorizeDocuments(int hotDocumentsSize)
+{
+ categorizeHotColdDocuments(hotDocumentsSize, documents.documents(), hotDocuments,
+ coldDocuments);
+}
+
+ClangBackEnd::SuspendResumeJobs
+DocumentSuspenderResumer::createSuspendResumeJobs(int hotDocumentsSize)
+{
+ return ClangBackEnd::createSuspendResumeJobs(documents.documents(), hotDocumentsSize);
+}
+
+} // anonymous
diff --git a/tests/unit/unittest/clangjobqueue-test.cpp b/tests/unit/unittest/clangjobqueue-test.cpp
index 1b295acf76..ea786e87f1 100644
--- a/tests/unit/unittest/clangjobqueue-test.cpp
+++ b/tests/unit/unittest/clangjobqueue-test.cpp
@@ -430,6 +430,28 @@ TEST_F(JobQueue, RequestReferencesOutdatableByDocumentClose)
ASSERT_THAT(jobQueue.size(), Eq(0));
}
+TEST_F(JobQueue, RequestReferencesDoesNotRunOnSuspendedDocument)
+{
+ jobQueue.add(createJobRequest(filePath1, JobRequest::Type::RequestReferences));
+ document.setIsSuspended(true);
+
+ const JobRequests jobsToStart = jobQueue.processQueue();
+
+ ASSERT_THAT(jobsToStart.size(), Eq(0));
+ ASSERT_THAT(jobQueue.size(), Eq(1));
+}
+
+TEST_F(JobQueue, ResumeDocumentDoesNotRunOnUnsuspended)
+{
+ jobQueue.add(createJobRequest(filePath1, JobRequest::Type::ResumeDocument));
+ document.setIsSuspended(false);
+
+ const JobRequests jobsToStart = jobQueue.processQueue();
+
+ ASSERT_THAT(jobsToStart.size(), Eq(0));
+ ASSERT_THAT(jobQueue.size(), Eq(1));
+}
+
void JobQueue::SetUp()
{
projects.createOrUpdate({ProjectPartContainer(projectPartId)});
diff --git a/tests/unit/unittest/clangresumedocumentjob-test.cpp b/tests/unit/unittest/clangresumedocumentjob-test.cpp
new file mode 100644
index 0000000000..11a9e49072
--- /dev/null
+++ b/tests/unit/unittest/clangresumedocumentjob-test.cpp
@@ -0,0 +1,92 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "clangasyncjob-base.h"
+
+#include <clangresumedocumentjob.h>
+
+using namespace ClangBackEnd;
+
+using testing::_;
+
+namespace {
+
+class ResumeDocumentJob : public ClangAsyncJobTest
+{
+protected:
+ void SetUp() override { BaseSetUp(JobRequest::Type::ResumeDocument, job); }
+ void suspendDocument()
+ {
+ document.parse();
+ document.translationUnit().suspend();
+ document.setIsSuspended(true);
+ }
+
+protected:
+ ClangBackEnd::ResumeDocumentJob job;
+};
+
+TEST_F(ResumeDocumentJob, PrepareAsyncRun)
+{
+ job.setContext(jobContext);
+
+ ASSERT_TRUE(job.prepareAsyncRun());
+}
+
+TEST_F(ResumeDocumentJob, RunAsync)
+{
+ suspendDocument();
+ job.setContext(jobContext);
+ job.prepareAsyncRun();
+
+ job.runAsync();
+
+ ASSERT_TRUE(waitUntilJobFinished(job));
+}
+
+TEST_F(ResumeDocumentJob, DocumentIsResumedAfterRun)
+{
+ suspendDocument();
+ job.setContext(jobContext);
+ job.prepareAsyncRun();
+
+ job.runAsync();
+ ASSERT_TRUE(waitUntilJobFinished(job));
+
+ ASSERT_FALSE(document.isSuspended());
+}
+
+TEST_F(ResumeDocumentJob, SendsAnnotationsAfterResume)
+{
+ suspendDocument();
+ job.setContext(jobContextWithMockClient);
+ job.prepareAsyncRun();
+ EXPECT_CALL(mockIpcClient, documentAnnotationsChanged(_)).Times(1);
+
+ job.runAsync();
+ ASSERT_TRUE(waitUntilJobFinished(job));
+}
+
+} // anonymous
diff --git a/tests/unit/unittest/clangsuspenddocumentjob-test.cpp b/tests/unit/unittest/clangsuspenddocumentjob-test.cpp
new file mode 100644
index 0000000000..b9f92f3beb
--- /dev/null
+++ b/tests/unit/unittest/clangsuspenddocumentjob-test.cpp
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "clangasyncjob-base.h"
+
+#include <clangsuspenddocumentjob.h>
+
+using namespace ClangBackEnd;
+
+namespace {
+
+class SuspendDocumentJob : public ClangAsyncJobTest
+{
+protected:
+ void SetUp() override { BaseSetUp(JobRequest::Type::SuspendDocument, job); }
+
+protected:
+ ClangBackEnd::SuspendDocumentJob job;
+};
+
+TEST_F(SuspendDocumentJob, PrepareAsyncRun)
+{
+ job.setContext(jobContext);
+
+ ASSERT_TRUE(job.prepareAsyncRun());
+}
+
+TEST_F(SuspendDocumentJob, RunAsync)
+{
+ document.parse();
+ job.setContext(jobContext);
+ job.prepareAsyncRun();
+
+ job.runAsync();
+
+ ASSERT_TRUE(waitUntilJobFinished(job));
+}
+
+TEST_F(SuspendDocumentJob, DocumentIsSuspendedAfterRun)
+{
+ document.parse();
+ job.setContext(jobContext);
+ job.prepareAsyncRun();
+
+ job.runAsync();
+ ASSERT_TRUE(waitUntilJobFinished(job));
+
+ ASSERT_TRUE(document.isSuspended());
+}
+
+} // anonymous
diff --git a/tests/unit/unittest/data/empty1.cpp b/tests/unit/unittest/data/empty1.cpp
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/unit/unittest/data/empty1.cpp
diff --git a/tests/unit/unittest/data/empty2.cpp b/tests/unit/unittest/data/empty2.cpp
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/unit/unittest/data/empty2.cpp
diff --git a/tests/unit/unittest/data/empty3.cpp b/tests/unit/unittest/data/empty3.cpp
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/unit/unittest/data/empty3.cpp
diff --git a/tests/unit/unittest/unittest.pro b/tests/unit/unittest/unittest.pro
index be7632ecd5..67226416af 100644
--- a/tests/unit/unittest/unittest.pro
+++ b/tests/unit/unittest/unittest.pro
@@ -84,6 +84,7 @@ SOURCES += \
clangdocumentprocessors-test.cpp \
clangdocumentprocessor-test.cpp \
clangdocuments-test.cpp \
+ clangdocumentsuspenderresumer-test.cpp \
clangdocument-test.cpp \
clangfixitoperation-test.cpp \
clangisdiagnosticrelatedtolocation-test.cpp \
@@ -94,8 +95,10 @@ SOURCES += \
clangreparsesupportivetranslationunitjob-test.cpp \
clangrequestdocumentannotationsjob-test.cpp \
clangrequestreferencesjob-test.cpp \
+ clangresumedocumentjob-test.cpp \
clangstring-test.cpp \
clangsupportivetranslationunitinitializer-test.cpp \
+ clangsuspenddocumentjob-test.cpp \
clangtranslationunits-test.cpp \
clangtranslationunit-test.cpp \
clangupdatedocumentannotationsjob-test.cpp \