Clang: Rename directory ipcsource to source

Now it's in accordance with clangrefactoringbackend/source and
clangpchmanagerbackend/source.

Change-Id: I939cfc72cffb8fcde0649f125e6efb6670d1cbc3
Reviewed-by: Tim Jenssen <tim.jenssen@qt.io>
This commit is contained in:
Nikolai Kosjar
2017-09-25 16:15:14 +02:00
parent 917592970d
commit 087ea0e531
113 changed files with 4 additions and 4 deletions

View File

@@ -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 "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() final
{
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;
}
void preventFinalization() final
{
m_futureWatcher.disconnect();
}
private:
Runner m_runner;
QFutureWatcher<Result> m_futureWatcher;
};
} // namespace ClangBackEnd

View File

@@ -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 <clang-c/Index.h>
namespace ClangBackEnd {
enum class PreferredTranslationUnit
{
RecentlyParsed,
PreviouslyParsed,
LastUninitialized,
};
// CLANG-UPGRADE-CHECK: Remove IS_SUSPEND_SUPPORTED once we require clang >= 5.0
#if defined(CINDEX_VERSION_HAS_BACKPORTED_SUSPEND) || CINDEX_VERSION_MINOR >= 41
# define IS_SUSPEND_SUPPORTED
#endif
} // namespace ClangBackEnd

View File

@@ -0,0 +1,114 @@
INCLUDEPATH += $$PWD
HEADERS += \
$$PWD/clangasyncjob.h \
$$PWD/clangbackend_global.h \
$$PWD/clangclock.h \
$$PWD/clangcodecompleteresults.h \
$$PWD/clangcodemodelserver.h \
$$PWD/clangcompletecodejob.h \
$$PWD/clangcreateinitialdocumentpreamblejob.h \
$$PWD/clangdocument.h \
$$PWD/clangdocumentjob.h \
$$PWD/clangdocumentprocessor.h \
$$PWD/clangdocumentprocessors.h \
$$PWD/clangdocuments.h \
$$PWD/clangdocumentsuspenderresumer.h \
$$PWD/clangexceptions.h \
$$PWD/clangfilepath.h \
$$PWD/clangfilesystemwatcher.h \
$$PWD/clangfollowsymboljob.h \
$$PWD/clangfollowsymbol.h \
$$PWD/clangiasyncjob.h \
$$PWD/clangjobcontext.h \
$$PWD/clangjobqueue.h \
$$PWD/clangjobrequest.h \
$$PWD/clangjobs.h \
$$PWD/clangparsesupportivetranslationunitjob.h \
$$PWD/clangreferencescollector.h \
$$PWD/clangreparsesupportivetranslationunitjob.h \
$$PWD/clangrequestdocumentannotationsjob.h \
$$PWD/clangrequestreferencesjob.h \
$$PWD/clangresumedocumentjob.h \
$$PWD/clangstring.h \
$$PWD/clangsupportivetranslationunitinitializer.h \
$$PWD/clangsuspenddocumentjob.h \
$$PWD/clangtranslationunit.h \
$$PWD/clangtranslationunits.h \
$$PWD/clangtranslationunitupdater.h \
$$PWD/clangtype.h \
$$PWD/clangunsavedfilesshallowarguments.h \
$$PWD/clangupdatedocumentannotationsjob.h \
$$PWD/codecompleter.h \
$$PWD/codecompletionchunkconverter.h \
$$PWD/codecompletionsextractor.h \
$$PWD/commandlinearguments.h \
$$PWD/cursor.h \
$$PWD/diagnostic.h \
$$PWD/diagnosticset.h \
$$PWD/diagnosticsetiterator.h \
$$PWD/fixit.h \
$$PWD/highlightingmark.h \
$$PWD/highlightingmarks.h \
$$PWD/highlightingmarksiterator.h \
$$PWD/projectpart.h \
$$PWD/projects.h \
$$PWD/skippedsourceranges.h \
$$PWD/sourcelocation.h \
$$PWD/sourcerange.h \
$$PWD/unsavedfile.h \
$$PWD/unsavedfiles.h \
$$PWD/utf8positionfromlinecolumn.h
SOURCES += \
$$PWD/clangcodecompleteresults.cpp \
$$PWD/clangcodemodelserver.cpp \
$$PWD/clangcompletecodejob.cpp \
$$PWD/clangcreateinitialdocumentpreamblejob.cpp \
$$PWD/clangdocument.cpp \
$$PWD/clangdocumentprocessor.cpp \
$$PWD/clangdocumentprocessors.cpp \
$$PWD/clangdocuments.cpp \
$$PWD/clangdocumentsuspenderresumer.cpp \
$$PWD/clangexceptions.cpp \
$$PWD/clangfilepath.cpp \
$$PWD/clangfilesystemwatcher.cpp \
$$PWD/clangfollowsymboljob.cpp \
$$PWD/clangfollowsymbol.cpp \
$$PWD/clangiasyncjob.cpp \
$$PWD/clangjobcontext.cpp \
$$PWD/clangjobqueue.cpp \
$$PWD/clangjobrequest.cpp \
$$PWD/clangjobs.cpp \
$$PWD/clangparsesupportivetranslationunitjob.cpp \
$$PWD/clangresumedocumentjob.cpp \
$$PWD/clangreferencescollector.cpp \
$$PWD/clangreparsesupportivetranslationunitjob.cpp \
$$PWD/clangrequestdocumentannotationsjob.cpp \
$$PWD/clangrequestreferencesjob.cpp \
$$PWD/clangsuspenddocumentjob.cpp \
$$PWD/clangsupportivetranslationunitinitializer.cpp \
$$PWD/clangtranslationunit.cpp \
$$PWD/clangtranslationunits.cpp \
$$PWD/clangtranslationunitupdater.cpp \
$$PWD/clangtype.cpp \
$$PWD/clangunsavedfilesshallowarguments.cpp \
$$PWD/clangupdatedocumentannotationsjob.cpp \
$$PWD/codecompleter.cpp \
$$PWD/codecompletionchunkconverter.cpp \
$$PWD/codecompletionsextractor.cpp \
$$PWD/commandlinearguments.cpp \
$$PWD/cursor.cpp \
$$PWD/diagnostic.cpp \
$$PWD/diagnosticset.cpp \
$$PWD/fixit.cpp \
$$PWD/highlightingmark.cpp \
$$PWD/highlightingmarks.cpp \
$$PWD/projectpart.cpp \
$$PWD/projects.cpp \
$$PWD/skippedsourceranges.cpp \
$$PWD/sourcelocation.cpp \
$$PWD/sourcerange.cpp \
$$PWD/unsavedfile.cpp \
$$PWD/unsavedfiles.cpp \
$$PWD/utf8positionfromlinecolumn.cpp

View File

@@ -0,0 +1,36 @@
/****************************************************************************
**
** 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 <chrono>
namespace ClangBackEnd {
using Clock = std::chrono::steady_clock;
using Duration = std::chrono::steady_clock::duration;
using TimePoint = std::chrono::steady_clock::time_point;
} // namespace ClangBackEnd

View File

@@ -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 "clangcodecompleteresults.h"
#include <memory>
namespace ClangBackEnd {
using std::swap;
ClangCodeCompleteResults::ClangCodeCompleteResults(CXCodeCompleteResults *cxCodeCompleteResults)
: cxCodeCompleteResults(cxCodeCompleteResults)
{
}
ClangCodeCompleteResults::~ClangCodeCompleteResults()
{
clang_disposeCodeCompleteResults(cxCodeCompleteResults);
}
bool ClangCodeCompleteResults::isNull() const
{
return cxCodeCompleteResults == nullptr;
}
bool ClangCodeCompleteResults::isEmpty() const
{
return cxCodeCompleteResults->NumResults == 0;
}
bool ClangCodeCompleteResults::hasResults() const
{
return !isNull() && !isEmpty();
}
bool ClangCodeCompleteResults::hasNoResultsForDotCompletion() const
{
return !hasResults() && isDotCompletion();
}
bool ClangCodeCompleteResults::hasUnknownContext() const
{
const unsigned long long contexts = clang_codeCompleteGetContexts(cxCodeCompleteResults);
return contexts == CXCompletionContext_Unknown;
}
bool ClangCodeCompleteResults::isDotCompletion() const
{
const unsigned long long contexts = clang_codeCompleteGetContexts(cxCodeCompleteResults);
return contexts & CXCompletionContext_DotMemberAccess;
}
CXCodeCompleteResults *ClangCodeCompleteResults::data() const
{
return cxCodeCompleteResults;
}
ClangCodeCompleteResults &ClangCodeCompleteResults::operator=(ClangCodeCompleteResults &&clangCodeCompleteResults)
{
swap(cxCodeCompleteResults, clangCodeCompleteResults.cxCodeCompleteResults);
return *this;
}
ClangCodeCompleteResults::ClangCodeCompleteResults(ClangCodeCompleteResults &&clangCodeCompleteResults)
{
swap(cxCodeCompleteResults, clangCodeCompleteResults.cxCodeCompleteResults);
}
} // namespace ClangBackEnd

View File

@@ -0,0 +1,63 @@
/****************************************************************************
**
** 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 <clang-c/Index.h>
#include <utf8string.h>
namespace ClangBackEnd {
class ClangCodeCompleteResults
{
public:
ClangCodeCompleteResults() = default;
ClangCodeCompleteResults(CXCodeCompleteResults *cxCodeCompleteResults);
~ClangCodeCompleteResults();
ClangCodeCompleteResults(const ClangCodeCompleteResults &ClangCodeCompleteResults) = delete;
const ClangCodeCompleteResults &operator=(const ClangCodeCompleteResults &ClangCodeCompleteResults) = delete;
ClangCodeCompleteResults(ClangCodeCompleteResults &&ClangCodeCompleteResults);
ClangCodeCompleteResults &operator=(ClangCodeCompleteResults &&ClangCodeCompleteResults);
bool isNull() const;
bool isEmpty() const;
bool hasResults() const;
bool hasNoResultsForDotCompletion() const;
bool hasUnknownContext() const;
bool isDotCompletion() const;
CXCodeCompleteResults *data() const;
private:
CXCodeCompleteResults *cxCodeCompleteResults = nullptr;
};
} // namespace ClangBackEnd

View File

@@ -0,0 +1,425 @@
/****************************************************************************
**
** 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 "clangcodemodelserver.h"
#include "clangdocuments.h"
#include "clangdocumentsuspenderresumer.h"
#include "clangfilesystemwatcher.h"
#include "clangtranslationunits.h"
#include "codecompleter.h"
#include "diagnosticset.h"
#include "highlightingmarks.h"
#include "clangexceptions.h"
#include "skippedsourceranges.h"
#include <clangsupport/clangsupportdebugutils.h>
#include <clangsupport/clangcodemodelservermessages.h>
#include <utils/algorithm.h>
#include <utils/qtcassert.h>
#include <QCoreApplication>
#include <QDebug>
static bool useSupportiveTranslationUnit()
{
static bool use = !qEnvironmentVariableIntValue("QTC_CLANG_NO_SUPPORTIVE_TRANSLATIONUNIT");
return use;
}
namespace ClangBackEnd {
ClangCodeModelServer::ClangCodeModelServer()
: documents(projects, unsavedFiles)
{
updateDocumentAnnotationsTimer.setSingleShot(true);
QObject::connect(&updateDocumentAnnotationsTimer,
&QTimer::timeout,
[this]() {
processJobsForDirtyAndVisibleDocuments();
});
updateVisibleButNotCurrentDocumentsTimer.setSingleShot(true);
QObject::connect(&updateVisibleButNotCurrentDocumentsTimer,
&QTimer::timeout,
[this]() {
processJobsForDirtyAndVisibleButNotCurrentDocuments();
});
QObject::connect(documents.clangFileSystemWatcher(),
&ClangFileSystemWatcher::fileChanged,
[this](const Utf8String &filePath) {
ClangCodeModelServer::startDocumentAnnotationsTimerIfFileIsNotOpenAsDocument(filePath);
});
}
void ClangCodeModelServer::end()
{
QCoreApplication::exit();
}
void ClangCodeModelServer::registerTranslationUnitsForEditor(const ClangBackEnd::RegisterTranslationUnitForEditorMessage &message)
{
TIME_SCOPE_DURATION("ClangCodeModelServer::registerTranslationUnitsForEditor");
try {
auto createdDocuments = documents.create(message.fileContainers());
for (const auto &document : createdDocuments)
documentProcessors().create(document);
unsavedFiles.createOrUpdate(message.fileContainers());
documents.setUsedByCurrentEditor(message.currentEditorFilePath());
documents.setVisibleInEditors(message.visibleEditorFilePaths());
processSuspendResumeJobs(documents.documents());
processInitialJobsForDocuments(createdDocuments);
} catch (const std::exception &exception) {
qWarning() << "Error in ClangCodeModelServer::registerTranslationUnitsForEditor:" << exception.what();
}
}
void ClangCodeModelServer::updateTranslationUnitsForEditor(const UpdateTranslationUnitsForEditorMessage &message)
{
TIME_SCOPE_DURATION("ClangCodeModelServer::updateTranslationUnitsForEditor");
try {
const auto newerFileContainers = documents.newerFileContainers(message.fileContainers());
if (newerFileContainers.size() > 0) {
std::vector<Document> updateDocuments = documents.update(newerFileContainers);
unsavedFiles.createOrUpdate(newerFileContainers);
for (Document &document : updateDocuments) {
if (!document.isResponsivenessIncreased())
document.setResponsivenessIncreaseNeeded(true);
}
// Start the jobs on the next event loop iteration since otherwise
// we might block the translation unit for a completion request
// that comes right after this message.
updateDocumentAnnotationsTimer.start(0);
}
} catch (const std::exception &exception) {
qWarning() << "Error in ClangCodeModelServer::updateTranslationUnitsForEditor:" << exception.what();
}
}
void ClangCodeModelServer::unregisterTranslationUnitsForEditor(const ClangBackEnd::UnregisterTranslationUnitsForEditorMessage &message)
{
TIME_SCOPE_DURATION("ClangCodeModelServer::unregisterTranslationUnitsForEditor");
try {
for (const auto &fileContainer : message.fileContainers()) {
const Document &document = documents.document(fileContainer);
documentProcessors().remove(document);
}
documents.remove(message.fileContainers());
unsavedFiles.remove(message.fileContainers());
} catch (const std::exception &exception) {
qWarning() << "Error in ClangCodeModelServer::unregisterTranslationUnitsForEditor:" << exception.what();
}
}
void ClangCodeModelServer::registerProjectPartsForEditor(const RegisterProjectPartsForEditorMessage &message)
{
TIME_SCOPE_DURATION("ClangCodeModelServer::registerProjectPartsForEditor");
try {
projects.createOrUpdate(message.projectContainers());
std::vector<Document> affectedDocuments = documents.setDocumentsDirtyIfProjectPartChanged();
for (Document &document : affectedDocuments) {
document.setResponsivenessIncreaseNeeded(document.isResponsivenessIncreased());
documentProcessors().remove(document);
document.translationUnits().removeAll();
document.translationUnits().createAndAppend();
documentProcessors().create(document);
}
processJobsForDirtyAndVisibleDocuments();
} catch (const std::exception &exception) {
qWarning() << "Error in ClangCodeModelServer::registerProjectPartsForEditor:" << exception.what();
}
}
void ClangCodeModelServer::unregisterProjectPartsForEditor(const UnregisterProjectPartsForEditorMessage &message)
{
TIME_SCOPE_DURATION("ClangCodeModelServer::unregisterProjectPartsForEditor");
try {
projects.remove(message.projectPartIds());
} catch (const std::exception &exception) {
qWarning() << "Error in ClangCodeModelServer::unregisterProjectPartsForEditor:" << exception.what();
}
}
void ClangCodeModelServer::registerUnsavedFilesForEditor(const RegisterUnsavedFilesForEditorMessage &message)
{
TIME_SCOPE_DURATION("ClangCodeModelServer::registerUnsavedFilesForEditor");
try {
unsavedFiles.createOrUpdate(message.fileContainers());
documents.updateDocumentsWithChangedDependencies(message.fileContainers());
updateDocumentAnnotationsTimer.start(updateDocumentAnnotationsTimeOutInMs);
} catch (const std::exception &exception) {
qWarning() << "Error in ClangCodeModelServer::registerUnsavedFilesForEditor:" << exception.what();
}
}
void ClangCodeModelServer::unregisterUnsavedFilesForEditor(const UnregisterUnsavedFilesForEditorMessage &message)
{
TIME_SCOPE_DURATION("ClangCodeModelServer::unregisterUnsavedFilesForEditor");
try {
unsavedFiles.remove(message.fileContainers());
documents.updateDocumentsWithChangedDependencies(message.fileContainers());
} catch (const std::exception &exception) {
qWarning() << "Error in ClangCodeModelServer::unregisterUnsavedFilesForEditor:" << exception.what();
}
}
void ClangCodeModelServer::completeCode(const ClangBackEnd::CompleteCodeMessage &message)
{
TIME_SCOPE_DURATION("ClangCodeModelServer::completeCode");
try {
Document document = documents.document(message.filePath(), message.projectPartId());
DocumentProcessor processor = documentProcessors().processor(document);
JobRequest jobRequest = processor.createJobRequest(JobRequest::Type::CompleteCode);
jobRequest.line = message.line();
jobRequest.column = message.column();
jobRequest.funcNameStartLine = message.funcNameStartLine();
jobRequest.funcNameStartColumn = message.funcNameStartColumn();
jobRequest.ticketNumber = message.ticketNumber();
processor.addJob(jobRequest);
processor.process();
} catch (const std::exception &exception) {
qWarning() << "Error in ClangCodeModelServer::completeCode:" << exception.what();
}
}
void ClangCodeModelServer::requestDocumentAnnotations(const RequestDocumentAnnotationsMessage &message)
{
TIME_SCOPE_DURATION("ClangCodeModelServer::requestDocumentAnnotations");
try {
auto document = documents.document(message.fileContainer().filePath(),
message.fileContainer().projectPartId());
DocumentProcessor processor = documentProcessors().processor(document);
processor.addJob(JobRequest::Type::RequestDocumentAnnotations);
processor.process();
} catch (const std::exception &exception) {
qWarning() << "Error in ClangCodeModelServer::requestDocumentAnnotations:" << exception.what();
}
}
template <class MessageType>
static void fillJobRequest(JobRequest &jobRequest, const MessageType &message)
{
jobRequest.line = message.line();
jobRequest.column = message.column();
jobRequest.ticketNumber = message.ticketNumber();
// The unsaved files might get updater later, so take the current
// revision for the request.
jobRequest.documentRevision = message.fileContainer().documentRevision();
}
void ClangCodeModelServer::requestReferences(const RequestReferencesMessage &message)
{
TIME_SCOPE_DURATION("ClangCodeModelServer::requestReferences");
try {
const Document document = documents.document(message.fileContainer().filePath(),
message.fileContainer().projectPartId());
DocumentProcessor processor = documentProcessors().processor(document);
JobRequest jobRequest = processor.createJobRequest(JobRequest::Type::RequestReferences);
fillJobRequest(jobRequest, message);
processor.addJob(jobRequest);
processor.process();
} catch (const std::exception &exception) {
qWarning() << "Error in ClangCodeModelServer::requestReferences:" << exception.what();
}
}
void ClangCodeModelServer::requestFollowSymbol(const RequestFollowSymbolMessage &message)
{
TIME_SCOPE_DURATION("ClangCodeModelServer::requestFollowSymbol");
try {
auto projectPartId = message.fileContainer().projectPartId();
Document document = documents.document(message.fileContainer().filePath(),
projectPartId);
DocumentProcessor processor = documentProcessors().processor(document);
JobRequest jobRequest = processor.createJobRequest(JobRequest::Type::FollowSymbol);
fillJobRequest(jobRequest, message);
jobRequest.dependentFiles = message.dependentFiles();
processor.addJob(jobRequest);
processor.process();
} catch (const std::exception &exception) {
qWarning() << "Error in ClangCodeModelServer::requestFollowSymbol:" << exception.what();
}
}
void ClangCodeModelServer::updateVisibleTranslationUnits(const UpdateVisibleTranslationUnitsMessage &message)
{
TIME_SCOPE_DURATION("ClangCodeModelServer::updateVisibleTranslationUnits");
try {
documents.setUsedByCurrentEditor(message.currentEditorFilePath());
documents.setVisibleInEditors(message.visibleEditorFilePaths());
processSuspendResumeJobs(documents.documents());
updateDocumentAnnotationsTimer.start(0);
} catch (const std::exception &exception) {
qWarning() << "Error in ClangCodeModelServer::updateVisibleTranslationUnits:" << exception.what();
}
}
const Documents &ClangCodeModelServer::documentsForTestOnly() const
{
return documents;
}
void ClangCodeModelServer::startDocumentAnnotationsTimerIfFileIsNotOpenAsDocument(const Utf8String &filePath)
{
if (!documents.hasDocumentWithFilePath(filePath))
updateDocumentAnnotationsTimer.start(0);
}
QList<Jobs::RunningJob> ClangCodeModelServer::runningJobsForTestsOnly()
{
return documentProcessors().runningJobs();
}
int ClangCodeModelServer::queueSizeForTestsOnly()
{
return documentProcessors().queueSize();
}
bool ClangCodeModelServer::isTimerRunningForTestOnly() const
{
return updateDocumentAnnotationsTimer.isActive();
}
void ClangCodeModelServer::processJobsForDirtyAndVisibleDocuments()
{
processJobsForDirtyCurrentDocument();
processTimerForVisibleButNotCurrentDocuments();
}
void ClangCodeModelServer::processJobsForDirtyCurrentDocument()
{
auto currentDirtyDocuments = documents.filtered([](const Document &document) {
return document.isDirty() && document.isUsedByCurrentEditor();
});
QTC_CHECK(currentDirtyDocuments.size() <= 1);
addAndRunUpdateJobs(currentDirtyDocuments);
}
void ClangCodeModelServer::addAndRunUpdateJobs(std::vector<Document> documents)
{
for (auto &document : documents) {
DocumentProcessor processor = documentProcessors().processor(document);
// Run the regular edit-reparse-job
processor.addJob(JobRequest::Type::UpdateDocumentAnnotations,
PreferredTranslationUnit::PreviouslyParsed);
processor.process();
// If requested, run jobs to increase the responsiveness of the document
if (useSupportiveTranslationUnit() && document.isResponsivenessIncreaseNeeded()) {
QTC_CHECK(!document.isResponsivenessIncreased());
QTC_CHECK(!processor.hasSupportiveTranslationUnit());
document.setResponsivenessIncreaseNeeded(false);
processor.startInitializingSupportiveTranslationUnit();
}
}
}
void ClangCodeModelServer::processTimerForVisibleButNotCurrentDocuments()
{
if (documents.dirtyAndVisibleButNotCurrentDocuments().empty()) {
updateVisibleButNotCurrentDocumentsTimer.stop();
} else {
updateVisibleButNotCurrentDocumentsTimer.start(
updateVisibleButNotCurrentDocumentsTimeOutInMs);
}
}
void ClangCodeModelServer::processJobsForDirtyAndVisibleButNotCurrentDocuments()
{
addAndRunUpdateJobs(documents.dirtyAndVisibleButNotCurrentDocuments());
}
void ClangCodeModelServer::processSuspendResumeJobs(const std::vector<Document> &documents)
{
const SuspendResumeJobs suspendResumeJobs = createSuspendResumeJobs(documents);
for (const SuspendResumeJobsEntry &entry : suspendResumeJobs) {
DocumentProcessor processor = documentProcessors().processor(entry.document);
processor.addJob(entry.jobRequestType, entry.preferredTranslationUnit);
processor.process();
}
}
void ClangCodeModelServer::processInitialJobsForDocuments(const std::vector<Document> &documents)
{
for (const auto &document : documents) {
DocumentProcessor processor = documentProcessors().processor(document);
processor.addJob(JobRequest::Type::UpdateDocumentAnnotations);
processor.addJob(JobRequest::Type::CreateInitialDocumentPreamble);
processor.process();
}
}
void ClangCodeModelServer::setUpdateDocumentAnnotationsTimeOutInMsForTestsOnly(int value)
{
updateDocumentAnnotationsTimeOutInMs = value;
}
void ClangCodeModelServer::setUpdateVisibleButNotCurrentDocumentsTimeOutInMsForTestsOnly(int value)
{
updateVisibleButNotCurrentDocumentsTimeOutInMs = value;
}
DocumentProcessors &ClangCodeModelServer::documentProcessors()
{
if (!documentProcessors_) {
// DocumentProcessors needs a reference to the client, but the client
// is not known at construction time of ClangCodeModelServer, so
// construct DocumentProcessors in a lazy manner.
documentProcessors_.reset(new DocumentProcessors(documents, unsavedFiles, projects, *client()));
}
return *documentProcessors_.data();
}
} // namespace ClangBackEnd

View File

@@ -0,0 +1,100 @@
/****************************************************************************
**
** 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 "projectpart.h"
#include "projects.h"
#include "clangdocument.h"
#include "clangdocuments.h"
#include "clangdocumentprocessors.h"
#include "clangjobrequest.h"
#include "unsavedfiles.h"
#include <clangcodemodelserverinterface.h>
#include <ipcclientprovider.h>
#include <utf8string.h>
#include <QScopedPointer>
#include <QTimer>
namespace ClangBackEnd {
class ClangCodeModelServer : public ClangCodeModelServerInterface,
public IpcClientProvider<ClangCodeModelClientInterface>
{
public:
ClangCodeModelServer();
void end() override;
void registerTranslationUnitsForEditor(const RegisterTranslationUnitForEditorMessage &message) override;
void updateTranslationUnitsForEditor(const UpdateTranslationUnitsForEditorMessage &message) override;
void unregisterTranslationUnitsForEditor(const UnregisterTranslationUnitsForEditorMessage &message) override;
void registerProjectPartsForEditor(const RegisterProjectPartsForEditorMessage &message) override;
void unregisterProjectPartsForEditor(const UnregisterProjectPartsForEditorMessage &message) override;
void registerUnsavedFilesForEditor(const RegisterUnsavedFilesForEditorMessage &message) override;
void unregisterUnsavedFilesForEditor(const UnregisterUnsavedFilesForEditorMessage &message) override;
void completeCode(const CompleteCodeMessage &message) override;
void updateVisibleTranslationUnits(const UpdateVisibleTranslationUnitsMessage &message) override;
void requestDocumentAnnotations(const RequestDocumentAnnotationsMessage &message) override;
void requestReferences(const RequestReferencesMessage &message) override;
void requestFollowSymbol(const RequestFollowSymbolMessage &message) override;
public: // for tests
const Documents &documentsForTestOnly() const;
QList<Jobs::RunningJob> runningJobsForTestsOnly();
int queueSizeForTestsOnly();
bool isTimerRunningForTestOnly() const;
void setUpdateDocumentAnnotationsTimeOutInMsForTestsOnly(int value);
void setUpdateVisibleButNotCurrentDocumentsTimeOutInMsForTestsOnly(int value);
DocumentProcessors &documentProcessors();
private:
void startDocumentAnnotationsTimerIfFileIsNotOpenAsDocument(const Utf8String &filePath);
void processInitialJobsForDocuments(const std::vector<Document> &documents);
void processJobsForDirtyAndVisibleDocuments();
void processJobsForDirtyCurrentDocument();
void processTimerForVisibleButNotCurrentDocuments();
void processJobsForDirtyAndVisibleButNotCurrentDocuments();
void processSuspendResumeJobs(const std::vector<Document> &documents);
void addAndRunUpdateJobs(std::vector<Document> documents);
private:
ProjectParts projects;
UnsavedFiles unsavedFiles;
Documents documents;
QScopedPointer<DocumentProcessors> documentProcessors_; // Delayed initialization
QTimer updateDocumentAnnotationsTimer;
int updateDocumentAnnotationsTimeOutInMs = 1500;
QTimer updateVisibleButNotCurrentDocumentsTimer;
int updateVisibleButNotCurrentDocumentsTimeOutInMs = 2000;
};
} // namespace ClangBackEnd

View File

@@ -0,0 +1,79 @@
/****************************************************************************
**
** 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 <clangsupport/clangsupportdebugutils.h>
#include <clangsupport/clangcodemodelclientinterface.h>
#include <clangsupport/cmbcodecompletedmessage.h>
#include <utils/qtcassert.h>
namespace ClangBackEnd {
IAsyncJob::AsyncPrepareResult CompleteCodeJob::prepareAsyncRun()
{
const JobRequest jobRequest = context().jobRequest;
QTC_ASSERT(jobRequest.type == JobRequest::Type::CompleteCode, return AsyncPrepareResult());
QTC_ASSERT(acquireDocument(), return AsyncPrepareResult());
const TranslationUnit translationUnit = *m_translationUnit;
const UnsavedFiles unsavedFiles = *context().unsavedFiles;
const quint32 line = jobRequest.line;
const quint32 column = jobRequest.column;
const qint32 funcNameStartLine = jobRequest.funcNameStartLine;
const qint32 funcNameStartColumn = jobRequest.funcNameStartColumn;
setRunner([translationUnit, unsavedFiles, line, column,
funcNameStartLine, funcNameStartColumn]() {
TIME_SCOPE_DURATION("CompleteCodeJobRunner");
UnsavedFiles theUnsavedFiles = unsavedFiles;
const TranslationUnit::CodeCompletionResult results
= translationUnit.complete(theUnsavedFiles, line, column,
funcNameStartLine, funcNameStartColumn);
CompleteCodeJob::AsyncResult asyncResult;
asyncResult.completions = results.completions;
asyncResult.correction = results.correction;
return asyncResult;
});
return AsyncPrepareResult{translationUnit.id()};
}
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

View File

@@ -0,0 +1,49 @@
/****************************************************************************
**
** 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 "clangdocumentjob.h"
#include <clangsupport/codecompletion.h>
namespace ClangBackEnd {
struct CompleteCodeJobResult
{
CodeCompletions completions;
CompletionCorrection correction = CompletionCorrection::NoCorrection;
};
class CompleteCodeJob : public DocumentJob<CompleteCodeJobResult>
{
public:
using AsyncResult = CompleteCodeJobResult;
AsyncPrepareResult prepareAsyncRun() override;
void finalizeAsyncRun() override;
};
} // namespace ClangBackEnd

View File

@@ -0,0 +1,55 @@
/****************************************************************************
**
** 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 <clangsupport/clangsupportdebugutils.h>
#include <utils/qtcassert.h>
namespace ClangBackEnd {
IAsyncJob::AsyncPrepareResult CreateInitialDocumentPreambleJob::prepareAsyncRun()
{
const JobRequest jobRequest = context().jobRequest;
QTC_ASSERT(jobRequest.type == JobRequest::Type::CreateInitialDocumentPreamble, return AsyncPrepareResult());
QTC_ASSERT(acquireDocument(), return AsyncPrepareResult());
const TranslationUnit translationUnit = *m_translationUnit;
const TranslationUnitUpdateInput updateInput = m_pinnedDocument.createUpdateInput();
setRunner([translationUnit, updateInput]() {
TIME_SCOPE_DURATION("CreateInitialDocumentPreambleJobRunner");
translationUnit.reparse(updateInput);
});
return AsyncPrepareResult{translationUnit.id()};
}
void CreateInitialDocumentPreambleJob::finalizeAsyncRun()
{
}
} // namespace ClangBackEnd

View File

@@ -0,0 +1,39 @@
/****************************************************************************
**
** 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 "clangdocumentjob.h"
namespace ClangBackEnd {
class CreateInitialDocumentPreambleJob : public DocumentJob<void>
{
public:
AsyncPrepareResult prepareAsyncRun() override;
void finalizeAsyncRun() override;
};
} // namespace ClangBackEnd

View File

@@ -0,0 +1,468 @@
/****************************************************************************
**
** 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 "clangdocument.h"
#include "clangdocuments.h"
#include "clangstring.h"
#include "clangunsavedfilesshallowarguments.h"
#include "codecompleter.h"
#include "projectpart.h"
#include "clangexceptions.h"
#include "clangtranslationunit.h"
#include "clangtranslationunits.h"
#include "clangtranslationunitupdater.h"
#include "unsavedfiles.h"
#include "unsavedfile.h"
#include <utf8string.h>
#include <QDebug>
#include <QFileInfo>
#include <QLoggingCategory>
#include <ostream>
namespace ClangBackEnd {
class DocumentData
{
public:
DocumentData(const Utf8String &filePath,
const ProjectPart &projectPart,
const Utf8StringVector &fileArguments,
Documents &documents);
~DocumentData();
public:
Documents &documents;
const Utf8String filePath;
const Utf8StringVector fileArguments;
ProjectPart projectPart;
TimePoint lastProjectPartChangeTimePoint;
TranslationUnits translationUnits;
QSet<Utf8String> dependedFilePaths;
uint documentRevision = 0;
TimePoint visibleTimePoint;
TimePoint isDirtyChangeTimePoint;
bool isDirty = false;
bool hasParseOrReparseFailed = false;
bool isUsedByCurrentEditor = false;
bool isVisibleInEditor = false;
bool increaseResponsiveness = false;
bool isSuspended = false;
};
DocumentData::DocumentData(const Utf8String &filePath,
const ProjectPart &projectPart,
const Utf8StringVector &fileArguments,
Documents &documents)
: documents(documents),
filePath(filePath),
fileArguments(fileArguments),
projectPart(projectPart),
lastProjectPartChangeTimePoint(Clock::now()),
translationUnits(filePath),
isDirtyChangeTimePoint(lastProjectPartChangeTimePoint)
{
dependedFilePaths.insert(filePath);
translationUnits.createAndAppend();
}
DocumentData::~DocumentData()
{
}
Document::Document(const Utf8String &filePath,
const ProjectPart &projectPart,
const Utf8StringVector &fileArguments,
Documents &documents,
FileExistsCheck fileExistsCheck)
: d(std::make_shared<DocumentData>(filePath,
projectPart,
fileArguments,
documents))
{
if (fileExistsCheck == FileExistsCheck::Check)
checkIfFileExists();
}
Document::~Document() = default;
Document::Document(const Document &) = default;
Document &Document::operator=(const Document &) = default;
Document::Document(Document &&other)
: d(std::move(other.d))
{
}
Document &Document::operator=(Document &&other)
{
d = std::move(other.d);
return *this;
}
void Document::reset()
{
d.reset();
}
bool Document::isNull() const
{
return !d;
}
bool Document::isIntact() const
{
return !isNull()
&& fileExists()
&& !d->hasParseOrReparseFailed;
}
bool Document::isParsed() const
{
return d->translationUnits.areAllTranslationUnitsParsed();
}
Utf8String Document::filePath() const
{
checkIfNull();
return d->filePath;
}
Utf8StringVector Document::fileArguments() const
{
checkIfNull();
return d->fileArguments;
}
FileContainer Document::fileContainer() const
{
checkIfNull();
return FileContainer(d->filePath,
d->projectPart.id(),
Utf8String(),
false,
d->documentRevision);
}
const ProjectPart &Document::projectPart() const
{
checkIfNull();
return d->projectPart;
}
const TimePoint Document::lastProjectPartChangeTimePoint() const
{
checkIfNull();
return d->lastProjectPartChangeTimePoint;
}
bool Document::isProjectPartOutdated() const
{
checkIfNull();
return d->projectPart.lastChangeTimePoint() >= d->lastProjectPartChangeTimePoint;
}
uint Document::documentRevision() const
{
checkIfNull();
return d->documentRevision;
}
void Document::setDocumentRevision(uint revision)
{
checkIfNull();
d->documentRevision = revision;
}
bool Document::isResponsivenessIncreased() const
{
return d->translationUnits.size() > 1;
}
bool Document::isResponsivenessIncreaseNeeded() const
{
checkIfNull();
return d->increaseResponsiveness;
}
void Document::setResponsivenessIncreaseNeeded(bool responsivenessIncreaseNeeded)
{
d->increaseResponsiveness = responsivenessIncreaseNeeded;
}
bool Document::isSuspended() const
{
checkIfNull();
return d->isSuspended;
}
void Document::setIsSuspended(bool isSuspended)
{
checkIfNull();
d->isSuspended = isSuspended;
}
bool Document::isUsedByCurrentEditor() const
{
checkIfNull();
return d->isUsedByCurrentEditor;
}
void Document::setIsUsedByCurrentEditor(bool isUsedByCurrentEditor)
{
checkIfNull();
d->isUsedByCurrentEditor = isUsedByCurrentEditor;
}
bool Document::isVisibleInEditor() const
{
checkIfNull();
return d->isVisibleInEditor;
}
void Document::setIsVisibleInEditor(bool isVisibleInEditor, const TimePoint &timePoint)
{
checkIfNull();
if (isVisibleInEditor)
d->visibleTimePoint = timePoint;
d->isVisibleInEditor = isVisibleInEditor;
}
TimePoint Document::visibleTimePoint() const
{
checkIfNull();
return d->visibleTimePoint;;
}
bool Document::isDirty() const
{
checkIfNull();
return d->isDirty;
}
TimePoint Document::isDirtyTimeChangePoint() const
{
checkIfNull();
return d->isDirtyChangeTimePoint;
}
bool Document::setDirtyIfProjectPartIsOutdated()
{
if (isProjectPartOutdated()) {
setDirty();
return true;
}
return false;
}
void Document::setDirtyIfDependencyIsMet(const Utf8String &filePath)
{
if (d->dependedFilePaths.contains(filePath) && isMainFileAndExistsOrIsOtherFile(filePath))
setDirty();
}
TranslationUnitUpdateInput Document::createUpdateInput() const
{
TranslationUnitUpdateInput updateInput;
updateInput.parseNeeded = isProjectPartOutdated();
updateInput.reparseNeeded = d->isDirty;
updateInput.needsToBeReparsedChangeTimePoint = d->isDirtyChangeTimePoint;
updateInput.filePath = filePath();
updateInput.fileArguments = fileArguments();
updateInput.unsavedFiles = d->documents.unsavedFiles();
updateInput.projectId = projectPart().id();
updateInput.projectArguments = projectPart().arguments();
return updateInput;
}
TranslationUnitUpdater Document::createUpdater() const
{
TranslationUnit unit = translationUnit();
const TranslationUnitUpdateInput updateInput = createUpdateInput();
TranslationUnitUpdater updater(unit.id(),
unit.cxIndex(),
unit.cxTranslationUnit(),
updateInput);
return updater;
}
void Document::setHasParseOrReparseFailed(bool hasFailed)
{
d->hasParseOrReparseFailed = hasFailed;
}
void Document::incorporateUpdaterResult(const TranslationUnitUpdateResult &result) const
{
d->hasParseOrReparseFailed = result.hasParseOrReparseFailed;
if (d->hasParseOrReparseFailed) {
d->isDirty = false;
return;
}
if (result.hasParsed())
d->lastProjectPartChangeTimePoint = result.parseTimePoint;
if (result.hasParsed() || result.hasReparsed()) {
d->dependedFilePaths = result.dependedOnFilePaths;
const TimePoint timePoint = qMax(result.parseTimePoint, result.reparseTimePoint);
d->translationUnits.updateParseTimePoint(result.translationUnitId, timePoint);
}
d->documents.addWatchedFiles(d->dependedFilePaths);
if (result.hasReparsed()
&& result.needsToBeReparsedChangeTimePoint == d->isDirtyChangeTimePoint) {
d->isDirty = false;
}
}
TranslationUnit Document::translationUnit(PreferredTranslationUnit preferredTranslationUnit) const
{
checkIfNull();
return d->translationUnits.get(preferredTranslationUnit);
}
TranslationUnits &Document::translationUnits() const
{
return d->translationUnits;
}
void Document::parse() const
{
checkIfNull();
const TranslationUnitUpdateInput updateInput = createUpdateInput();
TranslationUnitUpdateResult result = translationUnit().parse(updateInput);
incorporateUpdaterResult(result);
}
void Document::reparse() const
{
checkIfNull();
const TranslationUnitUpdateInput updateInput = createUpdateInput();
TranslationUnitUpdateResult result = translationUnit().reparse(updateInput);
incorporateUpdaterResult(result);
}
const QSet<Utf8String> Document::dependedFilePaths() const
{
checkIfNull();
checkIfFileExists();
return d->dependedFilePaths;
}
void Document::setDependedFilePaths(const QSet<Utf8String> &filePaths)
{
d->dependedFilePaths = filePaths;
}
void Document::setDirty()
{
d->isDirtyChangeTimePoint = Clock::now();
d->isDirty = true;
}
void Document::checkIfNull() const
{
if (isNull())
throw DocumentIsNullException();
}
void Document::checkIfFileExists() const
{
if (!fileExists())
throw DocumentFileDoesNotExistException(d->filePath);
}
bool Document::fileExists() const
{
return QFileInfo::exists(d->filePath.toString());
}
bool Document::isMainFileAndExistsOrIsOtherFile(const Utf8String &filePath) const
{
if (filePath == d->filePath)
return QFileInfo::exists(d->filePath);
return true;
}
bool operator==(const Document &first, const Document &second)
{
return first.filePath() == second.filePath()
&& first.projectPart().id() == second.projectPart().id();
}
std::ostream &operator<<(std::ostream &os, const Document &document)
{
os << "("
<< document.filePath() << ", "
<< document.projectPart().id() << ", "
<< document.documentRevision()
<< ")";
return os;
}
} // namespace ClangBackEnd

View File

@@ -0,0 +1,142 @@
/****************************************************************************
**
** 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 "clangtranslationunitupdater.h"
#include "clangbackend_global.h"
#include "clangtranslationunit.h"
#include <utf8stringvector.h>
#include <clang-c/Index.h>
#include <QSet>
#include <QtGlobal>
#include <memory>
class Utf8String;
namespace ClangBackEnd {
class TranslationUnit;
class TranslationUnits;
class DocumentData;
class TranslationUnitUpdateResult;
class ProjectPart;
class FileContainer;
class Documents;
class Document
{
public:
enum class FileExistsCheck {
Check,
DoNotCheck
};
Document() = default;
Document(const Utf8String &filePath,
const ProjectPart &projectPart,
const Utf8StringVector &fileArguments,
Documents &documents,
FileExistsCheck fileExistsCheck = FileExistsCheck::Check);
~Document();
Document(const Document &document);
Document &operator=(const Document &document);
Document(Document &&document);
Document &operator=(Document &&document);
void reset();
bool isNull() const;
bool isIntact() const;
bool isParsed() const;
Utf8String filePath() const;
Utf8StringVector fileArguments() const;
FileContainer fileContainer() const;
const ProjectPart &projectPart() const;
const TimePoint lastProjectPartChangeTimePoint() const;
bool isProjectPartOutdated() const;
uint documentRevision() const;
void setDocumentRevision(uint revision);
bool isResponsivenessIncreased() const;
bool isResponsivenessIncreaseNeeded() const;
void setResponsivenessIncreaseNeeded(bool responsivenessIncreaseNeeded);
bool isSuspended() const;
void setIsSuspended(bool isSuspended);
bool isUsedByCurrentEditor() const;
void setIsUsedByCurrentEditor(bool isUsedByCurrentEditor);
bool isVisibleInEditor() const;
void setIsVisibleInEditor(bool isVisibleInEditor, const TimePoint &timePoint);
TimePoint visibleTimePoint() const;
bool isDirty() const;
TimePoint isDirtyTimeChangePoint() const;
bool setDirtyIfProjectPartIsOutdated();
void setDirtyIfDependencyIsMet(const Utf8String &filePath);
TranslationUnitUpdateInput createUpdateInput() const;
void incorporateUpdaterResult(const TranslationUnitUpdateResult &result) const;
TranslationUnit translationUnit(PreferredTranslationUnit preferredTranslationUnit
= PreferredTranslationUnit::RecentlyParsed) const;
TranslationUnits &translationUnits() const;
public: // for tests
void parse() const;
void reparse() const;
const QSet<Utf8String> dependedFilePaths() const;
void setDependedFilePaths(const QSet<Utf8String> &filePaths);
TranslationUnitUpdater createUpdater() const;
void setHasParseOrReparseFailed(bool hasFailed);
private:
void setDirty();
void checkIfNull() const;
void checkIfFileExists() const;
bool fileExists() const;
bool isMainFileAndExistsOrIsOtherFile(const Utf8String &filePath) const;
private:
mutable std::shared_ptr<DocumentData> d;
};
bool operator==(const Document &first, const Document &second);
std::ostream &operator<<(std::ostream &os, const Document &document);
} // namespace ClangBackEnd

View File

@@ -0,0 +1,64 @@
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include "clangasyncjob.h"
#include "clangdocument.h"
#include <clangsupport/filecontainer.h>
#include <memory>
namespace ClangBackEnd {
template<class Result>
class DocumentJob : public AsyncJob<Result>
{
protected:
bool acquireDocument()
{
try {
m_pinnedDocument = IAsyncJob::context().documentForJobRequest();
m_pinnedFileContainer = m_pinnedDocument.fileContainer();
const PreferredTranslationUnit preferredTranslationUnit
= IAsyncJob::context().jobRequest.preferredTranslationUnit;
m_translationUnit.reset(
new TranslationUnit(m_pinnedDocument.translationUnit(preferredTranslationUnit)));
return true;
} catch (const std::exception &) {
return false;
}
}
protected:
Document m_pinnedDocument;
FileContainer m_pinnedFileContainer;
std::unique_ptr<TranslationUnit> m_translationUnit;
};
} // namespace ClangBackEnd

View File

@@ -0,0 +1,140 @@
/****************************************************************************
**
** 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 "clangdocumentprocessor.h"
#include "clangdocuments.h"
#include "clangjobs.h"
#include "clangsupportivetranslationunitinitializer.h"
#include "clangdocument.h"
#include "clangtranslationunits.h"
#include <utils/algorithm.h>
#include <utils/qtcassert.h>
namespace ClangBackEnd {
class DocumentProcessorData
{
public:
DocumentProcessorData(const Document &document,
Documents &documents,
UnsavedFiles &unsavedFiles,
ProjectParts &projects,
ClangCodeModelClientInterface &client)
: document(document)
, documents(documents)
, jobs(documents, unsavedFiles, projects, client)
, supportiveTranslationUnitInitializer(document, jobs)
{
const auto isDocumentClosedChecker = [this](const Utf8String &filePath,
const Utf8String &projectPartId) {
return !this->documents.hasDocument(filePath, projectPartId);
};
supportiveTranslationUnitInitializer.setIsDocumentClosedChecker(isDocumentClosedChecker);
}
public:
Document document;
Documents &documents;
Jobs jobs;
SupportiveTranslationUnitInitializer supportiveTranslationUnitInitializer;
};
DocumentProcessor::DocumentProcessor(const Document &document,
Documents &documents,
UnsavedFiles &unsavedFiles,
ProjectParts &projects,
ClangCodeModelClientInterface &client)
: d(std::make_shared<DocumentProcessorData>(document,
documents,
unsavedFiles,
projects,
client))
{
}
JobRequest DocumentProcessor::createJobRequest(
JobRequest::Type type,
PreferredTranslationUnit preferredTranslationUnit) const
{
return d->jobs.createJobRequest(d->document, type, preferredTranslationUnit);
}
void DocumentProcessor::addJob(const JobRequest &jobRequest)
{
d->jobs.add(jobRequest);
}
void DocumentProcessor::addJob(JobRequest::Type type, PreferredTranslationUnit preferredTranslationUnit)
{
d->jobs.add(d->document, type, preferredTranslationUnit);
}
JobRequests DocumentProcessor::process()
{
return d->jobs.process();
}
Document DocumentProcessor::document() const
{
return d->document;
}
bool DocumentProcessor::hasSupportiveTranslationUnit() const
{
return d->supportiveTranslationUnitInitializer.state()
!= SupportiveTranslationUnitInitializer::State::NotInitialized;
}
void DocumentProcessor::startInitializingSupportiveTranslationUnit()
{
d->supportiveTranslationUnitInitializer.startInitializing();
}
bool DocumentProcessor::isSupportiveTranslationUnitInitialized() const
{
return d->supportiveTranslationUnitInitializer.state()
== SupportiveTranslationUnitInitializer::State::Initialized;
}
JobRequests &DocumentProcessor::queue()
{
return d->jobs.queue();
}
QList<Jobs::RunningJob> DocumentProcessor::runningJobs() const
{
return d->jobs.runningJobs();
}
int DocumentProcessor::queueSize() const
{
return d->jobs.queue().size();
}
} // namespace ClangBackEnd

View File

@@ -0,0 +1,78 @@
/****************************************************************************
**
** 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 "clangjobs.h"
#include <memory>
namespace ClangBackEnd {
class ClangCodeModelClientInterface;
class Document;
class Documents;
class DocumentProcessorData;
class JobRequest;
class ProjectParts;
class UnsavedFiles;
class DocumentProcessor
{
public:
DocumentProcessor(const Document &document,
Documents &documents,
UnsavedFiles &unsavedFiles,
ProjectParts &projects,
ClangCodeModelClientInterface &client);
JobRequest createJobRequest(JobRequest::Type type,
PreferredTranslationUnit preferredTranslationUnit
= PreferredTranslationUnit::RecentlyParsed) const;
void addJob(const JobRequest &jobRequest);
void addJob(JobRequest::Type type,
PreferredTranslationUnit preferredTranslationUnit
= PreferredTranslationUnit::RecentlyParsed);
JobRequests process();
Document document() const;
bool hasSupportiveTranslationUnit() const;
void startInitializingSupportiveTranslationUnit();
public: // for tests
bool isSupportiveTranslationUnitInitialized() const;
JobRequests &queue();
QList<Jobs::RunningJob> runningJobs() const;
int queueSize() const;
private:
std::shared_ptr<DocumentProcessorData> d;
};
} // namespace ClangBackEnd

View File

@@ -0,0 +1,114 @@
/****************************************************************************
**
** 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 "clangdocumentprocessors.h"
#include "clangdocument.h"
#include "clangexceptions.h"
#include "projectpart.h"
namespace ClangBackEnd {
DocumentProcessors::DocumentProcessors(Documents &documents,
UnsavedFiles &unsavedFiles,
ProjectParts &projects,
ClangCodeModelClientInterface &client)
: m_documents(documents)
, m_unsavedFiles(unsavedFiles)
, m_projects(projects)
, m_client(client)
{
}
static bool operator<(const DocumentId &lhs, const DocumentId &rhs)
{
return lhs.filePath < rhs.filePath
|| (lhs.filePath == rhs.filePath && lhs.projectPartId < lhs.projectPartId);
}
DocumentProcessor DocumentProcessors::create(const Document &document)
{
const DocumentId id{document.filePath(), document.projectPart().id()};
if (m_processors.contains(id))
throw DocumentProcessorAlreadyExists(document.filePath(), document.projectPart().id());
const DocumentProcessor element(document, m_documents, m_unsavedFiles, m_projects, m_client);
m_processors.insert(id, element);
return element;
}
DocumentProcessor DocumentProcessors::processor(const Document &document)
{
const DocumentId id{document.filePath(), document.projectPart().id()};
const auto it = m_processors.find(id);
if (it == m_processors.end())
throw DocumentProcessorDoesNotExist(document.filePath(), document.projectPart().id());
return *it;
}
QList<DocumentProcessor> DocumentProcessors::processors() const
{
return m_processors.values();
}
void DocumentProcessors::remove(const Document &document)
{
const DocumentId id{document.filePath(), document.projectPart().id()};
const int itemsRemoved = m_processors.remove(id);
if (itemsRemoved != 1)
throw DocumentProcessorDoesNotExist(document.filePath(), document.projectPart().id());
}
JobRequests DocumentProcessors::process()
{
JobRequests jobsStarted;
for (auto &processor : m_processors)
jobsStarted += processor.process();
return jobsStarted;
}
QList<Jobs::RunningJob> DocumentProcessors::runningJobs() const
{
QList<Jobs::RunningJob> jobs;
for (auto &processor : m_processors)
jobs += processor.runningJobs();
return jobs;
}
int DocumentProcessors::queueSize() const
{
int total = 0;
for (auto &processor : m_processors)
total += processor.queueSize();
return total;
}
} // namespace ClangBackEnd

View File

@@ -0,0 +1,74 @@
/****************************************************************************
**
** 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 "clangdocumentprocessor.h"
#include "clangjobs.h"
#include <utf8string.h>
#include <QMap>
namespace ClangBackEnd {
class Document;
class DocumentProcessor;
class DocumentId {
public:
Utf8String filePath;
Utf8String projectPartId;
};
class DocumentProcessors
{
public:
DocumentProcessors(Documents &documents,
UnsavedFiles &unsavedFiles,
ProjectParts &projects,
ClangCodeModelClientInterface &client);
DocumentProcessor create(const Document &document);
DocumentProcessor processor(const Document &document);
void remove(const Document &document);
JobRequests process();
public: // for tests
QList<DocumentProcessor> processors() const;
QList<Jobs::RunningJob> runningJobs() const;
int queueSize() const;
private:
Documents &m_documents;
UnsavedFiles &m_unsavedFiles;
ProjectParts &m_projects;
ClangCodeModelClientInterface &m_client;
QMap<DocumentId, DocumentProcessor> m_processors;
};
} // namespace ClangBackEnd

View File

@@ -0,0 +1,353 @@
/****************************************************************************
**
** 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 "clangdocuments.h"
#include <diagnosticset.h>
#include <highlightingmarks.h>
#include <clangexceptions.h>
#include <projects.h>
#include <skippedsourceranges.h>
#include <unsavedfiles.h>
#include <utils/algorithm.h>
#include <QDebug>
#include <algorithm>
namespace ClangBackEnd {
bool operator==(const FileContainer &fileContainer, const Document &document)
{
return fileContainer.filePath() == document.filePath()
&& fileContainer.projectPartId() == document.projectPart().id();
}
bool operator==(const Document &document, const FileContainer &fileContainer)
{
return fileContainer == document;
}
Documents::Documents(ProjectParts &projects, UnsavedFiles &unsavedFiles)
: fileSystemWatcher(*this),
projectParts(projects),
unsavedFiles_(unsavedFiles)
{
}
std::vector<Document> Documents::create(const QVector<FileContainer> &fileContainers)
{
checkIfDocumentsDoNotExist(fileContainers);
std::vector<Document> createdDocuments;
for (const FileContainer &fileContainer : fileContainers) {
if (fileContainer.hasUnsavedFileContent())
updateDocumentsWithChangedDependency(fileContainer.filePath());
createdDocuments.push_back(createDocument(fileContainer));
}
return createdDocuments;
}
std::vector<Document> Documents::update(const QVector<FileContainer> &fileContainers)
{
checkIfDocumentsForFilePathsExist(fileContainers);
std::vector<Document> createdDocuments;
for (const FileContainer &fileContainer : fileContainers) {
const std::vector<Document> documents = updateDocument(fileContainer);
createdDocuments.insert(createdDocuments.end(), documents.begin(), documents.end());
updateDocumentsWithChangedDependency(fileContainer.filePath());
}
return createdDocuments;
}
static bool removeFromFileContainer(QVector<FileContainer> &fileContainers, const Document &document)
{
auto position = std::remove(fileContainers.begin(), fileContainers.end(), document);
bool entryIsRemoved = position != fileContainers.end();
fileContainers.erase(position, fileContainers.end());
return entryIsRemoved;
}
void Documents::remove(const QVector<FileContainer> &fileContainers)
{
checkIfProjectPartsExists(fileContainers);
removeDocuments(fileContainers);
updateDocumentsWithChangedDependencies(fileContainers);
}
void Documents::setUsedByCurrentEditor(const Utf8String &filePath)
{
for (Document &document : documents_)
document.setIsUsedByCurrentEditor(document.filePath() == filePath);
}
void Documents::setVisibleInEditors(const Utf8StringVector &filePaths)
{
const TimePoint timePoint = Clock::now();
for (Document &document : documents_)
document.setIsVisibleInEditor(filePaths.contains(document.filePath()), timePoint);
}
const Document &Documents::document(const Utf8String &filePath, const Utf8String &projectPartId) const
{
checkIfProjectPartExists(projectPartId);
auto findIterator = findDocument(filePath, projectPartId);
if (findIterator == documents_.end())
throw DocumentDoesNotExistException(filePath, projectPartId);
return *findIterator;
}
const Document &Documents::document(const FileContainer &fileContainer) const
{
return document(fileContainer.filePath(), fileContainer.projectPartId());
}
bool Documents::hasDocument(const Utf8String &filePath,
const Utf8String &projectPartId) const
{
return hasDocument(FileContainer(filePath, projectPartId));
}
const std::vector<Document> &Documents::documents() const
{
return documents_;
}
const std::vector<Document> Documents::filtered(const IsMatchingDocument &isMatchingDocument) const
{
return Utils::filtered(documents_, isMatchingDocument);
}
std::vector<Document> Documents::dirtyAndVisibleButNotCurrentDocuments() const
{
return filtered([](const Document &document) {
return document.isDirty()
&& document.isVisibleInEditor()
&& !document.isUsedByCurrentEditor();
});
}
UnsavedFiles Documents::unsavedFiles() const
{
return unsavedFiles_;
}
void Documents::addWatchedFiles(QSet<Utf8String> &filePaths)
{
fileSystemWatcher.addFiles(filePaths);
}
void Documents::updateDocumentsWithChangedDependency(const Utf8String &filePath)
{
for (auto &document : documents_)
document.setDirtyIfDependencyIsMet(filePath);
}
void Documents::updateDocumentsWithChangedDependencies(const QVector<FileContainer> &fileContainers)
{
for (const FileContainer &fileContainer : fileContainers)
updateDocumentsWithChangedDependency(fileContainer.filePath());
}
std::vector<Document> Documents::setDocumentsDirtyIfProjectPartChanged()
{
std::vector<Document> notDirtyBefore;
for (auto &document : documents_) {
if (!document.isDirty() && document.setDirtyIfProjectPartIsOutdated())
notDirtyBefore.push_back(document);
}
return notDirtyBefore;
}
QVector<FileContainer> Documents::newerFileContainers(const QVector<FileContainer> &fileContainers) const
{
QVector<FileContainer> newerContainers;
auto documentIsNewer = [this] (const FileContainer &fileContainer) {
try {
return document(fileContainer).documentRevision() != fileContainer.documentRevision();
} catch (const DocumentDoesNotExistException &) {
return true;
}
};
std::copy_if(fileContainers.cbegin(),
fileContainers.cend(),
std::back_inserter(newerContainers),
documentIsNewer);
return newerContainers;
}
const ClangFileSystemWatcher *Documents::clangFileSystemWatcher() const
{
return &fileSystemWatcher;
}
Document Documents::createDocument(const FileContainer &fileContainer)
{
const Document::FileExistsCheck checkIfFileExists = fileContainer.hasUnsavedFileContent()
? Document::FileExistsCheck::DoNotCheck
: Document::FileExistsCheck::Check;
documents_.emplace_back(fileContainer.filePath(),
projectParts.project(fileContainer.projectPartId()),
fileContainer.fileArguments(),
*this,
checkIfFileExists);
documents_.back().setDocumentRevision(fileContainer.documentRevision());
return documents_.back();
}
std::vector<Document> Documents::updateDocument(const FileContainer &fileContainer)
{
const auto documents = findAllDocumentsWithFilePath(fileContainer.filePath());
for (auto document : documents)
document.setDocumentRevision(fileContainer.documentRevision());
return documents;
}
std::vector<Document>::iterator Documents::findDocument(const FileContainer &fileContainer)
{
return std::find(documents_.begin(), documents_.end(), fileContainer);
}
std::vector<Document> Documents::findAllDocumentsWithFilePath(const Utf8String &filePath)
{
const auto filePathCompare = [&filePath] (const Document &document) {
return document.filePath() == filePath;
};
std::vector<Document> documents;
std::copy_if(documents_.begin(),
documents_.end(),
std::back_inserter(documents),
filePathCompare);
return documents;
}
std::vector<Document>::const_iterator Documents::findDocument(const Utf8String &filePath, const Utf8String &projectPartId) const
{
FileContainer fileContainer(filePath, projectPartId);
return std::find(documents_.begin(), documents_.end(), fileContainer);
}
bool Documents::hasDocument(const FileContainer &fileContainer) const
{
auto findIterator = std::find(documents_.begin(), documents_.end(), fileContainer);
return findIterator != documents_.end();
}
bool Documents::hasDocumentWithFilePath(const Utf8String &filePath) const
{
auto filePathCompare = [&filePath] (const Document &document) {
return document.filePath() == filePath;
};
auto findIterator = std::find_if(documents_.begin(), documents_.end(), filePathCompare);
return findIterator != documents_.end();
}
void Documents::checkIfProjectPartExists(const Utf8String &projectFileName) const
{
projectParts.project(projectFileName);
}
void Documents::checkIfProjectPartsExists(const QVector<FileContainer> &fileContainers) const
{
Utf8StringVector notExistingProjectParts;
for (const FileContainer &fileContainer : fileContainers) {
if (!projectParts.hasProjectPart(fileContainer.projectPartId()))
notExistingProjectParts.push_back(fileContainer.projectPartId());
}
if (!notExistingProjectParts.isEmpty())
throw ProjectPartDoNotExistException(notExistingProjectParts);
}
void Documents::checkIfDocumentsDoNotExist(const QVector<FileContainer> &fileContainers) const
{
for (const FileContainer &fileContainer : fileContainers) {
if (hasDocument(fileContainer)) {
throw DocumentAlreadyExistsException(fileContainer.filePath(),
fileContainer.projectPartId());
}
}
}
void Documents::checkIfDocumentsForFilePathsExist(const QVector<FileContainer> &fileContainers) const
{
for (const FileContainer &fileContainer : fileContainers) {
if (!hasDocumentWithFilePath(fileContainer.filePath())) {
throw DocumentDoesNotExistException(fileContainer.filePath(),
fileContainer.projectPartId());
}
}
}
void Documents::removeDocuments(const QVector<FileContainer> &fileContainers)
{
QVector<FileContainer> processedFileContainers = fileContainers;
auto removeBeginIterator = std::remove_if(documents_.begin(), documents_.end(), [&processedFileContainers] (const Document &document) {
return removeFromFileContainer(processedFileContainers, document);
});
documents_.erase(removeBeginIterator, documents_.end());
if (!processedFileContainers.isEmpty()) {
const FileContainer fileContainer = processedFileContainers.first();
throw DocumentDoesNotExistException(fileContainer.filePath(),
fileContainer.projectPartId());
}
}
} // namespace ClangBackEnd

View File

@@ -0,0 +1,98 @@
/****************************************************************************
**
** 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 "clangdocument.h"
#include "clangfilesystemwatcher.h"
#include <filecontainer.h>
#include <QVector>
#include <functional>
#include <vector>
namespace ClangBackEnd {
class ProjectParts;
class UnsavedFiles;
class Documents
{
public:
Documents(ProjectParts &projectParts, UnsavedFiles &unsavedFiles);
std::vector<Document> create(const QVector<FileContainer> &fileContainers);
std::vector<Document> update(const QVector<FileContainer> &fileContainers);
void remove(const QVector<FileContainer> &fileContainers);
void setUsedByCurrentEditor(const Utf8String &filePath);
void setVisibleInEditors(const Utf8StringVector &filePaths);
const Document &document(const Utf8String &filePath, const Utf8String &projectPartId) const;
const Document &document(const FileContainer &fileContainer) const;
bool hasDocument(const Utf8String &filePath, const Utf8String &projectPartId) const;
bool hasDocumentWithFilePath(const Utf8String &filePath) const;
const std::vector<Document> &documents() const;
using IsMatchingDocument = std::function<bool(const Document &document)>;
const std::vector<Document> filtered(const IsMatchingDocument &isMatchingDocument) const;
std::vector<Document> dirtyAndVisibleButNotCurrentDocuments() const;
UnsavedFiles unsavedFiles() const;
void addWatchedFiles(QSet<Utf8String> &filePaths);
void updateDocumentsWithChangedDependency(const Utf8String &filePath);
void updateDocumentsWithChangedDependencies(const QVector<FileContainer> &fileContainers);
std::vector<Document> setDocumentsDirtyIfProjectPartChanged();
QVector<FileContainer> newerFileContainers(const QVector<FileContainer> &fileContainers) const;
const ClangFileSystemWatcher *clangFileSystemWatcher() const;
private:
Document createDocument(const FileContainer &fileContainer);
std::vector<Document> updateDocument(const FileContainer &fileContainer);
std::vector<Document>::iterator findDocument(const FileContainer &fileContainer);
std::vector<Document> findAllDocumentsWithFilePath(const Utf8String &filePath);
std::vector<Document>::const_iterator findDocument(const Utf8String &filePath, const Utf8String &projectPartId) const;
bool hasDocument(const FileContainer &fileContainer) const;
void checkIfProjectPartExists(const Utf8String &projectFileName) const;
void checkIfProjectPartsExists(const QVector<FileContainer> &fileContainers) const;
void checkIfDocumentsDoNotExist(const QVector<FileContainer> &fileContainers) const;
void checkIfDocumentsForFilePathsExist(const QVector<FileContainer> &fileContainers) const;
void removeDocuments(const QVector<FileContainer> &fileContainers);
private:
ClangFileSystemWatcher fileSystemWatcher;
std::vector<Document> documents_;
ProjectParts &projectParts;
UnsavedFiles &unsavedFiles_;
};
} // namespace ClangBackEnd

View File

@@ -0,0 +1,142 @@
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "clangdocumentsuspenderresumer.h"
#include "clangsupport_global.h"
#include "clangdocumentprocessors.h"
#include "clangdocuments.h"
#include <utils/algorithm.h>
#include <algorithm>
namespace ClangBackEnd {
constexpr int DefaultHotDocumentsSize = 7;
void categorizeHotColdDocuments(int hotDocumentsSize,
const std::vector<Document> &inDocuments,
std::vector<Document> &hotDocuments,
std::vector<Document> &coldDocuments)
{
// Sort documents, most recently used/visible at top
std::vector<Document> documents = inDocuments;
std::stable_sort(documents.begin(), documents.end(), [](const Document &a, const Document &b) {
return a.visibleTimePoint() > b.visibleTimePoint();
});
// Ensure that visible documents are always hot, otherwise not all visible
// documents will be resumed.
const auto isVisible = [](const Document &document) { return document.isVisibleInEditor(); };
const int visibleDocumentsSize = Utils::count(documents, isVisible);
hotDocumentsSize = std::max(hotDocumentsSize, visibleDocumentsSize);
if (documents.size() <= uint(hotDocumentsSize)) {
hotDocuments = documents;
coldDocuments.clear();
} else {
const auto firstColdIterator = documents.begin() + hotDocumentsSize;
hotDocuments = std::vector<Document>(documents.begin(), firstColdIterator);
coldDocuments = std::vector<Document>(firstColdIterator, documents.end());
}
}
#ifdef IS_SUSPEND_SUPPORTED
static int hotDocumentsSize()
{
static int hotDocuments = -1;
if (hotDocuments == -1) {
bool ok = false;
const int fromEnvironment = qEnvironmentVariableIntValue("QTC_CLANG_HOT_DOCUMENTS", &ok);
hotDocuments = ok && fromEnvironment >= 1 ? fromEnvironment : DefaultHotDocumentsSize;
}
return hotDocuments;
}
static SuspendResumeJobs createJobs(const Document &document, JobRequest::Type type)
{
SuspendResumeJobs jobs;
jobs.append({document, type, PreferredTranslationUnit::RecentlyParsed});
if (document.isResponsivenessIncreased())
jobs.append({document, type, PreferredTranslationUnit::PreviouslyParsed});
return jobs;
}
static bool isFineDocument(const Document &document)
{
return !document.isNull() && document.isIntact();
}
static bool isSuspendable(const Document &document)
{
return isFineDocument(document)
&& !document.isSuspended()
&& !document.isVisibleInEditor()
&& document.isParsed();
}
static bool isResumable(const Document &document)
{
return isFineDocument(document)
&& document.isSuspended()
&& document.isVisibleInEditor();
}
#endif // IS_SUSPEND_SUPPORTED
SuspendResumeJobs createSuspendResumeJobs(const std::vector<Document> &documents,
int customHotDocumentSize)
{
Q_UNUSED(documents);
Q_UNUSED(customHotDocumentSize);
SuspendResumeJobs jobs;
#ifdef IS_SUSPEND_SUPPORTED
std::vector<Document> hotDocuments;
std::vector<Document> coldDocuments;
const int size = (customHotDocumentSize == -1) ? hotDocumentsSize() : customHotDocumentSize;
categorizeHotColdDocuments(size, documents, hotDocuments, coldDocuments);
// Cold documents should be suspended...
const std::vector<Document> toSuspend = Utils::filtered(coldDocuments, &isSuspendable);
for (const Document &document : toSuspend)
jobs += createJobs(document, JobRequest::Type::SuspendDocument);
// ...and hot documents that were suspended should be resumed
const std::vector<Document> toResume = Utils::filtered(hotDocuments, &isResumable);
for (const Document &document : toResume)
jobs += createJobs(document, JobRequest::Type::ResumeDocument);
#endif // IS_SUSPEND_SUPPORTED
return jobs;
}
} // namespace ClangBackEnd

View File

@@ -0,0 +1,62 @@
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include "clangdocument.h"
#include "clangjobrequest.h"
#include <vector>
namespace ClangBackEnd {
class SuspendResumeJobsEntry {
public:
SuspendResumeJobsEntry() = default;
SuspendResumeJobsEntry(const Document &document,
JobRequest::Type jobRequestType,
PreferredTranslationUnit preferredTranslationUnit)
: document(document)
, jobRequestType(jobRequestType)
, preferredTranslationUnit(preferredTranslationUnit)
{
}
Document document;
JobRequest::Type jobRequestType = JobRequest::Type::SuspendDocument;
PreferredTranslationUnit preferredTranslationUnit = PreferredTranslationUnit::RecentlyParsed;
};
using SuspendResumeJobs = QVector<SuspendResumeJobsEntry>;
SuspendResumeJobs createSuspendResumeJobs(const std::vector<Document> &documents,
int customHotDocumentCounts = -1);
// for tests
void categorizeHotColdDocuments(int hotDocumentsSize,
const std::vector<Document> &inDocuments,
std::vector<Document> &hotDocuments,
std::vector<Document> &coldDocuments);
} // namespace ClangBackEnd

View File

@@ -0,0 +1,104 @@
/****************************************************************************
**
** 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 "clangexceptions.h"
namespace ClangBackEnd {
const char *ClangBaseException::what() const Q_DECL_NOEXCEPT
{
return m_info.constData();
}
ProjectPartDoNotExistException::ProjectPartDoNotExistException(
const Utf8StringVector &projectPartIds)
{
m_info += Utf8StringLiteral("ProjectPart files ")
+ projectPartIds.join(Utf8StringLiteral(", "))
+ Utf8StringLiteral(" does not exist!");
}
DocumentAlreadyExistsException::DocumentAlreadyExistsException(
const Utf8String &filePath,
const Utf8String &projectPartId)
{
m_info += Utf8StringLiteral("Document '")
+ filePath
+ Utf8StringLiteral("' with the project part id '")
+ projectPartId
+ Utf8StringLiteral("' already exists!");
}
DocumentDoesNotExistException::DocumentDoesNotExistException(const Utf8String &filePath,
const Utf8String &projectPartId)
{
m_info += Utf8StringLiteral("Document '")
+ filePath
+ Utf8StringLiteral("' with the project part id '")
+ projectPartId
+ Utf8StringLiteral("' does not exists!");
}
DocumentFileDoesNotExistException::DocumentFileDoesNotExistException(
const Utf8String &filePath)
{
m_info += Utf8StringLiteral("File ")
+ filePath
+ Utf8StringLiteral(" does not exist in file system!");
}
DocumentIsNullException::DocumentIsNullException()
{
m_info = Utf8String::fromUtf8("Tried to access a null Document!");
}
DocumentProcessorAlreadyExists::DocumentProcessorAlreadyExists(const Utf8String &filePath,
const Utf8String &projectPartId)
{
m_info = Utf8StringLiteral("Document processor for file '")
+ filePath
+ Utf8StringLiteral("' and project part id '")
+ projectPartId
+ Utf8StringLiteral("' already exists!");
}
DocumentProcessorDoesNotExist::DocumentProcessorDoesNotExist(const Utf8String &filePath,
const Utf8String &projectPartId)
{
m_info = Utf8StringLiteral("Document processor for file '")
+ filePath
+ Utf8StringLiteral("' and project part id '")
+ projectPartId
+ Utf8StringLiteral("' does not exist!");
}
TranslationUnitDoesNotExist::TranslationUnitDoesNotExist(const Utf8String &filePath)
{
m_info += Utf8StringLiteral("TranslationUnit for file '")
+ filePath
+ Utf8StringLiteral("' does not exist.");
}
} // namespace ClangBackEnd

View File

@@ -0,0 +1,97 @@
/****************************************************************************
**
** 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 <utf8stringvector.h>
#include <clang-c/Index.h>
#include <exception>
namespace ClangBackEnd {
class ClangBaseException : public std::exception
{
public:
const char *what() const Q_DECL_NOEXCEPT override;
protected:
Utf8String m_info;
};
class ProjectPartDoNotExistException : public ClangBaseException
{
public:
ProjectPartDoNotExistException(const Utf8StringVector &projectPartIds);
};
class DocumentAlreadyExistsException : public ClangBaseException
{
public:
DocumentAlreadyExistsException(const Utf8String &filePath,
const Utf8String &projectPartId);
};
class DocumentDoesNotExistException : public ClangBaseException
{
public:
DocumentDoesNotExistException(const Utf8String &filePath,
const Utf8String &projectPartId);
};
class DocumentFileDoesNotExistException : public ClangBaseException
{
public:
DocumentFileDoesNotExistException(const Utf8String &filePath);
};
class DocumentIsNullException : public ClangBaseException
{
public:
DocumentIsNullException();
};
class DocumentProcessorAlreadyExists : public ClangBaseException
{
public:
DocumentProcessorAlreadyExists(const Utf8String &filePath,
const Utf8String &projectPartId);
};
class DocumentProcessorDoesNotExist : public ClangBaseException
{
public:
DocumentProcessorDoesNotExist(const Utf8String &filePath,
const Utf8String &projectPartId);
};
class TranslationUnitDoesNotExist : public ClangBaseException
{
public:
TranslationUnitDoesNotExist(const Utf8String &filePath);
};
} // namespace ClangBackEnd

View File

@@ -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.
**
****************************************************************************/
#include "clangfilepath.h"
#include <utf8string.h>
#include <QByteArray>
#if defined(Q_OS_WIN)
// Parameterized QDir::toNativeSeparators/-fromNativeSeparators for QByteArray
static inline QByteArray replace(const QByteArray &pathName, char toReplace, char replacement)
{
int i = pathName.indexOf(toReplace);
if (i != -1) {
QByteArray n(pathName);
char * const data = n.data();
data[i++] = replacement;
for (; i < n.length(); ++i) {
if (data[i] == toReplace)
data[i] = replacement;
}
return n;
}
return pathName;
}
#endif
static QByteArray fromNativeSeparatorsForQByteArray(const QByteArray &pathName)
{
#if defined(Q_OS_WIN)
return replace(pathName, '\\', '/');
#else
return pathName;
#endif
}
static QByteArray toNativeSeparatorsForQByteArray(const QByteArray &pathName)
{
#if defined(Q_OS_WIN)
return replace(pathName, '/', '\\');
#else
return pathName;
#endif
}
namespace ClangBackEnd {
Utf8String FilePath::fromNativeSeparators(const Utf8String &pathName)
{
const QByteArray pathNameAsByteArray = pathName.toByteArray();
return Utf8String::fromUtf8(fromNativeSeparatorsForQByteArray(pathNameAsByteArray));
}
Utf8String FilePath::toNativeSeparators(const Utf8String &pathName)
{
const QByteArray pathNameAsByteArray = pathName.toByteArray();
return Utf8String::fromUtf8(toNativeSeparatorsForQByteArray(pathNameAsByteArray));
}
} // namespace ClangBackEnd

View File

@@ -0,0 +1,38 @@
/****************************************************************************
**
** 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
class Utf8String;
namespace ClangBackEnd {
class FilePath {
public:
static Utf8String fromNativeSeparators(const Utf8String &pathName);
static Utf8String toNativeSeparators(const Utf8String &pathName);
};
} // namespace ClangBackEnd

View File

@@ -0,0 +1,91 @@
/****************************************************************************
**
** 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 "clangfilesystemwatcher.h"
#include "clangdocuments.h"
#include <utf8stringvector.h>
#include <QFileInfo>
#include <QStringList>
#include <algorithm>
#include <iterator>
namespace ClangBackEnd {
namespace {
QStringList toStringList(const QSet<Utf8String> &files)
{
QStringList resultList;
resultList.reserve(files.size());
std::copy(files.cbegin(), files.cend(), std::back_inserter(resultList));
return resultList;
}
QStringList filterExistingFiles(QStringList &&filePaths)
{
auto fileExists = [] (const QString &filePath) {
return QFileInfo::exists(filePath);
};
auto startOfNonExistingFilePaths = std::partition(filePaths.begin(),
filePaths.end(),
fileExists);
filePaths.erase(startOfNonExistingFilePaths, filePaths.end());
return filePaths;
}
}
ClangFileSystemWatcher::ClangFileSystemWatcher(Documents &documents)
: documents(documents)
{
connect(&watcher,
&QFileSystemWatcher::fileChanged,
this,
&ClangFileSystemWatcher::updateDocumentsWithChangedDependencies);
}
void ClangFileSystemWatcher::addFiles(const QSet<Utf8String> &filePaths)
{
const auto existingFiles = filterExistingFiles(toStringList(filePaths));
if (!existingFiles.isEmpty())
watcher.addPaths(existingFiles);
}
void ClangFileSystemWatcher::updateDocumentsWithChangedDependencies(const QString &filePath)
{
documents.updateDocumentsWithChangedDependency(filePath);
emit fileChanged(filePath);
}
} // namespace ClangBackEnd

View File

@@ -0,0 +1,57 @@
/****************************************************************************
**
** 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 <QFileSystemWatcher>
#include <QSet>
class Utf8String;
namespace ClangBackEnd {
class Documents;
class ClangFileSystemWatcher : public QObject
{
Q_OBJECT
public:
ClangFileSystemWatcher(Documents &documents);
void addFiles(const QSet<Utf8String> &filePaths);
signals:
void fileChanged(const Utf8String &filePath);
private:
void updateDocumentsWithChangedDependencies(const QString &filePath);
private:
QFileSystemWatcher watcher;
Documents &documents;
};
} // namespace ClangBackEnd

View File

@@ -0,0 +1,337 @@
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "clangfollowsymbol.h"
#include "clangfollowsymboljob.h"
#include "commandlinearguments.h"
#include "cursor.h"
#include "clangstring.h"
#include "sourcerange.h"
#include "clangsupportdebugutils.h"
#include <utils/qtcassert.h>
#include <future>
namespace ClangBackEnd {
namespace {
struct Tokens
{
Tokens(const Tokens &) = delete;
Tokens(const Cursor &cursor) {
tu = cursor.cxTranslationUnit();
clang_tokenize(tu, cursor.cxSourceRange(), &data, &tokenCount);
}
Tokens(const CXTranslationUnit &tu) {
const CXSourceRange range
= clang_getCursorExtent(clang_getTranslationUnitCursor(tu));
clang_tokenize(tu, range, &data, &tokenCount);
}
~Tokens() {
clang_disposeTokens(tu, data, tokenCount);
}
CXToken *data = nullptr;
uint tokenCount = 0;
private:
CXTranslationUnit tu;
};
class FollowSymbolData {
public:
FollowSymbolData() = delete;
FollowSymbolData(const Utf8String &usr, const Utf8String &tokenSpelling, bool isFunctionLike,
std::atomic<bool> &ready)
: m_usr(usr)
, m_spelling(tokenSpelling)
, m_isFunctionLike(isFunctionLike)
, m_ready(ready)
{}
FollowSymbolData(const FollowSymbolData &other)
: m_usr(other.m_usr)
, m_spelling(other.m_spelling)
, m_isFunctionLike(other.m_isFunctionLike)
, m_ready(other.m_ready)
{}
const Utf8String &usr() const { return m_usr; }
const Utf8String &spelling() const { return m_spelling; }
bool isFunctionLike() const { return m_isFunctionLike; }
bool ready() const { return m_ready; }
const SourceRangeContainer &result() const { return m_result; }
void setReady(bool ready = true) { m_ready = ready; }
void setResult(const SourceRangeContainer &result) { m_result = result; }
private:
const Utf8String &m_usr;
const Utf8String &m_spelling;
SourceRangeContainer m_result;
bool m_isFunctionLike;
std::atomic<bool> &m_ready;
};
} // anonymous namespace
static SourceRange getOperatorRange(const CXTranslationUnit tu,
const Tokens &tokens,
uint operatorIndex)
{
const CXSourceLocation start = clang_getTokenLocation(tu, tokens.data[operatorIndex]);
operatorIndex += 2;
while (operatorIndex < tokens.tokenCount
&& !(ClangString(clang_getTokenSpelling(tu, tokens.data[operatorIndex])) == "(")) {
++operatorIndex;
}
const CXSourceLocation end = clang_getTokenLocation(tu, tokens.data[operatorIndex]);
return SourceRange(clang_getRange(start, end));
}
static SourceRangeContainer extractMatchingTokenRange(const Cursor &cursor,
const Utf8String &tokenStr)
{
Tokens tokens(cursor);
const CXTranslationUnit tu = cursor.cxTranslationUnit();
for (uint i = 0; i < tokens.tokenCount; ++i) {
if (!(tokenStr == ClangString(clang_getTokenSpelling(tu, tokens.data[i]))))
continue;
if (cursor.isFunctionLike() || cursor.isConstructorOrDestructor()) {
if (tokenStr == "operator")
return getOperatorRange(tu, tokens, i);
if (i+1 > tokens.tokenCount
|| !(ClangString(clang_getTokenSpelling(tu, tokens.data[i+1])) == "(")) {
continue;
}
}
return SourceRange(clang_getTokenExtent(tu, tokens.data[i]));
}
return SourceRangeContainer();
}
static void handleDeclaration(CXClientData client_data, const CXIdxDeclInfo *declInfo)
{
if (!declInfo || !declInfo->isDefinition)
return;
const Cursor currentCursor(declInfo->cursor);
auto* data = reinterpret_cast<FollowSymbolData*>(client_data);
if (data->ready())
return;
if (data->usr() != currentCursor.canonical().unifiedSymbolResolution())
return;
QString str = Utf8String(currentCursor.displayName());
if (currentCursor.isFunctionLike() || currentCursor.isConstructorOrDestructor()) {
if (!data->isFunctionLike())
return;
str = str.mid(0, str.indexOf('('));
} else if (data->isFunctionLike()) {
return;
}
if (!str.endsWith(data->spelling()))
return;
const CXTranslationUnit tu = clang_Cursor_getTranslationUnit(declInfo->cursor);
Tokens tokens(currentCursor);
for (uint i = 0; i < tokens.tokenCount; ++i) {
Utf8String curSpelling = ClangString(clang_getTokenSpelling(tu, tokens.data[i]));
if (data->spelling() == curSpelling) {
if (data->isFunctionLike()
&& (i+1 >= tokens.tokenCount
|| !(ClangString(clang_getTokenSpelling(tu, tokens.data[i+1])) == "("))) {
continue;
}
data->setResult(SourceRange(clang_getTokenExtent(tu, tokens.data[i])));
data->setReady();
return;
}
}
}
static int getTokenIndex(CXTranslationUnit tu, const Tokens &tokens, uint line, uint column)
{
int tokenIndex = -1;
for (int i = static_cast<int>(tokens.tokenCount - 1); i >= 0; --i) {
const SourceRange range = clang_getTokenExtent(tu, tokens.data[i]);
if (range.contains(line, column)) {
tokenIndex = i;
break;
}
}
return tokenIndex;
}
static IndexerCallbacks createIndexerCallbacks()
{
return {
[](CXClientData client_data, void *) {
auto* data = reinterpret_cast<FollowSymbolData*>(client_data);
return data->ready() ? 1 : 0;
},
[](CXClientData, CXDiagnosticSet, void *) {},
[](CXClientData, CXFile, void *) { return CXIdxClientFile(); },
[](CXClientData, const CXIdxIncludedFileInfo *) { return CXIdxClientFile(); },
[](CXClientData, const CXIdxImportedASTFileInfo *) { return CXIdxClientASTFile(); },
[](CXClientData, void *) { return CXIdxClientContainer(); },
handleDeclaration,
[](CXClientData, const CXIdxEntityRefInfo *) {}
};
}
static SourceRangeContainer followSymbolInDependentFiles(CXIndex index,
const Cursor &cursor,
const Utf8String &tokenSpelling,
const QVector<Utf8String> &dependentFiles,
const CommandLineArguments &currentArgs)
{
int argsCount = 0;
if (currentArgs.data())
argsCount = currentArgs.count() - 1;
const Utf8String usr = cursor.canonical().unifiedSymbolResolution();
// ready is shared for all data in vector
std::atomic<bool> ready {false};
std::vector<FollowSymbolData> dataVector(
dependentFiles.size(),
FollowSymbolData(usr, tokenSpelling,
cursor.isFunctionLike() || cursor.isConstructorOrDestructor(),
ready));
std::vector<std::future<void>> indexFutures;
for (int i = 0; i < dependentFiles.size(); ++i) {
if (i > 0 && ready)
break;
indexFutures.emplace_back(std::async([&, i]() {
TIME_SCOPE_DURATION("Dependent file " + dependentFiles.at(i) + " indexer runner");
const CXIndexAction indexAction = clang_IndexAction_create(index);
IndexerCallbacks callbacks = createIndexerCallbacks();
clang_indexSourceFile(indexAction,
&dataVector[i],
&callbacks,
sizeof(callbacks),
CXIndexOpt_SkipParsedBodiesInSession
| CXIndexOpt_SuppressRedundantRefs
| CXIndexOpt_SuppressWarnings,
dependentFiles.at(i).constData(),
currentArgs.data(),
argsCount,
nullptr,
0,
nullptr,
CXTranslationUnit_SkipFunctionBodies
| CXTranslationUnit_KeepGoing);
clang_IndexAction_dispose(indexAction);
}));
}
for (const std::future<void> &future: indexFutures)
future.wait();
for (const FollowSymbolData &data: dataVector) {
if (!data.result().start().filePath().isEmpty()) {
return data.result();
}
}
return SourceRangeContainer();
}
SourceRangeContainer FollowSymbol::followSymbol(CXTranslationUnit tu,
CXIndex index,
const Cursor &fullCursor,
uint line,
uint column,
const QVector<Utf8String> &dependentFiles,
const CommandLineArguments &currentArgs)
{
std::unique_ptr<Tokens> tokens(new Tokens(fullCursor));
if (!tokens->tokenCount)
tokens.reset(new Tokens(tu));
if (!tokens->tokenCount)
return SourceRangeContainer();
QVector<CXCursor> cursors(static_cast<int>(tokens->tokenCount));
clang_annotateTokens(tu, tokens->data, tokens->tokenCount, cursors.data());
int tokenIndex = getTokenIndex(tu, *tokens, line, column);
QTC_ASSERT(tokenIndex >= 0, return SourceRangeContainer());
const Utf8String tokenSpelling = ClangString(
clang_getTokenSpelling(tu, tokens->data[tokenIndex]));
if (tokenSpelling.isEmpty())
return SourceRangeContainer();
Cursor cursor{cursors[tokenIndex]};
if (cursor.kind() == CXCursor_InclusionDirective) {
CXFile file = clang_getIncludedFile(cursors[tokenIndex]);
const ClangString filename(clang_getFileName(file));
const SourceLocation loc(tu, filename, 1, 1);
return SourceRange(loc, loc);
}
// For definitions we can always find a declaration in current TU
if (cursor.isDefinition())
return extractMatchingTokenRange(cursor.canonical(), tokenSpelling);
SourceRangeContainer result;
if (!cursor.isDeclaration()) {
// This is the symbol usage
// We want to return definition or at least declaration of this symbol
const Cursor referencedCursor = cursor.referenced();
if (referencedCursor.isNull() || referencedCursor == cursor)
return SourceRangeContainer();
result = extractMatchingTokenRange(referencedCursor, tokenSpelling);
// We've already found what we need
if (referencedCursor.isDefinition())
return result;
cursor = referencedCursor;
}
const Cursor definitionCursor = cursor.definition();
if (!definitionCursor.isNull() && definitionCursor != cursor) {
// If we are able to find a definition in current TU
return extractMatchingTokenRange(definitionCursor, tokenSpelling);
}
// Search for the definition in the dependent files
SourceRangeContainer dependentFilesResult = followSymbolInDependentFiles(index,
cursor,
tokenSpelling,
dependentFiles,
currentArgs);
return dependentFilesResult.start().filePath().isEmpty() ?
result : dependentFilesResult;
}
} // namespace ClangBackEnd

View File

@@ -0,0 +1,52 @@
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include <QVector>
#include <clang-c/Index.h>
class Utf8String;
namespace ClangBackEnd {
class Cursor;
class SourceRangeContainer;
class CommandLineArguments;
class FollowSymbol
{
public:
static SourceRangeContainer followSymbol(CXTranslationUnit tu,
CXIndex index,
const Cursor &fullCursor,
uint line,
uint column,
const QVector<Utf8String> &dependentFiles,
const CommandLineArguments &currentArgs);
};
} // namespace ClangBackEnd

View File

@@ -0,0 +1,73 @@
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "clangfollowsymboljob.h"
#include <clangsupport/clangsupportdebugutils.h>
#include <clangsupport/followsymbolmessage.h>
#include <clangsupport/clangcodemodelclientinterface.h>
#include <utils/qtcassert.h>
namespace ClangBackEnd {
IAsyncJob::AsyncPrepareResult FollowSymbolJob::prepareAsyncRun()
{
const JobRequest jobRequest = context().jobRequest;
QTC_ASSERT(jobRequest.type == JobRequest::Type::FollowSymbol,
return AsyncPrepareResult());
QTC_ASSERT(acquireDocument(), return AsyncPrepareResult());
const TranslationUnit translationUnit = *m_translationUnit;
const TranslationUnitUpdateInput updateInput = m_pinnedDocument.createUpdateInput();
const CommandLineArguments currentArgs(updateInput.filePath.constData(),
updateInput.projectArguments,
updateInput.fileArguments,
false);
const quint32 line = jobRequest.line;
const quint32 column = jobRequest.column;
const QVector<Utf8String> &dependentFiles = jobRequest.dependentFiles;
setRunner([translationUnit, line, column, dependentFiles, currentArgs]() {
TIME_SCOPE_DURATION("FollowSymbolJobRunner");
return translationUnit.followSymbol(line, column, dependentFiles, currentArgs);
});
return AsyncPrepareResult{translationUnit.id()};
}
void FollowSymbolJob::finalizeAsyncRun()
{
if (!context().isOutdated()) {
const AsyncResult result = asyncResult();
const FollowSymbolMessage message(m_pinnedFileContainer,
result,
context().jobRequest.ticketNumber);
context().client->followSymbol(message);
}
}
} // namespace ClangBackEnd

View File

@@ -0,0 +1,42 @@
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include "clangdocumentjob.h"
#include <clangsupport/sourcerangecontainer.h>
namespace ClangBackEnd {
class FollowSymbolJob : public DocumentJob<SourceRangeContainer>
{
public:
using AsyncResult = SourceRangeContainer;
AsyncPrepareResult prepareAsyncRun() override;
void finalizeAsyncRun() override;
};
} // namespace ClangBackEnd

View File

@@ -0,0 +1,71 @@
/****************************************************************************
**
** 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"
Q_LOGGING_CATEGORY(jobsLog, "qtc.clangbackend.jobs");
namespace ClangBackEnd {
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

View File

@@ -0,0 +1,74 @@
/****************************************************************************
**
** 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:
struct AsyncPrepareResult {
operator bool() const { return !translationUnitId.isEmpty(); }
Utf8String translationUnitId;
};
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 AsyncPrepareResult prepareAsyncRun() = 0;
virtual QFuture<void> runAsync() = 0;
virtual void finalizeAsyncRun() = 0;
virtual void preventFinalization() = 0;
public: // for tests
bool isFinished() const;
void setIsFinished(bool isFinished);
private:
bool m_isFinished = false;
FinishedHandler m_finishedHandler;
JobContext m_context;
};
} // namespace ClangBackEnd

View File

@@ -0,0 +1,73 @@
/****************************************************************************
**
** 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 "clangdocuments.h"
namespace ClangBackEnd {
JobContext::JobContext(const JobRequest &jobRequest,
Documents *documents,
UnsavedFiles *unsavedFiles,
ClangCodeModelClientInterface *clientInterface)
: jobRequest(jobRequest)
, documents(documents)
, unsavedFiles(unsavedFiles)
, client(clientInterface)
{
}
Document JobContext::documentForJobRequest() const
{
return documents->document(jobRequest.filePath, jobRequest.projectPartId);
}
bool JobContext::isOutdated() const
{
return !isDocumentOpen() || documentRevisionChanged();
}
bool JobContext::isDocumentOpen() const
{
const bool hasDocument = documents->hasDocument(jobRequest.filePath, jobRequest.projectPartId);
if (!hasDocument)
qCDebug(jobsLog) << "Document already closed for results of" << jobRequest;
return hasDocument;
}
bool JobContext::documentRevisionChanged() const
{
const Document &document = documents->document(jobRequest.filePath, jobRequest.projectPartId);
const bool revisionChanged = document.documentRevision() != jobRequest.documentRevision;
if (revisionChanged)
qCDebug(jobsLog) << "Document revision changed for results of" << jobRequest;
return revisionChanged;
}
} // ClangBackEnd

View File

@@ -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 Document;
class Documents;
class UnsavedFiles;
class JobContext
{
public:
JobContext() = default;
JobContext(const JobRequest &jobRequest,
Documents *documents,
UnsavedFiles *unsavedFiles,
ClangCodeModelClientInterface *client);
Document documentForJobRequest() const;
bool isOutdated() const;
bool isDocumentOpen() const;
bool documentRevisionChanged() const;
public:
JobRequest jobRequest;
Documents *documents = nullptr;
UnsavedFiles *unsavedFiles = nullptr;
ClangCodeModelClientInterface *client = nullptr;
};
} // namespace ClangBackEnd

View File

@@ -0,0 +1,313 @@
/****************************************************************************
**
** 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 "clangdocument.h"
#include "clangdocuments.h"
#include "clangtranslationunits.h"
#include "projects.h"
#include "unsavedfiles.h"
#include <utils/algorithm.h>
namespace ClangBackEnd {
JobQueue::JobQueue(Documents &documents, ProjectParts &projectParts)
: m_documents(documents)
, m_projectParts(projectParts)
{
}
bool JobQueue::add(const JobRequest &job)
{
if (m_queue.contains(job)) {
qCDebug(jobsLog) << "Not adding duplicate request" << job;
return false;
}
if (isJobRunningForJobRequest(job)) {
qCDebug(jobsLog) << "Not adding duplicate request for already running job" << job;
return false;
}
if (!m_documents.hasDocument(job.filePath, job.projectPartId)) {
qCDebug(jobsLog) << "Not adding / cancelling due to already closed document:" << job;
cancelJobRequest(job);
return false;
}
const Document document = m_documents.document(job.filePath, job.projectPartId);
if (!document.isIntact()) {
qCDebug(jobsLog) << "Not adding / cancelling due not intact document:" << job;
cancelJobRequest(job);
return false;
}
qCDebug(jobsLog) << "Adding" << job;
m_queue.append(job);
return true;
}
int JobQueue::size() const
{
return m_queue.size();
}
JobRequests JobQueue::processQueue()
{
removeExpiredRequests();
prioritizeRequests();
const JobRequests jobsToRun = takeJobRequestsToRunNow();
return jobsToRun;
}
void JobQueue::removeExpiredRequests()
{
JobRequests cleanedRequests;
foreach (const JobRequest &jobRequest, m_queue) {
try {
if (!isJobRequestExpired(jobRequest))
cleanedRequests.append(jobRequest);
} catch (const std::exception &exception) {
qWarning() << "Error in Jobs::removeOutDatedRequests for"
<< jobRequest << ":" << exception.what();
}
}
m_queue = cleanedRequests;
}
bool JobQueue::isJobRequestExpired(const JobRequest &jobRequest)
{
const JobRequest::ExpirationConditions conditions = jobRequest.expirationConditions;
const UnsavedFiles unsavedFiles = m_documents.unsavedFiles();
using Condition = JobRequest::ExpirationCondition;
if (conditions.testFlag(Condition::UnsavedFilesChanged)) {
if (jobRequest.unsavedFilesChangeTimePoint != unsavedFiles.lastChangeTimePoint()) {
qCDebug(jobsLog) << "Removing due to outdated unsaved files:" << jobRequest;
return true;
}
}
bool projectCheckedAndItExists = false;
if (conditions.testFlag(Condition::DocumentClosed)) {
if (!m_documents.hasDocument(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 Document document
= m_documents.document(jobRequest.filePath, jobRequest.projectPartId);
if (!document.isIntact()) {
qCDebug(jobsLog) << "Removing/Cancelling due to not intact document:" << jobRequest;
cancelJobRequest(jobRequest);
return true;
}
if (conditions.testFlag(Condition::DocumentRevisionChanged)) {
if (document.documentRevision() > jobRequest.documentRevision) {
qCDebug(jobsLog) << "Removing due to changed document revision:" << jobRequest;
return true;
}
}
}
if (conditions.testFlag(Condition::ProjectChanged)) {
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 Document &document)
{
int thePriority = 0;
if (document.isUsedByCurrentEditor())
thePriority += 1000;
if (document.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 Document &t1 = m_documents.document(r1.filePath, r1.projectPartId);
const Document &t2 = m_documents.document(r2.filePath, r2.projectPartId);
return priority(t1) > priority(t2);
};
std::stable_sort(m_queue.begin(), m_queue.end(), lessThan);
}
void JobQueue::cancelJobRequest(const JobRequest &jobRequest)
{
if (m_cancelJobRequest)
m_cancelJobRequest(jobRequest);
}
static bool areRunConditionsMet(const JobRequest &request, const Document &document)
{
using Condition = JobRequest::RunCondition;
const JobRequest::RunConditions conditions = request.runConditions;
if (conditions.testFlag(Condition::DocumentSuspended) && !document.isSuspended()) {
qCDebug(jobsLog) << "Not choosing due to unsuspended document:" << request;
return false;
}
if (conditions.testFlag(Condition::DocumentUnsuspended) && document.isSuspended()) {
qCDebug(jobsLog) << "Not choosing due to suspended document:" << request;
return false;
}
if (conditions.testFlag(Condition::DocumentVisible) && !document.isVisibleInEditor()) {
qCDebug(jobsLog) << "Not choosing due to invisble document:" << request;
return false;
}
if (conditions.testFlag(Condition::DocumentNotVisible) && document.isVisibleInEditor()) {
qCDebug(jobsLog) << "Not choosing due to visble document:" << request;
return false;
}
if (conditions.testFlag(Condition::CurrentDocumentRevision)) {
if (document.isDirty()) {
// TODO: If the document is dirty due to a project update,
// references are processes later than ideal.
qCDebug(jobsLog) << "Not choosing due to dirty document:" << request;
return false;
}
if (request.documentRevision != document.documentRevision()) {
qCDebug(jobsLog) << "Not choosing due to revision mismatch:" << request;
return false;
}
}
return true;
}
JobRequests JobQueue::takeJobRequestsToRunNow()
{
JobRequests jobsToRun;
using TranslationUnitIds = QSet<Utf8String>;
TranslationUnitIds translationUnitsScheduledForThisRun;
QMutableVectorIterator<JobRequest> i(m_queue);
while (i.hasNext()) {
const JobRequest &request = i.next();
try {
const Document &document = m_documents.document(request.filePath,
request.projectPartId);
if (!areRunConditionsMet(request, document))
continue;
const Utf8String id = document.translationUnit(request.preferredTranslationUnit).id();
if (translationUnitsScheduledForThisRun.contains(id))
continue;
if (isJobRunningForTranslationUnit(id))
continue;
translationUnitsScheduledForThisRun.insert(id);
jobsToRun += request;
i.remove();
} catch (const std::exception &exception) {
qWarning() << "Error in Jobs::takeJobRequestsToRunNow for"
<< request << ":" << exception.what();
}
}
return jobsToRun;
}
bool JobQueue::isJobRunningForTranslationUnit(const Utf8String &translationUnitId)
{
if (m_isJobRunningForTranslationUnitHandler)
return m_isJobRunningForTranslationUnitHandler(translationUnitId);
return false;
}
bool JobQueue::isJobRunningForJobRequest(const JobRequest &jobRequest)
{
if (m_isJobRunningForJobRequestHandler)
return m_isJobRunningForJobRequestHandler(jobRequest);
return false;
}
void JobQueue::setIsJobRunningForTranslationUnitHandler(
const IsJobRunningForTranslationUnitHandler &isJobRunningHandler)
{
m_isJobRunningForTranslationUnitHandler = isJobRunningHandler;
}
void JobQueue::setIsJobRunningForJobRequestHandler(
const JobQueue::IsJobRunningForJobRequestHandler &isJobRunningHandler)
{
m_isJobRunningForJobRequestHandler = isJobRunningHandler;
}
void JobQueue::setCancelJobRequest(const JobQueue::CancelJobRequest &cancelJobRequest)
{
m_cancelJobRequest = cancelJobRequest;
}
JobRequests &JobQueue::queue()
{
return m_queue;
}
} // namespace ClangBackEnd

View File

@@ -0,0 +1,81 @@
/****************************************************************************
**
** 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 ProjectParts;
class Documents;
class JobQueue
{
public:
JobQueue(Documents &documents, ProjectParts &projects);
bool add(const JobRequest &job);
JobRequests processQueue();
using IsJobRunningForTranslationUnitHandler = std::function<bool(const Utf8String &)>;
void setIsJobRunningForTranslationUnitHandler(
const IsJobRunningForTranslationUnitHandler &isJobRunningHandler);
using IsJobRunningForJobRequestHandler = std::function<bool(const JobRequest &)>;
void setIsJobRunningForJobRequestHandler(
const IsJobRunningForJobRequestHandler &isJobRunningHandler);
using CancelJobRequest = std::function<void(const JobRequest &)>;
void setCancelJobRequest(const CancelJobRequest &cancelJobRequest);
public: // for tests
JobRequests &queue();
int size() const;
void prioritizeRequests();
private:
void cancelJobRequest(const JobRequest &jobRequest);
bool isJobRunningForTranslationUnit(const Utf8String &translationUnitId);
bool isJobRunningForJobRequest(const JobRequest &jobRequest);
JobRequests takeJobRequestsToRunNow();
void removeExpiredRequests();
bool isJobRequestExpired(const JobRequest &jobRequest);
private:
Documents &m_documents;
ProjectParts &m_projectParts;
IsJobRunningForTranslationUnitHandler m_isJobRunningForTranslationUnitHandler;
IsJobRunningForJobRequestHandler m_isJobRunningForJobRequestHandler;
CancelJobRequest m_cancelJobRequest;
JobRequests m_queue;
};
} // namespace ClangBackEnd

View File

@@ -0,0 +1,258 @@
/****************************************************************************
**
** 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"
#include "clangcompletecodejob.h"
#include "clangcreateinitialdocumentpreamblejob.h"
#include "clangfollowsymboljob.h"
#include "clangparsesupportivetranslationunitjob.h"
#include "clangreparsesupportivetranslationunitjob.h"
#include "clangrequestdocumentannotationsjob.h"
#include "clangrequestreferencesjob.h"
#include "clangresumedocumentjob.h"
#include "clangsuspenddocumentjob.h"
#include "clangupdatedocumentannotationsjob.h"
#include <clangsupport/clangcodemodelclientinterface.h>
#include <clangsupport/cmbcodecompletedmessage.h>
#include <clangsupport/followsymbolmessage.h>
#include <clangsupport/referencesmessage.h>
#include <utils/qtcassert.h>
#include <QFileInfo>
#include <ostream>
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(Invalid);
RETURN_TEXT_FOR_CASE(UpdateDocumentAnnotations);
RETURN_TEXT_FOR_CASE(ParseSupportiveTranslationUnit);
RETURN_TEXT_FOR_CASE(ReparseSupportiveTranslationUnit);
RETURN_TEXT_FOR_CASE(CreateInitialDocumentPreamble);
RETURN_TEXT_FOR_CASE(CompleteCode);
RETURN_TEXT_FOR_CASE(RequestDocumentAnnotations);
RETURN_TEXT_FOR_CASE(RequestReferences);
RETURN_TEXT_FOR_CASE(FollowSymbol);
RETURN_TEXT_FOR_CASE(SuspendDocument);
RETURN_TEXT_FOR_CASE(ResumeDocument);
}
return "UnhandledJobRequestType";
}
#undef RETURN_TEXT_FOR_CASE
#define RETURN_TEXT_FOR_CASE(enumValue) case PreferredTranslationUnit::enumValue: return #enumValue
const char *preferredTranslationUnitToText(PreferredTranslationUnit type)
{
switch (type) {
RETURN_TEXT_FOR_CASE(RecentlyParsed);
RETURN_TEXT_FOR_CASE(PreviouslyParsed);
RETURN_TEXT_FOR_CASE(LastUninitialized);
}
return "UnhandledPreferredTranslationUnitType";
}
#undef RETURN_TEXT_FOR_CASE
QDebug operator<<(QDebug debug, JobRequest::Type type)
{
debug << JobRequestTypeToText(type);
return debug;
}
std::ostream &operator<<(std::ostream &os, JobRequest::Type type)
{
return os << JobRequestTypeToText(type);
}
std::ostream &operator<<(std::ostream &os, PreferredTranslationUnit preferredTranslationUnit)
{
return os << preferredTranslationUnitToText(preferredTranslationUnit);
}
QDebug operator<<(QDebug debug, const JobRequest &jobRequest)
{
debug.nospace() << "Job<"
<< jobRequest.id
<< ","
<< QFileInfo(jobRequest.filePath).fileName()
<< ","
<< JobRequestTypeToText(jobRequest.type)
<< ","
<< preferredTranslationUnitToText(jobRequest.preferredTranslationUnit)
<< ">";
return debug.space();
}
static JobRequest::ExpirationConditions expirationConditionsForType(JobRequest::Type type)
{
using Type = JobRequest::Type;
using Condition = JobRequest::ExpirationCondition;
using Conditions = JobRequest::ExpirationConditions;
switch (type) {
case Type::UpdateDocumentAnnotations:
return Conditions(Condition::AnythingChanged);
case Type::RequestReferences:
case Type::RequestDocumentAnnotations:
case Type::FollowSymbol:
return Conditions(Condition::DocumentClosed)
| Conditions(Condition::DocumentRevisionChanged);
default:
return Condition::DocumentClosed;
}
}
static JobRequest::RunConditions conditionsForType(JobRequest::Type type)
{
using Type = JobRequest::Type;
using Condition = JobRequest::RunCondition;
using Conditions = JobRequest::RunConditions;
if (type == Type::SuspendDocument) {
return Conditions(Condition::DocumentUnsuspended)
| Conditions(Condition::DocumentNotVisible);
}
if (type == Type::ResumeDocument) {
return Conditions(Condition::DocumentSuspended)
| Conditions(Condition::DocumentVisible);
}
Conditions conditions = Conditions(Condition::DocumentUnsuspended)
| Conditions(Condition::DocumentVisible);
if (type == Type::RequestReferences)
conditions |= Condition::CurrentDocumentRevision;
return conditions;
}
JobRequest::JobRequest(Type type)
{
static quint64 idCounter = 0;
id = ++idCounter;
this->type = type;
runConditions = conditionsForType(type);
expirationConditions = expirationConditionsForType(type);
}
IAsyncJob *JobRequest::createJob() const
{
switch (type) {
case JobRequest::Type::Invalid:
QTC_CHECK(false && "Cannot create job for invalid job request.");
break;
case JobRequest::Type::UpdateDocumentAnnotations:
return new UpdateDocumentAnnotationsJob();
case JobRequest::Type::ParseSupportiveTranslationUnit:
return new ParseSupportiveTranslationUnitJob();
case JobRequest::Type::ReparseSupportiveTranslationUnit:
return new ReparseSupportiveTranslationUnitJob();
case JobRequest::Type::CreateInitialDocumentPreamble:
return new CreateInitialDocumentPreambleJob();
case JobRequest::Type::CompleteCode:
return new CompleteCodeJob();
case JobRequest::Type::RequestDocumentAnnotations:
return new RequestDocumentAnnotationsJob();
case JobRequest::Type::RequestReferences:
return new RequestReferencesJob();
case JobRequest::Type::FollowSymbol:
return new FollowSymbolJob();
case JobRequest::Type::SuspendDocument:
return new SuspendDocumentJob();
case JobRequest::Type::ResumeDocument:
return new ResumeDocumentJob();
}
return nullptr;
}
void JobRequest::cancelJob(ClangCodeModelClientInterface &client) const
{
// If a job request with a ticket number is cancelled, the plugin side
// must get back some results in order to clean up the state there.
switch (type) {
case JobRequest::Type::Invalid:
case JobRequest::Type::UpdateDocumentAnnotations:
case JobRequest::Type::ParseSupportiveTranslationUnit:
case JobRequest::Type::ReparseSupportiveTranslationUnit:
case JobRequest::Type::CreateInitialDocumentPreamble:
case JobRequest::Type::RequestDocumentAnnotations:
case JobRequest::Type::SuspendDocument:
case JobRequest::Type::ResumeDocument:
break;
case JobRequest::Type::RequestReferences:
client.references(ReferencesMessage(FileContainer(),
QVector<SourceRangeContainer>(),
false,
ticketNumber));
break;
case JobRequest::Type::CompleteCode:
client.codeCompleted(CodeCompletedMessage(CodeCompletions(),
CompletionCorrection::NoCorrection,
ticketNumber));
break;
case JobRequest::Type::FollowSymbol:
client.followSymbol(FollowSymbolMessage(FileContainer(),
SourceRangeContainer(),
ticketNumber));
break;
}
}
bool JobRequest::operator==(const JobRequest &other) const
{
return type == other.type
&& expirationConditions == other.expirationConditions
&& runConditions == other.runConditions
&& filePath == other.filePath
&& projectPartId == other.projectPartId
&& unsavedFilesChangeTimePoint == other.unsavedFilesChangeTimePoint
&& projectChangeTimePoint == other.projectChangeTimePoint
&& documentRevision == other.documentRevision
&& preferredTranslationUnit == other.preferredTranslationUnit
&& line == other.line
&& column == other.column
&& ticketNumber == other.ticketNumber;
// Additional members that are not compared here explicitly are
// supposed to depend on the already compared ones.
}
} // namespace ClangBackEnd

View File

@@ -0,0 +1,130 @@
/****************************************************************************
**
** 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 "clangbackend_global.h"
#include "clangclock.h"
#include <utf8string.h>
#include <utf8stringvector.h>
#include <QFlags>
#include <QDebug>
#include <QVector>
#include <functional>
namespace ClangBackEnd {
class ClangCodeModelClientInterface;
class Document;
class IAsyncJob;
class JobRequest
{
public:
enum class Type {
Invalid,
UpdateDocumentAnnotations,
CreateInitialDocumentPreamble,
ParseSupportiveTranslationUnit,
ReparseSupportiveTranslationUnit,
CompleteCode,
RequestDocumentAnnotations,
RequestReferences,
FollowSymbol,
SuspendDocument,
ResumeDocument,
};
enum class RunCondition {
NoCondition = 1 << 0,
DocumentVisible = 1 << 1,
DocumentNotVisible = 1 << 2,
DocumentSuspended = 1 << 3,
DocumentUnsuspended = 1 << 4,
CurrentDocumentRevision = 1 << 5,
};
Q_DECLARE_FLAGS(RunConditions, RunCondition)
enum class ExpirationCondition {
Never = 1 << 0,
DocumentClosed = 1 << 1,
DocumentRevisionChanged = 1 << 2, // Only effective if DocumentIsClosed is also set
UnsavedFilesChanged = 1 << 3,
ProjectChanged = 1 << 4,
AnythingChanged = DocumentClosed
| DocumentRevisionChanged
| UnsavedFilesChanged
| ProjectChanged,
};
Q_DECLARE_FLAGS(ExpirationConditions, ExpirationCondition)
public:
JobRequest(Type type = Type::Invalid);
IAsyncJob *createJob() const;
void cancelJob(ClangCodeModelClientInterface &client) const;
bool operator==(const JobRequest &other) const;
public:
quint64 id = 0;
Type type;
ExpirationConditions expirationConditions;
RunConditions runConditions;
// General
Utf8String filePath;
Utf8String projectPartId;
TimePoint unsavedFilesChangeTimePoint;
TimePoint projectChangeTimePoint;
uint documentRevision = 0;
PreferredTranslationUnit preferredTranslationUnit = PreferredTranslationUnit::RecentlyParsed;
// Specific to some jobs
quint32 line = 0;
quint32 column = 0;
qint32 funcNameStartLine = -1;
qint32 funcNameStartColumn = -1;
quint64 ticketNumber = 0;
Utf8StringVector dependentFiles;
};
using JobRequests = QVector<JobRequest>;
QDebug operator<<(QDebug debug, const JobRequest &jobRequest);
std::ostream &operator<<(std::ostream &os, JobRequest::Type type);
std::ostream &operator<<(std::ostream &os, PreferredTranslationUnit preferredTranslationUnit);
} // namespace ClangBackEnd

View File

@@ -0,0 +1,200 @@
/****************************************************************************
**
** 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 "clangdocument.h"
#include "clangiasyncjob.h"
#include "projects.h"
#include <QDebug>
#include <QFutureSynchronizer>
#include <QLoggingCategory>
#include <utils/algorithm.h>
#include <utils/qtcassert.h>
namespace ClangBackEnd {
Jobs::Jobs(Documents &documents,
UnsavedFiles &unsavedFiles,
ProjectParts &projectParts,
ClangCodeModelClientInterface &client)
: m_documents(documents)
, m_unsavedFiles(unsavedFiles)
, m_projectParts(projectParts)
, m_client(client)
, m_queue(documents, projectParts)
{
m_queue.setIsJobRunningForTranslationUnitHandler([this](const Utf8String &translationUnitId) {
return isJobRunningForTranslationUnit(translationUnitId);
});
m_queue.setIsJobRunningForJobRequestHandler([this](const JobRequest &jobRequest) {
return isJobRunningForJobRequest(jobRequest);
});
m_queue.setCancelJobRequest([this](const JobRequest &jobRequest) {
jobRequest.cancelJob(m_client);
});
}
Jobs::~Jobs()
{
foreach (IAsyncJob *asyncJob, m_running.keys())
asyncJob->preventFinalization();
QFutureSynchronizer<void> waitForFinishedJobs;
foreach (const RunningJob &runningJob, m_running.values())
waitForFinishedJobs.addFuture(runningJob.future);
foreach (IAsyncJob *asyncJob, m_running.keys())
delete asyncJob;
}
JobRequest Jobs::createJobRequest(const Document &document,
JobRequest::Type type,
PreferredTranslationUnit preferredTranslationUnit) const
{
JobRequest jobRequest(type);
jobRequest.filePath = document.filePath();
jobRequest.projectPartId = document.projectPart().id();
jobRequest.unsavedFilesChangeTimePoint = m_unsavedFiles.lastChangeTimePoint();
jobRequest.documentRevision = document.documentRevision();
jobRequest.preferredTranslationUnit = preferredTranslationUnit;
const ProjectPart &projectPart = m_projectParts.project(document.projectPart().id());
jobRequest.projectChangeTimePoint = projectPart.lastChangeTimePoint();
return jobRequest;
}
void Jobs::add(const JobRequest &job)
{
m_queue.add(job);
}
void Jobs::add(const Document &document,
JobRequest::Type type,
PreferredTranslationUnit preferredTranslationUnit)
{
const JobRequest jobRequest = createJobRequest(document, type, preferredTranslationUnit);
m_queue.add(jobRequest);
}
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)
{
IAsyncJob *asyncJob = jobRequest.createJob();
QTC_ASSERT(asyncJob, return false);
JobContext context(jobRequest, &m_documents, &m_unsavedFiles, &m_client);
asyncJob->setContext(context);
if (const IAsyncJob::AsyncPrepareResult prepareResult = asyncJob->prepareAsyncRun()) {
qCDebug(jobsLog) << "Running" << jobRequest
<< "with TranslationUnit" << prepareResult.translationUnitId;
asyncJob->setFinishedHandler([this](IAsyncJob *asyncJob){ onJobFinished(asyncJob); });
const QFuture<void> future = asyncJob->runAsync();
const RunningJob runningJob{jobRequest, prepareResult.translationUnitId, future};
m_running.insert(asyncJob, runningJob);
return true;
} else {
qCDebug(jobsLog) << "Preparation failed for " << jobRequest;
delete asyncJob;
}
return false;
}
void Jobs::onJobFinished(IAsyncJob *asyncJob)
{
qCDebug(jobsLog) << "Finishing" << asyncJob->context().jobRequest;
if (m_jobFinishedCallback) {
const RunningJob runningJob = m_running.value(asyncJob);
m_jobFinishedCallback(runningJob);
}
m_running.remove(asyncJob);
delete asyncJob;
process();
}
void Jobs::setJobFinishedCallback(const JobFinishedCallback &jobFinishedCallback)
{
m_jobFinishedCallback = jobFinishedCallback;
}
QList<Jobs::RunningJob> Jobs::runningJobs() const
{
return m_running.values();
}
JobRequests &Jobs::queue()
{
return m_queue.queue();
}
bool Jobs::isJobRunningForTranslationUnit(const Utf8String &translationUnitId) const
{
const auto hasTranslationUnitId = [translationUnitId](const RunningJob &runningJob) {
return runningJob.translationUnitId == translationUnitId;
};
return Utils::anyOf(m_running.values(), hasTranslationUnitId);
}
bool Jobs::isJobRunningForJobRequest(const JobRequest &jobRequest) const
{
const auto hasJobRequest = [jobRequest](const RunningJob &runningJob) {
return runningJob.jobRequest == jobRequest;
};
return Utils::anyOf(m_running.values(), hasJobRequest);
}
} // namespace ClangBackEnd

View File

@@ -0,0 +1,98 @@
/****************************************************************************
**
** 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 <clangsupport/clangcodemodelclientinterface.h>
#include <QFuture>
#include <functional>
namespace ClangBackEnd {
class ClangCodeModelClientInterface;
class Documents;
class IAsyncJob;
class UnsavedFiles;
class Jobs
{
public:
struct RunningJob {
JobRequest jobRequest;
Utf8String translationUnitId;
QFuture<void> future;
};
using RunningJobs = QHash<IAsyncJob *, RunningJob>;
using JobFinishedCallback = std::function<void(RunningJob)>;
public:
Jobs(Documents &documents,
UnsavedFiles &unsavedFiles,
ProjectParts &projects,
ClangCodeModelClientInterface &client);
~Jobs();
JobRequest createJobRequest(const Document &document, JobRequest::Type type,
PreferredTranslationUnit preferredTranslationUnit
= PreferredTranslationUnit::RecentlyParsed) const;
void add(const JobRequest &job);
void add(const Document &document,
JobRequest::Type type,
PreferredTranslationUnit preferredTranslationUnit
= PreferredTranslationUnit::RecentlyParsed);
JobRequests process();
void setJobFinishedCallback(const JobFinishedCallback &jobFinishedCallback);
public /*for tests*/:
QList<RunningJob> runningJobs() const;
JobRequests &queue();
bool isJobRunningForTranslationUnit(const Utf8String &translationUnitId) const;
bool isJobRunningForJobRequest(const JobRequest &jobRequest) const;
private:
JobRequests runJobs(const JobRequests &jobRequest);
bool runJob(const JobRequest &jobRequest);
void onJobFinished(IAsyncJob *asyncJob);
private:
Documents &m_documents;
UnsavedFiles &m_unsavedFiles;
ProjectParts &m_projectParts;
ClangCodeModelClientInterface &m_client;
JobQueue m_queue;
RunningJobs m_running;
JobFinishedCallback m_jobFinishedCallback;
};
} // namespace ClangBackEnd

View File

@@ -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.
**
****************************************************************************/
#include "clangparsesupportivetranslationunitjob.h"
#include <clangsupport/clangsupportdebugutils.h>
#include <utils/qtcassert.h>
namespace ClangBackEnd {
IAsyncJob::AsyncPrepareResult ParseSupportiveTranslationUnitJob::prepareAsyncRun()
{
const JobRequest jobRequest = context().jobRequest;
QTC_ASSERT(jobRequest.type == JobRequest::Type::ParseSupportiveTranslationUnit, return AsyncPrepareResult());
QTC_ASSERT(acquireDocument(), return AsyncPrepareResult());
const TranslationUnit translationUnit = *m_translationUnit;
const TranslationUnitUpdateInput updateInput = m_pinnedDocument.createUpdateInput();
setRunner([translationUnit, updateInput]() {
TIME_SCOPE_DURATION("ParseSupportiveTranslationUnitJob");
TranslationUnitUpdateInput theUpdateInput = updateInput;
theUpdateInput.parseNeeded = true;
return translationUnit.update(updateInput);
});
return AsyncPrepareResult{translationUnit.id()};
}
void ParseSupportiveTranslationUnitJob::finalizeAsyncRun()
{
}
} // namespace ClangBackEnd

View File

@@ -0,0 +1,42 @@
/****************************************************************************
**
** 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 "clangdocumentjob.h"
#include "clangtranslationunitupdater.h"
namespace ClangBackEnd {
class ParseSupportiveTranslationUnitJob : public DocumentJob<TranslationUnitUpdateResult>
{
public:
using AsyncResult = TranslationUnitUpdateResult;
AsyncPrepareResult prepareAsyncRun() override;
void finalizeAsyncRun() override;
};
} // namespace ClangBackEnd

View File

@@ -0,0 +1,248 @@
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "clangreferencescollector.h"
#include "clangstring.h"
#include "cursor.h"
#include "sourcerange.h"
#include <clangsupport/sourcerangecontainer.h>
#include <utils/qtcassert.h>
#include <utf8string.h>
#include <QDebug>
namespace ClangBackEnd {
namespace {
class ReferencedCursor
{
public:
static ReferencedCursor find(const Cursor &cursor)
{
// Query the referenced cursor directly instead of first testing with cursor.isReference().
// cursor.isReference() reports false for e.g. CXCursor_DeclRefExpr or CXCursor_CallExpr
// although it returns a valid cursor.
const Cursor referenced = cursor.referenced();
if (referenced.isValid())
return handleReferenced(referenced);
const Cursor definition = cursor.definition();
if (definition.isValid())
return definition;
return cursor;
}
Utf8String usr() const
{
return cursor.unifiedSymbolResolution() + usrSuffix;
}
bool isLocalVariable() const
{
return cursor.isLocalVariable();
}
private:
ReferencedCursor(const Cursor &cursor, const Utf8String &usrSuffix = Utf8String())
: cursor(cursor)
, usrSuffix(usrSuffix)
{}
static ReferencedCursor handleReferenced(const Cursor &cursor)
{
if (cursor.kind() == CXCursor_OverloadedDeclRef) {
// e.g. Text cursor is on "App" of "using N::App;".
if (cursor.overloadedDeclarationsCount() >= 1)
return cursor.overloadedDeclaration(0);
}
if (cursor.isConstructorOrDestructor()) {
const Type type = cursor.type();
if (type.isValid()) {
const Cursor typeDeclaration = type.declaration();
if (typeDeclaration.isValid()) {
// A CXCursor_CallExpr like "new Foo" has a type of CXType_Record and its
// declaration is e.g. CXCursor_ClassDecl.
return typeDeclaration;
} else {
// A CXCursor_Constructor like "Foo();" has a type of CXType_FunctionProto
// and its type declaration is invalid, so use the semantic parent.
const Cursor parent = cursor.semanticParent();
if (parent.isValid())
return parent;
}
}
}
if (cursor.isFunctionLike() || cursor.isTemplateLike()) {
const Cursor parent = cursor.semanticParent();
const ClangString spelling = cursor.spelling();
return {parent, Utf8StringLiteral("_qtc_") + Utf8String(spelling)};
}
return cursor;
}
private:
Cursor cursor;
Utf8String usrSuffix;
};
class ReferencesCollector
{
public:
ReferencesCollector(CXTranslationUnit cxTranslationUnit);
~ReferencesCollector();
ReferencesResult collect(uint line, uint column) const;
private:
bool isWithinTokenRange(CXToken token, uint line, uint column) const;
bool pointsToIdentifier(uint line, uint column, unsigned *tokenIndex) const;
bool matchesIdentifier(const CXToken &token, const Utf8String &identifier) const;
bool checkToken(unsigned index, const Utf8String &identifier, const Utf8String &usr) const;
private:
CXTranslationUnit m_cxTranslationUnit = nullptr;
CXToken *m_cxTokens = nullptr;
uint m_cxTokenCount = 0;
QVector<CXCursor> m_cxCursors;
};
ReferencesCollector::ReferencesCollector(CXTranslationUnit cxTranslationUnit)
: m_cxTranslationUnit(cxTranslationUnit)
{
const CXSourceRange range
= clang_getCursorExtent(clang_getTranslationUnitCursor(m_cxTranslationUnit));
clang_tokenize(cxTranslationUnit, range, &m_cxTokens, &m_cxTokenCount);
m_cxCursors.resize(static_cast<int>(m_cxTokenCount));
clang_annotateTokens(cxTranslationUnit, m_cxTokens, m_cxTokenCount, m_cxCursors.data());
}
ReferencesCollector::~ReferencesCollector()
{
clang_disposeTokens(m_cxTranslationUnit, m_cxTokens, m_cxTokenCount);
}
bool ReferencesCollector::isWithinTokenRange(CXToken token, uint line, uint column) const
{
const SourceRange range = clang_getTokenExtent(m_cxTranslationUnit, token);
return range.contains(line, column);
}
bool ReferencesCollector::pointsToIdentifier(uint line, uint column, unsigned *tokenIndex) const
{
for (uint i = 0; i < m_cxTokenCount; ++i) {
const CXToken token = m_cxTokens[i];
if (clang_getTokenKind(token) == CXToken_Identifier
&& isWithinTokenRange(token, line, column)) {
*tokenIndex = i;
return true;
}
}
return false;
}
bool ReferencesCollector::matchesIdentifier(const CXToken &token,
const Utf8String &identifier) const
{
const CXTokenKind tokenKind = clang_getTokenKind(token);
if (tokenKind == CXToken_Identifier) {
const Utf8String candidateIdentifier
= ClangString(clang_getTokenSpelling(m_cxTranslationUnit, token));
return candidateIdentifier == identifier;
}
return false;
}
bool ReferencesCollector::checkToken(unsigned index, const Utf8String &identifier,
const Utf8String &usr) const
{
const CXToken token = m_cxTokens[index];
if (!matchesIdentifier(token, identifier))
return false;
{ // For debugging only
// const SourceRange range = clang_getTokenExtent(m_cxTranslationUnit, token);
// const uint line = range.start().line();
// const ClangString spellingCs = clang_getTokenSpelling(m_cxTranslationUnit, token);
// const Utf8String spelling = spellingCs;
// qWarning() << "ReferencesCollector::checkToken:" << line << spelling;
}
const Cursor currentCursor(m_cxCursors[static_cast<int>(index)]);
const ReferencedCursor candidate = ReferencedCursor::find(currentCursor);
return candidate.usr() == usr;
}
ReferencesResult ReferencesCollector::collect(uint line, uint column) const
{
ReferencesResult result;
unsigned index = 0;
if (!pointsToIdentifier(line, column, &index))
return result;
const Cursor cursorFromUser = m_cxCursors[static_cast<int>(index)];
const ReferencedCursor refCursor = ReferencedCursor::find(cursorFromUser);
const Utf8String usr = refCursor.usr();
if (usr.isEmpty())
return result;
const CXToken token = m_cxTokens[index];
const Utf8String identifier = ClangString(clang_getTokenSpelling(m_cxTranslationUnit, token));
for (uint i = 0; i < m_cxTokenCount; ++i) {
if (checkToken(i, identifier, usr)) {
const SourceRange range = clang_getTokenExtent(m_cxTranslationUnit, m_cxTokens[i]);
result.references.append(range);
}
}
result.isLocalVariable = refCursor.isLocalVariable();
return result;
}
} // anonymous namespace
ReferencesResult collectReferences(CXTranslationUnit cxTranslationUnit,
uint line,
uint column)
{
ReferencesCollector collector(cxTranslationUnit);
return collector.collect(line, column);
}
} // namespace ClangBackEnd

View File

@@ -0,0 +1,60 @@
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include <clangsupport/sourcerangecontainer.h>
#include <QVector>
#include <clang-c/Index.h>
namespace ClangBackEnd {
class ReferencesResult
{
public:
ReferencesResult() = default;
ReferencesResult(bool isLocalVariable, const QVector<SourceRangeContainer> &references)
: isLocalVariable(isLocalVariable)
, references(references)
{}
bool operator==(const ReferencesResult &other) const
{
return isLocalVariable == other.isLocalVariable
&& references == other.references;
}
bool isLocalVariable = false;
QVector<SourceRangeContainer> references;
};
ReferencesResult collectReferences(CXTranslationUnit cxTranslationUnit,
uint line,
uint column);
} // namespace ClangBackEnd

View File

@@ -0,0 +1,66 @@
/****************************************************************************
**
** 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 "clangreparsesupportivetranslationunitjob.h"
#include <clangsupport/clangsupportdebugutils.h>
#include <utils/qtcassert.h>
namespace ClangBackEnd {
IAsyncJob::AsyncPrepareResult ReparseSupportiveTranslationUnitJob::prepareAsyncRun()
{
const JobRequest jobRequest = context().jobRequest;
QTC_ASSERT(jobRequest.type == JobRequest::Type::ReparseSupportiveTranslationUnit, return AsyncPrepareResult());
QTC_ASSERT(acquireDocument(), return AsyncPrepareResult());
const TranslationUnit translationUnit = *m_translationUnit;
const TranslationUnitUpdateInput updateInput = m_pinnedDocument.createUpdateInput();
setRunner([translationUnit, updateInput]() {
TIME_SCOPE_DURATION("ReparseSupportiveTranslationUnitJob");
TranslationUnitUpdateInput theUpdateInput = updateInput;
theUpdateInput.reparseNeeded = true;
ReparseSupportiveTranslationUnitJob::AsyncResult asyncResult;
asyncResult.updateResult = translationUnit.reparse(theUpdateInput);
return asyncResult;
});
return AsyncPrepareResult{translationUnit.id()};
}
void ReparseSupportiveTranslationUnitJob::finalizeAsyncRun()
{
if (!context().isOutdated()) {
const AsyncResult result = asyncResult();
m_pinnedDocument.incorporateUpdaterResult(result.updateResult);
}
}
} // namespace ClangBackEnd

View File

@@ -0,0 +1,46 @@
/****************************************************************************
**
** 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 "clangdocumentjob.h"
namespace ClangBackEnd {
struct ReparseSupportiveTranslationUnitJobResult
{
TranslationUnitUpdateResult updateResult;
};
class ReparseSupportiveTranslationUnitJob : public DocumentJob<ReparseSupportiveTranslationUnitJobResult>
{
public:
using AsyncResult = ReparseSupportiveTranslationUnitJobResult;
AsyncPrepareResult prepareAsyncRun() override;
void finalizeAsyncRun() override;
};
} // namespace ClangBackEnd

View File

@@ -0,0 +1,71 @@
/****************************************************************************
**
** 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 <clangsupport/clangsupportdebugutils.h>
#include <clangsupport/documentannotationschangedmessage.h>
#include <clangsupport/clangcodemodelclientinterface.h>
#include <utils/qtcassert.h>
namespace ClangBackEnd {
IAsyncJob::AsyncPrepareResult RequestDocumentAnnotationsJob::prepareAsyncRun()
{
const JobRequest jobRequest = context().jobRequest;
QTC_ASSERT(jobRequest.type == JobRequest::Type::RequestDocumentAnnotations,
return AsyncPrepareResult());
QTC_ASSERT(acquireDocument(), return AsyncPrepareResult());
const TranslationUnit translationUnit = *m_translationUnit;
setRunner([translationUnit]() {
TIME_SCOPE_DURATION("RequestDocumentAnnotationsJobRunner");
RequestDocumentAnnotationsJob::AsyncResult asyncResult;
translationUnit.extractDocumentAnnotations(asyncResult.firstHeaderErrorDiagnostic,
asyncResult.diagnostics,
asyncResult.highlightingMarks,
asyncResult.skippedSourceRanges);
return asyncResult;
});
return AsyncPrepareResult{translationUnit.id()};
}
void RequestDocumentAnnotationsJob::finalizeAsyncRun()
{
if (context().isDocumentOpen()) {
const AsyncResult result = asyncResult();
context().client->documentAnnotationsChanged(
DocumentAnnotationsChangedMessage(m_pinnedFileContainer,
result.diagnostics,
result.firstHeaderErrorDiagnostic,
result.highlightingMarks,
result.skippedSourceRanges));
}
}
} // namespace ClangBackEnd

View File

@@ -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 "clangdocumentjob.h"
#include <clangsupport/diagnosticcontainer.h>
#include <clangsupport/highlightingmarkcontainer.h>
#include <clangsupport/sourcerangecontainer.h>
namespace ClangBackEnd {
struct RequestDocumentAnnotationsJobResult
{
ClangBackEnd::DiagnosticContainer firstHeaderErrorDiagnostic;
QVector<ClangBackEnd::DiagnosticContainer> diagnostics;
QVector<HighlightingMarkContainer> highlightingMarks;
QVector<SourceRangeContainer> skippedSourceRanges;
};
class RequestDocumentAnnotationsJob : public DocumentJob<RequestDocumentAnnotationsJobResult>
{
public:
using AsyncResult = RequestDocumentAnnotationsJobResult;
AsyncPrepareResult prepareAsyncRun() override;
void finalizeAsyncRun() override;
};
} // namespace ClangBackEnd

View File

@@ -0,0 +1,67 @@
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "clangrequestreferencesjob.h"
#include <clangsupport/clangsupportdebugutils.h>
#include <clangsupport/referencesmessage.h>
#include <clangsupport/clangcodemodelclientinterface.h>
#include <utils/qtcassert.h>
namespace ClangBackEnd {
IAsyncJob::AsyncPrepareResult RequestReferencesJob::prepareAsyncRun()
{
const JobRequest jobRequest = context().jobRequest;
QTC_ASSERT(jobRequest.type == JobRequest::Type::RequestReferences,
return AsyncPrepareResult());
QTC_ASSERT(acquireDocument(), return AsyncPrepareResult());
const TranslationUnit translationUnit = *m_translationUnit;
const quint32 line = jobRequest.line;
const quint32 column = jobRequest.column;
setRunner([translationUnit, line, column]() {
TIME_SCOPE_DURATION("RequestReferencesJobRunner");
return translationUnit.references(line, column);
});
return AsyncPrepareResult{translationUnit.id()};
}
void RequestReferencesJob::finalizeAsyncRun()
{
if (!context().isOutdated()) {
const AsyncResult result = asyncResult();
const ReferencesMessage message(m_pinnedFileContainer,
result.references,
result.isLocalVariable,
context().jobRequest.ticketNumber);
context().client->references(message);
}
}
} // namespace ClangBackEnd

View File

@@ -0,0 +1,42 @@
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include "clangdocumentjob.h"
#include "clangreferencescollector.h"
namespace ClangBackEnd {
class RequestReferencesJob : public DocumentJob<ReferencesResult>
{
public:
using AsyncResult = ReferencesResult;
AsyncPrepareResult prepareAsyncRun() override;
void finalizeAsyncRun() override;
};
} // namespace ClangBackEnd

View File

@@ -0,0 +1,54 @@
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "clangresumedocumentjob.h"
#include <utils/qtcassert.h>
namespace ClangBackEnd {
void ResumeDocumentJob::finalizeAsyncRun()
{
if (context().isDocumentOpen()) {
if (QTC_GUARD(asyncResult().updateResult.hasReparsed()))
m_pinnedDocument.setIsSuspended(false);
}
UpdateDocumentAnnotationsJob::finalizeAsyncRun();
}
bool ResumeDocumentJob::isExpectedJobRequestType(const JobRequest &jobRequest) const
{
return jobRequest.type == JobRequest::Type::ResumeDocument;
}
TranslationUnitUpdateInput ResumeDocumentJob::createUpdateInput(const Document &document) const
{
TranslationUnitUpdateInput input = UpdateDocumentAnnotationsJob::createUpdateInput(document);
input.reparseNeeded = true;
return input;
}
} // namespace ClangBackEnd

View File

@@ -0,0 +1,44 @@
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include "clangasyncjob.h"
#include "clangdocument.h"
#include "clangupdatedocumentannotationsjob.h"
namespace ClangBackEnd {
class ResumeDocumentJob : public UpdateDocumentAnnotationsJob
{
public:
void finalizeAsyncRun() override;
private:
bool isExpectedJobRequestType(const JobRequest &jobRequest) const override;
TranslationUnitUpdateInput createUpdateInput(const Document &document) const override;
};
} // namespace ClangBackEnd

View File

@@ -0,0 +1,135 @@
/****************************************************************************
**
** 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 <clang-c/CXString.h>
#include <utf8string.h>
#include <cstring>
#include <ostream>
namespace ClangBackEnd {
class ClangString
{
public:
ClangString(CXString cxString)
: cxString(cxString)
{
}
~ClangString()
{
clang_disposeString(cxString);
}
ClangString(const ClangString &) = delete;
const ClangString &operator=(const ClangString &) = delete;
ClangString(ClangString &&other)
: cxString(std::move(other.cxString))
{
other.cxString.data = nullptr;
other.cxString.private_flags = 0;
}
ClangString &operator=(ClangString &&other)
{
if (this != &other) {
clang_disposeString(cxString);
cxString = std::move(other.cxString);
other.cxString.data = nullptr;
other.cxString.private_flags = 0;
}
return *this;
}
const char *cString() const
{
return clang_getCString(cxString);
}
operator Utf8String() const
{
return Utf8String(cString(), -1);
}
bool isNull() const
{
return cxString.data == nullptr;
}
bool hasContent() const
{
return !isNull() && std::strlen(cString()) > 0;
}
friend bool operator==(const ClangString &first, const ClangString &second)
{
return std::strcmp(first.cString(), second.cString()) == 0;
}
template<std::size_t Size>
friend bool operator==(const ClangString &first, const char(&second)[Size])
{
return std::strncmp(first.cString(), second, Size) == 0; // Size includes \0
}
template<std::size_t Size>
friend bool operator==(const char(&first)[Size], const ClangString &second)
{
return second == first;
}
template<typename Type,
typename = typename std::enable_if<std::is_pointer<Type>::value>::type
>
friend bool operator==(const ClangString &first, Type second)
{
return std::strcmp(first.cString(), second) == 0;
}
template<typename Type,
typename = typename std::enable_if<std::is_pointer<Type>::value>::type
>
friend bool operator==(Type first, const ClangString &second)
{
return second == first;
}
friend std::ostream &operator<<(std::ostream &os, const ClangString &string)
{
return os << string.cString();
}
private:
CXString cxString;
};
} // namespace ClangBackEnd

View File

@@ -0,0 +1,134 @@
/****************************************************************************
**
** 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 "clangsupportivetranslationunitinitializer.h"
#include "clangjobs.h"
#include "clangtranslationunits.h"
#include "projectpart.h"
#include <utils/qtcassert.h>
namespace ClangBackEnd {
// TODO: Check translation unit id?
SupportiveTranslationUnitInitializer::SupportiveTranslationUnitInitializer(
const Document &document,
Jobs &jobs)
: m_document(document)
, m_jobs(jobs)
{
}
void SupportiveTranslationUnitInitializer::setIsDocumentClosedChecker(
const IsDocumentClosedChecker &isDocumentClosedChecker)
{
m_isDocumentClosedChecker = isDocumentClosedChecker;
}
SupportiveTranslationUnitInitializer::State SupportiveTranslationUnitInitializer::state() const
{
return m_state;
}
void SupportiveTranslationUnitInitializer::startInitializing()
{
QTC_CHECK(m_state == State::NotInitialized);
if (abortIfDocumentIsClosed())
return;
m_document.translationUnits().createAndAppend();
m_jobs.setJobFinishedCallback([this](const Jobs::RunningJob &runningJob) {
checkIfParseJobFinished(runningJob);
});
addJob(JobRequest::Type::ParseSupportiveTranslationUnit);
m_jobs.process();
m_state = State::WaitingForParseJob;
}
void SupportiveTranslationUnitInitializer::checkIfParseJobFinished(const Jobs::RunningJob &job)
{
QTC_CHECK(m_state == State::WaitingForParseJob);
if (abortIfDocumentIsClosed())
return;
if (job.jobRequest.type == JobRequest::Type::ParseSupportiveTranslationUnit) {
m_jobs.setJobFinishedCallback([this](const Jobs::RunningJob &runningJob) {
checkIfReparseJobFinished(runningJob);
});
addJob(JobRequest::Type::ReparseSupportiveTranslationUnit);
m_state = State::WaitingForReparseJob;
}
}
void SupportiveTranslationUnitInitializer::checkIfReparseJobFinished(const Jobs::RunningJob &job)
{
QTC_CHECK(m_state == State::WaitingForReparseJob);
if (abortIfDocumentIsClosed())
return;
if (job.jobRequest.type == JobRequest::Type::ReparseSupportiveTranslationUnit) {
if (m_document.translationUnits().areAllTranslationUnitsParsed()) {
m_jobs.setJobFinishedCallback(nullptr);
m_state = State::Initialized;
} else {
// The supportive translation unit was reparsed, but the document
// revision changed in the meanwhile, so try again.
addJob(JobRequest::Type::ReparseSupportiveTranslationUnit);
}
}
}
bool SupportiveTranslationUnitInitializer::abortIfDocumentIsClosed()
{
QTC_CHECK(m_isDocumentClosedChecker);
if (m_isDocumentClosedChecker(m_document.filePath(), m_document.projectPart().id())) {
m_state = State::Aborted;
return true;
}
return false;
}
void SupportiveTranslationUnitInitializer::addJob(JobRequest::Type jobRequestType)
{
const JobRequest jobRequest = m_jobs.createJobRequest(
m_document, jobRequestType, PreferredTranslationUnit::LastUninitialized);
m_jobs.add(jobRequest);
}
void SupportiveTranslationUnitInitializer::setState(const State &state)
{
m_state = state;
}
} // namespace ClangBackEnd

View File

@@ -0,0 +1,73 @@
/****************************************************************************
**
** 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 "clangdocument.h"
#include "clangjobs.h"
#include <functional>
#pragma once
namespace ClangBackEnd {
class SupportiveTranslationUnitInitializer
{
public:
using IsDocumentClosedChecker = std::function<bool(const Utf8String &, const Utf8String &)>;
enum class State {
NotInitialized,
WaitingForParseJob,
WaitingForReparseJob,
Initialized,
Aborted
};
public:
SupportiveTranslationUnitInitializer(const Document &document, Jobs &jobs);
void setIsDocumentClosedChecker(const IsDocumentClosedChecker &isDocumentClosedChecker);
State state() const;
void startInitializing();
public: // for tests
void setState(const State &state);
void checkIfParseJobFinished(const Jobs::RunningJob &job);
void checkIfReparseJobFinished(const Jobs::RunningJob &job);
private:
bool abortIfDocumentIsClosed();
void addJob(JobRequest::Type jobRequestType);
private:
Document m_document;
Jobs &m_jobs;
State m_state = State::NotInitialized;
IsDocumentClosedChecker m_isDocumentClosedChecker;
};
} // namespace ClangBackEnd

View File

@@ -0,0 +1,59 @@
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "clangsuspenddocumentjob.h"
#include <clangsupport/clangsupportdebugutils.h>
#include <utils/qtcassert.h>
namespace ClangBackEnd {
IAsyncJob::AsyncPrepareResult SuspendDocumentJob::prepareAsyncRun()
{
const JobRequest jobRequest = context().jobRequest;
QTC_ASSERT(jobRequest.type == JobRequest::Type::SuspendDocument, return AsyncPrepareResult());
QTC_ASSERT(acquireDocument(), return AsyncPrepareResult());
TranslationUnit translationUnit = *m_translationUnit;
setRunner([translationUnit]() {
TIME_SCOPE_DURATION("SuspendDocumentJobRunner");
return translationUnit.suspend();
});
return AsyncPrepareResult{translationUnit.id()};
}
void SuspendDocumentJob::finalizeAsyncRun()
{
if (context().isDocumentOpen()) {
const bool suspendSucceeded = asyncResult();
if (QTC_GUARD(suspendSucceeded)) {
m_pinnedDocument.setIsSuspended(true);
}
}
}
} // namespace ClangBackEnd

View File

@@ -0,0 +1,39 @@
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include "clangdocumentjob.h"
namespace ClangBackEnd {
class SuspendDocumentJob : public DocumentJob<bool>
{
public:
AsyncPrepareResult prepareAsyncRun() override;
void finalizeAsyncRun() override;
};
} // namespace ClangBackEnd

View File

@@ -0,0 +1,255 @@
/****************************************************************************
**
** 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 "clangtranslationunit.h"
#include "clangbackend_global.h"
#include "clangreferencescollector.h"
#include "clangtranslationunitupdater.h"
#include "clangfollowsymbol.h"
#include "clangfollowsymboljob.h"
#include <codecompleter.h>
#include <cursor.h>
#include <diagnosticcontainer.h>
#include <diagnosticset.h>
#include <highlightingmark.h>
#include <highlightingmarks.h>
#include <skippedsourceranges.h>
#include <sourcelocation.h>
#include <sourcerange.h>
#include <commandlinearguments.h>
#include <utils/qtcassert.h>
namespace ClangBackEnd {
TranslationUnit::TranslationUnit(const Utf8String &id,
const Utf8String &filepath,
CXIndex &cxIndex,
CXTranslationUnit &cxTranslationUnit)
: m_id(id)
, m_filePath(filepath)
, m_cxIndex(cxIndex)
, m_cxTranslationUnit(cxTranslationUnit)
{
}
bool TranslationUnit::isNull() const
{
return !m_cxTranslationUnit || !m_cxIndex || m_filePath.isEmpty() || m_id.isEmpty();
}
Utf8String TranslationUnit::id() const
{
return m_id;
}
Utf8String TranslationUnit::filePath() const
{
return m_filePath;
}
CXIndex &TranslationUnit::cxIndex() const
{
return m_cxIndex;
}
CXTranslationUnit &TranslationUnit::cxTranslationUnit() const
{
return m_cxTranslationUnit;
}
TranslationUnitUpdateResult TranslationUnit::update(
const TranslationUnitUpdateInput &parseInput) const
{
TranslationUnitUpdater updater(id(), cxIndex(), cxTranslationUnit(), parseInput);
return updater.update(TranslationUnitUpdater::UpdateMode::AsNeeded);
}
TranslationUnitUpdateResult TranslationUnit::parse(
const TranslationUnitUpdateInput &parseInput) const
{
TranslationUnitUpdater updater(id(), cxIndex(), cxTranslationUnit(), parseInput);
return updater.update(TranslationUnitUpdater::UpdateMode::ParseIfNeeded);
}
TranslationUnitUpdateResult TranslationUnit::reparse(
const TranslationUnitUpdateInput &parseInput) const
{
TranslationUnitUpdater updater(id(), cxIndex(), cxTranslationUnit(), parseInput);
return updater.update(TranslationUnitUpdater::UpdateMode::ForceReparse);
}
bool TranslationUnit::suspend() const
{
#ifdef IS_SUSPEND_SUPPORTED
return clang_suspendTranslationUnit(cxTranslationUnit());
#else
QTC_CHECK(false && "clang_suspendTranslationUnit() not supported.");
return false;
#endif
}
TranslationUnit::CodeCompletionResult TranslationUnit::complete(
UnsavedFiles &unsavedFiles,
uint line,
uint column,
int funcNameStartLine,
int funcNameStartColumn) const
{
CodeCompleter codeCompleter(*this, unsavedFiles);
const CodeCompletions completions = codeCompleter.complete(line, column,
funcNameStartLine,
funcNameStartColumn);
const CompletionCorrection correction = codeCompleter.neededCorrection();
return CodeCompletionResult{completions, correction};
}
void TranslationUnit::extractDocumentAnnotations(
DiagnosticContainer &firstHeaderErrorDiagnostic,
QVector<DiagnosticContainer> &mainFileDiagnostics,
QVector<HighlightingMarkContainer> &highlightingMarks,
QVector<SourceRangeContainer> &skippedSourceRanges) const
{
extractDiagnostics(firstHeaderErrorDiagnostic, mainFileDiagnostics);
highlightingMarks = this->highlightingMarks().toHighlightingMarksContainers();
skippedSourceRanges = this->skippedSourceRanges().toSourceRangeContainers();
}
ReferencesResult TranslationUnit::references(uint line, uint column) const
{
return collectReferences(m_cxTranslationUnit, line, column);
}
DiagnosticSet TranslationUnit::diagnostics() const
{
return DiagnosticSet(clang_getDiagnosticSetFromTU(m_cxTranslationUnit));
}
SourceLocation TranslationUnit::sourceLocationAt(uint line,uint column) const
{
return SourceLocation(m_cxTranslationUnit, m_filePath, line, column);
}
SourceLocation TranslationUnit::sourceLocationAt(const Utf8String &filePath,
uint line,
uint column) const
{
return SourceLocation(m_cxTranslationUnit, filePath, line, column);
}
SourceRange TranslationUnit::sourceRange(uint fromLine,
uint fromColumn,
uint toLine,
uint toColumn) const
{
return SourceRange(sourceLocationAt(fromLine, fromColumn),
sourceLocationAt(toLine, toColumn));
}
Cursor TranslationUnit::cursorAt(uint line, uint column) const
{
return clang_getCursor(m_cxTranslationUnit, sourceLocationAt(line, column));
}
Cursor TranslationUnit::cursorAt(const Utf8String &filePath,
uint line,
uint column) const
{
return clang_getCursor(m_cxTranslationUnit, sourceLocationAt(filePath, line, column));
}
Cursor TranslationUnit::cursor() const
{
return clang_getTranslationUnitCursor(m_cxTranslationUnit);
}
HighlightingMarks TranslationUnit::highlightingMarks() const
{
return highlightingMarksInRange(cursor().sourceRange());
}
HighlightingMarks TranslationUnit::highlightingMarksInRange(const SourceRange &range) const
{
CXToken *cxTokens = 0;
uint cxTokensCount = 0;
clang_tokenize(m_cxTranslationUnit, range, &cxTokens, &cxTokensCount);
return HighlightingMarks(m_cxTranslationUnit, cxTokens, cxTokensCount);
}
SkippedSourceRanges TranslationUnit::skippedSourceRanges() const
{
return SkippedSourceRanges(m_cxTranslationUnit, m_filePath.constData());
}
static bool isMainFileDiagnostic(const Utf8String &mainFilePath, const Diagnostic &diagnostic)
{
return diagnostic.location().filePath() == mainFilePath;
}
static bool isHeaderErrorDiagnostic(const Utf8String &mainFilePath, const Diagnostic &diagnostic)
{
const bool isCritical = diagnostic.severity() == DiagnosticSeverity::Error
|| diagnostic.severity() == DiagnosticSeverity::Fatal;
return isCritical && diagnostic.location().filePath() != mainFilePath;
}
void TranslationUnit::extractDiagnostics(DiagnosticContainer &firstHeaderErrorDiagnostic,
QVector<DiagnosticContainer> &mainFileDiagnostics) const
{
mainFileDiagnostics.clear();
mainFileDiagnostics.reserve(int(diagnostics().size()));
bool hasFirstHeaderErrorDiagnostic = false;
for (const Diagnostic &diagnostic : diagnostics()) {
if (!hasFirstHeaderErrorDiagnostic && isHeaderErrorDiagnostic(m_filePath, diagnostic)) {
hasFirstHeaderErrorDiagnostic = true;
firstHeaderErrorDiagnostic = diagnostic.toDiagnosticContainer();
}
if (isMainFileDiagnostic(m_filePath, diagnostic))
mainFileDiagnostics.push_back(diagnostic.toDiagnosticContainer());
}
}
SourceRangeContainer TranslationUnit::followSymbol(uint line,
uint column,
const QVector<Utf8String> &dependentFiles,
const CommandLineArguments &currentArgs) const
{
return FollowSymbol::followSymbol(m_cxTranslationUnit, m_cxIndex, cursorAt(line, column), line,
column, dependentFiles, currentArgs);
}
} // namespace ClangBackEnd

View File

@@ -0,0 +1,115 @@
/****************************************************************************
**
** 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 <clangsupport/codecompletion.h>
#include <clang-c/Index.h>
namespace ClangBackEnd {
class Cursor;
class DiagnosticContainer;
class DiagnosticSet;
class HighlightingMarkContainer;
class HighlightingMarks;
class ReferencesResult;
class SkippedSourceRanges;
class SourceLocation;
class SourceRange;
class SourceRangeContainer;
class TranslationUnitUpdateInput;
class TranslationUnitUpdateResult;
class UnsavedFiles;
class CommandLineArguments;
class TranslationUnit
{
public:
struct CodeCompletionResult {
CodeCompletions completions;
CompletionCorrection correction;
};
public:
TranslationUnit(const Utf8String &id,
const Utf8String &filePath,
CXIndex &cxIndex,
CXTranslationUnit &cxTranslationUnit);
bool isNull() const;
Utf8String id() const;
Utf8String filePath() const;
CXIndex &cxIndex() const;
CXTranslationUnit &cxTranslationUnit() const;
bool suspend() const;
TranslationUnitUpdateResult update(const TranslationUnitUpdateInput &parseInput) const;
TranslationUnitUpdateResult parse(const TranslationUnitUpdateInput &parseInput) const;
TranslationUnitUpdateResult reparse(const TranslationUnitUpdateInput &parseInput) const;
CodeCompletionResult complete(UnsavedFiles &unsavedFiles, uint line, uint column,
int funcNameStartLine, int funcNameStartColumn) const;
void extractDiagnostics(DiagnosticContainer &firstHeaderErrorDiagnostic,
QVector<DiagnosticContainer> &mainFileDiagnostics) const;
void extractDocumentAnnotations(DiagnosticContainer &firstHeaderErrorDiagnostic,
QVector<DiagnosticContainer> &mainFileDiagnostics,
QVector<HighlightingMarkContainer> &highlightingMarks,
QVector<SourceRangeContainer> &skippedSourceRanges) const;
ReferencesResult references(uint line, uint column) const;
DiagnosticSet diagnostics() const;
SourceLocation sourceLocationAt(uint line, uint column) const;
SourceLocation sourceLocationAt(const Utf8String &filePath, uint line, uint column) const;
SourceRange sourceRange(uint fromLine, uint fromColumn, uint toLine, uint toColumn) const;
Cursor cursorAt(uint line, uint column) const;
Cursor cursorAt(const Utf8String &filePath, uint line, uint column) const;
Cursor cursor() const;
HighlightingMarks highlightingMarks() const;
HighlightingMarks highlightingMarksInRange(const SourceRange &range) const;
SkippedSourceRanges skippedSourceRanges() const;
SourceRangeContainer followSymbol(uint line,
uint column,
const QVector<Utf8String> &dependentFiles,
const CommandLineArguments &currentArgs) const;
private:
const Utf8String m_id;
const Utf8String m_filePath;
CXIndex &m_cxIndex;
CXTranslationUnit &m_cxTranslationUnit;
};
} // namespace ClangBackEnd

View File

@@ -0,0 +1,155 @@
/****************************************************************************
**
** 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 "clangtranslationunits.h"
#include "clangexceptions.h"
#include "clangtranslationunit.h"
#include <utils/algorithm.h>
#include <utils/qtcassert.h>
#include <QFileInfo>
#include <QLoggingCategory>
#include <QUuid>
Q_LOGGING_CATEGORY(tuLog, "qtc.clangbackend.translationunits");
namespace ClangBackEnd {
TranslationUnits::TranslationUnitData::TranslationUnitData(const Utf8String &id)
: id(id)
{}
TranslationUnits::TranslationUnitData::~TranslationUnitData()
{
qCDebug(tuLog) << "Destroying TranslationUnit" << id;
clang_disposeTranslationUnit(cxTranslationUnit);
clang_disposeIndex(cxIndex);
}
TranslationUnits::TranslationUnits(const Utf8String &filePath)
: m_filePath(filePath)
{
}
TranslationUnit TranslationUnits::createAndAppend()
{
const Utf8String id = Utf8String::fromByteArray(QUuid::createUuid().toByteArray());
qCDebug(tuLog) << "Creating TranslationUnit" << id << "for" << QFileInfo(m_filePath).fileName();
m_units.append(TranslationUnitDataPtr(new TranslationUnitData(id)));
return toTranslationUnit(m_units.last());
}
void TranslationUnits::removeAll()
{
m_units.clear();
}
TranslationUnit TranslationUnits::get(PreferredTranslationUnit type)
{
if (m_units.isEmpty())
throw TranslationUnitDoesNotExist(m_filePath);
if (m_units.size() == 1)
return toTranslationUnit(m_units.first());
if (areAllTranslationUnitsParsed())
return getPreferredTranslationUnit(type);
if (type == PreferredTranslationUnit::LastUninitialized)
return toTranslationUnit(m_units.last());
return toTranslationUnit(m_units.first());
}
void TranslationUnits::updateParseTimePoint(const Utf8String &translationUnitId,
TimePoint timePoint)
{
QTC_CHECK(timePoint != TimePoint());
findUnit(translationUnitId).parseTimePoint = timePoint;
qCDebug(tuLog) << "Updated" << translationUnitId << "for" << QFileInfo(m_filePath).fileName()
<< "RecentlyParsed:" << get(PreferredTranslationUnit::RecentlyParsed).id()
<< "PreviouslyParsed:" << get(PreferredTranslationUnit::PreviouslyParsed).id();
}
TimePoint TranslationUnits::parseTimePoint(const Utf8String &translationUnitId)
{
return findUnit(translationUnitId).parseTimePoint;
}
bool TranslationUnits::areAllTranslationUnitsParsed() const
{
return Utils::allOf(m_units, [](const TranslationUnitDataPtr &unit) {
return unit->parseTimePoint != TimePoint();
});
}
int TranslationUnits::size() const
{
return m_units.size();
}
TranslationUnit TranslationUnits::getPreferredTranslationUnit(PreferredTranslationUnit type)
{
using TuDataPtr = TranslationUnitDataPtr;
const auto lessThan = [](const TuDataPtr &a, const TuDataPtr &b) {
return a->parseTimePoint < b->parseTimePoint;
};
auto it = type == PreferredTranslationUnit::RecentlyParsed
? std::max_element(m_units.begin(), m_units.end(), lessThan)
: std::min_element(m_units.begin(), m_units.end(), lessThan);
if (it == m_units.end())
throw TranslationUnitDoesNotExist(m_filePath);
return toTranslationUnit(*it);
}
TranslationUnits::TranslationUnitData &TranslationUnits::findUnit(
const Utf8String &translationUnitId)
{
for (TranslationUnitDataPtr &unit : m_units) {
if (translationUnitId == unit->id)
return *unit;
}
throw TranslationUnitDoesNotExist(m_filePath);
}
TranslationUnit TranslationUnits::toTranslationUnit(const TranslationUnitDataPtr &unit)
{
return TranslationUnit(unit->id,
m_filePath,
unit->cxIndex,
unit->cxTranslationUnit);
}
} // namespace ClangBackEnd

View File

@@ -0,0 +1,83 @@
/****************************************************************************
**
** 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 "clangbackend_global.h"
#include "clangclock.h"
#include <utf8string.h>
#include <clang-c/Index.h>
#include <QList>
#include <QSharedPointer>
namespace ClangBackEnd {
class TranslationUnit;
class TranslationUnits
{
public:
class TranslationUnitData {
public:
TranslationUnitData(const Utf8String &id);
~TranslationUnitData();
Utf8String id;
CXTranslationUnit cxTranslationUnit = nullptr;
CXIndex cxIndex = nullptr;
TimePoint parseTimePoint;
};
using TranslationUnitDataPtr = QSharedPointer<TranslationUnitData>;
public:
TranslationUnits(const Utf8String &filePath);
TranslationUnit createAndAppend();
void removeAll();
TranslationUnit get(PreferredTranslationUnit type = PreferredTranslationUnit::RecentlyParsed);
void updateParseTimePoint(const Utf8String &translationUnitId, TimePoint timePoint);
bool areAllTranslationUnitsParsed() const;
public: // for tests
int size() const;
TimePoint parseTimePoint(const Utf8String &translationUnitId);
private:
TranslationUnit getPreferredTranslationUnit(PreferredTranslationUnit type);
TranslationUnitData &findUnit(const Utf8String &translationUnitId);
TranslationUnit toTranslationUnit(const TranslationUnitDataPtr &unit);
private:
Utf8String m_filePath;
QList<TranslationUnitDataPtr> m_units;
};
} // namespace ClangBackEnd

View File

@@ -0,0 +1,220 @@
/****************************************************************************
**
** 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 "clangtranslationunitupdater.h"
#include "clangfilepath.h"
#include "clangstring.h"
#include "clangunsavedfilesshallowarguments.h"
#include <QLoggingCategory>
static Q_LOGGING_CATEGORY(verboseLibLog, "qtc.clangbackend.verboselib");
static bool isVerboseModeEnabled()
{
return verboseLibLog().isDebugEnabled();
}
namespace ClangBackEnd {
TranslationUnitUpdater::TranslationUnitUpdater(const Utf8String translationUnitId,
CXIndex &index,
CXTranslationUnit &cxTranslationUnit,
const TranslationUnitUpdateInput &updateData)
: m_cxIndex(index)
, m_cxTranslationUnit(cxTranslationUnit)
, m_in(updateData)
{
m_out.translationUnitId = translationUnitId;
}
TranslationUnitUpdateResult TranslationUnitUpdater::update(UpdateMode mode)
{
createIndexIfNeeded();
switch (mode) {
case UpdateMode::AsNeeded:
recreateAndParseIfNeeded();
reparseIfNeeded();
break;
case UpdateMode::ParseIfNeeded:
recreateAndParseIfNeeded();
break;
case UpdateMode::ForceReparse:
reparse();
break;
}
return m_out;
}
void TranslationUnitUpdater::recreateAndParseIfNeeded()
{
removeTranslationUnitIfProjectPartWasChanged();
createTranslationUnitIfNeeded();
}
void TranslationUnitUpdater::removeTranslationUnitIfProjectPartWasChanged()
{
if (m_in.parseNeeded) {
clang_disposeTranslationUnit(m_cxTranslationUnit);
m_cxTranslationUnit = nullptr;
}
}
#define RETURN_TEXT_FOR_CASE(enumValue) case enumValue: return #enumValue
static const char *errorCodeToText(CXErrorCode errorCode)
{
switch (errorCode) {
RETURN_TEXT_FOR_CASE(CXError_Success);
RETURN_TEXT_FOR_CASE(CXError_Failure);
RETURN_TEXT_FOR_CASE(CXError_Crashed);
RETURN_TEXT_FOR_CASE(CXError_InvalidArguments);
RETURN_TEXT_FOR_CASE(CXError_ASTReadError);
}
return "UnknownCXErrorCode";
}
#undef RETURN_TEXT_FOR_CASE
void TranslationUnitUpdater::createTranslationUnitIfNeeded()
{
if (!m_cxTranslationUnit) {
m_cxTranslationUnit = CXTranslationUnit();
const auto args = commandLineArguments();
if (isVerboseModeEnabled())
args.print();
UnsavedFilesShallowArguments unsaved = m_in.unsavedFiles.shallowArguments();
m_parseErrorCode = clang_parseTranslationUnit2(m_cxIndex,
NULL,
args.data(),
args.count(),
unsaved.data(),
unsaved.count(),
defaultParseOptions(),
&m_cxTranslationUnit);
if (parseWasSuccessful()) {
updateIncludeFilePaths();
m_out.parseTimePoint = Clock::now();
} else {
qWarning() << "Parsing" << m_in.filePath << "failed:"
<< errorCodeToText(m_parseErrorCode);
m_out.hasParseOrReparseFailed = true;
}
}
}
void TranslationUnitUpdater::reparseIfNeeded()
{
if (m_in.reparseNeeded)
reparse();
}
void TranslationUnitUpdater::reparse()
{
UnsavedFilesShallowArguments unsaved = m_in.unsavedFiles.shallowArguments();
m_reparseErrorCode = clang_reparseTranslationUnit(
m_cxTranslationUnit,
unsaved.count(),
unsaved.data(),
clang_defaultReparseOptions(m_cxTranslationUnit));
if (reparseWasSuccessful()) {
updateIncludeFilePaths();
m_out.reparseTimePoint = Clock::now();
m_out.needsToBeReparsedChangeTimePoint = m_in.needsToBeReparsedChangeTimePoint;
} else {
qWarning() << "Reparsing" << m_in.filePath << "failed:" << m_reparseErrorCode;
m_out.hasParseOrReparseFailed = true;
}
}
void TranslationUnitUpdater::updateIncludeFilePaths()
{
m_out.dependedOnFilePaths.clear();
m_out.dependedOnFilePaths.insert(m_in.filePath);
clang_getInclusions(m_cxTranslationUnit,
includeCallback,
const_cast<TranslationUnitUpdater *>(this));
}
uint TranslationUnitUpdater::defaultParseOptions()
{
return CXTranslationUnit_CacheCompletionResults
| CXTranslationUnit_PrecompiledPreamble
| CXTranslationUnit_IncludeBriefCommentsInCodeCompletion
| CXTranslationUnit_DetailedPreprocessingRecord
| CXTranslationUnit_KeepGoing;
}
void TranslationUnitUpdater::createIndexIfNeeded()
{
if (!m_cxIndex) {
const bool displayDiagnostics = isVerboseModeEnabled();
m_cxIndex = clang_createIndex(1, displayDiagnostics);
}
}
void TranslationUnitUpdater::includeCallback(CXFile included_file,
CXSourceLocation *,
unsigned, CXClientData clientData)
{
ClangString includeFilePath(clang_getFileName(included_file));
TranslationUnitUpdater *updater = static_cast<TranslationUnitUpdater *>(clientData);
updater->m_out.dependedOnFilePaths.insert(FilePath::fromNativeSeparators(includeFilePath));
}
bool TranslationUnitUpdater::parseWasSuccessful() const
{
return m_parseErrorCode == CXError_Success;
}
bool TranslationUnitUpdater::reparseWasSuccessful() const
{
return m_reparseErrorCode == 0;
}
CommandLineArguments TranslationUnitUpdater::commandLineArguments() const
{
return CommandLineArguments(m_in.filePath.constData(),
m_in.projectArguments,
m_in.fileArguments,
isVerboseModeEnabled());
}
} // namespace ClangBackEnd

View File

@@ -0,0 +1,121 @@
/****************************************************************************
**
** 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 "clangclock.h"
#include "commandlinearguments.h"
#include "unsavedfiles.h"
#include "utf8stringvector.h"
#include <clang-c/Index.h>
#include <QSet>
namespace ClangBackEnd {
class TranslationUnitUpdateInput {
public:
bool parseNeeded = false;
bool reparseNeeded = false;
TimePoint needsToBeReparsedChangeTimePoint;
Utf8String filePath;
Utf8StringVector fileArguments;
UnsavedFiles unsavedFiles;
Utf8String projectId;
Utf8StringVector projectArguments;
};
class TranslationUnitUpdateResult {
public:
bool hasParsed() const
{ return parseTimePoint != TimePoint(); }
bool hasReparsed() const
{ return reparseTimePoint != TimePoint(); }
public:
Utf8String translationUnitId;
bool hasParseOrReparseFailed = false;
TimePoint parseTimePoint;
TimePoint reparseTimePoint;
TimePoint needsToBeReparsedChangeTimePoint;
QSet<Utf8String> dependedOnFilePaths;
};
class TranslationUnitUpdater {
public:
enum class UpdateMode {
AsNeeded,
ParseIfNeeded,
ForceReparse,
};
public:
TranslationUnitUpdater(const Utf8String translationUnitId,
CXIndex &index,
CXTranslationUnit &cxTranslationUnit,
const TranslationUnitUpdateInput &in);
TranslationUnitUpdateResult update(UpdateMode mode);
CommandLineArguments commandLineArguments() const;
static uint defaultParseOptions();
private:
void createIndexIfNeeded();
void createTranslationUnitIfNeeded();
void removeTranslationUnitIfProjectPartWasChanged();
void reparseIfNeeded();
void recreateAndParseIfNeeded();
void reparse();
void updateIncludeFilePaths();
static void includeCallback(CXFile included_file,
CXSourceLocation *,
unsigned,
CXClientData clientData);
bool parseWasSuccessful() const;
bool reparseWasSuccessful() const;
private:
CXIndex &m_cxIndex;
CXTranslationUnit &m_cxTranslationUnit;
CXErrorCode m_parseErrorCode = CXError_Success;
int m_reparseErrorCode = 0;
const TranslationUnitUpdateInput m_in;
TranslationUnitUpdateResult m_out;
};
} // namespace ClangBackEnd

View File

@@ -0,0 +1,165 @@
/****************************************************************************
**
** 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 "clangtype.h"
#include "clangstring.h"
#include "cursor.h"
#include <utf8string.h>
#include <ostream>
namespace ClangBackEnd {
bool Type::isValid() const
{
return cxType.kind != CXType_Invalid;
}
bool Type::isConstant() const
{
return clang_isConstQualifiedType(cxType);
}
bool Type::isConstantReference()
{
return isLValueReference() && pointeeType().isConstant();
}
bool Type::isPointer() const
{
return cxType.kind == CXType_Pointer;
}
bool Type::isPointerToConstant() const
{
return isPointer() && pointeeType().isConstant();
}
bool Type::isConstantPointer() const
{
return isPointer() && isConstant();
}
bool Type::isLValueReference() const
{
return cxType.kind == CXType_LValueReference;
}
bool Type::isReferencingConstant() const
{
return (isPointer() || isLValueReference()) && pointeeType().isConstant();
}
bool Type::isOutputArgument() const
{
return isLValueReference() && !pointeeType().isConstant();
}
bool Type::isBuiltinType() const
{
return cxType.kind >= CXType_FirstBuiltin && cxType.kind <= CXType_LastBuiltin;
}
Utf8String Type::utf8Spelling() const
{
return ClangString(clang_getTypeSpelling(cxType));
}
ClangString Type::spelling() const
{
return ClangString(clang_getTypeSpelling(cxType));
}
int Type::argumentCount() const
{
return clang_getNumArgTypes(cxType);
}
Type Type::alias() const
{
return clang_getTypedefDeclUnderlyingType(clang_getTypeDeclaration(cxType));
}
Type Type::canonical() const
{
return clang_getCanonicalType(cxType);
}
Type Type::classType() const
{
return clang_Type_getClassType(cxType);
}
Type Type::pointeeType() const
{
return clang_getPointeeType(cxType);
}
Type Type::argument(int index) const
{
return clang_getArgType(cxType, index);
}
Cursor Type::declaration() const
{
return clang_getTypeDeclaration(cxType);
}
CXTypeKind Type::kind() const
{
return cxType.kind;
}
Type::Type(CXType cxType)
: cxType(cxType)
{
}
bool operator==(Type first, Type second)
{
return clang_equalTypes(first.cxType, second.cxType);
}
std::ostream &operator<<(std::ostream &os, CXTypeKind typeKind)
{
ClangString typeKindSpelling(clang_getTypeKindSpelling(typeKind));
return os << typeKindSpelling.cString();
}
std::ostream &operator<<(std::ostream &os, const Type &type)
{
ClangString typeKindSpelling(clang_getTypeKindSpelling(type.kind()));
os << typeKindSpelling
<< ": \"" << type.spelling() << "\"";
return os;
}
} // namespace ClangBackEnd

View File

@@ -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 <clang-c/Index.h>
#include <iosfwd>
class Utf8String;
namespace ClangBackEnd {
class Cursor;
class ClangString;
class Type
{
friend class Cursor;
friend bool operator==(Type first, Type second);
public:
bool isValid() const;
bool isConstant() const;
bool isConstantReference();
bool isPointer() const;
bool isPointerToConstant() const;
bool isConstantPointer() const;
bool isLValueReference() const;
bool isReferencingConstant() const;
bool isOutputArgument() const;
bool isBuiltinType() const;
Utf8String utf8Spelling() const;
ClangString spelling() const;
int argumentCount() const;
Type alias() const;
Type canonical() const;
Type classType() const;
Type pointeeType() const;
Type argument(int index) const;
Cursor declaration() const;
CXTypeKind kind() const;
private:
Type(CXType cxType);
private:
CXType cxType;
};
bool operator==(Type first, Type second);
std::ostream &operator<<(std::ostream &os, CXTypeKind typeKind);
std::ostream &operator<<(std::ostream &os, const Type &type);
} // namespace ClangBackEnd

View File

@@ -0,0 +1,57 @@
/****************************************************************************
**
** 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 "clangunsavedfilesshallowarguments.h"
#include "clangfilepath.h"
#include "unsavedfile.h"
#include "unsavedfiles.h"
namespace ClangBackEnd {
UnsavedFilesShallowArguments::UnsavedFilesShallowArguments(const UnsavedFiles &unsavedFiles)
{
const int unsavedFilesCount = int(unsavedFiles.count());
m_cxUnsavedFiles.resize(unsavedFilesCount);
for (int i = 0, total = unsavedFilesCount; i < total; ++i) {
const UnsavedFile &unsavedFile = unsavedFiles.at(i);
m_cxUnsavedFiles[i].Filename = unsavedFile.nativeFilePath().constData();
m_cxUnsavedFiles[i].Contents = unsavedFile.fileContent().constData();
m_cxUnsavedFiles[i].Length = uint(unsavedFile.fileContent().byteSize());
}
}
uint UnsavedFilesShallowArguments::count() const
{
return uint(m_cxUnsavedFiles.count());
}
CXUnsavedFile *UnsavedFilesShallowArguments::data()
{
return m_cxUnsavedFiles.data();
}
} // namespace ClangBackEnd

View File

@@ -0,0 +1,49 @@
/****************************************************************************
**
** 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 <QVector>
#include <clang-c/Index.h>
namespace ClangBackEnd {
class UnsavedFile;
class UnsavedFiles;
class UnsavedFilesShallowArguments {
public:
UnsavedFilesShallowArguments() = default;
UnsavedFilesShallowArguments(const UnsavedFiles &unsavedFiles);
uint count() const;
CXUnsavedFile *data();
private:
QVector<CXUnsavedFile> m_cxUnsavedFiles;
};
} // namespace ClangBackEnd

View File

@@ -0,0 +1,90 @@
/****************************************************************************
**
** 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 <clangsupport/clangsupportdebugutils.h>
#include <clangsupport/clangcodemodelclientinterface.h>
#include <clangsupport/documentannotationschangedmessage.h>
#include <utils/qtcassert.h>
namespace ClangBackEnd {
IAsyncJob::AsyncPrepareResult UpdateDocumentAnnotationsJob::prepareAsyncRun()
{
const JobRequest jobRequest = context().jobRequest;
QTC_ASSERT(isExpectedJobRequestType(jobRequest), return AsyncPrepareResult());
QTC_ASSERT(acquireDocument(), return AsyncPrepareResult());
const TranslationUnit translationUnit = *m_translationUnit;
const TranslationUnitUpdateInput updateInput = createUpdateInput(m_pinnedDocument);
setRunner([translationUnit, updateInput]() {
TIME_SCOPE_DURATION("UpdateDocumentAnnotationsJobRunner");
// Update
UpdateDocumentAnnotationsJob::AsyncResult asyncResult;
asyncResult.updateResult = translationUnit.update(updateInput);
// Collect
translationUnit.extractDocumentAnnotations(asyncResult.firstHeaderErrorDiagnostic,
asyncResult.diagnostics,
asyncResult.highlightingMarks,
asyncResult.skippedSourceRanges);
return asyncResult;
});
return AsyncPrepareResult{translationUnit.id()};
}
void UpdateDocumentAnnotationsJob::finalizeAsyncRun()
{
if (!context().isOutdated()) {
const AsyncResult result = asyncResult();
m_pinnedDocument.incorporateUpdaterResult(result.updateResult);
context().client->documentAnnotationsChanged(
DocumentAnnotationsChangedMessage(m_pinnedFileContainer,
result.diagnostics,
result.firstHeaderErrorDiagnostic,
result.highlightingMarks,
result.skippedSourceRanges));
}
}
bool UpdateDocumentAnnotationsJob::isExpectedJobRequestType(const JobRequest &jobRequest) const
{
return jobRequest.type == JobRequest::Type::UpdateDocumentAnnotations;
}
TranslationUnitUpdateInput
UpdateDocumentAnnotationsJob::createUpdateInput(const Document &document) const
{
return document.createUpdateInput();
}
} // namespace ClangBackEnd

View File

@@ -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 "clangdocumentjob.h"
#include <clangsupport/diagnosticcontainer.h>
#include <clangsupport/highlightingmarkcontainer.h>
#include <clangsupport/sourcerangecontainer.h>
namespace ClangBackEnd {
struct UpdateDocumentAnnotationsJobResult
{
TranslationUnitUpdateResult updateResult;
ClangBackEnd::DiagnosticContainer firstHeaderErrorDiagnostic;
QVector<ClangBackEnd::DiagnosticContainer> diagnostics;
QVector<HighlightingMarkContainer> highlightingMarks;
QVector<SourceRangeContainer> skippedSourceRanges;
};
class UpdateDocumentAnnotationsJob : public DocumentJob<UpdateDocumentAnnotationsJobResult>
{
public:
using AsyncResult = UpdateDocumentAnnotationsJobResult;
AsyncPrepareResult prepareAsyncRun() override;
void finalizeAsyncRun() override;
protected:
virtual bool isExpectedJobRequestType(const JobRequest &jobRequest) const;
virtual TranslationUnitUpdateInput createUpdateInput(const Document &document) const;
};
} // namespace ClangBackEnd

View File

@@ -0,0 +1,232 @@
/****************************************************************************
**
** 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 "codecompleter.h"
#include "clangfilepath.h"
#include "clangcodecompleteresults.h"
#include "clangstring.h"
#include "cursor.h"
#include "clangexceptions.h"
#include "codecompletionsextractor.h"
#include "sourcelocation.h"
#include "unsavedfile.h"
#include "unsavedfiles.h"
#include "clangdocument.h"
#include "sourcerange.h"
#include "clangunsavedfilesshallowarguments.h"
#include "clangtranslationunitupdater.h"
#include <clang-c/Index.h>
namespace ClangBackEnd {
namespace {
CodeCompletions toCodeCompletions(const ClangCodeCompleteResults &results)
{
if (results.isNull())
return CodeCompletions();
CodeCompletionsExtractor extractor(results.data());
CodeCompletions codeCompletions = extractor.extractAll();
return codeCompletions;
}
void filterUnknownContextResults(ClangCodeCompleteResults &results,
const UnsavedFile &theUnsavedFile,
uint line,
uint column)
{
if (results.hasUnknownContext()) {
bool positionIsOk = false;
const uint position = theUnsavedFile.toUtf8Position(line, column - 1, &positionIsOk);
if (positionIsOk && (theUnsavedFile.hasCharacterAt(position, '.')
|| (theUnsavedFile.hasCharacterAt(position - 1, '-')
&& theUnsavedFile.hasCharacterAt(position, '>')))) {
results = {};
}
}
}
} // anonymous namespace
CodeCompleter::CodeCompleter(const TranslationUnit &translationUnit,
const UnsavedFiles &unsavedFiles)
: translationUnit(translationUnit)
, unsavedFiles(unsavedFiles)
{
}
CodeCompletions CodeCompleter::complete(uint line, uint column,
int funcNameStartLine,
int funcNameStartColumn)
{
neededCorrection_ = CompletionCorrection::NoCorrection;
// Check if we have a smart pointer completion and get proper constructor signatures in results.
// Results are empty when it's not a smart pointer or this completion failed.
ClangCodeCompleteResults results = completeSmartPointerCreation(line,
column,
funcNameStartLine,
funcNameStartColumn);
if (results.isNull() || results.isEmpty())
results = completeHelper(line, column);
filterUnknownContextResults(results, unsavedFile(), line, column);
tryDotArrowCorrectionIfNoResults(results, line, column);
return toCodeCompletions(results);
}
CompletionCorrection CodeCompleter::neededCorrection() const
{
return neededCorrection_;
}
// For given "make_unique<T>" / "make_shared<T>" / "QSharedPointer<T>::create" return "new T("
// Otherwize return empty QString
static QString tweakName(const QString &oldName)
{
QString fullName = oldName.trimmed();
if (!fullName.contains('>'))
return QString();
if (!fullName.endsWith('>')) {
// This is the class<type>::method case - remove ::method part
if (!fullName.endsWith("create") || !fullName.contains("QSharedPointer"))
return QString();
fullName = fullName.mid(0, fullName.lastIndexOf(':') - 1);
} else if (!fullName.contains("make_unique") && !fullName.contains("make_shared")) {
return QString();
}
int templateStart = fullName.indexOf('<');
QString name = fullName.mid(0, templateStart);
QString templatePart = fullName.mid(templateStart + 1,
fullName.length() - templateStart - 2);
return "new " + templatePart + "(";
}
ClangCodeCompleteResults CodeCompleter::completeSmartPointerCreation(uint line,
uint column,
int funcNameStartLine,
int funcNameStartColumn)
{
if (column <= 1 || funcNameStartLine == -1)
return ClangCodeCompleteResults();
UnsavedFile &file = unsavedFiles.unsavedFile(translationUnit.filePath());
if (!file.hasCharacterAt(line, column - 1, '('))
return ClangCodeCompleteResults();
bool ok;
const uint startPos = file.toUtf8Position(funcNameStartLine, funcNameStartColumn, &ok);
const uint endPos = file.toUtf8Position(line, column - 1, &ok);
Utf8String content = file.fileContent();
const QString oldName = content.mid(startPos, endPos - startPos);
const QString updatedName = tweakName(oldName);
if (updatedName.isEmpty())
return ClangCodeCompleteResults();
column += updatedName.length();
file.replaceAt(endPos + 1, 0, updatedName);
ClangCodeCompleteResults results = completeHelper(line, column);
if (results.isEmpty()) {
column -= updatedName.length();
file.replaceAt(endPos + 1, updatedName.length(), QString());
}
return results;
}
ClangCodeCompleteResults CodeCompleter::completeHelper(uint line, uint column)
{
const Utf8String nativeFilePath = FilePath::toNativeSeparators(translationUnit.filePath());
UnsavedFilesShallowArguments unsaved = unsavedFiles.shallowArguments();
return clang_codeCompleteAt(translationUnit.cxTranslationUnit(),
nativeFilePath.constData(),
line,
column,
unsaved.data(),
unsaved.count(),
defaultOptions());
}
uint CodeCompleter::defaultOptions() const
{
uint options = CXCodeComplete_IncludeMacros
| CXCodeComplete_IncludeCodePatterns;
if (TranslationUnitUpdater::defaultParseOptions()
& CXTranslationUnit_IncludeBriefCommentsInCodeCompletion) {
options |= CXCodeComplete_IncludeBriefComments;
}
return options;
}
UnsavedFile &CodeCompleter::unsavedFile()
{
return unsavedFiles.unsavedFile(translationUnit.filePath());
}
void CodeCompleter::tryDotArrowCorrectionIfNoResults(ClangCodeCompleteResults &results,
uint line,
uint column)
{
if (results.hasNoResultsForDotCompletion()) {
const UnsavedFile &theUnsavedFile = unsavedFile();
bool positionIsOk = false;
const uint dotPosition = theUnsavedFile.toUtf8Position(line, column - 1, &positionIsOk);
if (positionIsOk && theUnsavedFile.hasCharacterAt(dotPosition, '.'))
results = completeWithArrowInsteadOfDot(line, column, dotPosition);
}
}
ClangCodeCompleteResults CodeCompleter::completeWithArrowInsteadOfDot(uint line,
uint column,
uint dotPosition)
{
ClangCodeCompleteResults results;
const bool replaced = unsavedFile().replaceAt(dotPosition,
1,
Utf8StringLiteral("->"));
if (replaced) {
results = completeHelper(line, column + 1);
if (results.hasResults())
neededCorrection_ = CompletionCorrection::DotToArrowCorrection;
filterUnknownContextResults(results, unsavedFile(), line, column+1);
}
return results;
}
} // namespace ClangBackEnd

View File

@@ -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.
**
****************************************************************************/
#pragma once
#include "clangtranslationunit.h"
#include "unsavedfiles.h"
#include <codecompletion.h>
#include <utf8stringvector.h>
namespace ClangBackEnd {
class ClangCodeCompleteResults;
class CodeCompleter
{
public:
CodeCompleter() = default;
CodeCompleter(const TranslationUnit &translationUnit,
const UnsavedFiles &unsavedFiles);
CodeCompletions complete(uint line, uint column,
int funcNameStartLine = -1,
int funcNameStartColumn = -1);
CompletionCorrection neededCorrection() const;
private:
uint defaultOptions() const;
UnsavedFile &unsavedFile();
void tryDotArrowCorrectionIfNoResults(ClangCodeCompleteResults &results,
uint line,
uint column);
ClangCodeCompleteResults completeHelper(uint line, uint column);
ClangCodeCompleteResults completeSmartPointerCreation(uint line,
uint column,
int funcNameStartLine,
int funcNameStartColumn);
ClangCodeCompleteResults completeWithArrowInsteadOfDot(uint line,
uint column,
uint dotPosition);
private:
TranslationUnit translationUnit;
UnsavedFiles unsavedFiles;
CompletionCorrection neededCorrection_ = CompletionCorrection::NoCorrection;
};
} // namespace ClangBackEnd

View File

@@ -0,0 +1,83 @@
/****************************************************************************
**
** 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 "codecompletionchunkconverter.h"
#include "clangstring.h"
namespace ClangBackEnd {
void CodeCompletionChunkConverter::extractCompletionChunks(CXCompletionString completionString)
{
const uint completionChunkCount = clang_getNumCompletionChunks(completionString);
chunks.reserve(completionChunkCount);
for (uint chunkIndex = 0; chunkIndex < completionChunkCount; ++chunkIndex) {
const CodeCompletionChunk::Kind kind = chunkKind(completionString, chunkIndex);
if (kind == CodeCompletionChunk::Optional) {
extractOptionalCompletionChunks(clang_getCompletionChunkCompletionString(completionString, chunkIndex));
} else {
chunks.append(CodeCompletionChunk(kind,
chunkText(completionString, chunkIndex)));
}
}
}
void CodeCompletionChunkConverter::extractOptionalCompletionChunks(CXCompletionString completionString)
{
const uint completionChunkCount = clang_getNumCompletionChunks(completionString);
for (uint chunkIndex = 0; chunkIndex < completionChunkCount; ++chunkIndex) {
const CodeCompletionChunk::Kind kind = chunkKind(completionString, chunkIndex);
if (kind == CodeCompletionChunk::Optional)
extractOptionalCompletionChunks(clang_getCompletionChunkCompletionString(completionString, chunkIndex));
else
chunks.append(CodeCompletionChunk(kind, chunkText(completionString, chunkIndex), true));
}
}
CodeCompletionChunk::Kind CodeCompletionChunkConverter::chunkKind(CXCompletionString completionString, uint chunkIndex)
{
return CodeCompletionChunk::Kind(clang_getCompletionChunkKind(completionString, chunkIndex));
}
CodeCompletionChunks CodeCompletionChunkConverter::extract(CXCompletionString completionString)
{
CodeCompletionChunkConverter converter;
converter.extractCompletionChunks(completionString);
return converter.chunks;
}
Utf8String CodeCompletionChunkConverter::chunkText(CXCompletionString completionString, uint chunkIndex)
{
return ClangString(clang_getCompletionChunkText(completionString, chunkIndex));
}
} // namespace ClangBackEnd

View File

@@ -0,0 +1,52 @@
/****************************************************************************
**
** 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 <codecompletionchunk.h>
#include <QVector>
#include <clang-c/Index.h>
namespace ClangBackEnd {
class CodeCompletionChunkConverter
{
public:
static CodeCompletionChunks extract(CXCompletionString completionString);
static Utf8String chunkText(CXCompletionString completionString, uint chunkIndex);
private:
static CodeCompletionChunk::Kind chunkKind(CXCompletionString completionString, uint chunkIndex);
void extractCompletionChunks(CXCompletionString completionString);
void extractOptionalCompletionChunks(CXCompletionString completionString);
private:
CodeCompletionChunks chunks;
};
} // namespace ClangBackEnd

View File

@@ -0,0 +1,354 @@
/****************************************************************************
**
** 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 "codecompletionsextractor.h"
#include "clangstring.h"
#include "codecompletionchunkconverter.h"
#include <QDebug>
namespace ClangBackEnd {
CodeCompletionsExtractor::CodeCompletionsExtractor(CXCodeCompleteResults *cxCodeCompleteResults)
: cxCodeCompleteResults(cxCodeCompleteResults)
{
}
bool CodeCompletionsExtractor::next()
{
const uint cxCodeCompleteResultCount = cxCodeCompleteResults->NumResults;
if (cxCodeCompleteResultIndex < cxCodeCompleteResultCount) {
currentCxCodeCompleteResult = cxCodeCompleteResults->Results[cxCodeCompleteResultIndex];
currentCodeCompletion_ = CodeCompletion();
extractCompletionKind();
extractText();
extractPriority();
extractAvailability();
extractHasParameters();
extractBriefComment();
extractCompletionChunks();
adaptPriority();
++cxCodeCompleteResultIndex;
return true;
}
return false;
}
bool CodeCompletionsExtractor::peek(const Utf8String &name)
{
const uint cxCodeCompleteResultCount = cxCodeCompleteResults->NumResults;
uint peekCxCodeCompleteResultIndex = cxCodeCompleteResultIndex;
while (peekCxCodeCompleteResultIndex < cxCodeCompleteResultCount) {
if (hasText(name, cxCodeCompleteResults->Results[peekCxCodeCompleteResultIndex].CompletionString))
return true;
++peekCxCodeCompleteResultIndex;
}
return false;
}
CodeCompletions CodeCompletionsExtractor::extractAll()
{
CodeCompletions codeCompletions;
codeCompletions.reserve(int(cxCodeCompleteResults->NumResults));
while (next())
codeCompletions.append(currentCodeCompletion_);
return codeCompletions;
}
void CodeCompletionsExtractor::extractCompletionKind()
{
switch (currentCxCodeCompleteResult.CursorKind) {
case CXCursor_FunctionTemplate:
currentCodeCompletion_.setCompletionKind(CodeCompletion::TemplateFunctionCompletionKind);
break;
case CXCursor_CXXMethod:
extractMethodCompletionKind();
break;
case CXCursor_FunctionDecl:
case CXCursor_ConversionFunction:
currentCodeCompletion_.setCompletionKind(CodeCompletion::FunctionCompletionKind);
break;
case CXCursor_VariableRef:
case CXCursor_VarDecl:
case CXCursor_FieldDecl:
case CXCursor_ParmDecl:
case CXCursor_NonTypeTemplateParameter:
currentCodeCompletion_.setCompletionKind(CodeCompletion::VariableCompletionKind);
break;
case CXCursor_StructDecl:
case CXCursor_UnionDecl:
case CXCursor_ClassDecl:
case CXCursor_TemplateTypeParameter:
currentCodeCompletion_.setCompletionKind(CodeCompletion::ClassCompletionKind);
break;
case CXCursor_TypedefDecl:
case CXCursor_TypeAliasDecl:
currentCodeCompletion_.setCompletionKind(CodeCompletion::TypeAliasCompletionKind);
break;
case CXCursor_ClassTemplatePartialSpecialization:
case CXCursor_ClassTemplate:
case CXCursor_TemplateTemplateParameter:
currentCodeCompletion_.setCompletionKind(CodeCompletion::TemplateClassCompletionKind);
break;
case CXCursor_Namespace:
case CXCursor_NamespaceAlias:
currentCodeCompletion_.setCompletionKind(CodeCompletion::NamespaceCompletionKind);
break;
case CXCursor_EnumDecl:
currentCodeCompletion_.setCompletionKind(CodeCompletion::EnumerationCompletionKind);
break;
case CXCursor_EnumConstantDecl:
currentCodeCompletion_.setCompletionKind(CodeCompletion::EnumeratorCompletionKind);
break;
case CXCursor_Constructor:
currentCodeCompletion_.setCompletionKind(CodeCompletion::ConstructorCompletionKind);
break;
case CXCursor_Destructor:
currentCodeCompletion_.setCompletionKind(CodeCompletion::DestructorCompletionKind);
break;
case CXCursor_MacroDefinition:
extractMacroCompletionKind();
break;
case CXCursor_NotImplemented:
currentCodeCompletion_.setCompletionKind(CodeCompletion::KeywordCompletionKind);
break;
case CXCursor_OverloadCandidate:
currentCodeCompletion_.setCompletionKind(CodeCompletion::FunctionOverloadCompletionKind);
break;
default:
currentCodeCompletion_.setCompletionKind(CodeCompletion::Other);
}
}
void CodeCompletionsExtractor::extractText()
{
const uint completionChunkCount = clang_getNumCompletionChunks(currentCxCodeCompleteResult.CompletionString);
for (uint chunkIndex = 0; chunkIndex < completionChunkCount; ++chunkIndex) {
const CXCompletionChunkKind chunkKind = clang_getCompletionChunkKind(currentCxCodeCompleteResult.CompletionString, chunkIndex);
if (chunkKind == CXCompletionChunk_TypedText) {
currentCodeCompletion_.setText(CodeCompletionChunkConverter::chunkText(currentCxCodeCompleteResult.CompletionString, chunkIndex));
break;
}
}
}
void CodeCompletionsExtractor::extractMethodCompletionKind()
{
CXCompletionString cxCompletionString = cxCodeCompleteResults->Results[cxCodeCompleteResultIndex].CompletionString;
const uint annotationCount = clang_getCompletionNumAnnotations(cxCompletionString);
for (uint annotationIndex = 0; annotationIndex < annotationCount; ++annotationIndex) {
ClangString annotation = clang_getCompletionAnnotation(cxCompletionString, annotationIndex);
if (annotation == Utf8StringLiteral("qt_signal")) {
currentCodeCompletion_.setCompletionKind(CodeCompletion::SignalCompletionKind);
return;
}
if (annotation == Utf8StringLiteral("qt_slot")) {
currentCodeCompletion_.setCompletionKind(CodeCompletion::SlotCompletionKind);
return;
}
}
currentCodeCompletion_.setCompletionKind(CodeCompletion::FunctionCompletionKind);
}
void CodeCompletionsExtractor::extractMacroCompletionKind()
{
CXCompletionString cxCompletionString = cxCodeCompleteResults->Results[cxCodeCompleteResultIndex].CompletionString;
const uint completionChunkCount = clang_getNumCompletionChunks(cxCompletionString);
for (uint chunkIndex = 0; chunkIndex < completionChunkCount; ++chunkIndex) {
CXCompletionChunkKind kind = clang_getCompletionChunkKind(cxCompletionString, chunkIndex);
if (kind == CXCompletionChunk_Placeholder) {
currentCodeCompletion_.setCompletionKind(CodeCompletion::FunctionCompletionKind);
return;
}
}
currentCodeCompletion_.setCompletionKind(CodeCompletion::PreProcessorCompletionKind);
}
void CodeCompletionsExtractor::extractPriority()
{
CXCompletionString cxCompletionString = cxCodeCompleteResults->Results[cxCodeCompleteResultIndex].CompletionString;
quint32 priority = clang_getCompletionPriority(cxCompletionString);
currentCodeCompletion_.setPriority(priority);
}
void CodeCompletionsExtractor::extractAvailability()
{
CXCompletionString cxCompletionString = cxCodeCompleteResults->Results[cxCodeCompleteResultIndex].CompletionString;
CXAvailabilityKind cxAvailabilityKind = clang_getCompletionAvailability(cxCompletionString);
switch (cxAvailabilityKind) {
case CXAvailability_Available:
currentCodeCompletion_.setAvailability(CodeCompletion::Available);
break;
case CXAvailability_Deprecated:
currentCodeCompletion_.setAvailability(CodeCompletion::Deprecated);
break;
case CXAvailability_NotAvailable:
currentCodeCompletion_.setAvailability(CodeCompletion::NotAvailable);
break;
case CXAvailability_NotAccessible:
currentCodeCompletion_.setAvailability(CodeCompletion::NotAccessible);
break;
}
}
void CodeCompletionsExtractor::extractHasParameters()
{
const uint completionChunkCount = clang_getNumCompletionChunks(currentCxCodeCompleteResult.CompletionString);
for (uint chunkIndex = 0; chunkIndex < completionChunkCount; ++chunkIndex) {
const CXCompletionChunkKind chunkKind = clang_getCompletionChunkKind(currentCxCodeCompleteResult.CompletionString, chunkIndex);
if (chunkKind == CXCompletionChunk_LeftParen) {
const CXCompletionChunkKind nextChunkKind = clang_getCompletionChunkKind(currentCxCodeCompleteResult.CompletionString, chunkIndex + 1);
currentCodeCompletion_.setHasParameters(nextChunkKind != CXCompletionChunk_RightParen);
return;
}
}
}
void CodeCompletionsExtractor::extractBriefComment()
{
ClangString briefComment = clang_getCompletionBriefComment(currentCxCodeCompleteResult.CompletionString);
currentCodeCompletion_.setBriefComment(briefComment);
}
void CodeCompletionsExtractor::extractCompletionChunks()
{
currentCodeCompletion_.setChunks(CodeCompletionChunkConverter::extract(currentCxCodeCompleteResult.CompletionString));
}
void CodeCompletionsExtractor::adaptPriority()
{
decreasePriorityForDestructors();
decreasePriorityForNonAvailableCompletions();
decreasePriorityForQObjectInternals();
decreasePriorityForSignals();
decreasePriorityForOperators();
}
void CodeCompletionsExtractor::decreasePriorityForNonAvailableCompletions()
{
if (currentCodeCompletion_.availability() != CodeCompletion::Available)
currentCodeCompletion_.setPriority(currentCodeCompletion_.priority() * 100);
}
void CodeCompletionsExtractor::decreasePriorityForDestructors()
{
if (currentCodeCompletion_.completionKind() == CodeCompletion::DestructorCompletionKind)
currentCodeCompletion_.setPriority(currentCodeCompletion_.priority() * 100);
}
void CodeCompletionsExtractor::decreasePriorityForSignals()
{
if (currentCodeCompletion_.completionKind() == CodeCompletion::SignalCompletionKind)
currentCodeCompletion_.setPriority(currentCodeCompletion_.priority() * 100);
}
void CodeCompletionsExtractor::decreasePriorityForQObjectInternals()
{
quint32 priority = currentCodeCompletion_.priority();
if (currentCodeCompletion_.text().startsWith("qt_"))
priority *= 100;
if (currentCodeCompletion_.text() == Utf8StringLiteral("metaObject"))
priority *= 10;
if (currentCodeCompletion_.text() == Utf8StringLiteral("staticMetaObject"))
priority *= 100;
currentCodeCompletion_.setPriority(priority);
}
bool isOperator(CXCursorKind cxCursorKind, const Utf8String &name)
{
return cxCursorKind == CXCursor_ConversionFunction
|| (cxCursorKind == CXCursor_CXXMethod
&& name.startsWith(Utf8StringLiteral("operator")));
}
void CodeCompletionsExtractor::decreasePriorityForOperators()
{
quint32 priority = currentCodeCompletion_.priority();
if (isOperator(currentCxCodeCompleteResult.CursorKind, currentCodeCompletion().text()))
priority *= 100;
currentCodeCompletion_.setPriority(priority);
}
bool CodeCompletionsExtractor::hasText(const Utf8String &text, CXCompletionString cxCompletionString) const
{
const uint completionChunkCount = clang_getNumCompletionChunks(cxCompletionString);
for (uint chunkIndex = 0; chunkIndex < completionChunkCount; ++chunkIndex) {
const CXCompletionChunkKind chunkKind = clang_getCompletionChunkKind(cxCompletionString, chunkIndex);
if (chunkKind == CXCompletionChunk_TypedText) {
const ClangString currentText(clang_getCompletionChunkText(cxCompletionString, chunkIndex));
return text == currentText;
}
}
return false;
}
const CodeCompletion &CodeCompletionsExtractor::currentCodeCompletion() const
{
return currentCodeCompletion_;
}
std::ostream &operator<<(std::ostream &os, const CodeCompletionsExtractor &extractor)
{
os << "name: " << extractor.currentCodeCompletion().text()
<< ", kind: " << extractor.currentCodeCompletion().completionKind()
<< ", priority: " << extractor.currentCodeCompletion().priority()
<< ", kind: " << extractor.currentCodeCompletion().availability();
return os;
}
} // namespace ClangBackEnd

View File

@@ -0,0 +1,84 @@
/****************************************************************************
**
** 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 <codecompletion.h>
#include <clang-c/Index.h>
#include <QVector>
#include <iosfwd>
namespace ClangBackEnd {
class CodeCompletionsExtractor
{
public:
CodeCompletionsExtractor(CXCodeCompleteResults *cxCodeCompleteResults);
CodeCompletionsExtractor(CodeCompletionsExtractor&) = delete;
CodeCompletionsExtractor &operator=(CodeCompletionsExtractor&) = delete;
CodeCompletionsExtractor(CodeCompletionsExtractor&&) = delete;
CodeCompletionsExtractor &operator=(CodeCompletionsExtractor&&) = delete;
bool next();
bool peek(const Utf8String &name);
CodeCompletions extractAll();
const CodeCompletion &currentCodeCompletion() const;
private:
void extractCompletionKind();
void extractText();
void extractMethodCompletionKind();
void extractMacroCompletionKind();
void extractPriority();
void extractAvailability();
void extractHasParameters();
void extractBriefComment();
void extractCompletionChunks();
void adaptPriority();
void decreasePriorityForNonAvailableCompletions();
void decreasePriorityForDestructors();
void decreasePriorityForSignals();
void decreasePriorityForQObjectInternals();
void decreasePriorityForOperators();
bool hasText(const Utf8String &text, CXCompletionString cxCompletionString) const;
private:
CodeCompletion currentCodeCompletion_;
CXCompletionResult currentCxCodeCompleteResult;
CXCodeCompleteResults *cxCodeCompleteResults;
uint cxCodeCompleteResultIndex = 0;
};
std::ostream &operator<<(std::ostream &os, const CodeCompletionsExtractor &extractor);
} // namespace ClangBackEnd

View File

@@ -0,0 +1,91 @@
/****************************************************************************
**
** 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 "commandlinearguments.h"
#include "clangfilepath.h"
#include <utf8string.h>
#include <utils/qtcprocess.h>
#include <QByteArray>
#include <iostream>
namespace ClangBackEnd {
CommandLineArguments::CommandLineArguments(const char *filePath,
const Utf8StringVector &projectPartArguments,
const Utf8StringVector &fileArguments,
bool addVerboseOption)
{
const auto elementsToReserve = projectPartArguments.size()
+ uint(fileArguments.size())
+ (addVerboseOption ? 1 : 0);
m_arguments.reserve(elementsToReserve);
for (const auto &argument : projectPartArguments)
m_arguments.push_back(argument.constData());
for (const auto &argument : fileArguments)
m_arguments.push_back(argument.constData());
if (addVerboseOption)
m_arguments.push_back("-v");
m_nativeFilePath = FilePath::toNativeSeparators(Utf8String::fromUtf8(filePath));
m_arguments.push_back(m_nativeFilePath.constData());
}
const char * const *CommandLineArguments::data() const
{
return m_arguments.data();
}
int CommandLineArguments::count() const
{
return int(m_arguments.size());
}
const char *CommandLineArguments::at(int position) const
{
return m_arguments.at(uint(position));
}
static Utf8String maybeQuoted(const char *argumentAsCString)
{
const QString argumentAsQString = QString::fromUtf8(argumentAsCString);
const QString quotedArgument = Utils::QtcProcess::quoteArg(argumentAsQString);
return Utf8String::fromString(quotedArgument);
}
void CommandLineArguments::print() const
{
using namespace std;
cerr << "Arguments to libclang:";
for (const auto &argument : m_arguments)
cerr << ' ' << maybeQuoted(argument).constData();
cerr << endl;
}
} // namespace ClangBackEnd

View File

@@ -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 <utf8stringvector.h>
#include <vector>
namespace ClangBackEnd {
class CommandLineArguments
{
public:
CommandLineArguments(const char *filePath,
const Utf8StringVector &projectPartArguments,
const Utf8StringVector &fileArguments,
bool addVerboseOption);
const char * const *data() const;
int count() const;
const char * at(int position) const;
void print() const;
private:
Utf8String m_nativeFilePath;
std::vector<const char *> m_arguments;
};
} // namespace ClangBackEnd

View File

@@ -0,0 +1,439 @@
/****************************************************************************
**
** 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 "cursor.h"
#include "clangstring.h"
#include "sourcelocation.h"
#include "sourcerange.h"
#include <ostream>
namespace ClangBackEnd {
Cursor::Cursor()
: cxCursor(clang_getNullCursor())
{
}
Cursor::Cursor(CXCursor cxCursor)
: cxCursor(cxCursor)
{
}
bool Cursor::isNull() const
{
return clang_Cursor_isNull(cxCursor);
}
bool Cursor::isValid() const
{
return !clang_isInvalid(kind());
}
bool Cursor::isTranslationUnit() const
{
return clang_isTranslationUnit(kind());
}
bool Cursor::isDefinition() const
{
return clang_isCursorDefinition(cxCursor);
}
bool Cursor::isDynamicCall() const
{
return clang_Cursor_isDynamicCall(cxCursor);
}
bool Cursor::isVirtualMethod() const
{
return clang_CXXMethod_isVirtual(cxCursor);
}
bool Cursor::isPureVirtualMethod() const
{
return clang_CXXMethod_isPureVirtual(cxCursor);
}
bool Cursor::isConstantMethod() const
{
return clang_CXXMethod_isConst(cxCursor);
}
bool Cursor::isStaticMethod() const
{
return clang_CXXMethod_isStatic(cxCursor);
}
bool Cursor::isCompoundType() const
{
switch (kind()) {
case CXCursor_ClassDecl:
case CXCursor_StructDecl:
case CXCursor_UnionDecl: return true;
default: return false;
}
}
bool Cursor::isDeclaration() const
{
return clang_isDeclaration(kind());
}
bool Cursor::isLocalVariable() const
{
switch (semanticParent().kind()) {
case CXCursor_FunctionDecl:
case CXCursor_CXXMethod:
case CXCursor_Constructor:
case CXCursor_Destructor:
case CXCursor_ConversionFunction:
case CXCursor_FunctionTemplate:
case CXCursor_ObjCInstanceMethodDecl: return true;
default:
return false;
}
}
bool Cursor::isReference() const
{
return clang_isReference(kind());
}
bool Cursor::isExpression() const
{
return clang_isExpression(kind());
}
bool Cursor::isFunctionLike() const
{
const CXCursorKind k = kind();
return k == CXCursor_FunctionDecl
|| k == CXCursor_CXXMethod
|| k == CXCursor_FunctionTemplate;
}
bool Cursor::isConstructorOrDestructor() const
{
const CXCursorKind k = kind();
return k == CXCursor_Constructor
|| k == CXCursor_Destructor;
}
bool Cursor::isTemplateLike() const
{
switch (kind()) {
case CXCursor_ClassTemplate:
case CXCursor_ClassTemplatePartialSpecialization:
return true;
case CXCursor_ClassDecl:
return specializedCursorTemplate().isValid();
default:
return false;
}
Q_UNREACHABLE();
}
bool Cursor::hasFinalFunctionAttribute() const
{
bool hasFinal = false;
visit([&] (Cursor cursor, Cursor /*parent*/) {
if (cursor.kind() == CXCursor_CXXFinalAttr) {
hasFinal = true;
return CXChildVisit_Break;
} else {
return CXChildVisit_Recurse;
}
});
return hasFinal;
}
bool Cursor::hasFinalClassAttribute() const
{
bool hasFinal = false;
visit([&] (Cursor cursor, Cursor /*parent*/) {
switch (cursor.kind()) {
case CXCursor_CXXFinalAttr:
hasFinal = true;
return CXChildVisit_Break;
case CXCursor_CXXMethod:
return CXChildVisit_Break;
default:
return CXChildVisit_Recurse;
}
});
return hasFinal;
}
bool Cursor::isUnexposed() const
{
return clang_isUnexposed(kind());
}
ClangString Cursor::unifiedSymbolResolution() const
{
return ClangString(clang_getCursorUSR(cxCursor));
}
ClangString Cursor::mangling() const
{
return ClangString(clang_Cursor_getMangling(cxCursor));
}
ClangString Cursor::spelling() const
{
return ClangString(clang_getCursorSpelling(cxCursor));
}
ClangString Cursor::displayName() const
{
return ClangString(clang_getCursorDisplayName(cxCursor));
}
ClangString Cursor::briefComment() const
{
return ClangString(clang_Cursor_getBriefCommentText(cxCursor));
}
ClangString Cursor::rawComment() const
{
return ClangString(clang_Cursor_getRawCommentText(cxCursor));
}
int Cursor::argumentCount() const
{
return clang_Cursor_getNumArguments(cxCursor);
}
Type Cursor::type() const
{
return clang_getCursorType(cxCursor);
}
Type Cursor::nonPointerTupe() const
{
auto typeResult = type();
if (typeResult.isPointer())
typeResult = typeResult.pointeeType();
return typeResult;
}
Cursor Cursor::specializedCursorTemplate() const
{
return clang_getSpecializedCursorTemplate(cxCursor);
}
SourceLocation Cursor::sourceLocation() const
{
return clang_getCursorLocation(cxCursor);
}
CXSourceLocation Cursor::cxSourceLocation() const
{
return clang_getCursorLocation(cxCursor);
}
SourceRange Cursor::sourceRange() const
{
return clang_getCursorExtent(cxCursor);
}
CXSourceRange Cursor::cxSourceRange() const
{
return clang_getCursorExtent(cxCursor);
}
CXTranslationUnit Cursor::cxTranslationUnit() const
{
return clang_Cursor_getTranslationUnit(cxCursor);
}
SourceRange Cursor::commentRange() const
{
return clang_Cursor_getCommentRange(cxCursor);
}
bool Cursor::hasSameSourceLocationAs(const Cursor &other) const
{
return clang_equalLocations(clang_getCursorLocation(cxCursor),
clang_getCursorLocation(other.cxCursor));
}
Cursor Cursor::definition() const
{
return clang_getCursorDefinition(cxCursor);
}
Cursor Cursor::canonical() const
{
return clang_getCanonicalCursor(cxCursor);
}
Cursor Cursor::referenced() const
{
return clang_getCursorReferenced(cxCursor);
}
Cursor Cursor::semanticParent() const
{
return clang_getCursorSemanticParent(cxCursor);
}
Cursor Cursor::lexicalParent() const
{
return clang_getCursorLexicalParent(cxCursor);
}
Cursor Cursor::functionBaseDeclaration() const
{
auto functionBaseCursor = functionBase();
if (functionBaseCursor.isValid())
return functionBaseCursor.nonPointerTupe().canonical().declaration();
else
return semanticParent().semanticParent();
}
Cursor Cursor::functionBase() const
{
Cursor functionBaseCursor;
visit([&] (Cursor cursor, Cursor /*parentCursor*/) {
switch (cursor.kind()) {
case CXCursor_DeclRefExpr:
functionBaseCursor = cursor; ;
return CXChildVisit_Break;
default:
return CXChildVisit_Recurse;
}
});
return functionBaseCursor;
}
Cursor Cursor::argument(int index) const
{
return clang_Cursor_getArgument(cxCursor, index);
}
unsigned Cursor::overloadedDeclarationsCount() const
{
return clang_getNumOverloadedDecls(cxCursor);
}
Cursor Cursor::overloadedDeclaration(unsigned index) const
{
return clang_getOverloadedDecl(cxCursor, index);
}
namespace {
bool isNotUnexposedLValueReference(const Cursor &argument, const Type &argumentType)
{
return !(argument.isUnexposed() && argumentType.isLValueReference());
}
}
void Cursor::collectOutputArgumentRangesTo(std::vector<CXSourceRange> &outputArgumentRanges) const
{
const Type callExpressionType = referenced().type();
const int argumentCount = this->argumentCount();
const std::size_t maxSize = std::size_t(std::max(0, argumentCount))
+ outputArgumentRanges.size();
outputArgumentRanges.reserve(maxSize);
for (int argumentIndex = 0; argumentIndex < argumentCount; ++argumentIndex) {
const Cursor argument = this->argument(argumentIndex);
const Type argumentType = callExpressionType.argument(argumentIndex);
if (isNotUnexposedLValueReference(argument, argumentType)
&& argumentType.isOutputArgument()) {
outputArgumentRanges.push_back(argument.cxSourceRange());
}
}
}
std::vector<CXSourceRange> Cursor::outputArgumentRanges() const
{
std::vector<CXSourceRange> outputArgumentRanges;
collectOutputArgumentRangesTo(outputArgumentRanges);
return outputArgumentRanges;
}
CXCursorKind Cursor::kind() const
{
return clang_getCursorKind(cxCursor);
}
bool operator==(const Cursor &first, const Cursor &second)
{
return clang_equalCursors(first.cxCursor, second.cxCursor);
}
bool operator!=(const Cursor &first, const Cursor &second)
{
return !(first == second);
}
std::ostream &operator<<(std::ostream &os, CXCursorKind cursorKind)
{
ClangString cursorKindSpelling(clang_getCursorKindSpelling(cursorKind));
return os << cursorKindSpelling.cString();
}
std::ostream &operator<<(std::ostream &os, const Cursor &cursor)
{
if (cursor.isValid()) {
ClangString cursorKindSpelling(clang_getCursorKindSpelling(cursor.kind()));
os << cursorKindSpelling << " ";
auto identifier = cursor.displayName();
if (identifier.hasContent()) {
os << "\""
<< identifier
<< "\": ";
}
os << cursor.sourceLocation();
} else {
os << "Invalid cursor!";
}
return os;
}
} // namespace ClangBackEnd

View File

@@ -0,0 +1,137 @@
/****************************************************************************
**
** 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 "clangtype.h"
#include <clang-c/Index.h>
#include <iosfwd>
#include <vector>
class Utf8String;
namespace ClangBackEnd {
class SourceLocation;
class SourceRange;
class ClangString;
class Cursor
{
friend class Type;
friend bool operator==(const Cursor &first, const Cursor &second);
public:
Cursor();
Cursor(CXCursor cxCursor);
bool isNull() const;
bool isValid() const;
bool isTranslationUnit() const;
bool isDefinition() const;
bool isDynamicCall() const;
bool isVirtualMethod() const;
bool isPureVirtualMethod() const;
bool isConstantMethod() const;
bool isStaticMethod() const;
bool isCompoundType() const;
bool isDeclaration() const;
bool isLocalVariable() const;
bool isReference() const;
bool isExpression() const;
bool isFunctionLike() const;
bool isConstructorOrDestructor() const;
bool isTemplateLike() const;
bool hasFinalFunctionAttribute() const;
bool hasFinalClassAttribute() const;
bool isUnexposed() const;
ClangString unifiedSymbolResolution() const;
ClangString mangling() const;
ClangString spelling() const;
ClangString displayName() const;
ClangString briefComment() const;
ClangString rawComment() const;
int argumentCount() const;
Type type() const;
Type nonPointerTupe() const;
SourceLocation sourceLocation() const;
CXSourceLocation cxSourceLocation() const;
SourceRange sourceRange() const;
CXSourceRange cxSourceRange() const;
CXTranslationUnit cxTranslationUnit() const;
SourceRange commentRange() const;
bool hasSameSourceLocationAs(const Cursor &other) const;
Cursor definition() const;
Cursor canonical() const;
Cursor alias() const;
Cursor referenced() const;
Cursor semanticParent() const;
Cursor lexicalParent() const;
Cursor functionBaseDeclaration() const;
Cursor functionBase() const;
Cursor argument(int index) const;
unsigned overloadedDeclarationsCount() const;
Cursor overloadedDeclaration(unsigned index) const;
Cursor specializedCursorTemplate() const;
void collectOutputArgumentRangesTo(
std::vector<CXSourceRange> &outputArgumentRanges) const;
std::vector<CXSourceRange> outputArgumentRanges() const;
CXCursorKind kind() const;
template <class VisitorCallback>
void visit(VisitorCallback visitorCallback) const;
private:
CXCursor cxCursor;
};
template <class VisitorCallback>
void Cursor::visit(VisitorCallback visitorCallback) const
{
auto visitor = [] (CXCursor cursor, CXCursor parent, CXClientData lambda) -> CXChildVisitResult {
auto &visitorCallback = *static_cast<VisitorCallback*>(lambda);
return visitorCallback(cursor, parent);
};
clang_visitChildren(cxCursor, visitor, &visitorCallback);
}
bool operator==(const Cursor &first, const Cursor &second);
bool operator!=(const Cursor &first, const Cursor &second);
std::ostream &operator<<(std::ostream &os, CXCursorKind cursorKind);
std::ostream &operator<<(std::ostream &os, const Cursor &cursor);
} // namespace ClangBackEnd

View File

@@ -0,0 +1,175 @@
/****************************************************************************
**
** 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 "diagnostic.h"
#include "clangstring.h"
#include "diagnosticset.h"
#include "fixit.h"
#include "sourcelocation.h"
#include "sourcerange.h"
#include <diagnosticcontainer.h>
#include <memory>
namespace ClangBackEnd {
Diagnostic::Diagnostic(CXDiagnostic cxDiagnostic)
: cxDiagnostic(cxDiagnostic)
{
}
Diagnostic::~Diagnostic()
{
clang_disposeDiagnostic(cxDiagnostic);
}
Diagnostic::Diagnostic(Diagnostic &&other)
: cxDiagnostic(std::move(other.cxDiagnostic))
{
other.cxDiagnostic = nullptr;
}
Diagnostic &Diagnostic::operator=(Diagnostic &&other)
{
if (this != &other) {
clang_disposeDiagnostic(cxDiagnostic);
cxDiagnostic = std::move(other.cxDiagnostic);
other.cxDiagnostic = nullptr;
}
return *this;
}
bool Diagnostic::isNull() const
{
return cxDiagnostic == nullptr;
}
Utf8String Diagnostic::text() const
{
return ClangString(clang_formatDiagnostic(cxDiagnostic, 0));
}
Utf8String Diagnostic::category() const
{
return ClangString(clang_getDiagnosticCategoryText(cxDiagnostic));
}
std::pair<Utf8String, Utf8String> Diagnostic::options() const
{
CXString disableString;
const Utf8String enableOption = ClangString(clang_getDiagnosticOption(cxDiagnostic, &disableString));
const Utf8String disableOption = ClangString(disableString);
return {enableOption, disableOption};
}
SourceLocation Diagnostic::location() const
{
return SourceLocation(clang_getDiagnosticLocation(cxDiagnostic));
}
DiagnosticSeverity Diagnostic::severity() const
{
return static_cast<DiagnosticSeverity>(clang_getDiagnosticSeverity(cxDiagnostic));
}
std::vector<SourceRange> Diagnostic::ranges() const
{
std::vector<SourceRange> ranges;
const uint rangesCount = clang_getDiagnosticNumRanges(cxDiagnostic);
ranges.reserve(rangesCount);
for (uint index = 0; index < rangesCount; ++index) {
const SourceRange sourceRange(clang_getDiagnosticRange(cxDiagnostic, index));
if (sourceRange.isValid())
ranges.push_back(std::move(sourceRange));
}
return ranges;
}
std::vector<FixIt> Diagnostic::fixIts() const
{
std::vector<FixIt> fixIts;
const uint fixItsCount = clang_getDiagnosticNumFixIts(cxDiagnostic);
fixIts.reserve(fixItsCount);
for (uint index = 0; index < fixItsCount; ++index)
fixIts.push_back(FixIt(cxDiagnostic, index));
return fixIts;
}
DiagnosticSet Diagnostic::childDiagnostics() const
{
return DiagnosticSet(clang_getChildDiagnostics(cxDiagnostic));
}
DiagnosticContainer Diagnostic::toDiagnosticContainer() const
{
return DiagnosticContainer(text(),
category(),
options(),
severity(),
location().toSourceLocationContainer(),
getSourceRangeContainers(),
getFixItContainers(),
childDiagnostics().toDiagnosticContainers());
}
QVector<SourceRangeContainer> Diagnostic::getSourceRangeContainers() const
{
auto rangeVector = ranges();
QVector<SourceRangeContainer> sourceRangeContainers;
sourceRangeContainers.reserve(int(rangeVector.size()));
for (auto &&sourceRange : rangeVector)
sourceRangeContainers.push_back(sourceRange.toSourceRangeContainer());
return sourceRangeContainers;
}
QVector<FixItContainer> Diagnostic::getFixItContainers() const
{
auto fixItVector = fixIts();
QVector<FixItContainer> fixItContainers;
fixItContainers.reserve(int(fixItVector.size()));
for (auto &&fixIt : fixItVector)
fixItContainers.push_back(fixIt.toFixItContainer());
return fixItContainers;
}
} // namespace ClangBackEnd

View File

@@ -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 <clangsupport_global.h>
#include <clang-c/Index.h>
#include <functional>
#include <vector>
class Utf8String;
namespace ClangBackEnd {
class SourceLocation;
class SourceRange;
class FixIt;
class DiagnosticSet;
class DiagnosticContainer;
class SourceRangeContainer;
class FixItContainer;
class Diagnostic
{
friend class DiagnosticSet;
friend class DiagnosticSetIterator;
friend bool operator==(Diagnostic first, Diagnostic second);
public:
~Diagnostic();
Diagnostic(const Diagnostic &) = delete;
const Diagnostic &operator=(const Diagnostic &) = delete;
Diagnostic(Diagnostic &&other);
Diagnostic &operator=(Diagnostic &&other);
bool isNull() const;
Utf8String text() const;
Utf8String category() const;
std::pair<Utf8String, Utf8String> options() const;
SourceLocation location() const;
DiagnosticSeverity severity() const;
std::vector<SourceRange> ranges() const;
std::vector<FixIt> fixIts() const;
DiagnosticSet childDiagnostics() const;
DiagnosticContainer toDiagnosticContainer() const;
private:
Diagnostic(CXDiagnostic cxDiagnostic);
QVector<SourceRangeContainer> getSourceRangeContainers() const;
QVector<FixItContainer> getFixItContainers() const;
private:
CXDiagnostic cxDiagnostic;
};
inline bool operator==(Diagnostic first, Diagnostic second)
{
return first.cxDiagnostic == second.cxDiagnostic;
}
} // namespace ClangBackEnd

View File

@@ -0,0 +1,120 @@
/****************************************************************************
**
** 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 "diagnosticset.h"
#include "diagnostic.h"
#include <diagnosticcontainer.h>
#include <memory>
namespace ClangBackEnd {
DiagnosticSet::DiagnosticSet(CXDiagnosticSet cxDiagnosticSet)
: cxDiagnosticSet(cxDiagnosticSet)
{
}
DiagnosticSet::~DiagnosticSet()
{
clang_disposeDiagnosticSet(cxDiagnosticSet);
}
DiagnosticSet::DiagnosticSet(DiagnosticSet &&other)
: cxDiagnosticSet(std::move(other.cxDiagnosticSet))
{
other.cxDiagnosticSet = nullptr;
}
DiagnosticSet &DiagnosticSet::operator=(DiagnosticSet &&other)
{
if (this != &other) {
clang_disposeDiagnosticSet(cxDiagnosticSet);
cxDiagnosticSet = std::move(other.cxDiagnosticSet);
other.cxDiagnosticSet = nullptr;
}
return *this;
}
Diagnostic DiagnosticSet::front() const
{
return Diagnostic(clang_getDiagnosticInSet(cxDiagnosticSet, 0));
}
Diagnostic DiagnosticSet::back() const
{
return Diagnostic(clang_getDiagnosticInSet(cxDiagnosticSet, size() - 1));
}
DiagnosticSet::ConstIterator DiagnosticSet::begin() const
{
return DiagnosticSetIterator(cxDiagnosticSet, 0);
}
DiagnosticSet::ConstIterator DiagnosticSet::end() const
{
return DiagnosticSetIterator(cxDiagnosticSet, size());
}
QVector<DiagnosticContainer> DiagnosticSet::toDiagnosticContainers() const
{
const auto isAcceptedDiagnostic = [](const Diagnostic &) { return true; };
return toDiagnosticContainers(isAcceptedDiagnostic);
}
QVector<DiagnosticContainer> DiagnosticSet::toDiagnosticContainers(
const IsAcceptedDiagnostic &isAcceptedDiagnostic) const
{
QVector<DiagnosticContainer> diagnosticContainers;
diagnosticContainers.reserve(size());
for (const Diagnostic &diagnostic : *this) {
if (isAcceptedDiagnostic(diagnostic))
diagnosticContainers.push_back(diagnostic.toDiagnosticContainer());
}
return diagnosticContainers;
}
uint DiagnosticSet::size() const
{
return clang_getNumDiagnosticsInSet(cxDiagnosticSet);
}
bool DiagnosticSet::isNull() const
{
return cxDiagnosticSet == nullptr;
}
Diagnostic DiagnosticSet::at(uint index) const
{
return Diagnostic(clang_getDiagnosticInSet(cxDiagnosticSet, index));
}
} // namespace ClangBackEnd

View File

@@ -0,0 +1,81 @@
/****************************************************************************
**
** 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 "diagnostic.h"
#include "diagnosticsetiterator.h"
#include <clang-c/Index.h>
#include <QVector>
#include <functional>
namespace ClangBackEnd {
class DiagnosticSetIterator;
class DiagnosticSet
{
friend class TranslationUnit;
friend class Diagnostic;
public:
using ConstIterator = DiagnosticSetIterator;
public:
~DiagnosticSet();
DiagnosticSet(const DiagnosticSet &) = delete;
const DiagnosticSet &operator=(const DiagnosticSet &) = delete;
DiagnosticSet(DiagnosticSet &&other);
DiagnosticSet &operator=(DiagnosticSet &&other);
uint size() const;
bool isNull() const;
Diagnostic at(uint index) const;
Diagnostic front() const;
Diagnostic back() const;
ConstIterator begin() const;
ConstIterator end() const;
using IsAcceptedDiagnostic = std::function<bool (const Diagnostic &)>;
QVector<DiagnosticContainer> toDiagnosticContainers() const;
QVector<DiagnosticContainer> toDiagnosticContainers(
const IsAcceptedDiagnostic &isAcceptedDiagnostic) const;
private:
DiagnosticSet(CXDiagnosticSet cxDiagnosticSet);
private:
CXDiagnosticSet cxDiagnosticSet;
};
} // namespace ClangBackEnd

View File

@@ -0,0 +1,84 @@
/****************************************************************************
**
** 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 <iterator>
#include <clang-c/Index.h>
namespace ClangBackEnd {
using uint = unsigned int;
class DiagnosticSet;
class Diagnostic;
class DiagnosticSetIterator : public std::iterator<std::random_access_iterator_tag, Diagnostic, uint>
{
public:
DiagnosticSetIterator(CXDiagnosticSet cxDiagnosticSet, uint index)
: cxDiagnosticSet(cxDiagnosticSet),
index(index)
{}
DiagnosticSetIterator(const DiagnosticSetIterator &other)
: cxDiagnosticSet(other.cxDiagnosticSet),
index(other.index)
{}
DiagnosticSetIterator& operator++()
{
++index;
return *this;
}
DiagnosticSetIterator operator++(int)
{
uint oldIndex = index++;
return DiagnosticSetIterator(cxDiagnosticSet, oldIndex);
}
bool operator==(const DiagnosticSetIterator &other)
{
return index == other.index && cxDiagnosticSet == other.cxDiagnosticSet;
}
bool operator!=(const DiagnosticSetIterator &other)
{
return index != other.index || cxDiagnosticSet != other.cxDiagnosticSet;
}
Diagnostic operator*()
{
return Diagnostic(clang_getDiagnosticInSet(cxDiagnosticSet, index));
}
private:
CXDiagnosticSet cxDiagnosticSet;
uint index;
};
}

View File

@@ -0,0 +1,58 @@
/****************************************************************************
**
** 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 "fixit.h"
#include "clangstring.h"
#include <fixitcontainer.h>
namespace ClangBackEnd {
const Utf8String &FixIt::text() const
{
return text_;
}
const SourceRange &FixIt::range() const
{
return sourceRange;
}
FixItContainer FixIt::toFixItContainer() const
{
return FixItContainer(text_, sourceRange.toSourceRangeContainer());
}
FixIt::FixIt(CXDiagnostic cxDiagnostic, uint index)
{
CXSourceRange cxSourceRange;
text_ = ClangString(clang_getDiagnosticFixIt(cxDiagnostic, index, &cxSourceRange));
sourceRange = SourceRange(cxSourceRange);
}
} // namespace ClangBackEnd

View File

@@ -0,0 +1,57 @@
/****************************************************************************
**
** 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 "sourcerange.h"
#include <utf8string.h>
#include <clang-c/Index.h>
namespace ClangBackEnd {
class FixItContainer;
using uint = unsigned int;
class FixIt
{
friend class Diagnostic;
public:
const Utf8String &text() const;
const SourceRange &range() const;
FixItContainer toFixItContainer() const;
private:
FixIt(CXDiagnostic cxDiagnostic, uint index);
private:
SourceRange sourceRange;
Utf8String text_;
};
} // namespace ClangBackEnd

View File

@@ -0,0 +1,460 @@
/****************************************************************************
**
** 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 <highlightingmarkcontainer.h>
#include "clangstring.h"
#include "cursor.h"
#include "highlightingmark.h"
#include "sourcelocation.h"
#include "sourcerange.h"
#include "sourcerangecontainer.h"
#include <cstring>
#include <ostream>
#include <QDebug>
namespace ClangBackEnd {
HighlightingMark::HighlightingMark(const CXCursor &cxCursor,
CXToken *cxToken,
CXTranslationUnit cxTranslationUnit,
std::vector<CXSourceRange> &currentOutputArgumentRanges)
: m_currentOutputArgumentRanges(&currentOutputArgumentRanges),
m_originalCursor(cxCursor)
{
const SourceRange sourceRange = clang_getTokenExtent(cxTranslationUnit, *cxToken);
const auto start = sourceRange.start();
const auto end = sourceRange.end();
m_line = start.line();
m_column = start.column();
m_offset = start.offset();
m_length = end.offset() - start.offset();
collectKinds(cxTranslationUnit, cxToken, m_originalCursor);
}
HighlightingMark::HighlightingMark(uint line, uint column, uint length, HighlightingTypes types)
: m_line(line),
m_column(column),
m_length(length),
m_types(types)
{
}
HighlightingMark::HighlightingMark(uint line, uint column, uint length, HighlightingType type)
: m_line(line),
m_column(column),
m_length(length),
m_types(HighlightingTypes())
{
m_types.mainHighlightingType = type;
}
bool HighlightingMark::hasInvalidMainType() const
{
return m_types.mainHighlightingType == HighlightingType::Invalid;
}
bool HighlightingMark::hasMainType(HighlightingType type) const
{
return m_types.mainHighlightingType == type;
}
bool HighlightingMark::hasMixinType(HighlightingType type) const
{
auto found = std::find(m_types.mixinHighlightingTypes.begin(),
m_types.mixinHighlightingTypes.end(),
type);
return found != m_types.mixinHighlightingTypes.end();
}
bool HighlightingMark::hasOnlyType(HighlightingType type) const
{
return m_types.mixinHighlightingTypes.size() == 0 && hasMainType(type);
}
bool HighlightingMark::hasFunctionArguments() const
{
return m_originalCursor.argumentCount() > 0;
}
HighlightingMark::operator HighlightingMarkContainer() const
{
return HighlightingMarkContainer(m_line, m_column, m_length, m_types, m_isIdentifier,
m_isInclusion);
}
namespace {
bool isFinalFunction(const Cursor &cursor)
{
auto referencedCursor = cursor.referenced();
if (referencedCursor.hasFinalFunctionAttribute())
return true;
else
return false;
}
bool isFunctionInFinalClass(const Cursor &cursor)
{
auto functionBase = cursor.functionBaseDeclaration();
if (functionBase.isValid() && functionBase.hasFinalClassAttribute())
return true;
return false;
}
}
void HighlightingMark::memberReferenceKind(const Cursor &cursor)
{
if (cursor.isDynamicCall()) {
if (isFinalFunction(cursor) || isFunctionInFinalClass(cursor))
m_types.mainHighlightingType = HighlightingType::Function;
else
m_types.mainHighlightingType = HighlightingType::VirtualFunction;
} else {
identifierKind(cursor.referenced(), Recursion::RecursivePass);
}
}
void HighlightingMark::referencedTypeKind(const Cursor &cursor)
{
const Cursor referencedCursor = cursor.referenced();
switch (referencedCursor.kind()) {
case CXCursor_ClassDecl:
case CXCursor_StructDecl:
case CXCursor_UnionDecl:
case CXCursor_TypedefDecl:
case CXCursor_TemplateTypeParameter:
case CXCursor_TypeAliasDecl:
case CXCursor_EnumDecl: m_types.mainHighlightingType = HighlightingType::Type; break;
default: m_types.mainHighlightingType = HighlightingType::Invalid; break;
}
}
void HighlightingMark::overloadedDeclRefKind(const Cursor &cursor)
{
m_types.mainHighlightingType = HighlightingType::Function;
// CLANG-UPGRADE-CHECK: Workaround still needed?
// Workaround https://bugs.llvm.org//show_bug.cgi?id=33256 - SomeType in
// "using N::SomeType" is mistakenly considered as a CXCursor_OverloadedDeclRef.
if (cursor.overloadedDeclarationsCount() >= 1
&& cursor.overloadedDeclaration(0).kind() != CXCursor_FunctionDecl
&& cursor.overloadedDeclaration(0).kind() != CXCursor_FunctionTemplate) {
m_types.mainHighlightingType = HighlightingType::Type;
}
}
void HighlightingMark::variableKind(const Cursor &cursor)
{
if (cursor.isLocalVariable())
m_types.mainHighlightingType = HighlightingType::LocalVariable;
else
m_types.mainHighlightingType = HighlightingType::GlobalVariable;
if (isOutputArgument())
m_types.mixinHighlightingTypes.push_back(HighlightingType::OutputArgument);
}
void HighlightingMark::fieldKind(const Cursor &)
{
m_types.mainHighlightingType = HighlightingType::Field;
if (isOutputArgument())
m_types.mixinHighlightingTypes.push_back(HighlightingType::OutputArgument);
}
bool HighlightingMark::isVirtualMethodDeclarationOrDefinition(const Cursor &cursor) const
{
return cursor.isVirtualMethod()
&& (m_originalCursor.isDeclaration() || m_originalCursor.isDefinition());
}
namespace {
bool isNotFinalFunction(const Cursor &cursor)
{
return !cursor.hasFinalFunctionAttribute();
}
}
bool HighlightingMark::isRealDynamicCall(const Cursor &cursor) const
{
return m_originalCursor.isDynamicCall() && isNotFinalFunction(cursor);
}
void HighlightingMark::addExtraTypeIfFirstPass(HighlightingType type,
Recursion recursion)
{
if (recursion == Recursion::FirstPass)
m_types.mixinHighlightingTypes.push_back(type);
}
bool HighlightingMark::isArgumentInCurrentOutputArgumentLocations() const
{
auto originalSourceLocation = m_originalCursor.cxSourceLocation();
const auto isNotSameOutputArgument = [&] (const CXSourceRange &currentSourceRange) {
return originalSourceLocation.int_data >= currentSourceRange.begin_int_data
&& originalSourceLocation.int_data <= currentSourceRange.end_int_data;
};
auto found = std::find_if(m_currentOutputArgumentRanges->begin(),
m_currentOutputArgumentRanges->end(),
isNotSameOutputArgument);
bool isOutputArgument = found != m_currentOutputArgumentRanges->end();
return isOutputArgument;
}
bool HighlightingMark::isOutputArgument() const
{
if (m_currentOutputArgumentRanges->empty())
return false;
return isArgumentInCurrentOutputArgumentLocations();
}
void HighlightingMark::collectOutputArguments(const Cursor &cursor)
{
cursor.collectOutputArgumentRangesTo(*m_currentOutputArgumentRanges);
filterOutPreviousOutputArguments();
}
namespace {
uint getEnd(CXSourceRange cxSourceRange)
{
CXSourceLocation startSourceLocation = clang_getRangeEnd(cxSourceRange);
uint endOffset;
clang_getFileLocation(startSourceLocation, nullptr, nullptr, nullptr, &endOffset);
return endOffset;
}
}
void HighlightingMark::filterOutPreviousOutputArguments()
{
auto isAfterLocation = [this] (CXSourceRange outputRange) {
return getEnd(outputRange) > m_offset;
};
auto precedingBegin = std::partition(m_currentOutputArgumentRanges->begin(),
m_currentOutputArgumentRanges->end(),
isAfterLocation);
m_currentOutputArgumentRanges->erase(precedingBegin, m_currentOutputArgumentRanges->end());
}
void HighlightingMark::functionKind(const Cursor &cursor, Recursion recursion)
{
if (isRealDynamicCall(cursor) || isVirtualMethodDeclarationOrDefinition(cursor))
m_types.mainHighlightingType = HighlightingType::VirtualFunction;
else
m_types.mainHighlightingType = HighlightingType::Function;
if (isOutputArgument())
m_types.mixinHighlightingTypes.push_back(HighlightingType::OutputArgument);
addExtraTypeIfFirstPass(HighlightingType::Declaration, recursion);
}
void HighlightingMark::identifierKind(const Cursor &cursor, Recursion recursion)
{
m_isIdentifier = (cursor.kind() != CXCursor_PreprocessingDirective);
switch (cursor.kind()) {
case CXCursor_Destructor:
case CXCursor_Constructor:
case CXCursor_FunctionDecl:
case CXCursor_CallExpr:
case CXCursor_CXXMethod: functionKind(cursor, recursion); break;
case CXCursor_NonTypeTemplateParameter:
case CXCursor_CompoundStmt: m_types.mainHighlightingType = HighlightingType::LocalVariable; break;
case CXCursor_ParmDecl:
case CXCursor_VarDecl: variableKind(cursor); break;
case CXCursor_DeclRefExpr: identifierKind(cursor.referenced(), Recursion::RecursivePass); break;
case CXCursor_MemberRefExpr: memberReferenceKind(cursor); break;
case CXCursor_FieldDecl:
case CXCursor_MemberRef: fieldKind(cursor); break;
case CXCursor_ObjCIvarDecl:
case CXCursor_ObjCPropertyDecl:
case CXCursor_ObjCClassMethodDecl:
case CXCursor_ObjCInstanceMethodDecl:
case CXCursor_ObjCSynthesizeDecl:
case CXCursor_ObjCDynamicDecl: m_types.mainHighlightingType = HighlightingType::Field; break;
case CXCursor_TypeRef: referencedTypeKind(cursor); break;
case CXCursor_ClassDecl:
case CXCursor_ClassTemplatePartialSpecialization:
case CXCursor_TemplateTypeParameter:
case CXCursor_TemplateTemplateParameter:
case CXCursor_UnionDecl:
case CXCursor_StructDecl:
case CXCursor_TemplateRef:
case CXCursor_Namespace:
case CXCursor_NamespaceRef:
case CXCursor_NamespaceAlias:
case CXCursor_TypeAliasDecl:
case CXCursor_TypedefDecl:
case CXCursor_ClassTemplate:
case CXCursor_EnumDecl:
case CXCursor_CXXStaticCastExpr:
case CXCursor_CXXReinterpretCastExpr:
case CXCursor_ObjCCategoryDecl:
case CXCursor_ObjCCategoryImplDecl:
case CXCursor_ObjCImplementationDecl:
case CXCursor_ObjCInterfaceDecl:
case CXCursor_ObjCProtocolDecl:
case CXCursor_ObjCProtocolRef:
case CXCursor_ObjCClassRef:
case CXCursor_ObjCSuperClassRef: m_types.mainHighlightingType = HighlightingType::Type; break;
case CXCursor_OverloadedDeclRef: overloadedDeclRefKind(cursor); break;
case CXCursor_FunctionTemplate: m_types.mainHighlightingType = HighlightingType::Function; break;
case CXCursor_EnumConstantDecl: m_types.mainHighlightingType = HighlightingType::Enumeration; break;
case CXCursor_PreprocessingDirective: m_types.mainHighlightingType = HighlightingType::Preprocessor; break;
case CXCursor_MacroExpansion: m_types.mainHighlightingType = HighlightingType::PreprocessorExpansion; break;
case CXCursor_MacroDefinition: m_types.mainHighlightingType = HighlightingType::PreprocessorDefinition; break;
case CXCursor_InclusionDirective: m_types.mainHighlightingType = HighlightingType::StringLiteral; break;
case CXCursor_LabelRef:
case CXCursor_LabelStmt: m_types.mainHighlightingType = HighlightingType::Label; break;
default: break;
}
}
namespace {
HighlightingType literalKind(const Cursor &cursor)
{
switch (cursor.kind()) {
case CXCursor_CharacterLiteral:
case CXCursor_StringLiteral:
case CXCursor_InclusionDirective:
case CXCursor_ObjCStringLiteral: return HighlightingType::StringLiteral;
case CXCursor_IntegerLiteral:
case CXCursor_ImaginaryLiteral:
case CXCursor_FloatingLiteral: return HighlightingType::NumberLiteral;
default: return HighlightingType::Invalid;
}
Q_UNREACHABLE();
}
bool hasOperatorName(const char *operatorString)
{
return std::strncmp(operatorString, "operator", 8) == 0;
}
HighlightingType operatorKind(const Cursor &cursor)
{
if (hasOperatorName(cursor.spelling().cString()))
return HighlightingType::Operator;
else
return HighlightingType::Invalid;
}
}
HighlightingType HighlightingMark::punctuationKind(const Cursor &cursor)
{
HighlightingType highlightingType = HighlightingType::Invalid;
switch (cursor.kind()) {
case CXCursor_DeclRefExpr: highlightingType = operatorKind(cursor); break;
case CXCursor_Constructor:
case CXCursor_CallExpr: collectOutputArguments(cursor); break;
default: break;
}
if (isOutputArgument())
m_types.mixinHighlightingTypes.push_back(HighlightingType::OutputArgument);
return highlightingType;
}
static HighlightingType highlightingTypeForKeyword(CXTranslationUnit cxTranslationUnit,
CXToken *cxToken,
const Cursor &cursor)
{
switch (cursor.kind()) {
case CXCursor_PreprocessingDirective: return HighlightingType::Preprocessor;
case CXCursor_InclusionDirective: return HighlightingType::StringLiteral;
default: break;
}
const ClangString spelling = clang_getTokenSpelling(cxTranslationUnit, *cxToken);
if (spelling == "bool"
|| spelling == "char"
|| spelling == "char16_t"
|| spelling == "char32_t"
|| spelling == "double"
|| spelling == "float"
|| spelling == "int"
|| spelling == "long"
|| spelling == "short"
|| spelling == "signed"
|| spelling == "unsigned"
|| spelling == "void"
|| spelling == "wchar_t") {
return HighlightingType::PrimitiveType;
}
return HighlightingType::Keyword;
}
void HighlightingMark::collectKinds(CXTranslationUnit cxTranslationUnit,
CXToken *cxToken, const Cursor &cursor)
{
auto cxTokenKind = clang_getTokenKind(*cxToken);
m_types = HighlightingTypes();
switch (cxTokenKind) {
case CXToken_Keyword: m_types.mainHighlightingType = highlightingTypeForKeyword(cxTranslationUnit, cxToken, m_originalCursor); break;
case CXToken_Punctuation: m_types.mainHighlightingType = punctuationKind(cursor); break;
case CXToken_Identifier: identifierKind(cursor, Recursion::FirstPass); break;
case CXToken_Comment: m_types.mainHighlightingType = HighlightingType::Comment; break;
case CXToken_Literal: m_types.mainHighlightingType = literalKind(cursor); break;
}
m_isInclusion = (cursor.kind() == CXCursor_InclusionDirective);
}
std::ostream &operator<<(std::ostream &os, const HighlightingMark& highlightingMark)
{
os << "(type: " << highlightingMark.m_types << ", "
<< " line: " << highlightingMark.m_line << ", "
<< " column: " << highlightingMark.m_column << ", "
<< " length: " << highlightingMark.m_length
<< ")";
return os;
}
} // namespace ClangBackEnd

View File

@@ -0,0 +1,103 @@
/****************************************************************************
**
** 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 <clangsupport_global.h>
#include <highlightingmarkcontainer.h>
#include "cursor.h"
#include <clang-c/Index.h>
namespace ClangBackEnd {
class HighlightingMark
{
friend bool operator==(const HighlightingMark &first, const HighlightingMark &second);
enum class Recursion {
FirstPass,
RecursivePass
};
public:
HighlightingMark(const CXCursor &cxCursor,
CXToken *cxToken,
CXTranslationUnit cxTranslationUnit,
std::vector<CXSourceRange> &m_currentOutputArgumentRanges);
HighlightingMark(uint m_line, uint m_column, uint m_length, HighlightingTypes m_types);
HighlightingMark(uint m_line, uint m_column, uint m_length, HighlightingType type);
bool hasInvalidMainType() const;
bool hasMainType(HighlightingType type) const;
bool hasMixinType(HighlightingType type) const;
bool hasOnlyType(HighlightingType type) const;
bool hasFunctionArguments() const;
operator HighlightingMarkContainer() const;
private:
void identifierKind(const Cursor &cursor, Recursion recursion);
void referencedTypeKind(const Cursor &cursor);
void overloadedDeclRefKind(const Cursor &cursor);
void variableKind(const Cursor &cursor);
void fieldKind(const Cursor &cursor);
bool isVirtualMethodDeclarationOrDefinition(const Cursor &cursor) const;
void functionKind(const Cursor &cursor, Recursion recursion);
void memberReferenceKind(const Cursor &cursor);
HighlightingType punctuationKind(const Cursor &cursor);
void collectKinds(CXTranslationUnit cxTranslationUnit, CXToken *cxToken, const Cursor &cursor);
bool isRealDynamicCall(const Cursor &cursor) const;
void addExtraTypeIfFirstPass(HighlightingType type, Recursion recursion);
bool isOutputArgument() const;
void collectOutputArguments(const Cursor &cursor);
void filterOutPreviousOutputArguments();
bool isArgumentInCurrentOutputArgumentLocations() const;
friend std::ostream &operator<<(std::ostream &os, const HighlightingMark& highlightingMark);
private:
std::vector<CXSourceRange> *m_currentOutputArgumentRanges = nullptr;
Cursor m_originalCursor;
uint m_line;
uint m_column;
uint m_length;
uint m_offset = 0;
HighlightingTypes m_types;
bool m_isIdentifier = false;
bool m_isInclusion = false;
};
inline bool operator==(const HighlightingMark &first, const HighlightingMark &second)
{
return first.m_line == second.m_line
&& first.m_column == second.m_column
&& first.m_length == second.m_length
&& first.m_types == second.m_types;
}
} // namespace ClangBackEnd

View File

@@ -0,0 +1,121 @@
/****************************************************************************
**
** 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 "highlightingmarks.h"
#include "highlightingmarkcontainer.h"
#include <QVector>
namespace ClangBackEnd {
HighlightingMarks::HighlightingMarks(CXTranslationUnit cxTranslationUnit, CXToken *tokens, uint tokensCount)
: cxTranslationUnit(cxTranslationUnit),
cxToken(tokens),
cxTokenCount(tokensCount)
{
cxCursor.resize(tokensCount);
clang_annotateTokens(cxTranslationUnit, cxToken, cxTokenCount, cxCursor.data());
}
HighlightingMarks::~HighlightingMarks()
{
clang_disposeTokens(cxTranslationUnit, cxToken, cxTokenCount);
}
HighlightingMarks::const_iterator HighlightingMarks::begin() const
{
return const_iterator(cxCursor.cbegin(),
cxToken,
cxTranslationUnit,
currentOutputArgumentRanges);
}
HighlightingMarks::const_iterator HighlightingMarks::end() const
{
return const_iterator(cxCursor.cend(),
cxToken + cxTokenCount,
cxTranslationUnit,
currentOutputArgumentRanges);
}
QVector<HighlightingMarkContainer> HighlightingMarks::toHighlightingMarksContainers() const
{
QVector<HighlightingMarkContainer> containers;
containers.reserve(size());
const auto isValidHighlightMark = [] (const HighlightingMark &highlightMark) {
return !highlightMark.hasInvalidMainType()
&& !highlightMark.hasMainType(HighlightingType::NumberLiteral)
&& !highlightMark.hasMainType(HighlightingType::Comment);
};
for (const HighlightingMark &highlightMark : *this)
if (isValidHighlightMark(highlightMark))
containers.push_back(highlightMark);
return containers;
}
bool HighlightingMarks::currentOutputArgumentRangesAreEmpty() const
{
return currentOutputArgumentRanges.empty();
}
bool HighlightingMarks::isEmpty() const
{
return cxTokenCount == 0;
}
bool ClangBackEnd::HighlightingMarks::isNull() const
{
return cxToken == nullptr;
}
uint HighlightingMarks::size() const
{
return cxTokenCount;
}
HighlightingMark HighlightingMarks::operator[](size_t index) const
{
return HighlightingMark(cxCursor[index],
cxToken + index,
cxTranslationUnit,
currentOutputArgumentRanges);
}
std::ostream &operator<<(std::ostream &out, const HighlightingMarks &marks)
{
out << "[";
for (const HighlightingMark entry : marks)
out << entry;
out << "]";
return out;
}
} // namespace ClangBackEnd

View File

@@ -0,0 +1,74 @@
/****************************************************************************
**
** 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 "highlightingmarksiterator.h"
#include <clang-c/Index.h>
#include <vector>
namespace ClangBackEnd {
using uint = unsigned int;
class HighlightingMarkContainer;
class HighlightingMarks
{
public:
using const_iterator = HighlightingMarksIterator;
using value_type = HighlightingMark;
public:
HighlightingMarks() = default;
HighlightingMarks(CXTranslationUnit cxTranslationUnit, CXToken *tokens, uint tokensCount);
~HighlightingMarks();
bool isEmpty() const;
bool isNull() const;
uint size() const;
HighlightingMark operator[](size_t index) const;
const_iterator begin() const;
const_iterator end() const;
QVector<HighlightingMarkContainer> toHighlightingMarksContainers() const;
bool currentOutputArgumentRangesAreEmpty() const;
private:
mutable std::vector<CXSourceRange> currentOutputArgumentRanges;
CXTranslationUnit cxTranslationUnit = nullptr;
CXToken *const cxToken = nullptr;
const uint cxTokenCount = 0;
std::vector<CXCursor> cxCursor;
};
std::ostream &operator<<(std::ostream &out, const HighlightingMarks &marks);
} // namespace ClangBackEnd

View File

@@ -0,0 +1,96 @@
/****************************************************************************
**
** 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 "highlightingmark.h"
#include <iterator>
#include <vector>
#include <clang-c/Index.h>
namespace ClangBackEnd {
using uint = unsigned int;
class DiagnosticSet;
class Diagnostic;
class HighlightingMarksIterator : public std::iterator<std::forward_iterator_tag, HighlightingMark, uint>
{
public:
HighlightingMarksIterator(std::vector<CXCursor>::const_iterator cxCursorIterator,
CXToken *cxToken,
CXTranslationUnit cxTranslationUnit,
std::vector<CXSourceRange> &currentOutputArgumentRanges)
: cxCursorIterator(cxCursorIterator),
cxToken(cxToken),
cxTranslationUnit(cxTranslationUnit),
currentOutputArgumentRanges(currentOutputArgumentRanges)
{}
HighlightingMarksIterator& operator++()
{
++cxCursorIterator;
++cxToken;
return *this;
}
HighlightingMarksIterator operator++(int)
{
return HighlightingMarksIterator(cxCursorIterator++,
cxToken++,
cxTranslationUnit,
currentOutputArgumentRanges);
}
bool operator==(HighlightingMarksIterator other) const
{
return cxCursorIterator == other.cxCursorIterator;
}
bool operator!=(HighlightingMarksIterator other) const
{
return cxCursorIterator != other.cxCursorIterator;
}
HighlightingMark operator*()
{
return HighlightingMark(*cxCursorIterator,
cxToken,
cxTranslationUnit,
currentOutputArgumentRanges);
}
private:
std::vector<CXCursor>::const_iterator cxCursorIterator;
CXToken *cxToken;
CXTranslationUnit cxTranslationUnit;
std::vector<CXSourceRange> &currentOutputArgumentRanges;
};
} // namespace ClangBackEnd

View File

@@ -0,0 +1,130 @@
/****************************************************************************
**
** 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 "projectpart.h"
#include <projectpartcontainer.h>
#include <utf8stringvector.h>
#include <cstring>
namespace ClangBackEnd {
class ProjectPartData {
public:
ProjectPartData(const Utf8String &projectPartId);
~ProjectPartData();
public:
TimePoint lastChangeTimePoint;
Utf8StringVector arguments;
Utf8String projectPartId;
};
ProjectPartData::ProjectPartData(const Utf8String &projectPartId)
: lastChangeTimePoint(Clock::now()),
projectPartId(projectPartId)
{
}
ProjectPartData::~ProjectPartData()
{
}
ProjectPart::ProjectPart(const Utf8String &projectPartId)
: d(std::make_shared<ProjectPartData>(projectPartId))
{
}
ProjectPart::ProjectPart(const Utf8String &projectPartId,
const Utf8StringVector &arguments)
: d(std::make_shared<ProjectPartData>(projectPartId))
{
setArguments(arguments);
}
ProjectPart::ProjectPart(const ProjectPartContainer &projectContainer)
: d(std::make_shared<ProjectPartData>(projectContainer.projectPartId()))
{
setArguments(projectContainer.arguments());
}
ProjectPart::~ProjectPart() = default;
ProjectPart::ProjectPart(const ProjectPart &) = default;
ProjectPart &ProjectPart::operator=(const ProjectPart &) = default;
ProjectPart::ProjectPart(ProjectPart &&other)
: d(std::move(other.d))
{
}
ProjectPart &ProjectPart::operator=(ProjectPart &&other)
{
d = std::move(other.d);
return *this;
}
void ProjectPart::clear()
{
d->projectPartId.clear();
d->arguments.clear();
updateLastChangeTimePoint();
}
Utf8String ProjectPart::id() const
{
return d->projectPartId;
}
void ProjectPart::setArguments(const Utf8StringVector &arguments)
{
d->arguments = arguments;
updateLastChangeTimePoint();
}
const Utf8StringVector ProjectPart::arguments() const
{
return d->arguments;
}
const TimePoint &ProjectPart::lastChangeTimePoint() const
{
return d->lastChangeTimePoint;
}
void ProjectPart::updateLastChangeTimePoint()
{
d->lastChangeTimePoint = Clock::now();
}
bool operator==(const ProjectPart &first, const ProjectPart &second)
{
return first.id() == second.id();
}
} // namespace ClangBackEnd

View File

@@ -0,0 +1,73 @@
/****************************************************************************
**
** 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 "clangclock.h"
#include <utf8string.h>
#include <memory>
class Utf8StringVector;
namespace ClangBackEnd {
class ProjectPartContainer;
class ProjectPartData;
class ProjectPart
{
public:
ProjectPart(const Utf8String &id = Utf8String());
ProjectPart(const Utf8String &id, const Utf8StringVector &arguments);
ProjectPart(const ProjectPartContainer &projectContainer);
~ProjectPart();
ProjectPart(const ProjectPart &project);
ProjectPart &operator=(const ProjectPart &project);
ProjectPart(ProjectPart &&project);
ProjectPart &operator=(ProjectPart &&project);
void clear();
Utf8String id() const;
void setArguments(const Utf8StringVector &arguments_);
const Utf8StringVector arguments() const;
const TimePoint &lastChangeTimePoint() const;
private:
void updateLastChangeTimePoint();
private:
std::shared_ptr<ProjectPartData> d;
};
bool operator==(const ProjectPart &first, const ProjectPart &second);
} // namespace ClangBackEnd

View File

@@ -0,0 +1,105 @@
/****************************************************************************
**
** 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 "projects.h"
#include "clangexceptions.h"
#include <QtGlobal>
namespace ClangBackEnd {
void ProjectParts::createOrUpdate(const QVector<ProjectPartContainer> &projectContainers)
{
for (const ProjectPartContainer &projectContainer : projectContainers)
createOrUpdateProjectPart(projectContainer);
}
void ProjectParts::remove(const Utf8StringVector &projectPartIds)
{
Utf8StringVector processedProjectPartFilePaths = projectPartIds;
const auto removeBeginIterator = std::remove_if(projects_.begin(), projects_.end(),
[&processedProjectPartFilePaths] (ProjectPart &project) {
const bool isRemoved = processedProjectPartFilePaths.removeFast(project.id());
if (isRemoved)
project.clear();
return isRemoved;
});
projects_.erase(removeBeginIterator, projects_.end());
if (!processedProjectPartFilePaths.isEmpty())
throw ProjectPartDoNotExistException(processedProjectPartFilePaths);
}
bool ProjectParts::hasProjectPart(const Utf8String &projectPartId) const
{
return findProjectPart(projectPartId) != projects_.cend();
}
const ProjectPart &ProjectParts::project(const Utf8String &projectPartId) const
{
const auto findIterator = findProjectPart(projectPartId);
if (findIterator == projects_.cend())
throw ProjectPartDoNotExistException({projectPartId});
return *findIterator;
}
std::vector<ProjectPart>::const_iterator ProjectParts::findProjectPart(const Utf8String &projectPartId) const
{
return std::find_if(projects_.begin(), projects_.end(), [projectPartId] (const ProjectPart &project) {
return project.id() == projectPartId;
});
}
std::vector<ProjectPart>::iterator ProjectParts::findProjectPart(const Utf8String &projectPartId)
{
return std::find_if(projects_.begin(), projects_.end(), [projectPartId] (const ProjectPart &project) {
return project.id() == projectPartId;
});
}
const std::vector<ProjectPart> &ProjectParts::projects() const
{
return projects_;
}
void ProjectParts::createOrUpdateProjectPart(const ProjectPartContainer &projectContainer)
{
auto findIterator = findProjectPart(projectContainer.projectPartId());
if (findIterator == projects_.cend())
projects_.push_back(ProjectPart(projectContainer));
else
findIterator->setArguments(projectContainer.arguments());
}
} // namespace ClangBackEnd

View File

@@ -0,0 +1,58 @@
/****************************************************************************
**
** 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 "projectpart.h"
#include <projectpartcontainer.h>
#include <vector>
namespace ClangBackEnd {
class ProjectParts
{
public:
void createOrUpdate(const QVector<ProjectPartContainer> &projectConainers);
void remove(const Utf8StringVector &projectPartIds);
bool hasProjectPart(const Utf8String &projectPartId) const;
const ProjectPart &project(const Utf8String &projectPartId) const;
std::vector<ProjectPart>::const_iterator findProjectPart(const Utf8String &projectPartId) const;
std::vector<ProjectPart>::iterator findProjectPart(const Utf8String &projectPartId);
const std::vector<ProjectPart> &projects() const;
private:
void createOrUpdateProjectPart(const ProjectPartContainer &projectConainer);
private:
std::vector<ProjectPart> projects_;
};
} // namespace ClangBackEnd

View File

@@ -0,0 +1,124 @@
/****************************************************************************
**
** 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 "skippedsourceranges.h"
#include "sourcerangecontainer.h"
#include <QVector>
#include <algorithm>
namespace ClangBackEnd {
SkippedSourceRanges::SkippedSourceRanges(CXTranslationUnit cxTranslationUnit, const char *filePath)
: cxTranslationUnit(cxTranslationUnit)
, cxSkippedSourceRanges(clang_getSkippedRanges(cxTranslationUnit,
clang_getFile(cxTranslationUnit, filePath)))
{
}
SkippedSourceRanges::~SkippedSourceRanges()
{
clang_disposeSourceRangeList(cxSkippedSourceRanges);
}
SkippedSourceRanges &SkippedSourceRanges::operator=(SkippedSourceRanges &&other)
{
if (this != &other) {
cxTranslationUnit = other.cxTranslationUnit;
cxSkippedSourceRanges = other.cxSkippedSourceRanges;
other.cxTranslationUnit = nullptr;
other.cxSkippedSourceRanges = nullptr;
}
return *this;
}
// The source range reported by clang includes the e.g. #endif line, but we do
// not want to have that grayed out, too. Overwrite the column number with 1 to
// exclude the line.
static SourceRange adaptedSourceRange(CXTranslationUnit cxTranslationUnit, const SourceRange &range)
{
const SourceLocation end = range.end();
return SourceRange {
range.start(),
SourceLocation(cxTranslationUnit, end.filePath(), end.line(), 1)
};
}
// TODO: This should report a line range.
std::vector<SourceRange> SkippedSourceRanges::sourceRanges() const
{
std::vector<SourceRange> sourceRanges;
auto sourceRangeCount = cxSkippedSourceRanges->count;
sourceRanges.reserve(sourceRangeCount);
for (uint i = 0; i < cxSkippedSourceRanges->count; ++i) {
const SourceRange range = cxSkippedSourceRanges->ranges[i];
const SourceRange adaptedRange = adaptedSourceRange(cxTranslationUnit, range);
sourceRanges.push_back(adaptedRange);
}
return sourceRanges;
}
QVector<SourceRangeContainer> SkippedSourceRanges::toSourceRangeContainers() const
{
QVector<SourceRangeContainer> sourceRangeContainers;
auto sourceRanges = this->sourceRanges();
std::copy(sourceRanges.cbegin(),
sourceRanges.cend(),
std::back_inserter(sourceRangeContainers));
return sourceRangeContainers;
}
bool SkippedSourceRanges::isNull() const
{
return cxTranslationUnit == nullptr || cxSkippedSourceRanges == nullptr;
}
ClangBackEnd::SkippedSourceRanges::operator QVector<SourceRangeContainer>() const
{
return toSourceRangeContainers();
}
SkippedSourceRanges::SkippedSourceRanges(SkippedSourceRanges &&other)
: cxTranslationUnit(other.cxTranslationUnit)
, cxSkippedSourceRanges(other.cxSkippedSourceRanges)
{
other.cxTranslationUnit = nullptr;
other.cxSkippedSourceRanges = nullptr;
}
} // namespace ClangBackEnd

View File

@@ -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 "sourcerange.h"
namespace ClangBackEnd {
class SourceRangeContainer;
class SkippedSourceRanges
{
public:
SkippedSourceRanges(CXTranslationUnit Document, const char *filePath);
~SkippedSourceRanges();
SkippedSourceRanges(const SkippedSourceRanges &) = delete;
const SkippedSourceRanges &operator=(const SkippedSourceRanges &) = delete;
SkippedSourceRanges(SkippedSourceRanges &&);
SkippedSourceRanges &operator=(SkippedSourceRanges &&);
std::vector<SourceRange> sourceRanges() const;
QVector<SourceRangeContainer> toSourceRangeContainers() const;
bool isNull() const;
operator QVector<SourceRangeContainer>() const;
private:
CXTranslationUnit cxTranslationUnit = nullptr;
CXSourceRangeList *cxSkippedSourceRanges = nullptr;
};
} // namespace ClangBackEnd

Some files were not shown because too many files have changed in this diff Show More