forked from qt-creator/qt-creator
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:
77
src/tools/clangbackend/source/clangasyncjob.h
Normal file
77
src/tools/clangbackend/source/clangasyncjob.h
Normal 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
|
||||
44
src/tools/clangbackend/source/clangbackend_global.h
Normal file
44
src/tools/clangbackend/source/clangbackend_global.h
Normal 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
|
||||
114
src/tools/clangbackend/source/clangbackendclangipc-source.pri
Normal file
114
src/tools/clangbackend/source/clangbackendclangipc-source.pri
Normal 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
|
||||
36
src/tools/clangbackend/source/clangclock.h
Normal file
36
src/tools/clangbackend/source/clangclock.h
Normal 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
|
||||
95
src/tools/clangbackend/source/clangcodecompleteresults.cpp
Normal file
95
src/tools/clangbackend/source/clangcodecompleteresults.cpp
Normal 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
|
||||
|
||||
63
src/tools/clangbackend/source/clangcodecompleteresults.h
Normal file
63
src/tools/clangbackend/source/clangcodecompleteresults.h
Normal 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
|
||||
425
src/tools/clangbackend/source/clangcodemodelserver.cpp
Normal file
425
src/tools/clangbackend/source/clangcodemodelserver.cpp
Normal 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
|
||||
100
src/tools/clangbackend/source/clangcodemodelserver.h
Normal file
100
src/tools/clangbackend/source/clangcodemodelserver.h
Normal 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
|
||||
79
src/tools/clangbackend/source/clangcompletecodejob.cpp
Normal file
79
src/tools/clangbackend/source/clangcompletecodejob.cpp
Normal 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
|
||||
49
src/tools/clangbackend/source/clangcompletecodejob.h
Normal file
49
src/tools/clangbackend/source/clangcompletecodejob.h
Normal 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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
468
src/tools/clangbackend/source/clangdocument.cpp
Normal file
468
src/tools/clangbackend/source/clangdocument.cpp
Normal 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
|
||||
142
src/tools/clangbackend/source/clangdocument.h
Normal file
142
src/tools/clangbackend/source/clangdocument.h
Normal 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
|
||||
64
src/tools/clangbackend/source/clangdocumentjob.h
Normal file
64
src/tools/clangbackend/source/clangdocumentjob.h
Normal 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
|
||||
140
src/tools/clangbackend/source/clangdocumentprocessor.cpp
Normal file
140
src/tools/clangbackend/source/clangdocumentprocessor.cpp
Normal 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
|
||||
78
src/tools/clangbackend/source/clangdocumentprocessor.h
Normal file
78
src/tools/clangbackend/source/clangdocumentprocessor.h
Normal 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
|
||||
114
src/tools/clangbackend/source/clangdocumentprocessors.cpp
Normal file
114
src/tools/clangbackend/source/clangdocumentprocessors.cpp
Normal 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
|
||||
74
src/tools/clangbackend/source/clangdocumentprocessors.h
Normal file
74
src/tools/clangbackend/source/clangdocumentprocessors.h
Normal 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
|
||||
353
src/tools/clangbackend/source/clangdocuments.cpp
Normal file
353
src/tools/clangbackend/source/clangdocuments.cpp
Normal 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
|
||||
98
src/tools/clangbackend/source/clangdocuments.h
Normal file
98
src/tools/clangbackend/source/clangdocuments.h
Normal 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
|
||||
142
src/tools/clangbackend/source/clangdocumentsuspenderresumer.cpp
Normal file
142
src/tools/clangbackend/source/clangdocumentsuspenderresumer.cpp
Normal 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
|
||||
@@ -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
|
||||
104
src/tools/clangbackend/source/clangexceptions.cpp
Normal file
104
src/tools/clangbackend/source/clangexceptions.cpp
Normal 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
|
||||
97
src/tools/clangbackend/source/clangexceptions.h
Normal file
97
src/tools/clangbackend/source/clangexceptions.h
Normal 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
|
||||
89
src/tools/clangbackend/source/clangfilepath.cpp
Normal file
89
src/tools/clangbackend/source/clangfilepath.cpp
Normal 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
|
||||
38
src/tools/clangbackend/source/clangfilepath.h
Normal file
38
src/tools/clangbackend/source/clangfilepath.h
Normal 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
|
||||
91
src/tools/clangbackend/source/clangfilesystemwatcher.cpp
Normal file
91
src/tools/clangbackend/source/clangfilesystemwatcher.cpp
Normal 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
|
||||
57
src/tools/clangbackend/source/clangfilesystemwatcher.h
Normal file
57
src/tools/clangbackend/source/clangfilesystemwatcher.h
Normal 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
|
||||
337
src/tools/clangbackend/source/clangfollowsymbol.cpp
Normal file
337
src/tools/clangbackend/source/clangfollowsymbol.cpp
Normal 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 ¤tArgs)
|
||||
{
|
||||
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 ¤tArgs)
|
||||
{
|
||||
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
|
||||
52
src/tools/clangbackend/source/clangfollowsymbol.h
Normal file
52
src/tools/clangbackend/source/clangfollowsymbol.h
Normal 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 ¤tArgs);
|
||||
};
|
||||
|
||||
} // namespace ClangBackEnd
|
||||
73
src/tools/clangbackend/source/clangfollowsymboljob.cpp
Normal file
73
src/tools/clangbackend/source/clangfollowsymboljob.cpp
Normal 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
|
||||
42
src/tools/clangbackend/source/clangfollowsymboljob.h
Normal file
42
src/tools/clangbackend/source/clangfollowsymboljob.h
Normal 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
|
||||
71
src/tools/clangbackend/source/clangiasyncjob.cpp
Normal file
71
src/tools/clangbackend/source/clangiasyncjob.cpp
Normal 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
|
||||
74
src/tools/clangbackend/source/clangiasyncjob.h
Normal file
74
src/tools/clangbackend/source/clangiasyncjob.h
Normal 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
|
||||
73
src/tools/clangbackend/source/clangjobcontext.cpp
Normal file
73
src/tools/clangbackend/source/clangjobcontext.cpp
Normal 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
|
||||
59
src/tools/clangbackend/source/clangjobcontext.h
Normal file
59
src/tools/clangbackend/source/clangjobcontext.h
Normal 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
|
||||
313
src/tools/clangbackend/source/clangjobqueue.cpp
Normal file
313
src/tools/clangbackend/source/clangjobqueue.cpp
Normal 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
|
||||
81
src/tools/clangbackend/source/clangjobqueue.h
Normal file
81
src/tools/clangbackend/source/clangjobqueue.h
Normal 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
|
||||
258
src/tools/clangbackend/source/clangjobrequest.cpp
Normal file
258
src/tools/clangbackend/source/clangjobrequest.cpp
Normal 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
|
||||
130
src/tools/clangbackend/source/clangjobrequest.h
Normal file
130
src/tools/clangbackend/source/clangjobrequest.h
Normal 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
|
||||
200
src/tools/clangbackend/source/clangjobs.cpp
Normal file
200
src/tools/clangbackend/source/clangjobs.cpp
Normal 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
|
||||
98
src/tools/clangbackend/source/clangjobs.h
Normal file
98
src/tools/clangbackend/source/clangjobs.h
Normal 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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
248
src/tools/clangbackend/source/clangreferencescollector.cpp
Normal file
248
src/tools/clangbackend/source/clangreferencescollector.cpp
Normal 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
|
||||
60
src/tools/clangbackend/source/clangreferencescollector.h
Normal file
60
src/tools/clangbackend/source/clangreferencescollector.h
Normal 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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
67
src/tools/clangbackend/source/clangrequestreferencesjob.cpp
Normal file
67
src/tools/clangbackend/source/clangrequestreferencesjob.cpp
Normal 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
|
||||
42
src/tools/clangbackend/source/clangrequestreferencesjob.h
Normal file
42
src/tools/clangbackend/source/clangrequestreferencesjob.h
Normal 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
|
||||
54
src/tools/clangbackend/source/clangresumedocumentjob.cpp
Normal file
54
src/tools/clangbackend/source/clangresumedocumentjob.cpp
Normal 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
|
||||
44
src/tools/clangbackend/source/clangresumedocumentjob.h
Normal file
44
src/tools/clangbackend/source/clangresumedocumentjob.h
Normal 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
|
||||
135
src/tools/clangbackend/source/clangstring.h
Normal file
135
src/tools/clangbackend/source/clangstring.h
Normal 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
|
||||
@@ -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
|
||||
@@ -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
|
||||
59
src/tools/clangbackend/source/clangsuspenddocumentjob.cpp
Normal file
59
src/tools/clangbackend/source/clangsuspenddocumentjob.cpp
Normal 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
|
||||
39
src/tools/clangbackend/source/clangsuspenddocumentjob.h
Normal file
39
src/tools/clangbackend/source/clangsuspenddocumentjob.h
Normal 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
|
||||
255
src/tools/clangbackend/source/clangtranslationunit.cpp
Normal file
255
src/tools/clangbackend/source/clangtranslationunit.cpp
Normal 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 ¤tArgs) const
|
||||
{
|
||||
return FollowSymbol::followSymbol(m_cxTranslationUnit, m_cxIndex, cursorAt(line, column), line,
|
||||
column, dependentFiles, currentArgs);
|
||||
}
|
||||
|
||||
} // namespace ClangBackEnd
|
||||
115
src/tools/clangbackend/source/clangtranslationunit.h
Normal file
115
src/tools/clangbackend/source/clangtranslationunit.h
Normal 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 ¤tArgs) const;
|
||||
|
||||
private:
|
||||
const Utf8String m_id;
|
||||
const Utf8String m_filePath;
|
||||
CXIndex &m_cxIndex;
|
||||
CXTranslationUnit &m_cxTranslationUnit;
|
||||
};
|
||||
|
||||
} // namespace ClangBackEnd
|
||||
155
src/tools/clangbackend/source/clangtranslationunits.cpp
Normal file
155
src/tools/clangbackend/source/clangtranslationunits.cpp
Normal 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
|
||||
83
src/tools/clangbackend/source/clangtranslationunits.h
Normal file
83
src/tools/clangbackend/source/clangtranslationunits.h
Normal 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
|
||||
220
src/tools/clangbackend/source/clangtranslationunitupdater.cpp
Normal file
220
src/tools/clangbackend/source/clangtranslationunitupdater.cpp
Normal 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
|
||||
121
src/tools/clangbackend/source/clangtranslationunitupdater.h
Normal file
121
src/tools/clangbackend/source/clangtranslationunitupdater.h
Normal 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
|
||||
165
src/tools/clangbackend/source/clangtype.cpp
Normal file
165
src/tools/clangbackend/source/clangtype.cpp
Normal 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
|
||||
|
||||
82
src/tools/clangbackend/source/clangtype.h
Normal file
82
src/tools/clangbackend/source/clangtype.h
Normal 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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
232
src/tools/clangbackend/source/codecompleter.cpp
Normal file
232
src/tools/clangbackend/source/codecompleter.cpp
Normal 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
|
||||
|
||||
75
src/tools/clangbackend/source/codecompleter.h
Normal file
75
src/tools/clangbackend/source/codecompleter.h
Normal 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
|
||||
@@ -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
|
||||
|
||||
52
src/tools/clangbackend/source/codecompletionchunkconverter.h
Normal file
52
src/tools/clangbackend/source/codecompletionchunkconverter.h
Normal 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
|
||||
354
src/tools/clangbackend/source/codecompletionsextractor.cpp
Normal file
354
src/tools/clangbackend/source/codecompletionsextractor.cpp
Normal 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
|
||||
|
||||
84
src/tools/clangbackend/source/codecompletionsextractor.h
Normal file
84
src/tools/clangbackend/source/codecompletionsextractor.h
Normal 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 ¤tCodeCompletion() 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
|
||||
91
src/tools/clangbackend/source/commandlinearguments.cpp
Normal file
91
src/tools/clangbackend/source/commandlinearguments.cpp
Normal 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
|
||||
53
src/tools/clangbackend/source/commandlinearguments.h
Normal file
53
src/tools/clangbackend/source/commandlinearguments.h
Normal 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
|
||||
439
src/tools/clangbackend/source/cursor.cpp
Normal file
439
src/tools/clangbackend/source/cursor.cpp
Normal 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
|
||||
|
||||
137
src/tools/clangbackend/source/cursor.h
Normal file
137
src/tools/clangbackend/source/cursor.h
Normal 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
|
||||
175
src/tools/clangbackend/source/diagnostic.cpp
Normal file
175
src/tools/clangbackend/source/diagnostic.cpp
Normal 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
|
||||
|
||||
89
src/tools/clangbackend/source/diagnostic.h
Normal file
89
src/tools/clangbackend/source/diagnostic.h
Normal 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
|
||||
120
src/tools/clangbackend/source/diagnosticset.cpp
Normal file
120
src/tools/clangbackend/source/diagnosticset.cpp
Normal 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
|
||||
|
||||
81
src/tools/clangbackend/source/diagnosticset.h
Normal file
81
src/tools/clangbackend/source/diagnosticset.h
Normal 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
|
||||
84
src/tools/clangbackend/source/diagnosticsetiterator.h
Normal file
84
src/tools/clangbackend/source/diagnosticsetiterator.h
Normal 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;
|
||||
};
|
||||
|
||||
}
|
||||
58
src/tools/clangbackend/source/fixit.cpp
Normal file
58
src/tools/clangbackend/source/fixit.cpp
Normal 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
|
||||
|
||||
57
src/tools/clangbackend/source/fixit.h
Normal file
57
src/tools/clangbackend/source/fixit.h
Normal 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
|
||||
460
src/tools/clangbackend/source/highlightingmark.cpp
Normal file
460
src/tools/clangbackend/source/highlightingmark.cpp
Normal 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> ¤tOutputArgumentRanges)
|
||||
: m_currentOutputArgumentRanges(¤tOutputArgumentRanges),
|
||||
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 ¤tSourceRange) {
|
||||
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
|
||||
103
src/tools/clangbackend/source/highlightingmark.h
Normal file
103
src/tools/clangbackend/source/highlightingmark.h
Normal 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
|
||||
121
src/tools/clangbackend/source/highlightingmarks.cpp
Normal file
121
src/tools/clangbackend/source/highlightingmarks.cpp
Normal 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
|
||||
74
src/tools/clangbackend/source/highlightingmarks.h
Normal file
74
src/tools/clangbackend/source/highlightingmarks.h
Normal 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
|
||||
96
src/tools/clangbackend/source/highlightingmarksiterator.h
Normal file
96
src/tools/clangbackend/source/highlightingmarksiterator.h
Normal 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> ¤tOutputArgumentRanges)
|
||||
: 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> ¤tOutputArgumentRanges;
|
||||
};
|
||||
|
||||
} // namespace ClangBackEnd
|
||||
130
src/tools/clangbackend/source/projectpart.cpp
Normal file
130
src/tools/clangbackend/source/projectpart.cpp
Normal 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
|
||||
|
||||
73
src/tools/clangbackend/source/projectpart.h
Normal file
73
src/tools/clangbackend/source/projectpart.h
Normal 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
|
||||
105
src/tools/clangbackend/source/projects.cpp
Normal file
105
src/tools/clangbackend/source/projects.cpp
Normal 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
|
||||
|
||||
58
src/tools/clangbackend/source/projects.h
Normal file
58
src/tools/clangbackend/source/projects.h
Normal 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
|
||||
124
src/tools/clangbackend/source/skippedsourceranges.cpp
Normal file
124
src/tools/clangbackend/source/skippedsourceranges.cpp
Normal 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
|
||||
|
||||
59
src/tools/clangbackend/source/skippedsourceranges.h
Normal file
59
src/tools/clangbackend/source/skippedsourceranges.h
Normal 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
Reference in New Issue
Block a user