summaryrefslogtreecommitdiff
path: root/src/tools
diff options
context:
space:
mode:
authorNikolai Kosjar <nikolai.kosjar@qt.io>2016-05-31 16:07:09 +0200
committerNikolai Kosjar <nikolai.kosjar@qt.io>2016-07-28 09:42:31 +0000
commit38f72855b61e104d2c597141756d140668f5b20a (patch)
tree459874eab6481194d47dbc5471cfebb6c1886899 /src/tools
parent90f94363db0cbaef4841f46db70d4ad5480871c0 (diff)
downloadqt-creator-38f72855b61e104d2c597141756d140668f5b20a.tar.gz
Clang: Process distinct documents concurrently
Speed ups the typical use cases that can profit from this: * Change a header file and switch then to source file * Open documents one after the other (Follow Symbol) * Change documents visible in splits (e.g. by refactoring action) * Restore a session with multiple splits Fixes the test ClangIpcServer.GetCodeCompletionDependingOnArgumets. Change-Id: Ia575bd59780df14146dfc091a4d48794e4a0543d Reviewed-by: Tim Jenssen <tim.jenssen@qt.io>
Diffstat (limited to 'src/tools')
-rw-r--r--src/tools/clangbackend/ipcsource/clangasyncjob.h72
-rw-r--r--src/tools/clangbackend/ipcsource/clangbackendclangipc-source.pri24
-rw-r--r--src/tools/clangbackend/ipcsource/clangcodemodelserver.cpp155
-rw-r--r--src/tools/clangbackend/ipcsource/clangcodemodelserver.h22
-rw-r--r--src/tools/clangbackend/ipcsource/clangcompletecodejob.cpp95
-rw-r--r--src/tools/clangbackend/ipcsource/clangcompletecodejob.h53
-rw-r--r--src/tools/clangbackend/ipcsource/clangcreateinitialdocumentpreamblejob.cpp75
-rw-r--r--src/tools/clangbackend/ipcsource/clangcreateinitialdocumentpreamblejob.h44
-rw-r--r--src/tools/clangbackend/ipcsource/clangiasyncjob.cpp92
-rw-r--r--src/tools/clangbackend/ipcsource/clangiasyncjob.h69
-rw-r--r--src/tools/clangbackend/ipcsource/clangjobcontext.cpp76
-rw-r--r--src/tools/clangbackend/ipcsource/clangjobcontext.h59
-rw-r--r--src/tools/clangbackend/ipcsource/clangjobqueue.cpp223
-rw-r--r--src/tools/clangbackend/ipcsource/clangjobqueue.h77
-rw-r--r--src/tools/clangbackend/ipcsource/clangjobrequest.cpp86
-rw-r--r--src/tools/clangbackend/ipcsource/clangjobrequest.h89
-rw-r--r--src/tools/clangbackend/ipcsource/clangjobs.cpp143
-rw-r--r--src/tools/clangbackend/ipcsource/clangjobs.h82
-rw-r--r--src/tools/clangbackend/ipcsource/clangrequestdocumentannotationsjob.cpp95
-rw-r--r--src/tools/clangbackend/ipcsource/clangrequestdocumentannotationsjob.h60
-rw-r--r--src/tools/clangbackend/ipcsource/clangtranslationunit.cpp315
-rw-r--r--src/tools/clangbackend/ipcsource/clangtranslationunit.h81
-rw-r--r--src/tools/clangbackend/ipcsource/clangtranslationunitupdater.cpp41
-rw-r--r--src/tools/clangbackend/ipcsource/clangtranslationunitupdater.h9
-rw-r--r--src/tools/clangbackend/ipcsource/clangupdatedocumentannotationsjob.cpp109
-rw-r--r--src/tools/clangbackend/ipcsource/clangupdatedocumentannotationsjob.h64
-rw-r--r--src/tools/clangbackend/ipcsource/translationunits.cpp91
-rw-r--r--src/tools/clangbackend/ipcsource/translationunits.h28
28 files changed, 1984 insertions, 445 deletions
diff --git a/src/tools/clangbackend/ipcsource/clangasyncjob.h b/src/tools/clangbackend/ipcsource/clangasyncjob.h
new file mode 100644
index 0000000000..b44227041e
--- /dev/null
+++ b/src/tools/clangbackend/ipcsource/clangasyncjob.h
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 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 "clangiasyncjob.h"
+
+#include <utils/runextensions.h>
+
+#include <QFutureWatcher>
+#include <QObject>
+
+namespace ClangBackEnd {
+
+template<class Result>
+class AsyncJob : public IAsyncJob
+{
+public:
+ AsyncJob() {}
+ ~AsyncJob() {}
+
+ using Runner = std::function<Result()>;
+ Runner runner() const { return m_runner; }
+ void setRunner(const Runner &runner) { m_runner = runner; }
+
+ Result asyncResult() const { return m_futureWatcher.future().result(); }
+
+ QFuture<void> runAsync() override
+ {
+ const auto onFinished = [this]() {
+ finalizeAsyncRun();
+ setIsFinished(true);
+ finishedHandler()(this);
+ };
+ QObject::connect(&m_futureWatcher,
+ &QFutureWatcher<Result>::finished,
+ onFinished);
+
+ const QFuture<Result> future = Utils::runAsync(m_runner);
+ m_futureWatcher.setFuture(future);
+
+ return future;
+ }
+
+private:
+ Runner m_runner;
+ QFutureWatcher<Result> m_futureWatcher;
+};
+
+} // namespace ClangBackEnd
diff --git a/src/tools/clangbackend/ipcsource/clangbackendclangipc-source.pri b/src/tools/clangbackend/ipcsource/clangbackendclangipc-source.pri
index 667ed1fb5d..f47655a6ea 100644
--- a/src/tools/clangbackend/ipcsource/clangbackendclangipc-source.pri
+++ b/src/tools/clangbackend/ipcsource/clangbackendclangipc-source.pri
@@ -36,9 +36,19 @@ HEADERS += $$PWD/clangcodemodelserver.h \
$$PWD/highlightingmarks.h \
$$PWD/highlightingmarksiterator.h \
$$PWD/utf8positionfromlinecolumn.h \
+ $$PWD/clangasyncjob.h \
+ $$PWD/clangcompletecodejob.h \
+ $$PWD/clangcreateinitialdocumentpreamblejob.h \
$$PWD/clangfilepath.h \
+ $$PWD/clangiasyncjob.h \
+ $$PWD/clangjobcontext.h \
+ $$PWD/clangjobqueue.h \
+ $$PWD/clangjobrequest.h \
+ $$PWD/clangjobs.h \
+ $$PWD/clangrequestdocumentannotationsjob.h \
+ $$PWD/clangtranslationunitcore.h \
$$PWD/clangunsavedfilesshallowarguments.h \
- $$PWD/clangtranslationunitcore.h
+ $$PWD/clangupdatedocumentannotationsjob.h
SOURCES += $$PWD/clangcodemodelserver.cpp \
$$PWD/codecompleter.cpp \
@@ -74,6 +84,16 @@ SOURCES += $$PWD/clangcodemodelserver.cpp \
$$PWD/highlightingmark.cpp \
$$PWD/highlightingmarks.cpp \
$$PWD/utf8positionfromlinecolumn.cpp \
+ $$PWD/clangcompletecodejob.cpp \
+ $$PWD/clangcreateinitialdocumentpreamblejob.cpp \
$$PWD/clangfilepath.cpp \
+ $$PWD/clangiasyncjob.cpp \
+ $$PWD/clangjobcontext.cpp \
+ $$PWD/clangjobqueue.cpp \
+ $$PWD/clangjobrequest.cpp \
+ $$PWD/clangjobs.cpp \
+ $$PWD/clangrequestdocumentannotationsjob.cpp \
+ $$PWD/clangtranslationunitcore.cpp \
$$PWD/clangunsavedfilesshallowarguments.cpp \
- $$PWD/clangtranslationunitcore.cpp
+ $$PWD/clangupdatedocumentannotationsjob.cpp \
+
diff --git a/src/tools/clangbackend/ipcsource/clangcodemodelserver.cpp b/src/tools/clangbackend/ipcsource/clangcodemodelserver.cpp
index 5d48966986..5f1161717a 100644
--- a/src/tools/clangbackend/ipcsource/clangcodemodelserver.cpp
+++ b/src/tools/clangbackend/ipcsource/clangcodemodelserver.cpp
@@ -82,41 +82,25 @@ int delayedDocumentAnnotationsTimerInterval()
return interval;
}
-}
+} // anonymous
ClangCodeModelServer::ClangCodeModelServer()
: translationUnits(projects, unsavedFiles)
+ , updateDocumentAnnotationsTimeOutInMs(delayedDocumentAnnotationsTimerInterval())
{
- const auto sendDocumentAnnotations
- = [this] (const DocumentAnnotationsChangedMessage &documentAnnotationsChangedMessage) {
- client()->documentAnnotationsChanged(documentAnnotationsChangedMessage);
- };
-
- const auto sendDelayedDocumentAnnotations = [this] () {
- try {
- auto sendState = translationUnits.sendDocumentAnnotations();
- if (sendState == DocumentAnnotationsSendState::MaybeThereAreDocumentAnnotations)
- sendDocumentAnnotationsTimer.setInterval(0);
- else
- sendDocumentAnnotationsTimer.stop();
- } catch (const std::exception &exception) {
- qWarning() << "Error in ClangCodeModelServer::sendDelayedDocumentAnnotationsTimer:" << exception.what();
- }
- };
-
- const auto onFileChanged = [this] (const Utf8String &filePath) {
- startDocumentAnnotationsTimerIfFileIsNotATranslationUnit(filePath);
- };
-
- translationUnits.setSendDocumentAnnotationsCallback(sendDocumentAnnotations);
+ updateDocumentAnnotationsTimer.setSingleShot(true);
- QObject::connect(&sendDocumentAnnotationsTimer,
+ QObject::connect(&updateDocumentAnnotationsTimer,
&QTimer::timeout,
- sendDelayedDocumentAnnotations);
+ [this]() {
+ processJobsForDirtyAndVisibleDocuments();
+ });
QObject::connect(translationUnits.clangFileSystemWatcher(),
&ClangFileSystemWatcher::fileChanged,
- onFileChanged);
+ [this](const Utf8String &filePath) {
+ ClangCodeModelServer::startDocumentAnnotationsTimerIfFileIsNotATranslationUnit(filePath);
+ });
}
void ClangCodeModelServer::end()
@@ -133,8 +117,8 @@ void ClangCodeModelServer::registerTranslationUnitsForEditor(const ClangBackEnd:
unsavedFiles.createOrUpdate(message.fileContainers());
translationUnits.setUsedByCurrentEditor(message.currentEditorFilePath());
translationUnits.setVisibleInEditors(message.visibleEditorFilePaths());
- startDocumentAnnotations();
- reparseVisibleDocuments(createdTranslationUnits);
+
+ processInitialJobsForDocuments(createdTranslationUnits);
} catch (const ProjectPartDoNotExistException &exception) {
client()->projectPartsDoNotExist(ProjectPartsDoNotExistMessage(exception.projectPartIds()));
} catch (const std::exception &exception) {
@@ -151,7 +135,8 @@ void ClangCodeModelServer::updateTranslationUnitsForEditor(const UpdateTranslati
if (newerFileContainers.size() > 0) {
translationUnits.update(newerFileContainers);
unsavedFiles.createOrUpdate(newerFileContainers);
- sendDocumentAnnotationsTimer.start(delayedDocumentAnnotationsTimerInterval());
+
+ updateDocumentAnnotationsTimer.start(updateDocumentAnnotationsTimeOutInMs);
}
} catch (const ProjectPartDoNotExistException &exception) {
client()->projectPartsDoNotExist(ProjectPartsDoNotExistMessage(exception.projectPartIds()));
@@ -185,7 +170,8 @@ void ClangCodeModelServer::registerProjectPartsForEditor(const RegisterProjectPa
try {
projects.createOrUpdate(message.projectContainers());
translationUnits.setTranslationUnitsDirtyIfProjectPartChanged();
- sendDocumentAnnotationsTimer.start(0);
+
+ processJobsForDirtyAndVisibleDocuments();
} catch (const std::exception &exception) {
qWarning() << "Error in ClangCodeModelServer::registerProjectPartsForEditor:" << exception.what();
}
@@ -211,7 +197,8 @@ void ClangCodeModelServer::registerUnsavedFilesForEditor(const RegisterUnsavedFi
try {
unsavedFiles.createOrUpdate(message.fileContainers());
translationUnits.updateTranslationUnitsWithChangedDependencies(message.fileContainers());
- sendDocumentAnnotationsTimer.start(delayedDocumentAnnotationsTimerInterval());
+
+ updateDocumentAnnotationsTimer.start(updateDocumentAnnotationsTimeOutInMs);
} catch (const ProjectPartDoNotExistException &exception) {
client()->projectPartsDoNotExist(ProjectPartsDoNotExistMessage(exception.projectPartIds()));
} catch (const std::exception &exception) {
@@ -240,16 +227,16 @@ void ClangCodeModelServer::completeCode(const ClangBackEnd::CompleteCodeMessage
TIME_SCOPE_DURATION("ClangCodeModelServer::completeCode");
try {
- auto translationUnit = translationUnits.translationUnit(message.filePath(), message.projectPartId());
- auto translationUnitCore = translationUnit.translationUnitCore();
+ auto translationUnit = translationUnits.translationUnit(message.filePath(),
+ message.projectPartId());
- CodeCompleter codeCompleter(translationUnitCore, unsavedFiles);
+ JobRequest jobRequest = createJobRequest(translationUnit, JobRequest::Type::CompleteCode);
+ jobRequest.line = message.line();
+ jobRequest.column = message.column();
+ jobRequest.ticketNumber = message.ticketNumber();
- const auto codeCompletions = codeCompleter.complete(message.line(), message.column());
-
- client()->codeCompleted(CodeCompletedMessage(codeCompletions,
- codeCompleter.neededCorrection(),
- message.ticketNumber()));
+ jobs().add(jobRequest);
+ jobs().process();
} catch (const TranslationUnitDoesNotExistException &exception) {
client()->translationUnitDoesNotExist(TranslationUnitDoesNotExistMessage(exception.fileContainer()));
} catch (const ProjectPartDoNotExistException &exception) {
@@ -266,13 +253,12 @@ void ClangCodeModelServer::requestDocumentAnnotations(const RequestDocumentAnnot
try {
auto translationUnit = translationUnits.translationUnit(message.fileContainer().filePath(),
message.fileContainer().projectPartId());
- auto translationUnitCore = translationUnit.translationUnitCore();
- client()->documentAnnotationsChanged(DocumentAnnotationsChangedMessage(
- translationUnit.fileContainer(),
- translationUnitCore.mainFileDiagnostics(),
- translationUnitCore.highlightingMarks().toHighlightingMarksContainers(),
- translationUnitCore.skippedSourceRanges().toSourceRangeContainers()));
+ const JobRequest jobRequest = createJobRequest(translationUnit,
+ JobRequest::Type::RequestDocumentAnnotations);
+
+ jobs().add(jobRequest);
+ jobs().process();
} catch (const TranslationUnitDoesNotExistException &exception) {
client()->translationUnitDoesNotExist(TranslationUnitDoesNotExistMessage(exception.fileContainer()));
} catch (const ProjectPartDoNotExistException &exception) {
@@ -289,7 +275,7 @@ void ClangCodeModelServer::updateVisibleTranslationUnits(const UpdateVisibleTran
try {
translationUnits.setUsedByCurrentEditor(message.currentEditorFilePath());
translationUnits.setVisibleInEditors(message.visibleEditorFilePaths());
- sendDocumentAnnotationsTimer.start(0);
+ updateDocumentAnnotationsTimer.start(0);
} catch (const std::exception &exception) {
qWarning() << "Error in ClangCodeModelServer::updateVisibleTranslationUnits:" << exception.what();
}
@@ -302,23 +288,80 @@ const TranslationUnits &ClangCodeModelServer::translationUnitsForTestOnly() cons
void ClangCodeModelServer::startDocumentAnnotationsTimerIfFileIsNotATranslationUnit(const Utf8String &filePath)
{
- if (!translationUnits.hasTranslationUnit(filePath))
- sendDocumentAnnotationsTimer.start(0);
+ if (!translationUnits.hasTranslationUnitWithFilePath(filePath))
+ updateDocumentAnnotationsTimer.start(0);
+}
+
+const Jobs &ClangCodeModelServer::jobsForTestOnly()
+{
+ return jobs();
+}
+
+bool ClangCodeModelServer::isTimerRunningForTestOnly() const
+{
+ return updateDocumentAnnotationsTimer.isActive();
}
-void ClangCodeModelServer::startDocumentAnnotations()
+void ClangCodeModelServer::addJobRequestsForDirtyAndVisibleDocuments()
{
- DocumentAnnotationsSendState sendState = DocumentAnnotationsSendState::MaybeThereAreDocumentAnnotations;
+ for (const auto &translationUnit : translationUnits.translationUnits()) {
+ if (translationUnit.isNeedingReparse() && translationUnit.isVisibleInEditor()) {
+ jobs().add(createJobRequest(translationUnit,
+ JobRequest::Type::UpdateDocumentAnnotations));
+ }
+ }
+}
+
+void ClangCodeModelServer::processJobsForDirtyAndVisibleDocuments()
+{
+ addJobRequestsForDirtyAndVisibleDocuments();
+ jobs().process();
+}
+
+void ClangCodeModelServer::processInitialJobsForDocuments(
+ const std::vector<TranslationUnit> &translationUnits)
+{
+ for (const auto &translationUnit : translationUnits) {
+ jobs().add(createJobRequest(translationUnit,
+ JobRequest::Type::UpdateDocumentAnnotations));
+ jobs().add(createJobRequest(translationUnit,
+ JobRequest::Type::CreateInitialDocumentPreamble));
+ }
+
+ jobs().process();
+}
- while (sendState == DocumentAnnotationsSendState::MaybeThereAreDocumentAnnotations)
- sendState = translationUnits.sendDocumentAnnotations();
+JobRequest ClangCodeModelServer::createJobRequest(const TranslationUnit &translationUnit,
+ JobRequest::Type type) const
+{
+ JobRequest jobRequest;
+ jobRequest.type = type;
+ jobRequest.requirements = JobRequest::requirementsForType(type);
+ jobRequest.filePath = translationUnit.filePath();
+ jobRequest.projectPartId = translationUnit.projectPartId();
+ jobRequest.unsavedFilesChangeTimePoint = unsavedFiles.lastChangeTimePoint();
+ jobRequest.documentRevision = translationUnit.documentRevision();
+ const ProjectPart &projectPart = projects.project(translationUnit.projectPartId());
+ jobRequest.projectChangeTimePoint = projectPart.lastChangeTimePoint();
+
+ return jobRequest;
}
-void ClangCodeModelServer::reparseVisibleDocuments(std::vector<TranslationUnit> &translationUnits)
+void ClangCodeModelServer::setUpdateDocumentAnnotationsTimeOutInMsForTestsOnly(int value)
{
- for (TranslationUnit &translationUnit : translationUnits)
- if (translationUnit.isVisibleInEditor())
- translationUnit.reparse();
+ updateDocumentAnnotationsTimeOutInMs = value;
}
+Jobs &ClangCodeModelServer::jobs()
+{
+ if (!jobs_) {
+ // Jobs needs a reference to the client, but the client is not known at
+ // construction time of ClangCodeModelServer, so construct Jobs in a
+ // lazy manner.
+ jobs_.reset(new Jobs(translationUnits, unsavedFiles, projects, *client()));
+ }
+
+ return *jobs_.data();
}
+
+} // namespace ClangBackEnd
diff --git a/src/tools/clangbackend/ipcsource/clangcodemodelserver.h b/src/tools/clangbackend/ipcsource/clangcodemodelserver.h
index 7dd52e0b77..82c64b560d 100644
--- a/src/tools/clangbackend/ipcsource/clangcodemodelserver.h
+++ b/src/tools/clangbackend/ipcsource/clangcodemodelserver.h
@@ -32,10 +32,11 @@
#include "clangtranslationunit.h"
#include "translationunits.h"
#include "unsavedfiles.h"
+#include "clangjobs.h"
#include <utf8string.h>
-#include <QMap>
+#include <QScopedPointer>
#include <QTimer>
namespace ClangBackEnd {
@@ -57,18 +58,31 @@ public:
void updateVisibleTranslationUnits(const UpdateVisibleTranslationUnitsMessage &message) override;
void requestDocumentAnnotations(const RequestDocumentAnnotationsMessage &message) override;
+public /*for tests*/:
const TranslationUnits &translationUnitsForTestOnly() const;
+ const Jobs &jobsForTestOnly();
+ bool isTimerRunningForTestOnly() const;
+ void setUpdateDocumentAnnotationsTimeOutInMsForTestsOnly(int value);
private:
+ Jobs &jobs();
+
void startDocumentAnnotationsTimerIfFileIsNotATranslationUnit(const Utf8String &filePath);
- void startDocumentAnnotations();
- void reparseVisibleDocuments(std::vector<TranslationUnit> &translationUnits);
+ void addJobRequestsForDirtyAndVisibleDocuments();
+ void processJobsForDirtyAndVisibleDocuments();
+ void processInitialJobsForDocuments(const std::vector<TranslationUnit> &translationUnits);
+
+ JobRequest createJobRequest(const TranslationUnit &translationUnit,
+ JobRequest::Type type) const;
private:
ProjectParts projects;
UnsavedFiles unsavedFiles;
TranslationUnits translationUnits;
- QTimer sendDocumentAnnotationsTimer;
+ QScopedPointer<Jobs> jobs_;
+
+ QTimer updateDocumentAnnotationsTimer;
+ int updateDocumentAnnotationsTimeOutInMs;
};
} // namespace ClangBackEnd
diff --git a/src/tools/clangbackend/ipcsource/clangcompletecodejob.cpp b/src/tools/clangbackend/ipcsource/clangcompletecodejob.cpp
new file mode 100644
index 0000000000..d85c93190c
--- /dev/null
+++ b/src/tools/clangbackend/ipcsource/clangcompletecodejob.cpp
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 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 "clangcompletecodejob.h"
+
+#include <clangbackendipc/clangbackendipcdebugutils.h>
+#include <clangbackendipc/clangcodemodelclientinterface.h>
+#include <clangbackendipc/cmbcodecompletedmessage.h>
+
+#include <utils/qtcassert.h>
+
+namespace ClangBackEnd {
+
+static CompleteCodeJob::AsyncResult runAsyncHelper(const TranslationUnitCore &translationUnitCore,
+ UnsavedFiles unsavedFiles,
+ quint32 line,
+ quint32 column)
+{
+ TIME_SCOPE_DURATION("CompleteCodeJobRunner");
+
+ CompleteCodeJob::AsyncResult asyncResult;
+
+ try {
+ const TranslationUnitCore::CodeCompletionResult results
+ = translationUnitCore.complete(unsavedFiles, line, column);
+
+ asyncResult.completions = results.completions;
+ asyncResult.correction = results.correction;
+ } catch (const std::exception &exception) {
+ qWarning() << "Error in CompleteCodeJobRunner:" << exception.what();
+ }
+
+ return asyncResult;
+}
+
+bool CompleteCodeJob::prepareAsyncRun()
+{
+ const JobRequest jobRequest = context().jobRequest;
+ QTC_ASSERT(jobRequest.type == JobRequest::Type::CompleteCode, return false);
+
+ try {
+ m_pinnedTranslationUnit = context().translationUnitForJobRequest();
+
+ const TranslationUnitCore translationUnitCore = m_pinnedTranslationUnit.translationUnitCore();
+ const UnsavedFiles unsavedFiles = *context().unsavedFiles;
+ const quint32 line = jobRequest.line;
+ const quint32 column = jobRequest.column;
+ setRunner([translationUnitCore, unsavedFiles, line, column]() {
+ return runAsyncHelper(translationUnitCore, unsavedFiles, line, column);
+ });
+
+
+ } catch (const std::exception &exception) {
+ qWarning() << "Error in CompleteCodeJob::prepareAsyncRun:" << exception.what();
+ return false;
+ }
+
+ return true;
+}
+
+void CompleteCodeJob::finalizeAsyncRun()
+{
+ if (context().isDocumentOpen()) {
+ const AsyncResult result = asyncResult();
+
+ const CodeCompletedMessage message(result.completions,
+ result.correction,
+ context().jobRequest.ticketNumber);
+ context().client->codeCompleted(message);
+ }
+}
+
+} // namespace ClangBackEnd
diff --git a/src/tools/clangbackend/ipcsource/clangcompletecodejob.h b/src/tools/clangbackend/ipcsource/clangcompletecodejob.h
new file mode 100644
index 0000000000..d3ee9dbc6b
--- /dev/null
+++ b/src/tools/clangbackend/ipcsource/clangcompletecodejob.h
@@ -0,0 +1,53 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 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 "clangtranslationunit.h"
+
+#include <clangbackendipc/codecompletion.h>
+
+namespace ClangBackEnd {
+
+struct CompleteCodeJobResult
+{
+ CodeCompletions completions;
+ CompletionCorrection correction = CompletionCorrection::NoCorrection;
+};
+
+class CompleteCodeJob : public AsyncJob<CompleteCodeJobResult>
+{
+public:
+ using AsyncResult = CompleteCodeJobResult;
+
+ bool prepareAsyncRun() override;
+ void finalizeAsyncRun() override;
+
+private:
+ TranslationUnit m_pinnedTranslationUnit;
+};
+
+} // namespace ClangBackEnd
diff --git a/src/tools/clangbackend/ipcsource/clangcreateinitialdocumentpreamblejob.cpp b/src/tools/clangbackend/ipcsource/clangcreateinitialdocumentpreamblejob.cpp
new file mode 100644
index 0000000000..77ee981518
--- /dev/null
+++ b/src/tools/clangbackend/ipcsource/clangcreateinitialdocumentpreamblejob.cpp
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 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 "clangcreateinitialdocumentpreamblejob.h"
+
+#include <clangbackendipc/clangbackendipcdebugutils.h>
+
+#include <utils/qtcassert.h>
+
+namespace ClangBackEnd {
+
+static void runAsyncHelper(const TranslationUnitCore &translationUnitCore,
+ const TranslationUnitUpdateInput &translationUnitUpdateInput)
+{
+ TIME_SCOPE_DURATION("CreateInitialDocumentPreambleJobRunner");
+
+ try {
+ translationUnitCore.reparse(translationUnitUpdateInput);
+ } catch (const std::exception &exception) {
+ qWarning() << "Error in CreateInitialDocumentPreambleJobRunner:" << exception.what();
+ }
+}
+
+bool CreateInitialDocumentPreambleJob::prepareAsyncRun()
+{
+ const JobRequest jobRequest = context().jobRequest;
+ QTC_ASSERT(jobRequest.type == JobRequest::Type::CreateInitialDocumentPreamble, return false);
+
+ try {
+ m_pinnedTranslationUnit = context().translationUnitForJobRequest();
+ m_pinnedFileContainer = m_pinnedTranslationUnit.fileContainer();
+
+ const TranslationUnitCore translationUnitCore = m_pinnedTranslationUnit.translationUnitCore();
+ const TranslationUnitUpdateInput updateInput = m_pinnedTranslationUnit.createUpdateInput();
+ setRunner([translationUnitCore, updateInput]() {
+ return runAsyncHelper(translationUnitCore, updateInput);
+ });
+
+ } catch (const std::exception &exception) {
+ qWarning() << "Error in CreateInitialDocumentPreambleJob::prepareAsyncRun:"
+ << exception.what();
+ return false;
+ }
+
+ return true;
+}
+
+void CreateInitialDocumentPreambleJob::finalizeAsyncRun()
+{
+}
+
+} // namespace ClangBackEnd
+
diff --git a/src/tools/clangbackend/ipcsource/clangcreateinitialdocumentpreamblejob.h b/src/tools/clangbackend/ipcsource/clangcreateinitialdocumentpreamblejob.h
new file mode 100644
index 0000000000..023a34c8f3
--- /dev/null
+++ b/src/tools/clangbackend/ipcsource/clangcreateinitialdocumentpreamblejob.h
@@ -0,0 +1,44 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 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 "clangtranslationunit.h"
+
+namespace ClangBackEnd {
+
+class CreateInitialDocumentPreambleJob : public AsyncJob<void>
+{
+public:
+ bool prepareAsyncRun() override;
+ void finalizeAsyncRun() override;
+
+private:
+ TranslationUnit m_pinnedTranslationUnit;
+ FileContainer m_pinnedFileContainer;
+};
+
+} // namespace ClangBackEnd
diff --git a/src/tools/clangbackend/ipcsource/clangiasyncjob.cpp b/src/tools/clangbackend/ipcsource/clangiasyncjob.cpp
new file mode 100644
index 0000000000..8c433c4092
--- /dev/null
+++ b/src/tools/clangbackend/ipcsource/clangiasyncjob.cpp
@@ -0,0 +1,92 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 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 "clangiasyncjob.h"
+
+#include "clangcompletecodejob.h"
+#include "clangcreateinitialdocumentpreamblejob.h"
+#include "clangrequestdocumentannotationsjob.h"
+#include "clangupdatedocumentannotationsjob.h"
+
+Q_LOGGING_CATEGORY(jobsLog, "qtc.clangbackend.jobs");
+
+namespace ClangBackEnd {
+
+IAsyncJob *IAsyncJob::create(JobRequest::Type type)
+{
+ switch (type) {
+ case JobRequest::Type::UpdateDocumentAnnotations:
+ return new UpdateDocumentAnnotationsJob();
+ case JobRequest::Type::CreateInitialDocumentPreamble:
+ return new CreateInitialDocumentPreambleJob();
+ case JobRequest::Type::CompleteCode:
+ return new CompleteCodeJob();
+ case JobRequest::Type::RequestDocumentAnnotations:
+ return new RequestDocumentAnnotationsJob();
+ }
+
+ return nullptr;
+}
+
+IAsyncJob::IAsyncJob()
+ : m_context(JobContext())
+{
+}
+
+IAsyncJob::~IAsyncJob()
+{
+}
+
+JobContext IAsyncJob::context() const
+{
+ return m_context;
+}
+
+void IAsyncJob::setContext(const JobContext &context)
+{
+ m_context = context;
+}
+
+IAsyncJob::FinishedHandler IAsyncJob::finishedHandler() const
+{
+ return m_finishedHandler;
+}
+
+void IAsyncJob::setFinishedHandler(const IAsyncJob::FinishedHandler &finishedHandler)
+{
+ m_finishedHandler = finishedHandler;
+}
+
+bool IAsyncJob::isFinished() const
+{
+ return m_isFinished;
+}
+
+void IAsyncJob::setIsFinished(bool isFinished)
+{
+ m_isFinished = isFinished;
+}
+
+} // namespace ClangBackEnd
diff --git a/src/tools/clangbackend/ipcsource/clangiasyncjob.h b/src/tools/clangbackend/ipcsource/clangiasyncjob.h
new file mode 100644
index 0000000000..44f503f3cb
--- /dev/null
+++ b/src/tools/clangbackend/ipcsource/clangiasyncjob.h
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 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 "clangjobcontext.h"
+
+#include <QFuture>
+#include <QLoggingCategory>
+
+#include <functional>
+
+Q_DECLARE_LOGGING_CATEGORY(jobsLog);
+
+namespace ClangBackEnd {
+
+class IAsyncJob
+{
+public:
+ static IAsyncJob *create(JobRequest::Type type);
+
+public:
+ IAsyncJob();
+ virtual ~IAsyncJob();
+
+ JobContext context() const;
+ void setContext(const JobContext &context);
+
+ using FinishedHandler = std::function<void(IAsyncJob *job)>;
+ FinishedHandler finishedHandler() const;
+ void setFinishedHandler(const FinishedHandler &finishedHandler);
+
+ virtual bool prepareAsyncRun() = 0;
+ virtual QFuture<void> runAsync() = 0;
+ virtual void finalizeAsyncRun() = 0;
+
+public: // for tests
+ bool isFinished() const;
+ void setIsFinished(bool isFinished);
+
+private:
+ bool m_isFinished = false;
+ FinishedHandler m_finishedHandler;
+ JobContext m_context;
+};
+
+} // namespace ClangBackEnd
diff --git a/src/tools/clangbackend/ipcsource/clangjobcontext.cpp b/src/tools/clangbackend/ipcsource/clangjobcontext.cpp
new file mode 100644
index 0000000000..9c9c520fce
--- /dev/null
+++ b/src/tools/clangbackend/ipcsource/clangjobcontext.cpp
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 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 "clangiasyncjob.h"
+
+#include "translationunits.h"
+
+namespace ClangBackEnd {
+
+JobContext::JobContext(const JobRequest &jobRequest,
+ TranslationUnits *translationUnits,
+ UnsavedFiles *unsavedFiles,
+ ClangCodeModelClientInterface *clientInterface)
+ : jobRequest(jobRequest)
+ , translationUnits(translationUnits)
+ , unsavedFiles(unsavedFiles)
+ , client(clientInterface)
+{
+}
+
+TranslationUnit JobContext::translationUnitForJobRequest() const
+{
+ return translationUnits->translationUnit(jobRequest.filePath, jobRequest.projectPartId);
+}
+
+bool JobContext::isOutdated() const
+{
+ return !isDocumentOpen() || documentRevisionChanged();
+}
+
+bool JobContext::isDocumentOpen() const
+{
+ const bool hasTranslationUnit
+ = translationUnits->hasTranslationUnit(jobRequest.filePath, jobRequest.projectPartId);
+
+ if (!hasTranslationUnit)
+ qCDebug(jobsLog) << "Document already closed for results of" << jobRequest;
+
+ return hasTranslationUnit;
+}
+
+bool JobContext::documentRevisionChanged() const
+{
+ const TranslationUnit &translationUnit
+ = translationUnits->translationUnit(jobRequest.filePath, jobRequest.projectPartId);
+ const bool revisionChanged = translationUnit.documentRevision() != jobRequest.documentRevision;
+
+ if (revisionChanged)
+ qCDebug(jobsLog) << "Document revision changed for results of" << jobRequest;
+
+ return revisionChanged;
+}
+
+} // ClangBackEnd
diff --git a/src/tools/clangbackend/ipcsource/clangjobcontext.h b/src/tools/clangbackend/ipcsource/clangjobcontext.h
new file mode 100644
index 0000000000..6e124c609e
--- /dev/null
+++ b/src/tools/clangbackend/ipcsource/clangjobcontext.h
@@ -0,0 +1,59 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 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 "clangjobrequest.h"
+
+namespace ClangBackEnd {
+
+class ClangCodeModelClientInterface;
+class TranslationUnit;
+class TranslationUnits;
+class UnsavedFiles;
+
+class JobContext
+{
+public:
+ JobContext() = default;
+ JobContext(const JobRequest &jobRequest,
+ TranslationUnits *translationUnits,
+ UnsavedFiles *unsavedFiles,
+ ClangCodeModelClientInterface *client);
+
+ TranslationUnit translationUnitForJobRequest() const;
+
+ bool isOutdated() const;
+ bool isDocumentOpen() const;
+ bool documentRevisionChanged() const;
+
+public:
+ JobRequest jobRequest;
+ TranslationUnits *translationUnits = nullptr;
+ UnsavedFiles *unsavedFiles = nullptr;
+ ClangCodeModelClientInterface *client = nullptr;
+};
+
+} // namespace ClangBackEnd
diff --git a/src/tools/clangbackend/ipcsource/clangjobqueue.cpp b/src/tools/clangbackend/ipcsource/clangjobqueue.cpp
new file mode 100644
index 0000000000..59d5e5ba9e
--- /dev/null
+++ b/src/tools/clangbackend/ipcsource/clangjobqueue.cpp
@@ -0,0 +1,223 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 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 "clangiasyncjob.h"
+#include "clangjobqueue.h"
+#include "clangtranslationunit.h"
+#include "translationunits.h"
+#include "projects.h"
+#include "unsavedfiles.h"
+
+#include <utils/algorithm.h>
+
+namespace ClangBackEnd {
+
+JobQueue::JobQueue(TranslationUnits &translationUnits,
+ UnsavedFiles &unsavedFiles,
+ ProjectParts &projectParts,
+ ClangCodeModelClientInterface &client)
+ : m_translationUnits(translationUnits)
+ , m_unsavedFiles(unsavedFiles)
+ , m_projectParts(projectParts)
+ , m_client(client)
+{
+}
+
+void JobQueue::add(const JobRequest &job)
+{
+ qCDebug(jobsLog) << "Adding" << job;
+
+ m_queue.append(job);
+}
+
+int JobQueue::size() const
+{
+ return m_queue.size();
+}
+
+JobRequests JobQueue::processQueue()
+{
+ removeOutDatedRequests();
+ prioritizeRequests();
+ const JobRequests jobsToRun = takeJobRequestsToRunNow();
+
+ return jobsToRun;
+}
+
+void JobQueue::removeOutDatedRequests()
+{
+ JobRequests cleanedRequests;
+
+ foreach (const JobRequest &jobRequest, m_queue) {
+ try {
+ if (!isJobRequestOutDated(jobRequest))
+ cleanedRequests.append(jobRequest);
+ } catch (const std::exception &exception) {
+ qWarning() << "Error in Jobs::removeOutDatedRequests for"
+ << jobRequest << ":" << exception.what();
+ }
+ }
+
+ m_queue = cleanedRequests;
+}
+
+bool JobQueue::isJobRequestOutDated(const JobRequest &jobRequest) const
+{
+ const JobRequest::Requirements requirements = jobRequest.requirements;
+ const UnsavedFiles unsavedFiles = m_translationUnits.unsavedFiles();
+
+ if (requirements.testFlag(JobRequest::CurrentUnsavedFiles)) {
+ if (jobRequest.unsavedFilesChangeTimePoint != unsavedFiles.lastChangeTimePoint()) {
+ qCDebug(jobsLog) << "Removing due to outdated unsaved files:" << jobRequest;
+ return true;
+ }
+ }
+
+ bool projectCheckedAndItExists = false;
+
+ if (requirements.testFlag(JobRequest::DocumentValid)) {
+ if (!m_translationUnits.hasTranslationUnit(jobRequest.filePath, jobRequest.projectPartId)) {
+ qCDebug(jobsLog) << "Removing due to already closed document:" << jobRequest;
+ return true;
+ }
+
+ if (!m_projectParts.hasProjectPart(jobRequest.projectPartId)) {
+ qCDebug(jobsLog) << "Removing due to already closed project:" << jobRequest;
+ return true;
+ }
+ projectCheckedAndItExists = true;
+
+ const TranslationUnit translationUnit
+ = m_translationUnits.translationUnit(jobRequest.filePath, jobRequest.projectPartId);
+ if (!translationUnit.isIntact()) {
+ qCDebug(jobsLog) << "Removing due to not intact translation unit:" << jobRequest;
+ return true;
+ }
+
+ if (requirements.testFlag(JobRequest::CurrentDocumentRevision)) {
+ if (translationUnit.documentRevision() != jobRequest.documentRevision) {
+ qCDebug(jobsLog) << "Removing due to changed document revision:" << jobRequest;
+ return true;
+ }
+ }
+ }
+
+ if (requirements.testFlag(JobRequest::CurrentProject)) {
+ if (!projectCheckedAndItExists && !m_projectParts.hasProjectPart(jobRequest.projectPartId)) {
+ qCDebug(jobsLog) << "Removing due to already closed project:" << jobRequest;
+ return true;
+ }
+
+ const ProjectPart &project = m_projectParts.project(jobRequest.projectPartId);
+ if (project.lastChangeTimePoint() != jobRequest.projectChangeTimePoint) {
+ qCDebug(jobsLog) << "Removing due to outdated project:" << jobRequest;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static int priority(const TranslationUnit &translationUnit)
+{
+ int thePriority = 0;
+
+ if (translationUnit.isUsedByCurrentEditor())
+ thePriority += 1000;
+
+ if (translationUnit.isVisibleInEditor())
+ thePriority += 100;
+
+ return thePriority;
+}
+
+void JobQueue::prioritizeRequests()
+{
+ const auto lessThan = [this] (const JobRequest &r1, const JobRequest &r2) {
+ // TODO: Getting the TU is O(n) currently, so this might become expensive for large n.
+ const TranslationUnit &t1 = m_translationUnits.translationUnit(r1.filePath, r1.projectPartId);
+ const TranslationUnit &t2 = m_translationUnits.translationUnit(r2.filePath, r2.projectPartId);
+
+ return priority(t1) > priority(t2);
+ };
+
+ std::stable_sort(m_queue.begin(), m_queue.end(), lessThan);
+}
+
+JobRequests JobQueue::takeJobRequestsToRunNow()
+{
+ JobRequests jobsToRun;
+ QSet<DocumentId> documentsScheduledForThisRun;
+
+ QMutableVectorIterator<JobRequest> i(m_queue);
+ while (i.hasNext()) {
+ const JobRequest &jobRequest = i.next();
+
+ try {
+ const TranslationUnit &translationUnit
+ = m_translationUnits.translationUnit(jobRequest.filePath,
+ jobRequest.projectPartId);
+ const DocumentId documentId = DocumentId(jobRequest.filePath, jobRequest.projectPartId);
+
+ if (!translationUnit.isUsedByCurrentEditor() && !translationUnit.isVisibleInEditor())
+ continue;
+
+ if (documentsScheduledForThisRun.contains(documentId))
+ continue;
+
+ if (isJobRunningForDocument(documentId))
+ continue;
+
+ documentsScheduledForThisRun.insert(documentId);
+ jobsToRun += jobRequest;
+ i.remove();
+ } catch (const std::exception &exception) {
+ qWarning() << "Error in Jobs::takeJobRequestsToRunNow for"
+ << jobRequest << ":" << exception.what();
+ }
+ }
+
+ return jobsToRun;
+}
+
+bool JobQueue::isJobRunningForDocument(const JobQueue::DocumentId &documentId)
+{
+ if (m_isJobRunningHandler)
+ return m_isJobRunningHandler(documentId.first, documentId.second);
+
+ return false;
+}
+
+void JobQueue::setIsJobRunningHandler(const IsJobRunningHandler &isJobRunningHandler)
+{
+ m_isJobRunningHandler = isJobRunningHandler;
+}
+
+JobRequests JobQueue::queue() const
+{
+ return m_queue;
+}
+
+} // namespace ClangBackEnd
diff --git a/src/tools/clangbackend/ipcsource/clangjobqueue.h b/src/tools/clangbackend/ipcsource/clangjobqueue.h
new file mode 100644
index 0000000000..f29be968d5
--- /dev/null
+++ b/src/tools/clangbackend/ipcsource/clangjobqueue.h
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 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 "clangjobrequest.h"
+
+#include <functional>
+
+namespace ClangBackEnd {
+
+class ClangCodeModelClientInterface;
+class ProjectParts;
+class TranslationUnits;
+class UnsavedFiles;
+
+class JobQueue
+{
+public:
+ JobQueue(TranslationUnits &translationUnits,
+ UnsavedFiles &unsavedFiles,
+ ProjectParts &projects,
+ ClangCodeModelClientInterface &client);
+
+ void add(const JobRequest &job);
+
+ JobRequests processQueue();
+
+ using IsJobRunningHandler = std::function<bool(const Utf8String &, const Utf8String &)>;
+ void setIsJobRunningHandler(const IsJobRunningHandler &isJobRunningHandler);
+
+public: // for tests
+ JobRequests queue() const;
+ int size() const;
+ void prioritizeRequests();
+
+private:
+ using DocumentId = QPair<Utf8String, Utf8String>;
+ bool isJobRunningForDocument(const DocumentId &documentId);
+ JobRequests takeJobRequestsToRunNow();
+ void removeOutDatedRequests();
+ bool isJobRequestOutDated(const JobRequest &jobRequest) const;
+
+private:
+ TranslationUnits &m_translationUnits;
+ UnsavedFiles &m_unsavedFiles;
+ ProjectParts &m_projectParts;
+ ClangCodeModelClientInterface &m_client;
+
+ IsJobRunningHandler m_isJobRunningHandler;
+
+ JobRequests m_queue;
+};
+
+} // namespace ClangBackEnd
diff --git a/src/tools/clangbackend/ipcsource/clangjobrequest.cpp b/src/tools/clangbackend/ipcsource/clangjobrequest.cpp
new file mode 100644
index 0000000000..4c3d692d08
--- /dev/null
+++ b/src/tools/clangbackend/ipcsource/clangjobrequest.cpp
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 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 "clangjobrequest.h"
+
+namespace ClangBackEnd {
+
+#define RETURN_TEXT_FOR_CASE(enumValue) case JobRequest::Type::enumValue: return #enumValue
+static const char *JobRequestTypeToText(JobRequest::Type type)
+{
+ switch (type) {
+ RETURN_TEXT_FOR_CASE(UpdateDocumentAnnotations);
+ RETURN_TEXT_FOR_CASE(CreateInitialDocumentPreamble);
+ RETURN_TEXT_FOR_CASE(CompleteCode);
+ RETURN_TEXT_FOR_CASE(RequestDocumentAnnotations);
+ }
+
+ return "UnhandledJobRequestType";
+}
+#undef RETURN_TEXT_FOR_CASE
+
+QDebug operator<<(QDebug debug, JobRequest::Type type)
+{
+ debug << JobRequestTypeToText(type);
+
+ return debug;
+}
+
+QDebug operator<<(QDebug debug, const JobRequest &jobRequest)
+{
+ debug.nospace() << "Job<"
+ << jobRequest.id
+ << ","
+ << JobRequestTypeToText(jobRequest.type)
+ << ","
+ << jobRequest.filePath
+ << ">";
+
+ return debug;
+}
+
+JobRequest::JobRequest()
+{
+ static quint64 idCounter = 0;
+ id = ++idCounter;
+}
+
+JobRequest::Requirements JobRequest::requirementsForType(Type type)
+{
+ switch (type) {
+ case JobRequest::Type::UpdateDocumentAnnotations:
+ return JobRequest::Requirements(JobRequest::All);
+ case JobRequest::Type::RequestDocumentAnnotations:
+ return JobRequest::Requirements(JobRequest::DocumentValid
+ |JobRequest::CurrentDocumentRevision);
+ case JobRequest::Type::CompleteCode:
+ case JobRequest::Type::CreateInitialDocumentPreamble:
+ return JobRequest::Requirements(JobRequest::DocumentValid);
+ }
+
+ return JobRequest::Requirements(JobRequest::DocumentValid);
+}
+
+} // namespace ClangBackEnd
diff --git a/src/tools/clangbackend/ipcsource/clangjobrequest.h b/src/tools/clangbackend/ipcsource/clangjobrequest.h
new file mode 100644
index 0000000000..ca75e4ec67
--- /dev/null
+++ b/src/tools/clangbackend/ipcsource/clangjobrequest.h
@@ -0,0 +1,89 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 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 <utf8string.h>
+
+#include <QFlags>
+#include <QDebug>
+#include <QVector>
+
+#include <chrono>
+
+namespace ClangBackEnd {
+
+using time_point = std::chrono::steady_clock::time_point;
+
+class JobRequest
+{
+public:
+ enum class Type {
+ UpdateDocumentAnnotations,
+ CreateInitialDocumentPreamble,
+ CompleteCode,
+ RequestDocumentAnnotations,
+ };
+
+ enum Requirement {
+ None = 1 << 0,
+
+ DocumentValid = 1 << 1,
+ CurrentDocumentRevision = 1 << 3, // Only effective if DocumentValid is also set
+ CurrentUnsavedFiles = 1 << 2,
+ CurrentProject = 1 << 4,
+
+ All = DocumentValid | CurrentUnsavedFiles | CurrentDocumentRevision | CurrentProject
+ };
+ Q_DECLARE_FLAGS(Requirements, Requirement)
+
+public:
+ static Requirements requirementsForType(Type type);
+
+ JobRequest();
+
+public:
+ quint64 id = 0;
+ Type type;
+ Requirements requirements;
+
+ // General
+ Utf8String filePath;
+ Utf8String projectPartId;
+ time_point unsavedFilesChangeTimePoint;
+ time_point projectChangeTimePoint;
+ uint documentRevision = 0;
+
+ // For code completion
+ quint32 line = 0;
+ quint32 column = 0;
+ quint64 ticketNumber = 0;
+};
+
+using JobRequests = QVector<JobRequest>;
+
+QDebug operator<<(QDebug debug, const JobRequest &jobRequest);
+
+} // namespace ClangBackEnd
diff --git a/src/tools/clangbackend/ipcsource/clangjobs.cpp b/src/tools/clangbackend/ipcsource/clangjobs.cpp
new file mode 100644
index 0000000000..6871b03a40
--- /dev/null
+++ b/src/tools/clangbackend/ipcsource/clangjobs.cpp
@@ -0,0 +1,143 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 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 "clangjobs.h"
+
+#include "clangiasyncjob.h"
+
+#include <QDebug>
+#include <QFutureSynchronizer>
+#include <QLoggingCategory>
+
+#include <utils/algorithm.h>
+#include <utils/qtcassert.h>
+
+namespace ClangBackEnd {
+
+Jobs::Jobs(TranslationUnits &translationUnits,
+ UnsavedFiles &unsavedFiles,
+ ProjectParts &projectParts,
+ ClangCodeModelClientInterface &client)
+ : m_translationUnits(translationUnits)
+ , m_unsavedFiles(unsavedFiles)
+ , m_projectParts(projectParts)
+ , m_client(client)
+ , m_queue(translationUnits, unsavedFiles, projectParts, client)
+{
+ m_queue.setIsJobRunningHandler([this](const Utf8String &filePath,
+ const Utf8String &projectPartId) {
+ return isJobRunning(filePath, projectPartId);
+ });
+}
+
+Jobs::~Jobs()
+{
+ QFutureSynchronizer<void> waitForFinishedJobs;
+ foreach (const RunningJob &runningJob, m_running.values())
+ waitForFinishedJobs.addFuture(runningJob.future);
+}
+
+void Jobs::add(const JobRequest &job)
+{
+ m_queue.add(job);
+}
+
+JobRequests Jobs::process()
+{
+ const JobRequests jobsToRun = m_queue.processQueue();
+ const JobRequests jobsStarted = runJobs(jobsToRun);
+
+ QTC_CHECK(jobsToRun.size() == jobsStarted.size());
+
+ return jobsStarted;
+}
+
+JobRequests Jobs::runJobs(const JobRequests &jobsRequests)
+{
+ JobRequests jobsStarted;
+
+ foreach (const JobRequest &jobRequest, jobsRequests) {
+ if (runJob(jobRequest))
+ jobsStarted += jobRequest;
+ }
+
+ return jobsStarted;
+}
+
+bool Jobs::runJob(const JobRequest &jobRequest)
+{
+ if (IAsyncJob *asyncJob = IAsyncJob::create(jobRequest.type)) {
+ JobContext context(jobRequest, &m_translationUnits, &m_unsavedFiles, &m_client);
+ asyncJob->setContext(context);
+
+ if (asyncJob->prepareAsyncRun()) {
+ qCDebug(jobsLog) << "Running" << jobRequest;
+
+ asyncJob->setFinishedHandler([this](IAsyncJob *asyncJob){ onJobFinished(asyncJob); });
+ const QFuture<void> future = asyncJob->runAsync();
+
+ m_running.insert(asyncJob, RunningJob{jobRequest, future});
+ return true;
+ } else {
+ qCDebug(jobsLog) << "Preparation failed for " << jobRequest;
+ delete asyncJob;
+ }
+ }
+
+ return false;
+}
+
+void Jobs::onJobFinished(IAsyncJob *asyncJob)
+{
+ qCDebug(jobsLog) << "Finishing" << asyncJob->context().jobRequest;
+
+ m_running.remove(asyncJob);
+ delete asyncJob;
+
+ process();
+}
+
+int Jobs::runningJobs() const
+{
+ return m_running.size();
+}
+
+JobRequests Jobs::queue() const
+{
+ return m_queue.queue();
+}
+
+bool Jobs::isJobRunning(const Utf8String &filePath, const Utf8String &projectPartId) const
+{
+ const auto hasJobRequest = [filePath, projectPartId](const RunningJob &runningJob) {
+ const JobRequest &jobRequest = runningJob.jobRequest;
+ return filePath == jobRequest.filePath
+ && projectPartId == jobRequest.projectPartId;
+ };
+
+ return Utils::anyOf(m_running.values(), hasJobRequest);
+}
+
+} // namespace ClangBackEnd
diff --git a/src/tools/clangbackend/ipcsource/clangjobs.h b/src/tools/clangbackend/ipcsource/clangjobs.h
new file mode 100644
index 0000000000..30e2fef7d8
--- /dev/null
+++ b/src/tools/clangbackend/ipcsource/clangjobs.h
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 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 "clangjobqueue.h"
+
+#include <clangbackendipc/clangcodemodelclientinterface.h>
+
+#include <QFuture>
+
+namespace ClangBackEnd {
+
+class ClangCodeModelClientInterface;
+class IAsyncJob;
+class ProjectParts;
+class TranslationUnits;
+class UnsavedFiles;
+
+class Jobs
+{
+public:
+ struct RunningJob {
+ JobRequest jobRequest;
+ QFuture<void> future;
+ };
+ using RunningJobs = QHash<IAsyncJob *, RunningJob>;
+
+public:
+ Jobs(TranslationUnits &translationUnits,
+ UnsavedFiles &unsavedFiles,
+ ProjectParts &projects,
+ ClangCodeModelClientInterface &client);
+ ~Jobs();
+
+ void add(const JobRequest &job);
+
+ JobRequests process();
+
+public /*for tests*/:
+ int runningJobs() const;
+ JobRequests queue() const;
+ bool isJobRunning(const Utf8String &filePath, const Utf8String &projectPartId) const;
+
+private:
+ JobRequests runJobs(const JobRequests &jobRequest);
+ bool runJob(const JobRequest &jobRequest);
+ void onJobFinished(IAsyncJob *asyncJob);
+
+private:
+ TranslationUnits &m_translationUnits;
+ UnsavedFiles &m_unsavedFiles;
+ ProjectParts &m_projectParts;
+ ClangCodeModelClientInterface &m_client;
+
+ JobQueue m_queue;
+ RunningJobs m_running;
+};
+
+} // namespace ClangBackEnd
diff --git a/src/tools/clangbackend/ipcsource/clangrequestdocumentannotationsjob.cpp b/src/tools/clangbackend/ipcsource/clangrequestdocumentannotationsjob.cpp
new file mode 100644
index 0000000000..ce9106d5cb
--- /dev/null
+++ b/src/tools/clangbackend/ipcsource/clangrequestdocumentannotationsjob.cpp
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 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 "clangrequestdocumentannotationsjob.h"
+
+#include <clangbackendipc/clangbackendipcdebugutils.h>
+#include <clangbackendipc/documentannotationschangedmessage.h>
+#include <clangbackendipc/clangcodemodelclientinterface.h>
+
+#include <utils/qtcassert.h>
+
+namespace ClangBackEnd {
+
+static RequestDocumentAnnotationsJob::AsyncResult runAsyncHelper(
+ const TranslationUnitCore &translationUnitCore)
+{
+ TIME_SCOPE_DURATION("RequestDocumentAnnotationsJobRunner");
+
+ RequestDocumentAnnotationsJob::AsyncResult asyncResult;
+
+ try {
+ translationUnitCore.extractDocumentAnnotations(asyncResult.diagnostics,
+ asyncResult.highlightingMarks,
+ asyncResult.skippedSourceRanges);
+ } catch (const std::exception &exception) {
+ qWarning() << "Error in RequestDocumentAnnotationsJobRunner:" << exception.what();
+ }
+
+ return asyncResult;
+}
+
+bool RequestDocumentAnnotationsJob::prepareAsyncRun()
+{
+ const JobRequest jobRequest = context().jobRequest;
+ QTC_ASSERT(jobRequest.type == JobRequest::Type::RequestDocumentAnnotations, return false);
+
+ try {
+ m_pinnedTranslationUnit = context().translationUnitForJobRequest();
+ m_pinnedFileContainer = m_pinnedTranslationUnit.fileContainer();
+
+ const TranslationUnitCore translationUnitCore = m_pinnedTranslationUnit.translationUnitCore();
+ setRunner([translationUnitCore]() {
+ return runAsyncHelper(translationUnitCore);
+ });
+
+ } catch (const std::exception &exception) {
+ qWarning() << "Error in RequestDocumentAnnotationsJob::prepareAsyncRun:" << exception.what();
+ return false;
+ }
+
+ return true;
+}
+
+void RequestDocumentAnnotationsJob::finalizeAsyncRun()
+{
+ if (context().isDocumentOpen()) {
+ const AsyncResult result = asyncResult();
+ sendAnnotations(result);
+ }
+}
+
+void RequestDocumentAnnotationsJob::sendAnnotations(
+ const RequestDocumentAnnotationsJob::AsyncResult &result)
+{
+ const DocumentAnnotationsChangedMessage message(m_pinnedFileContainer,
+ result.diagnostics,
+ result.highlightingMarks,
+ result.skippedSourceRanges);
+
+ context().client->documentAnnotationsChanged(message);
+}
+
+} // namespace ClangBackEnd
diff --git a/src/tools/clangbackend/ipcsource/clangrequestdocumentannotationsjob.h b/src/tools/clangbackend/ipcsource/clangrequestdocumentannotationsjob.h
new file mode 100644
index 0000000000..f44c50b190
--- /dev/null
+++ b/src/tools/clangbackend/ipcsource/clangrequestdocumentannotationsjob.h
@@ -0,0 +1,60 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 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 "clangtranslationunit.h"
+
+#include <clangbackendipc/diagnosticcontainer.h>
+#include <clangbackendipc/highlightingmarkcontainer.h>
+#include <clangbackendipc/sourcerangecontainer.h>
+
+namespace ClangBackEnd {
+
+struct RequestDocumentAnnotationsJobResult
+{
+ QVector<ClangBackEnd::DiagnosticContainer> diagnostics;
+ QVector<HighlightingMarkContainer> highlightingMarks;
+ QVector<SourceRangeContainer> skippedSourceRanges;
+};
+
+class RequestDocumentAnnotationsJob : public AsyncJob<RequestDocumentAnnotationsJobResult>
+{
+public:
+ using AsyncResult = RequestDocumentAnnotationsJobResult;
+
+ bool prepareAsyncRun() override;
+ void finalizeAsyncRun() override;
+
+private:
+ void sendAnnotations(const AsyncResult &result);
+
+private:
+ TranslationUnit m_pinnedTranslationUnit;
+ FileContainer m_pinnedFileContainer;
+};
+
+} // namespace ClangBackEnd
diff --git a/src/tools/clangbackend/ipcsource/clangtranslationunit.cpp b/src/tools/clangbackend/ipcsource/clangtranslationunit.cpp
index f271401b36..8907a285bd 100644
--- a/src/tools/clangbackend/ipcsource/clangtranslationunit.cpp
+++ b/src/tools/clangbackend/ipcsource/clangtranslationunit.cpp
@@ -25,19 +25,10 @@
#include "clangtranslationunit.h"
-#include "cursor.h"
-#include "clangfilepath.h"
#include "clangstring.h"
#include "clangunsavedfilesshallowarguments.h"
#include "codecompleter.h"
-#include "commandlinearguments.h"
-#include "diagnosticcontainer.h"
-#include "diagnosticset.h"
#include "projectpart.h"
-#include "skippedsourceranges.h"
-#include "sourcelocation.h"
-#include "sourcerange.h"
-#include "highlightingmarks.h"
#include "translationunitfilenotexitexception.h"
#include "translationunitisnullexception.h"
#include "translationunitparseerrorexception.h"
@@ -69,19 +60,22 @@ public:
public:
TranslationUnits &translationUnits;
- time_point lastProjectPartChangeTimePoint;
- QSet<Utf8String> dependedFilePaths;
+
+ const Utf8String filePath;
+ const Utf8StringVector fileArguments;
+
ProjectPart projectPart;
- Utf8StringVector fileArguments;
- Utf8String filePath;
+ time_point lastProjectPartChangeTimePoint;
+
CXTranslationUnit translationUnit = nullptr;
- CXErrorCode parseErrorCode = CXError_Success;
- int reparseErrorCode = 0;
CXIndex index = nullptr;
+
+ QSet<Utf8String> dependedFilePaths;
+
uint documentRevision = 0;
+ time_point needsToBeReparsedChangeTimePoint;
+ bool hasParseOrReparseFailed = false;
bool needsToBeReparsed = false;
- bool hasNewDiagnostics = true;
- bool hasNewHighlightingMarks = true;
bool isUsedByCurrentEditor = false;
bool isVisibleInEditor = false;
};
@@ -91,10 +85,11 @@ TranslationUnitData::TranslationUnitData(const Utf8String &filePath,
const Utf8StringVector &fileArguments,
TranslationUnits &translationUnits)
: translationUnits(translationUnits),
- lastProjectPartChangeTimePoint(std::chrono::steady_clock::now()),
- projectPart(projectPart),
+ filePath(filePath),
fileArguments(fileArguments),
- filePath(filePath)
+ projectPart(projectPart),
+ lastProjectPartChangeTimePoint(std::chrono::steady_clock::now()),
+ needsToBeReparsedChangeTimePoint(lastProjectPartChangeTimePoint)
{
dependedFilePaths.insert(filePath);
}
@@ -119,29 +114,20 @@ TranslationUnit::TranslationUnit(const Utf8String &filePath,
checkIfFileExists();
}
-bool TranslationUnit::isNull() const
-{
- return !d;
-}
-
-void TranslationUnit::setIsUsedByCurrentEditor(bool isUsedByCurrentEditor)
-{
- d->isUsedByCurrentEditor = isUsedByCurrentEditor;
-}
+TranslationUnit::~TranslationUnit() = default;
+TranslationUnit::TranslationUnit(const TranslationUnit &) = default;
+TranslationUnit &TranslationUnit::operator=(const TranslationUnit &) = default;
-bool TranslationUnit::isUsedByCurrentEditor() const
+TranslationUnit::TranslationUnit(TranslationUnit &&other)
+ : d(std::move(other.d))
{
- return d->isUsedByCurrentEditor;
}
-void TranslationUnit::setIsVisibleInEditor(bool isVisibleInEditor)
+TranslationUnit &TranslationUnit::operator=(TranslationUnit &&other)
{
- d->isVisibleInEditor = isVisibleInEditor;
-}
+ d = std::move(other.d);
-bool TranslationUnit::isVisibleInEditor() const
-{
- return d->isVisibleInEditor;
+ return *this;
}
void TranslationUnit::reset()
@@ -149,54 +135,16 @@ void TranslationUnit::reset()
d.reset();
}
-void TranslationUnit::parse() const
-{
- checkIfNull();
-
- const TranslationUnitUpdateInput updateInput = createUpdateInput();
- TranslationUnitUpdateResult result = translationUnitCore().parse(updateInput);
-
- incorporateUpdaterResult(result);
-}
-
-void TranslationUnit::reparse() const
-{
- parse(); // TODO: Remove
-
- const TranslationUnitUpdateInput updateInput = createUpdateInput();
- TranslationUnitUpdateResult result = translationUnitCore().reparse(updateInput);
-
- incorporateUpdaterResult(result);
-}
-
-bool TranslationUnit::parseWasSuccessful() const
-{
- return d->parseErrorCode == CXError_Success;
-}
-
-bool TranslationUnit::reparseWasSuccessful() const
-{
- return d->reparseErrorCode == 0;
-}
-
-CXIndex &TranslationUnit::index() const
-{
- checkIfNull();
-
- return d->index;
-}
-
-CXTranslationUnit &TranslationUnit::cxTranslationUnit() const
+bool TranslationUnit::isNull() const
{
- checkIfNull();
- checkIfFileExists();
-
- return d->translationUnit;
+ return !d;
}
-UnsavedFile TranslationUnit::unsavedFile() const
+bool TranslationUnit::isIntact() const
{
- return unsavedFiles().unsavedFile(filePath());
+ return !isNull()
+ && fileExists()
+ && !d->hasParseOrReparseFailed;
}
Utf8String TranslationUnit::filePath() const
@@ -213,13 +161,6 @@ Utf8StringVector TranslationUnit::fileArguments() const
return d->fileArguments;
}
-Utf8String TranslationUnit::projectPartId() const
-{
- checkIfNull();
-
- return d->projectPart.projectPartId();
-}
-
FileContainer TranslationUnit::fileContainer() const
{
checkIfNull();
@@ -231,137 +172,111 @@ FileContainer TranslationUnit::fileContainer() const
d->documentRevision);
}
-const ProjectPart &TranslationUnit::projectPart() const
+Utf8String TranslationUnit::projectPartId() const
{
checkIfNull();
- return d->projectPart;
+ return d->projectPart.projectPartId();
}
-void TranslationUnit::setDocumentRevision(uint revision)
+const ProjectPart &TranslationUnit::projectPart() const
{
- d->documentRevision = revision;
-}
+ checkIfNull();
-uint TranslationUnit::documentRevision() const
-{
- return d->documentRevision;
+ return d->projectPart;
}
-const time_point &TranslationUnit::lastProjectPartChangeTimePoint() const
+const time_point TranslationUnit::lastProjectPartChangeTimePoint() const
{
- return d->lastProjectPartChangeTimePoint;
-}
+ checkIfNull();
-bool TranslationUnit::isNeedingReparse() const
-{
- return d->needsToBeReparsed;
+ return d->lastProjectPartChangeTimePoint;
}
-bool TranslationUnit::hasNewDiagnostics() const
+bool TranslationUnit::isProjectPartOutdated() const
{
- return d->hasNewDiagnostics;
-}
+ checkIfNull();
-bool TranslationUnit::hasNewHighlightingMarks() const
-{
- return d->hasNewHighlightingMarks;
+ return d->projectPart.lastChangeTimePoint() >= d->lastProjectPartChangeTimePoint;
}
-DiagnosticSet TranslationUnit::diagnostics() const
+uint TranslationUnit::documentRevision() const
{
- d->hasNewDiagnostics = false;
+ checkIfNull();
- return translationUnitCore().diagnostics();
+ return d->documentRevision;
}
-QVector<ClangBackEnd::DiagnosticContainer> TranslationUnit::mainFileDiagnostics() const
+void TranslationUnit::setDocumentRevision(uint revision)
{
- d->hasNewDiagnostics = false;
+ checkIfNull();
- return translationUnitCore().mainFileDiagnostics();
+ d->documentRevision = revision;
}
-const QSet<Utf8String> &TranslationUnit::dependedFilePaths() const
+bool TranslationUnit::isUsedByCurrentEditor() const
{
- cxTranslationUnit();
+ checkIfNull();
- return d->dependedFilePaths;
+ return d->isUsedByCurrentEditor;
}
-void TranslationUnit::setDirtyIfProjectPartIsOutdated()
+void TranslationUnit::setIsUsedByCurrentEditor(bool isUsedByCurrentEditor)
{
- if (projectPartIsOutdated())
- setDirty();
-}
+ checkIfNull();
-void TranslationUnit::setDirtyIfDependencyIsMet(const Utf8String &filePath)
-{
- if (d->dependedFilePaths.contains(filePath) && isMainFileAndExistsOrIsOtherFile(filePath))
- setDirty();
+ d->isUsedByCurrentEditor = isUsedByCurrentEditor;
}
-HighlightingMarks TranslationUnit::highlightingMarks() const
+bool TranslationUnit::isVisibleInEditor() const
{
- d->hasNewHighlightingMarks = false;
+ checkIfNull();
- return translationUnitCore().highlightingMarks();
+ return d->isVisibleInEditor;
}
-void TranslationUnit::checkIfNull() const
+void TranslationUnit::setIsVisibleInEditor(bool isVisibleInEditor)
{
- if (isNull())
- throw TranslationUnitIsNullException();
-}
+ checkIfNull();
-void TranslationUnit::checkIfFileExists() const
-{
- if (!fileExists())
- throw TranslationUnitFileNotExitsException(d->filePath);
+ d->isVisibleInEditor = isVisibleInEditor;
}
-bool TranslationUnit::projectPartIsOutdated() const
+time_point TranslationUnit::isNeededReparseChangeTimePoint() const
{
- return d->projectPart.lastChangeTimePoint() >= d->lastProjectPartChangeTimePoint;
-}
+ checkIfNull();
-void TranslationUnit::setDirty()
-{
- d->needsToBeReparsed = true;
- d->hasNewDiagnostics = true;
- d->hasNewHighlightingMarks = true;
+ return d->needsToBeReparsedChangeTimePoint;
}
-bool TranslationUnit::isMainFileAndExistsOrIsOtherFile(const Utf8String &filePath) const
+bool TranslationUnit::isNeedingReparse() const
{
- if (filePath == d->filePath)
- return QFileInfo::exists(d->filePath);
+ checkIfNull();
- return true;
+ return d->needsToBeReparsed;
}
-void TranslationUnit::checkParseErrorCode() const
+void TranslationUnit::setDirtyIfProjectPartIsOutdated()
{
- if (!parseWasSuccessful()) {
- throw TranslationUnitParseErrorException(d->filePath,
- d->projectPart.projectPartId(),
- d->parseErrorCode);
- }
+ if (isProjectPartOutdated())
+ setDirty();
}
-bool TranslationUnit::fileExists() const
+void TranslationUnit::setDirtyIfDependencyIsMet(const Utf8String &filePath)
{
- return QFileInfo::exists(d->filePath.toString());
+ if (d->dependedFilePaths.contains(filePath) && isMainFileAndExistsOrIsOtherFile(filePath))
+ setDirty();
}
TranslationUnitUpdateInput TranslationUnit::createUpdateInput() const
{
TranslationUnitUpdateInput updateInput;
+ updateInput.parseNeeded = isProjectPartOutdated();
updateInput.reparseNeeded = isNeedingReparse();
- updateInput.parseNeeded = projectPartIsOutdated();
+ updateInput.needsToBeReparsedChangeTimePoint = d->needsToBeReparsedChangeTimePoint;
updateInput.filePath = filePath();
updateInput.fileArguments = fileArguments();
- updateInput.unsavedFiles = unsavedFiles();
+ updateInput.unsavedFiles = d->translationUnits.unsavedFiles();
updateInput.projectId = projectPart().projectPartId();
updateInput.projectArguments = projectPart().arguments();
@@ -371,66 +286,102 @@ TranslationUnitUpdateInput TranslationUnit::createUpdateInput() const
TranslationUnitUpdater TranslationUnit::createUpdater() const
{
const TranslationUnitUpdateInput updateInput = createUpdateInput();
- TranslationUnitUpdater updater(index(), d->translationUnit, updateInput);
+ TranslationUnitUpdater updater(d->index, d->translationUnit, updateInput);
return updater;
}
+void TranslationUnit::setHasParseOrReparseFailed(bool hasFailed)
+{
+ d->hasParseOrReparseFailed = hasFailed;
+}
+
void TranslationUnit::incorporateUpdaterResult(const TranslationUnitUpdateResult &result) const
{
+ d->hasParseOrReparseFailed = result.hasParseOrReparseFailed;
+ if (d->hasParseOrReparseFailed) {
+ d->needsToBeReparsed = false;
+ return;
+ }
+
if (result.parseTimePointIsSet)
d->lastProjectPartChangeTimePoint = result.parseTimePoint;
- d->dependedFilePaths = result.dependedOnFilePaths;
+ if (result.parseTimePointIsSet || result.reparsed)
+ d->dependedFilePaths = result.dependedOnFilePaths;
+
d->translationUnits.addWatchedFiles(d->dependedFilePaths);
- if (result.reparsed)
+ if (result.reparsed
+ && result.needsToBeReparsedChangeTimePoint == d->needsToBeReparsedChangeTimePoint) {
d->needsToBeReparsed = false;
+ }
}
-bool TranslationUnit::isIntact() const
+TranslationUnitCore TranslationUnit::translationUnitCore() const
{
- return !isNull()
- && fileExists()
- && parseWasSuccessful()
- && reparseWasSuccessful();
+ checkIfNull();
+
+ return TranslationUnitCore(d->filePath, d->index, d->translationUnit);
}
-CommandLineArguments TranslationUnit::commandLineArguments() const
+void TranslationUnit::parse() const
{
- return createUpdater().commandLineArguments();
+ checkIfNull();
+
+ const TranslationUnitUpdateInput updateInput = createUpdateInput();
+ TranslationUnitUpdateResult result = translationUnitCore().parse(updateInput);
+
+ incorporateUpdaterResult(result);
}
-TranslationUnitCore TranslationUnit::translationUnitCore() const
+void TranslationUnit::reparse() const
{
- return TranslationUnitCore(d->filePath, d->index, d->translationUnit);
+ checkIfNull();
+
+ const TranslationUnitUpdateInput updateInput = createUpdateInput();
+ TranslationUnitUpdateResult result = translationUnitCore().reparse(updateInput);
+
+ incorporateUpdaterResult(result);
}
-uint TranslationUnit::unsavedFilesCount() const
+const QSet<Utf8String> TranslationUnit::dependedFilePaths() const
{
- return unsavedFiles().count();
+ checkIfNull();
+ checkIfFileExists();
+
+ return d->dependedFilePaths;
}
-UnsavedFiles TranslationUnit::unsavedFiles() const
+void TranslationUnit::setDirty()
{
- return d->translationUnits.unsavedFiles();
+ d->needsToBeReparsedChangeTimePoint = std::chrono::steady_clock::now();
+ d->needsToBeReparsed = true;
}
-TranslationUnit::~TranslationUnit() = default;
+void TranslationUnit::checkIfNull() const
+{
+ if (isNull())
+ throw TranslationUnitIsNullException();
+}
-TranslationUnit::TranslationUnit(const TranslationUnit &) = default;
-TranslationUnit &TranslationUnit::operator=(const TranslationUnit &) = default;
+void TranslationUnit::checkIfFileExists() const
+{
+ if (!fileExists())
+ throw TranslationUnitFileNotExitsException(d->filePath);
+}
-TranslationUnit::TranslationUnit(TranslationUnit &&other)
- : d(std::move(other.d))
+bool TranslationUnit::fileExists() const
{
+ return QFileInfo::exists(d->filePath.toString());
}
-TranslationUnit &TranslationUnit::operator=(TranslationUnit &&other)
+bool TranslationUnit::isMainFileAndExistsOrIsOtherFile(const Utf8String &filePath) const
{
- d = std::move(other.d);
+ if (filePath == d->filePath)
+ return QFileInfo::exists(d->filePath);
- return *this;
+ return true;
}
bool operator==(const TranslationUnit &first, const TranslationUnit &second)
diff --git a/src/tools/clangbackend/ipcsource/clangtranslationunit.h b/src/tools/clangbackend/ipcsource/clangtranslationunit.h
index 36e03fd4dd..e3ec05fa87 100644
--- a/src/tools/clangbackend/ipcsource/clangtranslationunit.h
+++ b/src/tools/clangbackend/ipcsource/clangtranslationunit.h
@@ -33,11 +33,11 @@
#include <clang-c/Index.h>
+#include <QSet>
#include <QtGlobal>
#include <chrono>
#include <memory>
-#include <QSet>
class Utf8String;
@@ -46,20 +46,9 @@ namespace ClangBackEnd {
class TranslationUnitCore;
class TranslationUnitData;
class TranslationUnitUpdateResult;
-class CodeCompleter;
-class UnsavedFile;
-class UnsavedFiles;
class ProjectPart;
-class DiagnosticContainer;
-class DiagnosticSet;
class FileContainer;
-class HighlightingMarks;
class TranslationUnits;
-class CommandLineArguments;
-class Cursor;
-class SourceLocation;
-class SourceRange;
-class SkippedSourceRanges;
using time_point = std::chrono::steady_clock::time_point;
@@ -85,76 +74,54 @@ public:
TranslationUnit(TranslationUnit &&cxTranslationUnit);
TranslationUnit &operator=(TranslationUnit &&cxTranslationUnit);
- bool isNull() const;
-
- void setIsUsedByCurrentEditor(bool isUsedByCurrentEditor);
- bool isUsedByCurrentEditor() const;
-
- void setIsVisibleInEditor(bool isVisibleInEditor);
- bool isVisibleInEditor() const;
-
void reset();
- void parse() const;
- void reparse() const;
+ bool isNull() const;
bool isIntact() const;
- CXIndex &index() const;
-
- CXTranslationUnit &cxTranslationUnit() const;
-
- UnsavedFile unsavedFile() const;
- UnsavedFiles unsavedFiles() const;
- uint unsavedFilesCount() const;
-
Utf8String filePath() const;
Utf8StringVector fileArguments() const;
- Utf8String projectPartId() const;
FileContainer fileContainer() const;
+
+ Utf8String projectPartId() const;
const ProjectPart &projectPart() const;
+ const time_point lastProjectPartChangeTimePoint() const;
+ bool isProjectPartOutdated() const;
- void setDocumentRevision(uint revision);
uint documentRevision() const;
+ void setDocumentRevision(uint revision);
- const time_point &lastProjectPartChangeTimePoint() const;
-
- bool isNeedingReparse() const;
-
- // TODO: Remove the following two
- bool hasNewDiagnostics() const;
- bool hasNewHighlightingMarks() const;
-
- // TODO: Remove the following two
- DiagnosticSet diagnostics() const;
- QVector<DiagnosticContainer> mainFileDiagnostics() const;
+ bool isUsedByCurrentEditor() const;
+ void setIsUsedByCurrentEditor(bool isUsedByCurrentEditor);
- const QSet<Utf8String> &dependedFilePaths() const;
+ bool isVisibleInEditor() const;
+ void setIsVisibleInEditor(bool isVisibleInEditor);
+ bool isNeedingReparse() const;
void setDirtyIfProjectPartIsOutdated();
void setDirtyIfDependencyIsMet(const Utf8String &filePath);
- CommandLineArguments commandLineArguments() const;
-
- // TODO: Remove
- HighlightingMarks highlightingMarks() const;
+ TranslationUnitUpdateInput createUpdateInput() const;
+ void incorporateUpdaterResult(const TranslationUnitUpdateResult &result) const;
TranslationUnitCore translationUnitCore() const;
- bool projectPartIsOutdated() const;
+public: // for tests
+ void parse() const;
+ void reparse() const;
+ const QSet<Utf8String> dependedFilePaths() const;
+ TranslationUnitUpdater createUpdater() const;
+ void setHasParseOrReparseFailed(bool hasFailed);
+ time_point isNeededReparseChangeTimePoint() const;
private:
void setDirty();
+
void checkIfNull() const;
void checkIfFileExists() const;
- bool isMainFileAndExistsOrIsOtherFile(const Utf8String &filePath) const;
- void checkParseErrorCode() const;
- bool parseWasSuccessful() const;
- bool reparseWasSuccessful() const;
- bool fileExists() const;
- TranslationUnitUpdateInput createUpdateInput() const;
- TranslationUnitUpdater createUpdater() const;
- void incorporateUpdaterResult(const TranslationUnitUpdateResult &result) const;
+ bool fileExists() const;
+ bool isMainFileAndExistsOrIsOtherFile(const Utf8String &filePath) const;
private:
mutable std::shared_ptr<TranslationUnitData> d;
diff --git a/src/tools/clangbackend/ipcsource/clangtranslationunitupdater.cpp b/src/tools/clangbackend/ipcsource/clangtranslationunitupdater.cpp
index 9a09170c43..c907b6705d 100644
--- a/src/tools/clangbackend/ipcsource/clangtranslationunitupdater.cpp
+++ b/src/tools/clangbackend/ipcsource/clangtranslationunitupdater.cpp
@@ -28,8 +28,6 @@
#include "clangfilepath.h"
#include "clangstring.h"
#include "clangunsavedfilesshallowarguments.h"
-#include "translationunitparseerrorexception.h"
-#include "translationunitreparseerrorexception.h"
#include <QLoggingCategory>
@@ -105,11 +103,15 @@ void TranslationUnitUpdater::createTranslationUnitIfNeeded()
defaultParseOptions(),
&m_cxTranslationUnit);
- checkParseErrorCode();
- updateIncludeFilePaths();
- updateLastProjectPartChangeTimePoint();
+ if (parseWasSuccessful()) {
+ updateIncludeFilePaths();
+ updateLastProjectPartChangeTimePoint();
+ } else {
+ qWarning() << "Parsing" << m_in.filePath << "failed:" << m_parseErrorCode;
+ m_out.hasParseOrReparseFailed = true;
+ }
}
}
@@ -129,11 +131,16 @@ void TranslationUnitUpdater::reparse()
unsaved.data(),
clang_defaultReparseOptions(m_cxTranslationUnit));
- checkReparseErrorCode();
- updateIncludeFilePaths();
+ if (reparseWasSuccessful()) {
+ updateIncludeFilePaths();
- m_out.reparsed = true;
+ m_out.reparsed = true;
+ m_out.needsToBeReparsedChangeTimePoint = m_in.needsToBeReparsedChangeTimePoint;
+ } else {
+ qWarning() << "Reparsing" << m_in.filePath << "failed:" << m_reparseErrorCode;
+ m_out.hasParseOrReparseFailed = true;
+ }
}
void TranslationUnitUpdater::updateIncludeFilePaths()
@@ -146,24 +153,6 @@ void TranslationUnitUpdater::updateIncludeFilePaths()
const_cast<TranslationUnitUpdater *>(this));
}
-void TranslationUnitUpdater::checkParseErrorCode() const
-{
- if (!parseWasSuccessful()) {
- throw TranslationUnitParseErrorException(m_in.filePath,
- m_in.projectId,
- m_parseErrorCode);
- }
-}
-
-void TranslationUnitUpdater::checkReparseErrorCode() const
-{
- if (!reparseWasSuccessful()) {
- throw TranslationUnitReparseErrorException(m_in.filePath,
- m_in.projectId,
- m_reparseErrorCode);
- }
-}
-
uint TranslationUnitUpdater::defaultParseOptions()
{
return CXTranslationUnit_CacheCompletionResults
diff --git a/src/tools/clangbackend/ipcsource/clangtranslationunitupdater.h b/src/tools/clangbackend/ipcsource/clangtranslationunitupdater.h
index a7a9d88f23..cb7a06b7f6 100644
--- a/src/tools/clangbackend/ipcsource/clangtranslationunitupdater.h
+++ b/src/tools/clangbackend/ipcsource/clangtranslationunitupdater.h
@@ -41,9 +41,10 @@ using time_point = std::chrono::steady_clock::time_point;
class TranslationUnitUpdateInput {
public:
- bool reparseNeeded = false;
bool parseNeeded = false;
+ bool reparseNeeded = false;
+ time_point needsToBeReparsedChangeTimePoint;
Utf8String filePath;
Utf8StringVector fileArguments;
@@ -55,9 +56,12 @@ public:
class TranslationUnitUpdateResult {
public:
+ bool hasParseOrReparseFailed = false;
+
bool parseTimePointIsSet = false;
time_point parseTimePoint;
+ time_point needsToBeReparsedChangeTimePoint;
bool reparsed = false;
QSet<Utf8String> dependedOnFilePaths;
@@ -100,9 +104,6 @@ private:
bool parseWasSuccessful() const;
bool reparseWasSuccessful() const;
- void checkReparseErrorCode() const;
- void checkParseErrorCode() const;
-
private:
CXIndex &m_cxIndex;
CXTranslationUnit &m_cxTranslationUnit;
diff --git a/src/tools/clangbackend/ipcsource/clangupdatedocumentannotationsjob.cpp b/src/tools/clangbackend/ipcsource/clangupdatedocumentannotationsjob.cpp
new file mode 100644
index 0000000000..2e61c50b92
--- /dev/null
+++ b/src/tools/clangbackend/ipcsource/clangupdatedocumentannotationsjob.cpp
@@ -0,0 +1,109 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 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 "clangupdatedocumentannotationsjob.h"
+
+#include <clangbackendipc/clangbackendipcdebugutils.h>
+#include <clangbackendipc/clangcodemodelclientinterface.h>
+#include <clangbackendipc/documentannotationschangedmessage.h>
+
+#include <utils/qtcassert.h>
+
+namespace ClangBackEnd {
+
+static UpdateDocumentAnnotationsJob::AsyncResult runAsyncHelper(
+ const TranslationUnitCore &translationUnitCore,
+ const TranslationUnitUpdateInput &translationUnitUpdatInput)
+{
+ TIME_SCOPE_DURATION("UpdateDocumentAnnotationsJobRunner");
+
+ UpdateDocumentAnnotationsJob::AsyncResult asyncResult;
+
+ try {
+ // Update
+ asyncResult.updateResult = translationUnitCore.update(translationUnitUpdatInput);
+
+ // Collect
+ translationUnitCore.extractDocumentAnnotations(asyncResult.diagnostics,
+ asyncResult.highlightingMarks,
+ asyncResult.skippedSourceRanges);
+
+ } catch (const std::exception &exception) {
+ qWarning() << "Error in UpdateDocumentAnnotationsJobRunner:" << exception.what();
+ }
+
+ return asyncResult;
+}
+
+bool UpdateDocumentAnnotationsJob::prepareAsyncRun()
+{
+ const JobRequest jobRequest = context().jobRequest;
+ QTC_ASSERT(jobRequest.type == JobRequest::Type::UpdateDocumentAnnotations, return false);
+
+ try {
+ m_pinnedTranslationUnit = context().translationUnitForJobRequest();
+ m_pinnedFileContainer = m_pinnedTranslationUnit.fileContainer();
+
+ const TranslationUnitCore translationUnitCore = m_pinnedTranslationUnit.translationUnitCore();
+ const TranslationUnitUpdateInput updateInput = m_pinnedTranslationUnit.createUpdateInput();
+ setRunner([translationUnitCore, updateInput]() {
+ return runAsyncHelper(translationUnitCore, updateInput);
+ });
+
+ } catch (const std::exception &exception) {
+ qWarning() << "Error in UpdateDocumentAnnotationsJob::prepareAsyncRun:" << exception.what();
+ return false;
+ }
+
+ return true;
+}
+
+void UpdateDocumentAnnotationsJob::finalizeAsyncRun()
+{
+ if (!context().isOutdated()) {
+ const AsyncResult result = asyncResult();
+
+ incorporateUpdaterResult(result);
+ sendAnnotations(result);
+ }
+}
+
+void UpdateDocumentAnnotationsJob::incorporateUpdaterResult(const AsyncResult &result)
+{
+ m_pinnedTranslationUnit.incorporateUpdaterResult(result.updateResult);
+}
+
+void UpdateDocumentAnnotationsJob::sendAnnotations(const AsyncResult &result)
+{
+ const DocumentAnnotationsChangedMessage message(m_pinnedFileContainer,
+ result.diagnostics,
+ result.highlightingMarks,
+ result.skippedSourceRanges);
+
+ context().client->documentAnnotationsChanged(message);
+}
+
+} // namespace ClangBackEnd
+
diff --git a/src/tools/clangbackend/ipcsource/clangupdatedocumentannotationsjob.h b/src/tools/clangbackend/ipcsource/clangupdatedocumentannotationsjob.h
new file mode 100644
index 0000000000..643df07571
--- /dev/null
+++ b/src/tools/clangbackend/ipcsource/clangupdatedocumentannotationsjob.h
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 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 "clangtranslationunit.h"
+#include "clangtranslationunitupdater.h"
+
+#include <clangbackendipc/diagnosticcontainer.h>
+#include <clangbackendipc/highlightingmarkcontainer.h>
+#include <clangbackendipc/sourcerangecontainer.h>
+
+namespace ClangBackEnd {
+
+struct UpdateDocumentAnnotationsJobResult
+{
+ TranslationUnitUpdateResult updateResult;
+
+ QVector<ClangBackEnd::DiagnosticContainer> diagnostics;
+ QVector<HighlightingMarkContainer> highlightingMarks;
+ QVector<SourceRangeContainer> skippedSourceRanges;
+};
+
+class UpdateDocumentAnnotationsJob : public AsyncJob<UpdateDocumentAnnotationsJobResult>
+{
+public:
+ using AsyncResult = UpdateDocumentAnnotationsJobResult;
+
+ bool prepareAsyncRun() override;
+ void finalizeAsyncRun() override;
+
+private:
+ void incorporateUpdaterResult(const AsyncResult &result);
+ void sendAnnotations(const AsyncResult &result);
+
+private:
+ TranslationUnit m_pinnedTranslationUnit;
+ FileContainer m_pinnedFileContainer;
+};
+
+} // namespace ClangBackEnd
diff --git a/src/tools/clangbackend/ipcsource/translationunits.cpp b/src/tools/clangbackend/ipcsource/translationunits.cpp
index 2e90e0bf81..5fde27b8b9 100644
--- a/src/tools/clangbackend/ipcsource/translationunits.cpp
+++ b/src/tools/clangbackend/ipcsource/translationunits.cpp
@@ -128,14 +128,10 @@ const TranslationUnit &TranslationUnits::translationUnit(const FileContainer &fi
return translationUnit(fileContainer.filePath(), fileContainer.projectPartId());
}
-bool TranslationUnits::hasTranslationUnit(const Utf8String &filePath) const
+bool TranslationUnits::hasTranslationUnit(const Utf8String &filePath,
+ const Utf8String &projectPartId) const
{
- return std::any_of(translationUnits_.cbegin(),
- translationUnits_.cend(),
- [&filePath] (const TranslationUnit &translationUnit)
- {
- return translationUnit.filePath() == filePath;
- });
+ return hasTranslationUnit(FileContainer(filePath, projectPartId));
}
const std::vector<TranslationUnit> &TranslationUnits::translationUnits() const
@@ -171,75 +167,6 @@ void TranslationUnits::setTranslationUnitsDirtyIfProjectPartChanged()
translationUnit.setDirtyIfProjectPartIsOutdated();
}
-DocumentAnnotationsSendState TranslationUnits::sendDocumentAnnotations()
-{
- auto documentAnnotationsSendState = sendDocumentAnnotationsForCurrentEditor();
- if (documentAnnotationsSendState == DocumentAnnotationsSendState::NoDocumentAnnotationsSent)
- documentAnnotationsSendState = sendDocumentAnnotationsForVisibleEditors();
-
- return documentAnnotationsSendState;
-}
-
-template<class Predicate>
-DocumentAnnotationsSendState TranslationUnits::sendDocumentAnnotations(Predicate predicate)
-{
- auto foundTranslationUnit = std::find_if(translationUnits_.begin(),
- translationUnits_.end(),
- predicate);
-
- if (foundTranslationUnit != translationUnits().end()) {
- sendDocumentAnnotations(*foundTranslationUnit);
- return DocumentAnnotationsSendState::MaybeThereAreDocumentAnnotations;
- }
-
- return DocumentAnnotationsSendState::NoDocumentAnnotationsSent;
-}
-
-namespace {
-
-bool translationUnitHasNewDocumentAnnotations(const TranslationUnit &translationUnit)
-{
- return translationUnit.isIntact()
- && (translationUnit.hasNewDiagnostics()
- || translationUnit.hasNewHighlightingMarks());
-}
-
-}
-
-DocumentAnnotationsSendState TranslationUnits::sendDocumentAnnotationsForCurrentEditor()
-{
- auto hasDocumentAnnotationsForCurrentEditor = [] (const TranslationUnit &translationUnit) {
- return translationUnit.isUsedByCurrentEditor()
- && translationUnitHasNewDocumentAnnotations(translationUnit);
- };
-
- return sendDocumentAnnotations(hasDocumentAnnotationsForCurrentEditor);
-}
-
-DocumentAnnotationsSendState TranslationUnits::sendDocumentAnnotationsForVisibleEditors()
-{
- auto hasDocumentAnnotationsForVisibleEditor = [] (const TranslationUnit &translationUnit) {
- return translationUnit.isVisibleInEditor()
- && translationUnitHasNewDocumentAnnotations(translationUnit);
- };
-
- return sendDocumentAnnotations(hasDocumentAnnotationsForVisibleEditor);
-}
-
-DocumentAnnotationsSendState TranslationUnits::sendDocumentAnnotationsForAll()
-{
- auto hasDocumentAnnotations = [] (const TranslationUnit &translationUnit) {
- return translationUnitHasNewDocumentAnnotations(translationUnit);
- };
-
- return sendDocumentAnnotations(hasDocumentAnnotations);
-}
-
-void TranslationUnits::setSendDocumentAnnotationsCallback(SendDocumentAnnotationsCallback &&callback)
-{
- sendDocumentAnnotationsCallback = std::move(callback);
-}
-
QVector<FileContainer> TranslationUnits::newerFileContainers(const QVector<FileContainer> &fileContainers) const
{
QVector<FileContainer> newerContainers;
@@ -367,18 +294,6 @@ void TranslationUnits::checkIfTranslationUnitsForFilePathsDoesExists(const QVect
}
}
-void TranslationUnits::sendDocumentAnnotations(const TranslationUnit &translationUnit)
-{
- if (sendDocumentAnnotationsCallback) {
- DocumentAnnotationsChangedMessage message(translationUnit.fileContainer(),
- translationUnit.mainFileDiagnostics(),
- translationUnit.highlightingMarks().toHighlightingMarksContainers(),
- translationUnit.translationUnitCore().skippedSourceRanges().toSourceRangeContainers());
-
- sendDocumentAnnotationsCallback(std::move(message));
- }
-}
-
void TranslationUnits::removeTranslationUnits(const QVector<FileContainer> &fileContainers)
{
QVector<FileContainer> processedFileContainers = fileContainers;
diff --git a/src/tools/clangbackend/ipcsource/translationunits.h b/src/tools/clangbackend/ipcsource/translationunits.h
index 4081efd7ab..5607ebb665 100644
--- a/src/tools/clangbackend/ipcsource/translationunits.h
+++ b/src/tools/clangbackend/ipcsource/translationunits.h
@@ -32,28 +32,16 @@
#include <QVector>
-#include <functional>
#include <vector>
namespace ClangBackEnd {
class ProjectParts;
class UnsavedFiles;
-class DocumentAnnotationsChangedMessage;
-
-enum class DocumentAnnotationsSendState
-{
- NoDocumentAnnotationsSent,
- MaybeThereAreDocumentAnnotations,
-};
class TranslationUnits
{
public:
- using SendDocumentAnnotationsCallback
- = std::function<void (const DocumentAnnotationsChangedMessage &)>;
-
-public:
TranslationUnits(ProjectParts &projectParts, UnsavedFiles &unsavedFiles);
std::vector<TranslationUnit> create(const QVector<FileContainer> &fileContainers);
@@ -65,7 +53,8 @@ public:
const TranslationUnit &translationUnit(const Utf8String &filePath, const Utf8String &projectPartId) const;
const TranslationUnit &translationUnit(const FileContainer &fileContainer) const;
- bool hasTranslationUnit(const Utf8String &filePath) const;
+ bool hasTranslationUnit(const Utf8String &filePath, const Utf8String &projectPartId) const;
+ bool hasTranslationUnitWithFilePath(const Utf8String &filePath) const;
const std::vector<TranslationUnit> &translationUnits() const;
@@ -77,13 +66,6 @@ public:
void updateTranslationUnitsWithChangedDependencies(const QVector<FileContainer> &fileContainers);
void setTranslationUnitsDirtyIfProjectPartChanged();
- DocumentAnnotationsSendState sendDocumentAnnotationsForCurrentEditor();
- DocumentAnnotationsSendState sendDocumentAnnotationsForVisibleEditors();
- DocumentAnnotationsSendState sendDocumentAnnotationsForAll();
- DocumentAnnotationsSendState sendDocumentAnnotations();
-
- void setSendDocumentAnnotationsCallback(SendDocumentAnnotationsCallback &&callback);
-
QVector<FileContainer> newerFileContainers(const QVector<FileContainer> &fileContainers) const;
const ClangFileSystemWatcher *clangFileSystemWatcher() const;
@@ -95,7 +77,6 @@ private:
std::vector<TranslationUnit> findAllTranslationUnitWithFilePath(const Utf8String &filePath);
std::vector<TranslationUnit>::const_iterator findTranslationUnit(const Utf8String &filePath, const Utf8String &projectPartId) const;
bool hasTranslationUnit(const FileContainer &fileContainer) const;
- bool hasTranslationUnitWithFilePath(const Utf8String &filePath) const;
void checkIfProjectPartExists(const Utf8String &projectFileName) const;
void checkIfProjectPartsExists(const QVector<FileContainer> &fileContainers) const;
void checkIfTranslationUnitsDoesNotExists(const QVector<FileContainer> &fileContainers) const;
@@ -103,13 +84,8 @@ private:
void removeTranslationUnits(const QVector<FileContainer> &fileContainers);
- template<class Predicate>
- DocumentAnnotationsSendState sendDocumentAnnotations(Predicate predicate);
- void sendDocumentAnnotations(const TranslationUnit &translationUnit);
-
private:
ClangFileSystemWatcher fileSystemWatcher;
- SendDocumentAnnotationsCallback sendDocumentAnnotationsCallback;
std::vector<TranslationUnit> translationUnits_;
ProjectParts &projectParts;
UnsavedFiles &unsavedFiles_;