forked from qt-creator/qt-creator
Merge remote-tracking branch 'origin/master' into 4.2
Change-Id: I96904f9c65b6c25bb4e04ca34e2d1acb27b8dd58
This commit is contained in:
@@ -824,6 +824,9 @@
|
|||||||
For example, to turn the first character in the line edit to upper
|
For example, to turn the first character in the line edit to upper
|
||||||
case.
|
case.
|
||||||
|
|
||||||
|
\li \c isPassword is a boolean value that specifies that the line edit
|
||||||
|
contains a password, which will be masked.
|
||||||
|
|
||||||
\endlist
|
\endlist
|
||||||
|
|
||||||
\section2 Path Chooser
|
\section2 Path Chooser
|
||||||
|
@@ -63,7 +63,8 @@ Module {
|
|||||||
"QT_CREATOR",
|
"QT_CREATOR",
|
||||||
'IDE_LIBRARY_BASENAME="' + libDirName + '"',
|
'IDE_LIBRARY_BASENAME="' + libDirName + '"',
|
||||||
"QT_NO_CAST_TO_ASCII",
|
"QT_NO_CAST_TO_ASCII",
|
||||||
"QT_RESTRICTED_CAST_FROM_ASCII"
|
"QT_RESTRICTED_CAST_FROM_ASCII",
|
||||||
|
"QT_DISABLE_DEPRECATED_BEFORE=0x050600",
|
||||||
].concat(testsEnabled ? ["WITH_TESTS"] : [])
|
].concat(testsEnabled ? ["WITH_TESTS"] : [])
|
||||||
|
|
||||||
Rule {
|
Rule {
|
||||||
|
@@ -179,7 +179,11 @@ exists($$IDE_LIBRARY_PATH): LIBS *= -L$$IDE_LIBRARY_PATH # library path from ou
|
|||||||
DEFINES += IDE_LIBRARY_BASENAME=\\\"$$IDE_LIBRARY_BASENAME\\\"
|
DEFINES += IDE_LIBRARY_BASENAME=\\\"$$IDE_LIBRARY_BASENAME\\\"
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFINES += QT_CREATOR QT_NO_CAST_TO_ASCII QT_RESTRICTED_CAST_FROM_ASCII
|
DEFINES += \
|
||||||
|
QT_CREATOR \
|
||||||
|
QT_NO_CAST_TO_ASCII \
|
||||||
|
QT_RESTRICTED_CAST_FROM_ASCII \
|
||||||
|
QT_DISABLE_DEPRECATED_BEFORE=0x050600
|
||||||
!macx:DEFINES += QT_USE_FAST_OPERATOR_PLUS QT_USE_FAST_CONCATENATION
|
!macx:DEFINES += QT_USE_FAST_OPERATOR_PLUS QT_USE_FAST_CONCATENATION
|
||||||
|
|
||||||
unix {
|
unix {
|
||||||
|
@@ -37,6 +37,7 @@ QDebug operator<<(QDebug debug, const DocumentAnnotationsChangedMessage &message
|
|||||||
debug.nospace() << "DocumentAnnotationsChangedMessage("
|
debug.nospace() << "DocumentAnnotationsChangedMessage("
|
||||||
<< message.fileContainer()
|
<< message.fileContainer()
|
||||||
<< ", " << message.diagnostics().size()
|
<< ", " << message.diagnostics().size()
|
||||||
|
<< ", " << !message.firstHeaderErrorDiagnostic().text().isEmpty()
|
||||||
<< ", " << message.highlightingMarks().size()
|
<< ", " << message.highlightingMarks().size()
|
||||||
<< ", " << message.skippedPreprocessorRanges().size()
|
<< ", " << message.skippedPreprocessorRanges().size()
|
||||||
<< ")";
|
<< ")";
|
||||||
@@ -49,6 +50,7 @@ void PrintTo(const DocumentAnnotationsChangedMessage &message, ::std::ostream* o
|
|||||||
*os << "DocumentAnnotationsChangedMessage(";
|
*os << "DocumentAnnotationsChangedMessage(";
|
||||||
PrintTo(message.fileContainer(), os);
|
PrintTo(message.fileContainer(), os);
|
||||||
*os << "," << message.diagnostics().size();
|
*os << "," << message.diagnostics().size();
|
||||||
|
*os << "," << !message.firstHeaderErrorDiagnostic().text().isEmpty();
|
||||||
*os << "," << message.highlightingMarks().size();
|
*os << "," << message.highlightingMarks().size();
|
||||||
*os << "," << message.skippedPreprocessorRanges().size();
|
*os << "," << message.skippedPreprocessorRanges().size();
|
||||||
*os << ")";
|
*os << ")";
|
||||||
|
@@ -41,10 +41,12 @@ public:
|
|||||||
DocumentAnnotationsChangedMessage() = default;
|
DocumentAnnotationsChangedMessage() = default;
|
||||||
DocumentAnnotationsChangedMessage(const FileContainer &fileContainer,
|
DocumentAnnotationsChangedMessage(const FileContainer &fileContainer,
|
||||||
const QVector<DiagnosticContainer> &diagnostics,
|
const QVector<DiagnosticContainer> &diagnostics,
|
||||||
|
const DiagnosticContainer &firstHeaderErrorDiagnostic_,
|
||||||
const QVector<HighlightingMarkContainer> &highlightingMarks,
|
const QVector<HighlightingMarkContainer> &highlightingMarks,
|
||||||
const QVector<SourceRangeContainer> &skippedPreprocessorRanges)
|
const QVector<SourceRangeContainer> &skippedPreprocessorRanges)
|
||||||
: fileContainer_(fileContainer),
|
: fileContainer_(fileContainer),
|
||||||
diagnostics_(diagnostics),
|
diagnostics_(diagnostics),
|
||||||
|
firstHeaderErrorDiagnostic_(firstHeaderErrorDiagnostic_),
|
||||||
highlightingMarks_(highlightingMarks),
|
highlightingMarks_(highlightingMarks),
|
||||||
skippedPreprocessorRanges_(skippedPreprocessorRanges)
|
skippedPreprocessorRanges_(skippedPreprocessorRanges)
|
||||||
{
|
{
|
||||||
@@ -60,6 +62,11 @@ public:
|
|||||||
return diagnostics_;
|
return diagnostics_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const DiagnosticContainer &firstHeaderErrorDiagnostic() const
|
||||||
|
{
|
||||||
|
return firstHeaderErrorDiagnostic_;
|
||||||
|
}
|
||||||
|
|
||||||
const QVector<HighlightingMarkContainer> &highlightingMarks() const
|
const QVector<HighlightingMarkContainer> &highlightingMarks() const
|
||||||
{
|
{
|
||||||
return highlightingMarks_;
|
return highlightingMarks_;
|
||||||
@@ -74,6 +81,7 @@ public:
|
|||||||
{
|
{
|
||||||
out << message.fileContainer_;
|
out << message.fileContainer_;
|
||||||
out << message.diagnostics_;
|
out << message.diagnostics_;
|
||||||
|
out << message.firstHeaderErrorDiagnostic_;
|
||||||
out << message.highlightingMarks_;
|
out << message.highlightingMarks_;
|
||||||
out << message.skippedPreprocessorRanges_;
|
out << message.skippedPreprocessorRanges_;
|
||||||
|
|
||||||
@@ -84,6 +92,7 @@ public:
|
|||||||
{
|
{
|
||||||
in >> message.fileContainer_;
|
in >> message.fileContainer_;
|
||||||
in >> message.diagnostics_;
|
in >> message.diagnostics_;
|
||||||
|
in >> message.firstHeaderErrorDiagnostic_;
|
||||||
in >> message.highlightingMarks_;
|
in >> message.highlightingMarks_;
|
||||||
in >> message.skippedPreprocessorRanges_;
|
in >> message.skippedPreprocessorRanges_;
|
||||||
|
|
||||||
@@ -95,6 +104,7 @@ public:
|
|||||||
{
|
{
|
||||||
return first.fileContainer_ == second.fileContainer_
|
return first.fileContainer_ == second.fileContainer_
|
||||||
&& first.diagnostics_ == second.diagnostics_
|
&& first.diagnostics_ == second.diagnostics_
|
||||||
|
&& first.firstHeaderErrorDiagnostic_ == second.firstHeaderErrorDiagnostic_
|
||||||
&& first.highlightingMarks_ == second.highlightingMarks_
|
&& first.highlightingMarks_ == second.highlightingMarks_
|
||||||
&& first.skippedPreprocessorRanges_ == second.skippedPreprocessorRanges_;
|
&& first.skippedPreprocessorRanges_ == second.skippedPreprocessorRanges_;
|
||||||
}
|
}
|
||||||
@@ -102,6 +112,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
FileContainer fileContainer_;
|
FileContainer fileContainer_;
|
||||||
QVector<DiagnosticContainer> diagnostics_;
|
QVector<DiagnosticContainer> diagnostics_;
|
||||||
|
DiagnosticContainer firstHeaderErrorDiagnostic_;
|
||||||
QVector<HighlightingMarkContainer> highlightingMarks_;
|
QVector<HighlightingMarkContainer> highlightingMarks_;
|
||||||
QVector<SourceRangeContainer> skippedPreprocessorRanges_;
|
QVector<SourceRangeContainer> skippedPreprocessorRanges_;
|
||||||
};
|
};
|
||||||
|
@@ -32,6 +32,7 @@
|
|||||||
|
|
||||||
#include <coreplugin/editormanager/editormanager.h>
|
#include <coreplugin/editormanager/editormanager.h>
|
||||||
#include <coreplugin/icore.h>
|
#include <coreplugin/icore.h>
|
||||||
|
#include <coreplugin/messagemanager.h>
|
||||||
|
|
||||||
#include <cpptools/abstracteditorsupport.h>
|
#include <cpptools/abstracteditorsupport.h>
|
||||||
#include <cpptools/baseeditordocumentprocessor.h>
|
#include <cpptools/baseeditordocumentprocessor.h>
|
||||||
@@ -68,6 +69,7 @@
|
|||||||
|
|
||||||
#include <cplusplus/Icons.h>
|
#include <cplusplus/Icons.h>
|
||||||
|
|
||||||
|
#include <QDir>
|
||||||
#include <QElapsedTimer>
|
#include <QElapsedTimer>
|
||||||
#include <QLoggingCategory>
|
#include <QLoggingCategory>
|
||||||
#include <QProcess>
|
#include <QProcess>
|
||||||
@@ -180,7 +182,9 @@ void IpcReceiver::documentAnnotationsChanged(const DocumentAnnotationsChangedMes
|
|||||||
const QString documentProjectPartId = CppTools::CppToolsBridge::projectPartIdForFile(filePath);
|
const QString documentProjectPartId = CppTools::CppToolsBridge::projectPartIdForFile(filePath);
|
||||||
if (projectPartId == documentProjectPartId) {
|
if (projectPartId == documentProjectPartId) {
|
||||||
const quint32 documentRevision = message.fileContainer().documentRevision();
|
const quint32 documentRevision = message.fileContainer().documentRevision();
|
||||||
processor->updateCodeWarnings(message.diagnostics(), documentRevision);
|
processor->updateCodeWarnings(message.diagnostics(),
|
||||||
|
message.firstHeaderErrorDiagnostic(),
|
||||||
|
documentRevision);
|
||||||
processor->updateHighlighting(message.highlightingMarks(),
|
processor->updateHighlighting(message.highlightingMarks(),
|
||||||
message.skippedPreprocessorRanges(),
|
message.skippedPreprocessorRanges(),
|
||||||
documentRevision);
|
documentRevision);
|
||||||
@@ -304,10 +308,16 @@ public:
|
|||||||
void updateVisibleTranslationUnits(const UpdateVisibleTranslationUnitsMessage &) override {}
|
void updateVisibleTranslationUnits(const UpdateVisibleTranslationUnitsMessage &) override {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum { backEndStartTimeOutInMs = 10000 };
|
||||||
|
|
||||||
IpcCommunicator::IpcCommunicator()
|
IpcCommunicator::IpcCommunicator()
|
||||||
: m_connection(&m_ipcReceiver)
|
: m_connection(&m_ipcReceiver)
|
||||||
, m_ipcSender(new DummyIpcSender)
|
, m_ipcSender(new DummyIpcSender)
|
||||||
{
|
{
|
||||||
|
m_backendStartTimeOut.setSingleShot(true);
|
||||||
|
connect(&m_backendStartTimeOut, &QTimer::timeout,
|
||||||
|
this, &IpcCommunicator::logStartTimeOut);
|
||||||
|
|
||||||
m_ipcReceiver.setAliveHandler([this]() { m_connection.resetProcessAliveTimer(); });
|
m_ipcReceiver.setAliveHandler([this]() { m_connection.resetProcessAliveTimer(); });
|
||||||
|
|
||||||
connect(Core::EditorManager::instance(), &Core::EditorManager::editorAboutToClose,
|
connect(Core::EditorManager::instance(), &Core::EditorManager::editorAboutToClose,
|
||||||
@@ -326,8 +336,11 @@ IpcCommunicator::~IpcCommunicator()
|
|||||||
void IpcCommunicator::initializeBackend()
|
void IpcCommunicator::initializeBackend()
|
||||||
{
|
{
|
||||||
const QString clangBackEndProcessPath = backendProcessPath();
|
const QString clangBackEndProcessPath = backendProcessPath();
|
||||||
|
if (!QFileInfo(clangBackEndProcessPath).exists()) {
|
||||||
|
logExecutableDoesNotExist();
|
||||||
|
return;
|
||||||
|
}
|
||||||
qCDebug(log) << "Starting" << clangBackEndProcessPath;
|
qCDebug(log) << "Starting" << clangBackEndProcessPath;
|
||||||
QTC_ASSERT(QFileInfo(clangBackEndProcessPath).exists(), return);
|
|
||||||
|
|
||||||
m_connection.setProcessAliveTimerInterval(30 * 1000);
|
m_connection.setProcessAliveTimerInterval(30 * 1000);
|
||||||
m_connection.setProcessPath(clangBackEndProcessPath);
|
m_connection.setProcessPath(clangBackEndProcessPath);
|
||||||
@@ -338,6 +351,7 @@ void IpcCommunicator::initializeBackend()
|
|||||||
this, &IpcCommunicator::setupDummySender);
|
this, &IpcCommunicator::setupDummySender);
|
||||||
|
|
||||||
m_connection.startProcessAndConnectToServerAsynchronously();
|
m_connection.startProcessAndConnectToServerAsynchronously();
|
||||||
|
m_backendStartTimeOut.start(backEndStartTimeOutInMs);
|
||||||
}
|
}
|
||||||
|
|
||||||
static QStringList projectPartOptions(const CppTools::ProjectPart::Ptr &projectPart)
|
static QStringList projectPartOptions(const CppTools::ProjectPart::Ptr &projectPart)
|
||||||
@@ -622,11 +636,11 @@ void IpcCommunicator::updateUnsavedFile(Core::IDocument *document)
|
|||||||
|
|
||||||
void IpcCommunicator::onConnectedToBackend()
|
void IpcCommunicator::onConnectedToBackend()
|
||||||
{
|
{
|
||||||
|
m_backendStartTimeOut.stop();
|
||||||
|
|
||||||
++m_connectedCount;
|
++m_connectedCount;
|
||||||
if (m_connectedCount > 1) {
|
if (m_connectedCount > 1)
|
||||||
qWarning("Clang back end finished unexpectedly, restarted.");
|
logRestartedDueToUnexpectedFinish();
|
||||||
qCDebug(log) << "Backend restarted, re-initializing with project data and unsaved files.";
|
|
||||||
}
|
|
||||||
|
|
||||||
m_ipcReceiver.deleteAndClearWaitingAssistProcessors();
|
m_ipcReceiver.deleteAndClearWaitingAssistProcessors();
|
||||||
m_ipcSender.reset(new IpcSender(m_connection));
|
m_ipcSender.reset(new IpcSender(m_connection));
|
||||||
@@ -645,6 +659,42 @@ void IpcCommunicator::setupDummySender()
|
|||||||
m_ipcSender.reset(new DummyIpcSender);
|
m_ipcSender.reset(new DummyIpcSender);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void IpcCommunicator::logExecutableDoesNotExist()
|
||||||
|
{
|
||||||
|
const QString msg
|
||||||
|
= tr("Clang Code Model: Error: "
|
||||||
|
"The clangbackend executable \"%1\" does not exist.")
|
||||||
|
.arg(QDir::toNativeSeparators(backendProcessPath()));
|
||||||
|
|
||||||
|
logError(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IpcCommunicator::logStartTimeOut()
|
||||||
|
{
|
||||||
|
const QString msg
|
||||||
|
= tr("Clang Code Model: Error: "
|
||||||
|
"The clangbackend executable \"%1\" could not be started (timeout after %2ms).")
|
||||||
|
.arg(QDir::toNativeSeparators(backendProcessPath()))
|
||||||
|
.arg(backEndStartTimeOutInMs);
|
||||||
|
|
||||||
|
logError(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IpcCommunicator::logRestartedDueToUnexpectedFinish()
|
||||||
|
{
|
||||||
|
const QString msg
|
||||||
|
= tr("Clang Code Model: Error: "
|
||||||
|
"The clangbackend process has finished unexpectedly and was restarted.");
|
||||||
|
|
||||||
|
logError(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IpcCommunicator::logError(const QString &text)
|
||||||
|
{
|
||||||
|
Core::MessageManager::write(text, Core::MessageManager::Flash);
|
||||||
|
qWarning("%s", qPrintable(text));
|
||||||
|
}
|
||||||
|
|
||||||
void IpcCommunicator::initializeBackendWithCurrentData()
|
void IpcCommunicator::initializeBackendWithCurrentData()
|
||||||
{
|
{
|
||||||
registerFallbackProjectPart();
|
registerFallbackProjectPart();
|
||||||
|
@@ -171,12 +171,18 @@ private:
|
|||||||
void onDisconnectedFromBackend();
|
void onDisconnectedFromBackend();
|
||||||
void onEditorAboutToClose(Core::IEditor *editor);
|
void onEditorAboutToClose(Core::IEditor *editor);
|
||||||
|
|
||||||
|
void logExecutableDoesNotExist();
|
||||||
|
void logRestartedDueToUnexpectedFinish();
|
||||||
|
void logStartTimeOut();
|
||||||
|
void logError(const QString &text);
|
||||||
|
|
||||||
void updateTranslationUnitVisiblity(const Utf8String ¤tEditorFilePath,
|
void updateTranslationUnitVisiblity(const Utf8String ¤tEditorFilePath,
|
||||||
const Utf8StringVector &visibleEditorsFilePaths);
|
const Utf8StringVector &visibleEditorsFilePaths);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
IpcReceiver m_ipcReceiver;
|
IpcReceiver m_ipcReceiver;
|
||||||
ClangBackEnd::ClangCodeModelConnectionClient m_connection;
|
ClangBackEnd::ClangCodeModelConnectionClient m_connection;
|
||||||
|
QTimer m_backendStartTimeOut;
|
||||||
QScopedPointer<IpcSenderInterface> m_ipcSender;
|
QScopedPointer<IpcSenderInterface> m_ipcSender;
|
||||||
int m_connectedCount = 0;
|
int m_connectedCount = 0;
|
||||||
};
|
};
|
||||||
|
@@ -41,6 +41,7 @@
|
|||||||
#include <utils/proxyaction.h>
|
#include <utils/proxyaction.h>
|
||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
|
|
||||||
|
#include <QFileInfo>
|
||||||
#include <QTextBlock>
|
#include <QTextBlock>
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
@@ -129,9 +129,10 @@ enum IndentType { IndentDiagnostic, DoNotIndentDiagnostic };
|
|||||||
|
|
||||||
QWidget *createDiagnosticLabel(const ClangBackEnd::DiagnosticContainer &diagnostic,
|
QWidget *createDiagnosticLabel(const ClangBackEnd::DiagnosticContainer &diagnostic,
|
||||||
const QString &mainFilePath,
|
const QString &mainFilePath,
|
||||||
IndentType indentType = DoNotIndentDiagnostic)
|
IndentType indentType = DoNotIndentDiagnostic,
|
||||||
|
bool enableClickableFixits = true)
|
||||||
{
|
{
|
||||||
const bool hasFixit = !diagnostic.fixIts().isEmpty();
|
const bool hasFixit = enableClickableFixits ? !diagnostic.fixIts().isEmpty() : false;
|
||||||
const QString diagnosticText = diagnostic.text().toString().toHtmlEscaped();
|
const QString diagnosticText = diagnostic.text().toString().toHtmlEscaped();
|
||||||
const QString text = clickableLocation(mainFilePath, diagnostic.location())
|
const QString text = clickableLocation(mainFilePath, diagnostic.location())
|
||||||
+ QStringLiteral(": ")
|
+ QStringLiteral(": ")
|
||||||
@@ -159,25 +160,35 @@ class MainDiagnosticWidget : public QWidget
|
|||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
MainDiagnosticWidget(const ClangBackEnd::DiagnosticContainer &diagnostic)
|
MainDiagnosticWidget(const ClangBackEnd::DiagnosticContainer &diagnostic,
|
||||||
|
const ClangCodeModel::Internal::DisplayHints &displayHints)
|
||||||
{
|
{
|
||||||
setContentsMargins(0, 0, 0, 0);
|
setContentsMargins(0, 0, 0, 0);
|
||||||
auto *mainLayout = createLayout<QVBoxLayout>();
|
auto *mainLayout = createLayout<QVBoxLayout>();
|
||||||
|
|
||||||
// Set up header row: category + responsible option
|
|
||||||
const QString category = diagnostic.category();
|
|
||||||
const QString responsibleOption = diagnostic.enableOption();
|
|
||||||
const ClangBackEnd::SourceLocationContainer location = diagnostic.location();
|
const ClangBackEnd::SourceLocationContainer location = diagnostic.location();
|
||||||
|
|
||||||
auto *headerLayout = createLayout<QHBoxLayout>();
|
// Set up header row: category + responsible option
|
||||||
headerLayout->addWidget(new QLabel(wrapInBoldTags(category)), 1);
|
if (displayHints.showMainDiagnosticHeader) {
|
||||||
|
const QString category = diagnostic.category();
|
||||||
|
const QString responsibleOption = diagnostic.enableOption();
|
||||||
|
|
||||||
auto *responsibleOptionLabel = new QLabel(wrapInColor(responsibleOption, "gray"));
|
auto *headerLayout = createLayout<QHBoxLayout>();
|
||||||
headerLayout->addWidget(responsibleOptionLabel, 0);
|
headerLayout->addWidget(new QLabel(wrapInBoldTags(category)), 1);
|
||||||
mainLayout->addLayout(headerLayout);
|
|
||||||
|
auto *responsibleOptionLabel = new QLabel(wrapInColor(responsibleOption, "gray"));
|
||||||
|
headerLayout->addWidget(responsibleOptionLabel, 0);
|
||||||
|
mainLayout->addLayout(headerLayout);
|
||||||
|
}
|
||||||
|
|
||||||
// Set up main row: diagnostic text
|
// Set up main row: diagnostic text
|
||||||
mainLayout->addWidget(createDiagnosticLabel(diagnostic, location.filePath()));
|
const Utf8String mainFilePath = displayHints.showFileNameInMainDiagnostic
|
||||||
|
? Utf8String()
|
||||||
|
: location.filePath();
|
||||||
|
mainLayout->addWidget(createDiagnosticLabel(diagnostic,
|
||||||
|
mainFilePath,
|
||||||
|
DoNotIndentDiagnostic,
|
||||||
|
displayHints.enableClickableFixits));
|
||||||
|
|
||||||
setLayout(mainLayout);
|
setLayout(mainLayout);
|
||||||
}
|
}
|
||||||
@@ -186,26 +197,35 @@ public:
|
|||||||
void addChildrenToLayout(const QString &mainFilePath,
|
void addChildrenToLayout(const QString &mainFilePath,
|
||||||
const QVector<ClangBackEnd::DiagnosticContainer>::const_iterator first,
|
const QVector<ClangBackEnd::DiagnosticContainer>::const_iterator first,
|
||||||
const QVector<ClangBackEnd::DiagnosticContainer>::const_iterator last,
|
const QVector<ClangBackEnd::DiagnosticContainer>::const_iterator last,
|
||||||
|
bool enableClickableFixits,
|
||||||
QLayout &boxLayout)
|
QLayout &boxLayout)
|
||||||
{
|
{
|
||||||
for (auto it = first; it != last; ++it)
|
for (auto it = first; it != last; ++it) {
|
||||||
boxLayout.addWidget(createDiagnosticLabel(*it, mainFilePath, IndentDiagnostic));
|
boxLayout.addWidget(createDiagnosticLabel(*it,
|
||||||
|
mainFilePath,
|
||||||
|
IndentDiagnostic,
|
||||||
|
enableClickableFixits));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void setupChildDiagnostics(const QString &mainFilePath,
|
void setupChildDiagnostics(const QString &mainFilePath,
|
||||||
const QVector<ClangBackEnd::DiagnosticContainer> &diagnostics,
|
const QVector<ClangBackEnd::DiagnosticContainer> &diagnostics,
|
||||||
|
bool enableClickableFixits,
|
||||||
QLayout &boxLayout)
|
QLayout &boxLayout)
|
||||||
{
|
{
|
||||||
if (diagnostics.size() <= 10) {
|
if (diagnostics.size() <= 10) {
|
||||||
addChildrenToLayout(mainFilePath, diagnostics.begin(), diagnostics.end(), boxLayout);
|
addChildrenToLayout(mainFilePath, diagnostics.begin(), diagnostics.end(),
|
||||||
|
enableClickableFixits, boxLayout);
|
||||||
} else {
|
} else {
|
||||||
addChildrenToLayout(mainFilePath, diagnostics.begin(), diagnostics.begin() + 7, boxLayout);
|
addChildrenToLayout(mainFilePath, diagnostics.begin(), diagnostics.begin() + 7,
|
||||||
|
enableClickableFixits, boxLayout);
|
||||||
|
|
||||||
auto ellipsisLabel = new QLabel(QStringLiteral("..."));
|
auto ellipsisLabel = new QLabel(QStringLiteral("..."));
|
||||||
ellipsisLabel->setContentsMargins(childIndentationOnTheLeftInPixel, 0, 0, 0);
|
ellipsisLabel->setContentsMargins(childIndentationOnTheLeftInPixel, 0, 0, 0);
|
||||||
boxLayout.addWidget(ellipsisLabel);
|
boxLayout.addWidget(ellipsisLabel);
|
||||||
|
|
||||||
addChildrenToLayout(mainFilePath, diagnostics.end() - 3, diagnostics.end(), boxLayout);
|
addChildrenToLayout(mainFilePath, diagnostics.end() - 3, diagnostics.end(),
|
||||||
|
enableClickableFixits, boxLayout);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -214,13 +234,18 @@ void setupChildDiagnostics(const QString &mainFilePath,
|
|||||||
namespace ClangCodeModel {
|
namespace ClangCodeModel {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
void addToolTipToLayout(const ClangBackEnd::DiagnosticContainer &diagnostic, QLayout *target)
|
void addToolTipToLayout(const ClangBackEnd::DiagnosticContainer &diagnostic,
|
||||||
|
QLayout *target,
|
||||||
|
const DisplayHints &displayHints)
|
||||||
{
|
{
|
||||||
// Set up header and text row for main diagnostic
|
// Set up header and text row for main diagnostic
|
||||||
target->addWidget(new MainDiagnosticWidget(diagnostic));
|
target->addWidget(new MainDiagnosticWidget(diagnostic, displayHints));
|
||||||
|
|
||||||
// Set up child rows for notes
|
// Set up child rows for notes
|
||||||
setupChildDiagnostics(diagnostic.location().filePath(), diagnostic.children(), *target);
|
setupChildDiagnostics(diagnostic.location().filePath(),
|
||||||
|
diagnostic.children(),
|
||||||
|
displayHints.enableClickableFixits,
|
||||||
|
*target);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
|
@@ -34,7 +34,15 @@ QT_END_NAMESPACE
|
|||||||
namespace ClangCodeModel {
|
namespace ClangCodeModel {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
void addToolTipToLayout(const ClangBackEnd::DiagnosticContainer &diagnostic, QLayout *target);
|
struct DisplayHints {
|
||||||
|
bool showMainDiagnosticHeader = true;
|
||||||
|
bool showFileNameInMainDiagnostic = false;
|
||||||
|
bool enableClickableFixits = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
void addToolTipToLayout(const ClangBackEnd::DiagnosticContainer &diagnostic,
|
||||||
|
QLayout *target,
|
||||||
|
const DisplayHints &displayHints = DisplayHints());
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
} // namespace ClangCodeModel
|
} // namespace ClangCodeModel
|
||||||
|
@@ -57,6 +57,8 @@
|
|||||||
#include <utils/runextensions.h>
|
#include <utils/runextensions.h>
|
||||||
|
|
||||||
#include <QTextBlock>
|
#include <QTextBlock>
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
#include <QWidget>
|
||||||
|
|
||||||
namespace ClangCodeModel {
|
namespace ClangCodeModel {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
@@ -72,6 +74,11 @@ ClangEditorDocumentProcessor::ClangEditorDocumentProcessor(
|
|||||||
, m_semanticHighlighter(document)
|
, m_semanticHighlighter(document)
|
||||||
, m_builtinProcessor(document, /*enableSemanticHighlighter=*/ false)
|
, m_builtinProcessor(document, /*enableSemanticHighlighter=*/ false)
|
||||||
{
|
{
|
||||||
|
m_updateTranslationUnitTimer.setSingleShot(true);
|
||||||
|
m_updateTranslationUnitTimer.setInterval(350);
|
||||||
|
connect(&m_updateTranslationUnitTimer, &QTimer::timeout,
|
||||||
|
this, &ClangEditorDocumentProcessor::updateTranslationUnitIfProjectPartExists);
|
||||||
|
|
||||||
// Forwarding the semantic info from the builtin processor enables us to provide all
|
// Forwarding the semantic info from the builtin processor enables us to provide all
|
||||||
// editor (widget) related features that are not yet implemented by the clang plugin.
|
// editor (widget) related features that are not yet implemented by the clang plugin.
|
||||||
connect(&m_builtinProcessor, &CppTools::BuiltinEditorDocumentProcessor::cppDocumentUpdated,
|
connect(&m_builtinProcessor, &CppTools::BuiltinEditorDocumentProcessor::cppDocumentUpdated,
|
||||||
@@ -82,6 +89,8 @@ ClangEditorDocumentProcessor::ClangEditorDocumentProcessor(
|
|||||||
|
|
||||||
ClangEditorDocumentProcessor::~ClangEditorDocumentProcessor()
|
ClangEditorDocumentProcessor::~ClangEditorDocumentProcessor()
|
||||||
{
|
{
|
||||||
|
m_updateTranslationUnitTimer.stop();
|
||||||
|
|
||||||
m_parserWatcher.cancel();
|
m_parserWatcher.cancel();
|
||||||
m_parserWatcher.waitForFinished();
|
m_parserWatcher.waitForFinished();
|
||||||
|
|
||||||
@@ -93,7 +102,7 @@ ClangEditorDocumentProcessor::~ClangEditorDocumentProcessor()
|
|||||||
|
|
||||||
void ClangEditorDocumentProcessor::run()
|
void ClangEditorDocumentProcessor::run()
|
||||||
{
|
{
|
||||||
updateTranslationUnitIfProjectPartExists();
|
m_updateTranslationUnitTimer.start();
|
||||||
|
|
||||||
// Run clang parser
|
// Run clang parser
|
||||||
disconnect(&m_parserWatcher, &QFutureWatcher<void>::finished,
|
disconnect(&m_parserWatcher, &QFutureWatcher<void>::finished,
|
||||||
@@ -160,14 +169,21 @@ void ClangEditorDocumentProcessor::clearProjectPart()
|
|||||||
m_projectPart.clear();
|
m_projectPart.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClangEditorDocumentProcessor::updateCodeWarnings(const QVector<ClangBackEnd::DiagnosticContainer> &diagnostics,
|
void ClangEditorDocumentProcessor::updateCodeWarnings(
|
||||||
uint documentRevision)
|
const QVector<ClangBackEnd::DiagnosticContainer> &diagnostics,
|
||||||
|
const ClangBackEnd::DiagnosticContainer &firstHeaderErrorDiagnostic,
|
||||||
|
uint documentRevision)
|
||||||
{
|
{
|
||||||
if (documentRevision == revision()) {
|
if (documentRevision == revision()) {
|
||||||
m_diagnosticManager.processNewDiagnostics(diagnostics);
|
m_diagnosticManager.processNewDiagnostics(diagnostics);
|
||||||
const auto codeWarnings = m_diagnosticManager.takeExtraSelections();
|
const auto codeWarnings = m_diagnosticManager.takeExtraSelections();
|
||||||
const auto fixitAvailableMarkers = m_diagnosticManager.takeFixItAvailableMarkers();
|
const auto fixitAvailableMarkers = m_diagnosticManager.takeFixItAvailableMarkers();
|
||||||
emit codeWarningsUpdated(revision(), codeWarnings, fixitAvailableMarkers);
|
const auto creator = creatorForHeaderErrorDiagnosticWidget(firstHeaderErrorDiagnostic);
|
||||||
|
|
||||||
|
emit codeWarningsUpdated(revision(),
|
||||||
|
codeWarnings,
|
||||||
|
creator,
|
||||||
|
fixitAvailableMarkers);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
namespace {
|
namespace {
|
||||||
@@ -251,6 +267,11 @@ void ClangEditorDocumentProcessor::addDiagnosticToolTipToLayout(uint line,
|
|||||||
addToolTipToLayout(diagnostic, target);
|
addToolTipToLayout(diagnostic, target);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ClangEditorDocumentProcessor::editorDocumentTimerRestarted()
|
||||||
|
{
|
||||||
|
m_updateTranslationUnitTimer.stop(); // Wait for the next call to run().
|
||||||
|
}
|
||||||
|
|
||||||
ClangBackEnd::FileContainer ClangEditorDocumentProcessor::fileContainerWithArguments() const
|
ClangBackEnd::FileContainer ClangEditorDocumentProcessor::fileContainerWithArguments() const
|
||||||
{
|
{
|
||||||
return fileContainerWithArguments(m_projectPart.data());
|
return fileContainerWithArguments(m_projectPart.data());
|
||||||
@@ -321,6 +342,38 @@ void ClangEditorDocumentProcessor::requestDocumentAnnotations(const QString &pro
|
|||||||
m_ipcCommunicator.requestDocumentAnnotations(fileContainer);
|
m_ipcCommunicator.requestDocumentAnnotations(fileContainer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Internal::DisplayHints displayHintsForInfoBar()
|
||||||
|
{
|
||||||
|
Internal::DisplayHints displayHints;
|
||||||
|
displayHints.showMainDiagnosticHeader = false;
|
||||||
|
displayHints.showFileNameInMainDiagnostic = true;
|
||||||
|
displayHints.enableClickableFixits = false; // Tool chain headers might be changed, so disable.
|
||||||
|
|
||||||
|
return displayHints;
|
||||||
|
}
|
||||||
|
|
||||||
|
CppTools::BaseEditorDocumentProcessor::HeaderErrorDiagnosticWidgetCreator
|
||||||
|
ClangEditorDocumentProcessor::creatorForHeaderErrorDiagnosticWidget(
|
||||||
|
const ClangBackEnd::DiagnosticContainer &firstHeaderErrorDiagnostic)
|
||||||
|
{
|
||||||
|
if (firstHeaderErrorDiagnostic.text().isEmpty())
|
||||||
|
return CppTools::BaseEditorDocumentProcessor::HeaderErrorDiagnosticWidgetCreator();
|
||||||
|
|
||||||
|
return [firstHeaderErrorDiagnostic]() {
|
||||||
|
auto vbox = new QVBoxLayout;
|
||||||
|
vbox->setMargin(0);
|
||||||
|
vbox->setContentsMargins(10, 0, 0, 2);
|
||||||
|
vbox->setSpacing(2);
|
||||||
|
|
||||||
|
addToolTipToLayout(firstHeaderErrorDiagnostic, vbox, displayHintsForInfoBar());
|
||||||
|
|
||||||
|
auto widget = new QWidget;
|
||||||
|
widget->setLayout(vbox);
|
||||||
|
|
||||||
|
return widget;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
static CppTools::ProjectPart projectPartForLanguageOption(CppTools::ProjectPart *projectPart)
|
static CppTools::ProjectPart projectPartForLanguageOption(CppTools::ProjectPart *projectPart)
|
||||||
{
|
{
|
||||||
if (projectPart)
|
if (projectPart)
|
||||||
|
@@ -32,6 +32,7 @@
|
|||||||
#include <cpptools/semantichighlighter.h>
|
#include <cpptools/semantichighlighter.h>
|
||||||
|
|
||||||
#include <QFutureWatcher>
|
#include <QFutureWatcher>
|
||||||
|
#include <QTimer>
|
||||||
|
|
||||||
namespace ClangBackEnd {
|
namespace ClangBackEnd {
|
||||||
class DiagnosticContainer;
|
class DiagnosticContainer;
|
||||||
@@ -67,6 +68,7 @@ public:
|
|||||||
void clearProjectPart();
|
void clearProjectPart();
|
||||||
|
|
||||||
void updateCodeWarnings(const QVector<ClangBackEnd::DiagnosticContainer> &diagnostics,
|
void updateCodeWarnings(const QVector<ClangBackEnd::DiagnosticContainer> &diagnostics,
|
||||||
|
const ClangBackEnd::DiagnosticContainer &firstHeaderErrorDiagnostic,
|
||||||
uint documentRevision);
|
uint documentRevision);
|
||||||
void updateHighlighting(const QVector<ClangBackEnd::HighlightingMarkContainer> &highlightingMarks,
|
void updateHighlighting(const QVector<ClangBackEnd::HighlightingMarkContainer> &highlightingMarks,
|
||||||
const QVector<ClangBackEnd::SourceRangeContainer> &skippedPreprocessorRanges,
|
const QVector<ClangBackEnd::SourceRangeContainer> &skippedPreprocessorRanges,
|
||||||
@@ -78,6 +80,8 @@ public:
|
|||||||
bool hasDiagnosticsAt(uint line, uint column) const override;
|
bool hasDiagnosticsAt(uint line, uint column) const override;
|
||||||
void addDiagnosticToolTipToLayout(uint line, uint column, QLayout *target) const override;
|
void addDiagnosticToolTipToLayout(uint line, uint column, QLayout *target) const override;
|
||||||
|
|
||||||
|
void editorDocumentTimerRestarted() override;
|
||||||
|
|
||||||
ClangBackEnd::FileContainer fileContainerWithArguments() const;
|
ClangBackEnd::FileContainer fileContainerWithArguments() const;
|
||||||
|
|
||||||
void clearDiagnosticsWithFixIts();
|
void clearDiagnosticsWithFixIts();
|
||||||
@@ -93,6 +97,8 @@ private:
|
|||||||
void registerTranslationUnitForEditor(CppTools::ProjectPart *projectPart);
|
void registerTranslationUnitForEditor(CppTools::ProjectPart *projectPart);
|
||||||
void updateTranslationUnitIfProjectPartExists();
|
void updateTranslationUnitIfProjectPartExists();
|
||||||
void requestDocumentAnnotations(const QString &projectpartId);
|
void requestDocumentAnnotations(const QString &projectpartId);
|
||||||
|
HeaderErrorDiagnosticWidgetCreator creatorForHeaderErrorDiagnosticWidget(
|
||||||
|
const ClangBackEnd::DiagnosticContainer &firstHeaderErrorDiagnostic);
|
||||||
ClangBackEnd::FileContainer fileContainerWithArguments(CppTools::ProjectPart *projectPart) const;
|
ClangBackEnd::FileContainer fileContainerWithArguments(CppTools::ProjectPart *projectPart) const;
|
||||||
ClangBackEnd::FileContainer fileContainerWithDocumentContent(const QString &projectpartId) const;
|
ClangBackEnd::FileContainer fileContainerWithDocumentContent(const QString &projectpartId) const;
|
||||||
|
|
||||||
@@ -102,6 +108,7 @@ private:
|
|||||||
QSharedPointer<ClangEditorDocumentParser> m_parser;
|
QSharedPointer<ClangEditorDocumentParser> m_parser;
|
||||||
CppTools::ProjectPart::Ptr m_projectPart;
|
CppTools::ProjectPart::Ptr m_projectPart;
|
||||||
QFutureWatcher<void> m_parserWatcher;
|
QFutureWatcher<void> m_parserWatcher;
|
||||||
|
QTimer m_updateTranslationUnitTimer;
|
||||||
unsigned m_parserRevision;
|
unsigned m_parserRevision;
|
||||||
|
|
||||||
CppTools::SemanticHighlighter m_semanticHighlighter;
|
CppTools::SemanticHighlighter m_semanticHighlighter;
|
||||||
|
@@ -60,6 +60,8 @@ TextEditor::TextStyle toTextStyle(ClangBackEnd::HighlightingType type)
|
|||||||
return TextEditor::C_PREPROCESSOR;
|
return TextEditor::C_PREPROCESSOR;
|
||||||
case HighlightingType::Declaration:
|
case HighlightingType::Declaration:
|
||||||
return TextEditor::C_DECLARATION;
|
return TextEditor::C_DECLARATION;
|
||||||
|
case HighlightingType::OutputArgument:
|
||||||
|
return TextEditor::C_OUTPUT_ARGUMENT;
|
||||||
default:
|
default:
|
||||||
return TextEditor::C_TEXT; // never called
|
return TextEditor::C_TEXT; // never called
|
||||||
}
|
}
|
||||||
|
@@ -84,7 +84,7 @@ void ClangTextMark::setIcon(ClangBackEnd::DiagnosticSeverity severity)
|
|||||||
|
|
||||||
bool ClangTextMark::addToolTipContent(QLayout *target)
|
bool ClangTextMark::addToolTipContent(QLayout *target)
|
||||||
{
|
{
|
||||||
Internal::addToolTipToLayout(m_diagnostic, target);
|
Internal::addToolTipToLayout(m_diagnostic, target, Internal::DisplayHints());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -36,12 +36,16 @@
|
|||||||
#include <coreplugin/messagemanager.h>
|
#include <coreplugin/messagemanager.h>
|
||||||
#include <coreplugin/editormanager/editormanager.h>
|
#include <coreplugin/editormanager/editormanager.h>
|
||||||
#include <coreplugin/progressmanager/progressmanager.h>
|
#include <coreplugin/progressmanager/progressmanager.h>
|
||||||
|
#include <cpptools/projectpartbuilder.h>
|
||||||
|
#include <projectexplorer/headerpath.h>
|
||||||
#include <projectexplorer/kit.h>
|
#include <projectexplorer/kit.h>
|
||||||
|
#include <projectexplorer/kitinformation.h>
|
||||||
#include <projectexplorer/project.h>
|
#include <projectexplorer/project.h>
|
||||||
#include <projectexplorer/projectexplorerconstants.h>
|
#include <projectexplorer/projectexplorerconstants.h>
|
||||||
#include <projectexplorer/projectnodes.h>
|
#include <projectexplorer/projectnodes.h>
|
||||||
#include <projectexplorer/target.h>
|
#include <projectexplorer/target.h>
|
||||||
#include <projectexplorer/taskhub.h>
|
#include <projectexplorer/taskhub.h>
|
||||||
|
#include <projectexplorer/toolchain.h>
|
||||||
|
|
||||||
#include <utils/algorithm.h>
|
#include <utils/algorithm.h>
|
||||||
#include <utils/fileutils.h>
|
#include <utils/fileutils.h>
|
||||||
@@ -247,6 +251,44 @@ void BuildDirManager::generateProjectTree(CMakeProjectNode *root)
|
|||||||
m_files.clear(); // Some of the FileNodes in files() were deleted!
|
m_files.clear(); // Some of the FileNodes in files() were deleted!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QSet<Core::Id> BuildDirManager::updateCodeModel(CppTools::ProjectPartBuilder &ppBuilder)
|
||||||
|
{
|
||||||
|
QSet<Core::Id> languages;
|
||||||
|
ToolChain *tc = ToolChainKitInformation::toolChain(kit(), ToolChain::Language::Cxx);
|
||||||
|
const Utils::FileName sysroot = SysRootKitInformation::sysRoot(kit());
|
||||||
|
|
||||||
|
QHash<QString, QStringList> targetDataCache;
|
||||||
|
foreach (const CMakeBuildTarget &cbt, buildTargets()) {
|
||||||
|
if (cbt.targetType == UtilityType)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// CMake shuffles the include paths that it reports via the CodeBlocks generator
|
||||||
|
// So remove the toolchain include paths, so that at least those end up in the correct
|
||||||
|
// place.
|
||||||
|
QStringList cxxflags = getCXXFlagsFor(cbt, targetDataCache);
|
||||||
|
QSet<QString> tcIncludes;
|
||||||
|
foreach (const HeaderPath &hp, tc->systemHeaderPaths(cxxflags, sysroot))
|
||||||
|
tcIncludes.insert(hp.path());
|
||||||
|
QStringList includePaths;
|
||||||
|
foreach (const QString &i, cbt.includeFiles) {
|
||||||
|
if (!tcIncludes.contains(i))
|
||||||
|
includePaths.append(i);
|
||||||
|
}
|
||||||
|
includePaths += buildDirectory().toString();
|
||||||
|
ppBuilder.setIncludePaths(includePaths);
|
||||||
|
ppBuilder.setCFlags(cxxflags);
|
||||||
|
ppBuilder.setCxxFlags(cxxflags);
|
||||||
|
ppBuilder.setDefines(cbt.defines);
|
||||||
|
ppBuilder.setDisplayName(cbt.title);
|
||||||
|
|
||||||
|
const QSet<Core::Id> partLanguages
|
||||||
|
= QSet<Core::Id>::fromList(ppBuilder.createProjectPartsForFiles(cbt.files));
|
||||||
|
|
||||||
|
languages.unite(partLanguages);
|
||||||
|
}
|
||||||
|
return languages;
|
||||||
|
}
|
||||||
|
|
||||||
void BuildDirManager::parse()
|
void BuildDirManager::parse()
|
||||||
{
|
{
|
||||||
checkConfiguration();
|
checkConfiguration();
|
||||||
@@ -545,6 +587,102 @@ void BuildDirManager::processCMakeError()
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QStringList BuildDirManager::getCXXFlagsFor(const CMakeBuildTarget &buildTarget,
|
||||||
|
QHash<QString, QStringList> &cache)
|
||||||
|
{
|
||||||
|
// check cache:
|
||||||
|
auto it = cache.constFind(buildTarget.title);
|
||||||
|
if (it != cache.constEnd())
|
||||||
|
return *it;
|
||||||
|
|
||||||
|
if (extractCXXFlagsFromMake(buildTarget, cache))
|
||||||
|
return cache.value(buildTarget.title);
|
||||||
|
|
||||||
|
if (extractCXXFlagsFromNinja(buildTarget, cache))
|
||||||
|
return cache.value(buildTarget.title);
|
||||||
|
|
||||||
|
cache.insert(buildTarget.title, QStringList());
|
||||||
|
return QStringList();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BuildDirManager::extractCXXFlagsFromMake(const CMakeBuildTarget &buildTarget,
|
||||||
|
QHash<QString, QStringList> &cache)
|
||||||
|
{
|
||||||
|
QString makeCommand = QDir::fromNativeSeparators(buildTarget.makeCommand);
|
||||||
|
int startIndex = makeCommand.indexOf('\"');
|
||||||
|
int endIndex = makeCommand.indexOf('\"', startIndex + 1);
|
||||||
|
if (startIndex != -1 && endIndex != -1) {
|
||||||
|
startIndex += 1;
|
||||||
|
QString makefile = makeCommand.mid(startIndex, endIndex - startIndex);
|
||||||
|
int slashIndex = makefile.lastIndexOf('/');
|
||||||
|
makefile.truncate(slashIndex);
|
||||||
|
makefile.append("/CMakeFiles/" + buildTarget.title + ".dir/flags.make");
|
||||||
|
QFile file(makefile);
|
||||||
|
if (file.exists()) {
|
||||||
|
file.open(QIODevice::ReadOnly | QIODevice::Text);
|
||||||
|
QTextStream stream(&file);
|
||||||
|
while (!stream.atEnd()) {
|
||||||
|
QString line = stream.readLine().trimmed();
|
||||||
|
if (line.startsWith("CXX_FLAGS =")) {
|
||||||
|
// Skip past =
|
||||||
|
cache.insert(buildTarget.title,
|
||||||
|
line.mid(11).trimmed().split(' ', QString::SkipEmptyParts));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BuildDirManager::extractCXXFlagsFromNinja(const CMakeBuildTarget &buildTarget,
|
||||||
|
QHash<QString, QStringList> &cache)
|
||||||
|
{
|
||||||
|
Q_UNUSED(buildTarget)
|
||||||
|
if (!cache.isEmpty()) // We fill the cache in one go!
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Attempt to find build.ninja file and obtain FLAGS (CXX_FLAGS) from there if no suitable flags.make were
|
||||||
|
// found
|
||||||
|
// Get "all" target's working directory
|
||||||
|
QByteArray ninjaFile;
|
||||||
|
QString buildNinjaFile = QDir::fromNativeSeparators(buildTargets().at(0).workingDirectory);
|
||||||
|
buildNinjaFile += "/build.ninja";
|
||||||
|
QFile buildNinja(buildNinjaFile);
|
||||||
|
if (buildNinja.exists()) {
|
||||||
|
buildNinja.open(QIODevice::ReadOnly | QIODevice::Text);
|
||||||
|
ninjaFile = buildNinja.readAll();
|
||||||
|
buildNinja.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ninjaFile.isEmpty())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
QTextStream stream(ninjaFile);
|
||||||
|
bool cxxFound = false;
|
||||||
|
const QString targetSignature = "# Object build statements for ";
|
||||||
|
QString currentTarget;
|
||||||
|
|
||||||
|
while (!stream.atEnd()) {
|
||||||
|
// 1. Look for a block that refers to the current target
|
||||||
|
// 2. Look for a build rule which invokes CXX_COMPILER
|
||||||
|
// 3. Return the FLAGS definition
|
||||||
|
QString line = stream.readLine().trimmed();
|
||||||
|
if (line.startsWith('#')) {
|
||||||
|
if (line.startsWith(targetSignature)) {
|
||||||
|
int pos = line.lastIndexOf(' ');
|
||||||
|
currentTarget = line.mid(pos + 1);
|
||||||
|
}
|
||||||
|
} else if (!currentTarget.isEmpty() && line.startsWith("build")) {
|
||||||
|
cxxFound = line.indexOf("CXX_COMPILER") != -1;
|
||||||
|
} else if (cxxFound && line.startsWith("FLAGS =")) {
|
||||||
|
// Skip past =
|
||||||
|
cache.insert(currentTarget, line.mid(7).trimmed().split(' ', QString::SkipEmptyParts));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return !cache.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
void BuildDirManager::checkConfiguration()
|
void BuildDirManager::checkConfiguration()
|
||||||
{
|
{
|
||||||
if (m_tempDir) // always throw away changes in the tmpdir!
|
if (m_tempDir) // always throw away changes in the tmpdir!
|
||||||
@@ -656,6 +794,7 @@ CMakeConfig BuildDirManager::parseConfiguration(const Utils::FileName &cacheFile
|
|||||||
}
|
}
|
||||||
|
|
||||||
QSet<QByteArray> advancedSet;
|
QSet<QByteArray> advancedSet;
|
||||||
|
QMap<QByteArray, QByteArray> valuesMap;
|
||||||
QByteArray documentation;
|
QByteArray documentation;
|
||||||
while (!cache.atEnd()) {
|
while (!cache.atEnd()) {
|
||||||
const QByteArray line = trimCMakeCacheLine(cache.readLine());
|
const QByteArray line = trimCMakeCacheLine(cache.readLine());
|
||||||
@@ -679,6 +818,8 @@ CMakeConfig BuildDirManager::parseConfiguration(const Utils::FileName &cacheFile
|
|||||||
|
|
||||||
if (key.endsWith("-ADVANCED") && value == "1") {
|
if (key.endsWith("-ADVANCED") && value == "1") {
|
||||||
advancedSet.insert(key.left(key.count() - 9 /* "-ADVANCED" */));
|
advancedSet.insert(key.left(key.count() - 9 /* "-ADVANCED" */));
|
||||||
|
} else if (key.endsWith("-STRINGS") && fromByteArray(type) == CMakeConfigItem::INTERNAL) {
|
||||||
|
valuesMap[key.left(key.count() - 8) /* "-STRINGS" */] = value;
|
||||||
} else {
|
} else {
|
||||||
CMakeConfigItem::Type t = fromByteArray(type);
|
CMakeConfigItem::Type t = fromByteArray(type);
|
||||||
result << CMakeConfigItem(key, t, documentation, value);
|
result << CMakeConfigItem(key, t, documentation, value);
|
||||||
@@ -689,6 +830,13 @@ CMakeConfig BuildDirManager::parseConfiguration(const Utils::FileName &cacheFile
|
|||||||
for (int i = 0; i < result.count(); ++i) {
|
for (int i = 0; i < result.count(); ++i) {
|
||||||
CMakeConfigItem &item = result[i];
|
CMakeConfigItem &item = result[i];
|
||||||
item.isAdvanced = advancedSet.contains(item.key);
|
item.isAdvanced = advancedSet.contains(item.key);
|
||||||
|
|
||||||
|
if (valuesMap.contains(item.key)) {
|
||||||
|
item.values = CMakeConfigItem::cmakeSplitValue(QString::fromUtf8(valuesMap[item.key]));
|
||||||
|
} else if (item.key == "CMAKE_BUILD_TYPE") {
|
||||||
|
// WA for known options
|
||||||
|
item.values << "" << "Debug" << "Release" << "MinSizeRel" << "RelWithDebInfo";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Utils::sort(result, CMakeConfigItem::sortOperator());
|
Utils::sort(result, CMakeConfigItem::sortOperator());
|
||||||
|
@@ -45,6 +45,7 @@ QT_FORWARD_DECLARE_CLASS(QTemporaryDir);
|
|||||||
QT_FORWARD_DECLARE_CLASS(QFileSystemWatcher);
|
QT_FORWARD_DECLARE_CLASS(QFileSystemWatcher);
|
||||||
|
|
||||||
namespace Core { class IDocument; }
|
namespace Core { class IDocument; }
|
||||||
|
namespace CppTools { class ProjectPartBuilder; }
|
||||||
|
|
||||||
namespace ProjectExplorer {
|
namespace ProjectExplorer {
|
||||||
class FileNode;
|
class FileNode;
|
||||||
@@ -80,6 +81,7 @@ public:
|
|||||||
bool persistCMakeState();
|
bool persistCMakeState();
|
||||||
|
|
||||||
void generateProjectTree(CMakeProjectNode *root);
|
void generateProjectTree(CMakeProjectNode *root);
|
||||||
|
QSet<Core::Id> updateCodeModel(CppTools::ProjectPartBuilder &ppBuilder);
|
||||||
|
|
||||||
QList<CMakeBuildTarget> buildTargets() const;
|
QList<CMakeBuildTarget> buildTargets() const;
|
||||||
CMakeConfig parsedConfiguration() const;
|
CMakeConfig parsedConfiguration() const;
|
||||||
@@ -117,6 +119,10 @@ private:
|
|||||||
void processCMakeOutput();
|
void processCMakeOutput();
|
||||||
void processCMakeError();
|
void processCMakeError();
|
||||||
|
|
||||||
|
QStringList getCXXFlagsFor(const CMakeBuildTarget &buildTarget, QHash<QString, QStringList> &cache);
|
||||||
|
bool extractCXXFlagsFromMake(const CMakeBuildTarget &buildTarget, QHash<QString, QStringList> &cache);
|
||||||
|
bool extractCXXFlagsFromNinja(const CMakeBuildTarget &buildTarget, QHash<QString, QStringList> &cache);
|
||||||
|
|
||||||
bool m_hasData = false;
|
bool m_hasData = false;
|
||||||
|
|
||||||
CMakeBuildConfiguration *m_buildConfiguration = nullptr;
|
CMakeBuildConfiguration *m_buildConfiguration = nullptr;
|
||||||
|
@@ -211,6 +211,11 @@ void CMakeBuildConfiguration::generateProjectTree(CMakeProjectNode *root) const
|
|||||||
return m_buildDirManager->generateProjectTree(root);
|
return m_buildDirManager->generateProjectTree(root);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QSet<Core::Id> CMakeBuildConfiguration::updateCodeModel(CppTools::ProjectPartBuilder &ppBuilder)
|
||||||
|
{
|
||||||
|
return m_buildDirManager->updateCodeModel(ppBuilder);
|
||||||
|
}
|
||||||
|
|
||||||
FileName CMakeBuildConfiguration::shadowBuildDirectory(const FileName &projectFilePath,
|
FileName CMakeBuildConfiguration::shadowBuildDirectory(const FileName &projectFilePath,
|
||||||
const Kit *k,
|
const Kit *k,
|
||||||
const QString &bcName,
|
const QString &bcName,
|
||||||
@@ -240,6 +245,7 @@ QList<ConfigModel::DataItem> CMakeBuildConfiguration::completeCMakeConfiguration
|
|||||||
j.key = QString::fromUtf8(i.key);
|
j.key = QString::fromUtf8(i.key);
|
||||||
j.value = QString::fromUtf8(i.value);
|
j.value = QString::fromUtf8(i.value);
|
||||||
j.description = QString::fromUtf8(i.documentation);
|
j.description = QString::fromUtf8(i.documentation);
|
||||||
|
j.values = i.values;
|
||||||
|
|
||||||
j.isAdvanced = i.isAdvanced || i.type == CMakeConfigItem::INTERNAL;
|
j.isAdvanced = i.isAdvanced || i.type == CMakeConfigItem::INTERNAL;
|
||||||
switch (i.type) {
|
switch (i.type) {
|
||||||
@@ -275,6 +281,7 @@ void CMakeBuildConfiguration::setCurrentCMakeConfiguration(const QList<ConfigMod
|
|||||||
ni.value = i.value.toUtf8();
|
ni.value = i.value.toUtf8();
|
||||||
ni.documentation = i.description.toUtf8();
|
ni.documentation = i.description.toUtf8();
|
||||||
ni.isAdvanced = i.isAdvanced;
|
ni.isAdvanced = i.isAdvanced;
|
||||||
|
ni.values = i.values;
|
||||||
switch (i.type) {
|
switch (i.type) {
|
||||||
case CMakeProjectManager::ConfigModel::DataItem::BOOLEAN:
|
case CMakeProjectManager::ConfigModel::DataItem::BOOLEAN:
|
||||||
ni.type = CMakeConfigItem::BOOL;
|
ni.type = CMakeConfigItem::BOOL;
|
||||||
|
@@ -32,6 +32,7 @@
|
|||||||
#include <projectexplorer/buildconfiguration.h>
|
#include <projectexplorer/buildconfiguration.h>
|
||||||
#include <projectexplorer/abi.h>
|
#include <projectexplorer/abi.h>
|
||||||
|
|
||||||
|
namespace CppTools { class ProjectPartBuilder; }
|
||||||
namespace ProjectExplorer { class ToolChain; }
|
namespace ProjectExplorer { class ToolChain; }
|
||||||
|
|
||||||
namespace CMakeProjectManager {
|
namespace CMakeProjectManager {
|
||||||
@@ -82,6 +83,7 @@ public:
|
|||||||
|
|
||||||
QList<CMakeBuildTarget> buildTargets() const;
|
QList<CMakeBuildTarget> buildTargets() const;
|
||||||
void generateProjectTree(CMakeProjectNode *root) const;
|
void generateProjectTree(CMakeProjectNode *root) const;
|
||||||
|
QSet<Core::Id> updateCodeModel(CppTools::ProjectPartBuilder &ppBuilder);
|
||||||
|
|
||||||
static Utils::FileName
|
static Utils::FileName
|
||||||
shadowBuildDirectory(const Utils::FileName &projectFilePath, const ProjectExplorer::Kit *k,
|
shadowBuildDirectory(const Utils::FileName &projectFilePath, const ProjectExplorer::Kit *k,
|
||||||
|
@@ -26,6 +26,7 @@
|
|||||||
#include "cmakebuildsettingswidget.h"
|
#include "cmakebuildsettingswidget.h"
|
||||||
|
|
||||||
#include "configmodel.h"
|
#include "configmodel.h"
|
||||||
|
#include "configmodelitemdelegate.h"
|
||||||
#include "cmakeproject.h"
|
#include "cmakeproject.h"
|
||||||
#include "cmakebuildconfiguration.h"
|
#include "cmakebuildconfiguration.h"
|
||||||
|
|
||||||
@@ -140,6 +141,7 @@ CMakeBuildSettingsWidget::CMakeBuildSettingsWidget(CMakeBuildConfiguration *bc)
|
|||||||
m_configView->setSelectionBehavior(QAbstractItemView::SelectItems);
|
m_configView->setSelectionBehavior(QAbstractItemView::SelectItems);
|
||||||
m_configView->setFrameShape(QFrame::NoFrame);
|
m_configView->setFrameShape(QFrame::NoFrame);
|
||||||
m_configView->hideColumn(2); // Hide isAdvanced column
|
m_configView->hideColumn(2); // Hide isAdvanced column
|
||||||
|
m_configView->setItemDelegate(new ConfigModelItemDelegate(m_configView));
|
||||||
QFrame *findWrapper = Core::ItemViewFind::createSearchableWrapper(m_configView, Core::ItemViewFind::LightColored);
|
QFrame *findWrapper = Core::ItemViewFind::createSearchableWrapper(m_configView, Core::ItemViewFind::LightColored);
|
||||||
findWrapper->setFrameStyle(QFrame::StyledPanel);
|
findWrapper->setFrameStyle(QFrame::StyledPanel);
|
||||||
|
|
||||||
|
@@ -42,7 +42,7 @@ CMakeConfigItem::CMakeConfigItem() = default;
|
|||||||
|
|
||||||
CMakeConfigItem::CMakeConfigItem(const CMakeConfigItem &other) :
|
CMakeConfigItem::CMakeConfigItem(const CMakeConfigItem &other) :
|
||||||
key(other.key), type(other.type), isAdvanced(other.isAdvanced),
|
key(other.key), type(other.type), isAdvanced(other.isAdvanced),
|
||||||
value(other.value), documentation(other.documentation)
|
value(other.value), documentation(other.documentation), values(other.values)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
CMakeConfigItem::CMakeConfigItem(const QByteArray &k, Type t,
|
CMakeConfigItem::CMakeConfigItem(const QByteArray &k, Type t,
|
||||||
|
@@ -61,6 +61,7 @@ public:
|
|||||||
bool isAdvanced = false;
|
bool isAdvanced = false;
|
||||||
QByteArray value; // converted to string as needed
|
QByteArray value; // converted to string as needed
|
||||||
QByteArray documentation;
|
QByteArray documentation;
|
||||||
|
QStringList values;
|
||||||
};
|
};
|
||||||
using CMakeConfig = QList<CMakeConfigItem>;
|
using CMakeConfig = QList<CMakeConfigItem>;
|
||||||
|
|
||||||
|
@@ -94,102 +94,6 @@ CMakeProject::~CMakeProject()
|
|||||||
qDeleteAll(m_extraCompilers);
|
qDeleteAll(m_extraCompilers);
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList CMakeProject::getCXXFlagsFor(const CMakeBuildTarget &buildTarget,
|
|
||||||
QHash<QString, QStringList> &cache)
|
|
||||||
{
|
|
||||||
// check cache:
|
|
||||||
auto it = cache.constFind(buildTarget.title);
|
|
||||||
if (it != cache.constEnd())
|
|
||||||
return *it;
|
|
||||||
|
|
||||||
if (extractCXXFlagsFromMake(buildTarget, cache))
|
|
||||||
return cache.value(buildTarget.title);
|
|
||||||
|
|
||||||
if (extractCXXFlagsFromNinja(buildTarget, cache))
|
|
||||||
return cache.value(buildTarget.title);
|
|
||||||
|
|
||||||
cache.insert(buildTarget.title, QStringList());
|
|
||||||
return QStringList();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CMakeProject::extractCXXFlagsFromMake(const CMakeBuildTarget &buildTarget,
|
|
||||||
QHash<QString, QStringList> &cache)
|
|
||||||
{
|
|
||||||
QString makeCommand = QDir::fromNativeSeparators(buildTarget.makeCommand);
|
|
||||||
int startIndex = makeCommand.indexOf('\"');
|
|
||||||
int endIndex = makeCommand.indexOf('\"', startIndex + 1);
|
|
||||||
if (startIndex != -1 && endIndex != -1) {
|
|
||||||
startIndex += 1;
|
|
||||||
QString makefile = makeCommand.mid(startIndex, endIndex - startIndex);
|
|
||||||
int slashIndex = makefile.lastIndexOf('/');
|
|
||||||
makefile.truncate(slashIndex);
|
|
||||||
makefile.append("/CMakeFiles/" + buildTarget.title + ".dir/flags.make");
|
|
||||||
QFile file(makefile);
|
|
||||||
if (file.exists()) {
|
|
||||||
file.open(QIODevice::ReadOnly | QIODevice::Text);
|
|
||||||
QTextStream stream(&file);
|
|
||||||
while (!stream.atEnd()) {
|
|
||||||
QString line = stream.readLine().trimmed();
|
|
||||||
if (line.startsWith("CXX_FLAGS =")) {
|
|
||||||
// Skip past =
|
|
||||||
cache.insert(buildTarget.title,
|
|
||||||
line.mid(11).trimmed().split(' ', QString::SkipEmptyParts));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CMakeProject::extractCXXFlagsFromNinja(const CMakeBuildTarget &buildTarget,
|
|
||||||
QHash<QString, QStringList> &cache)
|
|
||||||
{
|
|
||||||
Q_UNUSED(buildTarget)
|
|
||||||
if (!cache.isEmpty()) // We fill the cache in one go!
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Attempt to find build.ninja file and obtain FLAGS (CXX_FLAGS) from there if no suitable flags.make were
|
|
||||||
// found
|
|
||||||
// Get "all" target's working directory
|
|
||||||
QByteArray ninjaFile;
|
|
||||||
QString buildNinjaFile = QDir::fromNativeSeparators(buildTargets().at(0).workingDirectory);
|
|
||||||
buildNinjaFile += "/build.ninja";
|
|
||||||
QFile buildNinja(buildNinjaFile);
|
|
||||||
if (buildNinja.exists()) {
|
|
||||||
buildNinja.open(QIODevice::ReadOnly | QIODevice::Text);
|
|
||||||
ninjaFile = buildNinja.readAll();
|
|
||||||
buildNinja.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ninjaFile.isEmpty())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
QTextStream stream(ninjaFile);
|
|
||||||
bool cxxFound = false;
|
|
||||||
const QString targetSignature = "# Object build statements for ";
|
|
||||||
QString currentTarget;
|
|
||||||
|
|
||||||
while (!stream.atEnd()) {
|
|
||||||
// 1. Look for a block that refers to the current target
|
|
||||||
// 2. Look for a build rule which invokes CXX_COMPILER
|
|
||||||
// 3. Return the FLAGS definition
|
|
||||||
QString line = stream.readLine().trimmed();
|
|
||||||
if (line.startsWith('#')) {
|
|
||||||
if (line.startsWith(targetSignature)) {
|
|
||||||
int pos = line.lastIndexOf(' ');
|
|
||||||
currentTarget = line.mid(pos + 1);
|
|
||||||
}
|
|
||||||
} else if (!currentTarget.isEmpty() && line.startsWith("build")) {
|
|
||||||
cxxFound = line.indexOf("CXX_COMPILER") != -1;
|
|
||||||
} else if (cxxFound && line.startsWith("FLAGS =")) {
|
|
||||||
// Skip past =
|
|
||||||
cache.insert(currentTarget, line.mid(7).trimmed().split(' ', QString::SkipEmptyParts));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return !cache.isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
void CMakeProject::updateProjectData()
|
void CMakeProject::updateProjectData()
|
||||||
{
|
{
|
||||||
auto cmakeBc = qobject_cast<CMakeBuildConfiguration *>(sender());
|
auto cmakeBc = qobject_cast<CMakeBuildConfiguration *>(sender());
|
||||||
@@ -225,39 +129,11 @@ void CMakeProject::updateProjectData()
|
|||||||
activeQtVersion = CppTools::ProjectPart::Qt5;
|
activeQtVersion = CppTools::ProjectPart::Qt5;
|
||||||
}
|
}
|
||||||
|
|
||||||
const FileName sysroot = SysRootKitInformation::sysRoot(k);
|
|
||||||
|
|
||||||
ppBuilder.setQtVersion(activeQtVersion);
|
ppBuilder.setQtVersion(activeQtVersion);
|
||||||
|
|
||||||
QHash<QString, QStringList> targetDataCache;
|
const QSet<Core::Id> languages = cmakeBc->updateCodeModel(ppBuilder);
|
||||||
foreach (const CMakeBuildTarget &cbt, buildTargets()) {
|
for (const auto &lid : languages)
|
||||||
if (cbt.targetType == UtilityType)
|
setProjectLanguage(lid, true);
|
||||||
continue;
|
|
||||||
|
|
||||||
// CMake shuffles the include paths that it reports via the CodeBlocks generator
|
|
||||||
// So remove the toolchain include paths, so that at least those end up in the correct
|
|
||||||
// place.
|
|
||||||
QStringList cxxflags = getCXXFlagsFor(cbt, targetDataCache);
|
|
||||||
QSet<QString> tcIncludes;
|
|
||||||
foreach (const HeaderPath &hp, tc->systemHeaderPaths(cxxflags, sysroot)) {
|
|
||||||
tcIncludes.insert(hp.path());
|
|
||||||
}
|
|
||||||
QStringList includePaths;
|
|
||||||
foreach (const QString &i, cbt.includeFiles) {
|
|
||||||
if (!tcIncludes.contains(i))
|
|
||||||
includePaths.append(i);
|
|
||||||
}
|
|
||||||
includePaths += projectDirectory().toString();
|
|
||||||
ppBuilder.setIncludePaths(includePaths);
|
|
||||||
ppBuilder.setCFlags(cxxflags);
|
|
||||||
ppBuilder.setCxxFlags(cxxflags);
|
|
||||||
ppBuilder.setDefines(cbt.defines);
|
|
||||||
ppBuilder.setDisplayName(cbt.title);
|
|
||||||
|
|
||||||
const QList<Core::Id> languages = ppBuilder.createProjectPartsForFiles(cbt.files);
|
|
||||||
foreach (Core::Id language, languages)
|
|
||||||
setProjectLanguage(language, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_codeModelFuture.cancel();
|
m_codeModelFuture.cancel();
|
||||||
pinfo.finish();
|
pinfo.finish();
|
||||||
|
@@ -120,9 +120,6 @@ private:
|
|||||||
QStringList filesGeneratedFrom(const QString &sourceFile) const final;
|
QStringList filesGeneratedFrom(const QString &sourceFile) const final;
|
||||||
void updateTargetRunConfigurations(ProjectExplorer::Target *t);
|
void updateTargetRunConfigurations(ProjectExplorer::Target *t);
|
||||||
void updateApplicationAndDeploymentTargets();
|
void updateApplicationAndDeploymentTargets();
|
||||||
QStringList getCXXFlagsFor(const CMakeBuildTarget &buildTarget, QHash<QString, QStringList> &cache);
|
|
||||||
bool extractCXXFlagsFromMake(const CMakeBuildTarget &buildTarget, QHash<QString, QStringList> &cache);
|
|
||||||
bool extractCXXFlagsFromNinja(const CMakeBuildTarget &buildTarget, QHash<QString, QStringList> &cache);
|
|
||||||
|
|
||||||
ProjectExplorer::Target *m_connectedTarget = nullptr;
|
ProjectExplorer::Target *m_connectedTarget = nullptr;
|
||||||
|
|
||||||
|
@@ -28,7 +28,8 @@ HEADERS = builddirmanager.h \
|
|||||||
cmakebuildsettingswidget.h \
|
cmakebuildsettingswidget.h \
|
||||||
cmakeindenter.h \
|
cmakeindenter.h \
|
||||||
cmakeautocompleter.h \
|
cmakeautocompleter.h \
|
||||||
configmodel.h
|
configmodel.h \
|
||||||
|
configmodelitemdelegate.h
|
||||||
|
|
||||||
SOURCES = builddirmanager.cpp \
|
SOURCES = builddirmanager.cpp \
|
||||||
cmakebuildstep.cpp \
|
cmakebuildstep.cpp \
|
||||||
@@ -54,6 +55,7 @@ SOURCES = builddirmanager.cpp \
|
|||||||
cmakebuildsettingswidget.cpp \
|
cmakebuildsettingswidget.cpp \
|
||||||
cmakeindenter.cpp \
|
cmakeindenter.cpp \
|
||||||
cmakeautocompleter.cpp \
|
cmakeautocompleter.cpp \
|
||||||
configmodel.cpp
|
configmodel.cpp \
|
||||||
|
configmodelitemdelegate.cpp
|
||||||
|
|
||||||
RESOURCES += cmakeproject.qrc
|
RESOURCES += cmakeproject.qrc
|
||||||
|
@@ -71,6 +71,8 @@ QtcPlugin {
|
|||||||
"cmakeautocompleter.h",
|
"cmakeautocompleter.h",
|
||||||
"cmakeautocompleter.cpp",
|
"cmakeautocompleter.cpp",
|
||||||
"configmodel.cpp",
|
"configmodel.cpp",
|
||||||
"configmodel.h"
|
"configmodel.h",
|
||||||
|
"configmodelitemdelegate.cpp",
|
||||||
|
"configmodelitemdelegate.h"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@@ -88,6 +88,15 @@ QVariant ConfigModel::data(const QModelIndex &index, int role) const
|
|||||||
|
|
||||||
const InternalDataItem &item = m_configuration[index.row()];
|
const InternalDataItem &item = m_configuration[index.row()];
|
||||||
|
|
||||||
|
if (index.column() < 2) {
|
||||||
|
switch (role) {
|
||||||
|
case ItemTypeRole:
|
||||||
|
return item.type;
|
||||||
|
case ItemValuesRole:
|
||||||
|
return item.values;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
switch (index.column()) {
|
switch (index.column()) {
|
||||||
case 0:
|
case 0:
|
||||||
switch (role) {
|
switch (role) {
|
||||||
@@ -97,8 +106,6 @@ QVariant ConfigModel::data(const QModelIndex &index, int role) const
|
|||||||
return item.key;
|
return item.key;
|
||||||
case Qt::ToolTipRole:
|
case Qt::ToolTipRole:
|
||||||
return item.description;
|
return item.description;
|
||||||
case Qt::UserRole:
|
|
||||||
return item.type;
|
|
||||||
case Qt::FontRole: {
|
case Qt::FontRole: {
|
||||||
QFont font;
|
QFont font;
|
||||||
font.setItalic(item.isCMakeChanged);
|
font.setItalic(item.isCMakeChanged);
|
||||||
@@ -126,8 +133,6 @@ QVariant ConfigModel::data(const QModelIndex &index, int role) const
|
|||||||
}
|
}
|
||||||
case Qt::ToolTipRole:
|
case Qt::ToolTipRole:
|
||||||
return item.description;
|
return item.description;
|
||||||
case Qt::UserRole:
|
|
||||||
return item.type;
|
|
||||||
default:
|
default:
|
||||||
return QVariant();
|
return QVariant();
|
||||||
}
|
}
|
||||||
@@ -209,13 +214,15 @@ QVariant ConfigModel::headerData(int section, Qt::Orientation orientation, int r
|
|||||||
void ConfigModel::appendConfiguration(const QString &key,
|
void ConfigModel::appendConfiguration(const QString &key,
|
||||||
const QString &value,
|
const QString &value,
|
||||||
const ConfigModel::DataItem::Type type,
|
const ConfigModel::DataItem::Type type,
|
||||||
const QString &description)
|
const QString &description,
|
||||||
|
const QStringList &values)
|
||||||
{
|
{
|
||||||
DataItem item;
|
DataItem item;
|
||||||
item.key = key;
|
item.key = key;
|
||||||
item.type = type;
|
item.type = type;
|
||||||
item.value = value;
|
item.value = value;
|
||||||
item.description = description;
|
item.description = description;
|
||||||
|
item.values = values;
|
||||||
|
|
||||||
InternalDataItem internalItem(item);
|
InternalDataItem internalItem(item);
|
||||||
internalItem.isUserNew = true;
|
internalItem.isUserNew = true;
|
||||||
|
@@ -34,6 +34,11 @@ class ConfigModel : public QAbstractTableModel
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
enum Roles {
|
||||||
|
ItemTypeRole = Qt::UserRole,
|
||||||
|
ItemValuesRole
|
||||||
|
};
|
||||||
|
|
||||||
class DataItem {
|
class DataItem {
|
||||||
public:
|
public:
|
||||||
enum Type { BOOLEAN, FILE, DIRECTORY, STRING, UNKNOWN};
|
enum Type { BOOLEAN, FILE, DIRECTORY, STRING, UNKNOWN};
|
||||||
@@ -43,6 +48,7 @@ public:
|
|||||||
bool isAdvanced = false;
|
bool isAdvanced = false;
|
||||||
QString value;
|
QString value;
|
||||||
QString description;
|
QString description;
|
||||||
|
QStringList values;
|
||||||
};
|
};
|
||||||
|
|
||||||
explicit ConfigModel(QObject *parent = nullptr);
|
explicit ConfigModel(QObject *parent = nullptr);
|
||||||
@@ -58,7 +64,8 @@ public:
|
|||||||
void appendConfiguration(const QString &key,
|
void appendConfiguration(const QString &key,
|
||||||
const QString &value = QString(),
|
const QString &value = QString(),
|
||||||
const DataItem::Type type = DataItem::UNKNOWN,
|
const DataItem::Type type = DataItem::UNKNOWN,
|
||||||
const QString &description = QString());
|
const QString &description = QString(),
|
||||||
|
const QStringList &values = QStringList());
|
||||||
void setConfiguration(const QList<DataItem> &config);
|
void setConfiguration(const QList<DataItem> &config);
|
||||||
void flush();
|
void flush();
|
||||||
void resetAllChanges();
|
void resetAllChanges();
|
||||||
|
78
src/plugins/cmakeprojectmanager/configmodelitemdelegate.cpp
Normal file
78
src/plugins/cmakeprojectmanager/configmodelitemdelegate.cpp
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2016 Alexander Drozdov.
|
||||||
|
** Contact: adrozdoff@gmail.com
|
||||||
|
**
|
||||||
|
** This file is part of CMakeProjectManager2 plugin.
|
||||||
|
**
|
||||||
|
** GNU Lesser General Public License Usage
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||||
|
** General Public License version 2.1 or version 3 as published by the Free
|
||||||
|
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
|
||||||
|
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
|
||||||
|
** following information to ensure the GNU Lesser General Public License
|
||||||
|
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
|
||||||
|
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include "configmodelitemdelegate.h"
|
||||||
|
#include "configmodel.h"
|
||||||
|
|
||||||
|
#include <QComboBox>
|
||||||
|
|
||||||
|
namespace CMakeProjectManager {
|
||||||
|
|
||||||
|
ConfigModelItemDelegate::ConfigModelItemDelegate(QObject* parent)
|
||||||
|
: QStyledItemDelegate(parent)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
ConfigModelItemDelegate::~ConfigModelItemDelegate()
|
||||||
|
{ }
|
||||||
|
|
||||||
|
QWidget* ConfigModelItemDelegate::createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const
|
||||||
|
{
|
||||||
|
// ComboBox ony in column 2
|
||||||
|
if (index.column() != 1)
|
||||||
|
return QStyledItemDelegate::createEditor(parent, option, index);
|
||||||
|
|
||||||
|
auto model = index.model();
|
||||||
|
auto values = model->data(index, ConfigModel::ItemValuesRole).toStringList();
|
||||||
|
if (values.isEmpty())
|
||||||
|
return QStyledItemDelegate::createEditor(parent, option, index);
|
||||||
|
|
||||||
|
// Create the combobox and populate it
|
||||||
|
auto cb = new QComboBox(parent);
|
||||||
|
cb->addItems(values);
|
||||||
|
cb->setEditable(true);
|
||||||
|
|
||||||
|
return cb;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigModelItemDelegate::setEditorData(QWidget* editor, const QModelIndex& index) const
|
||||||
|
{
|
||||||
|
if (QComboBox* cb = qobject_cast<QComboBox*>(editor)) {
|
||||||
|
// get the index of the text in the combobox that matches the current value of the itenm
|
||||||
|
QString currentText = index.data(Qt::EditRole).toString();
|
||||||
|
int cbIndex = cb->findText(currentText);
|
||||||
|
// if it is valid, adjust the combobox
|
||||||
|
if (cbIndex >= 0)
|
||||||
|
cb->setCurrentIndex(cbIndex);
|
||||||
|
else
|
||||||
|
cb->setEditText(currentText);
|
||||||
|
} else {
|
||||||
|
QStyledItemDelegate::setEditorData(editor, index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigModelItemDelegate::setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const
|
||||||
|
{
|
||||||
|
if (QComboBox* cb = qobject_cast<QComboBox*>(editor))
|
||||||
|
// save the current text of the combo box as the current value of the item
|
||||||
|
model->setData(index, cb->currentText(), Qt::EditRole);
|
||||||
|
else
|
||||||
|
QStyledItemDelegate::setModelData(editor, model, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace CMakeProjectManager
|
||||||
|
|
37
src/plugins/cmakeprojectmanager/configmodelitemdelegate.h
Normal file
37
src/plugins/cmakeprojectmanager/configmodelitemdelegate.h
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2016 Alexander Drozdov.
|
||||||
|
** Contact: adrozdoff@gmail.com
|
||||||
|
**
|
||||||
|
** This file is part of CMakeProjectManager2 plugin.
|
||||||
|
**
|
||||||
|
** GNU Lesser General Public License Usage
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||||
|
** General Public License version 2.1 or version 3 as published by the Free
|
||||||
|
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
|
||||||
|
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
|
||||||
|
** following information to ensure the GNU Lesser General Public License
|
||||||
|
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
|
||||||
|
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QStyledItemDelegate>
|
||||||
|
|
||||||
|
namespace CMakeProjectManager {
|
||||||
|
|
||||||
|
class ConfigModelItemDelegate : public QStyledItemDelegate
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
ConfigModelItemDelegate(QObject* parent=0);
|
||||||
|
~ConfigModelItemDelegate();
|
||||||
|
|
||||||
|
QWidget* createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const override;
|
||||||
|
void setEditorData(QWidget* editor, const QModelIndex& index) const override;
|
||||||
|
void setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const override;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace CMakeProjectManager
|
@@ -32,6 +32,7 @@
|
|||||||
|
|
||||||
#include <QFrame>
|
#include <QFrame>
|
||||||
#include <QHBoxLayout>
|
#include <QHBoxLayout>
|
||||||
|
#include <QVBoxLayout>
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
#include <QToolButton>
|
#include <QToolButton>
|
||||||
|
|
||||||
@@ -67,6 +68,20 @@ void InfoBarEntry::setCancelButtonInfo(const QString &_cancelButtonText, CallBac
|
|||||||
m_cancelButtonCallBack = callBack;
|
m_cancelButtonCallBack = callBack;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void InfoBarEntry::setSuppressionButtonInfo(InfoBarEntry::CallBack callback)
|
||||||
|
{
|
||||||
|
m_suppressionButtonCallBack = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
void InfoBarEntry::setShowDefaultCancelButton(bool yesno)
|
||||||
|
{
|
||||||
|
m_showDefaultCancelButton = yesno;
|
||||||
|
}
|
||||||
|
|
||||||
|
void InfoBarEntry::setDetailsWidgetCreator(const InfoBarEntry::DetailsWidgetCreator &creator)
|
||||||
|
{
|
||||||
|
m_detailsWidgetCreator = creator;
|
||||||
|
}
|
||||||
|
|
||||||
void InfoBar::addInfo(const InfoBarEntry &info)
|
void InfoBar::addInfo(const InfoBarEntry &info)
|
||||||
{
|
{
|
||||||
@@ -124,10 +139,13 @@ void InfoBar::clear()
|
|||||||
void InfoBar::globallySuppressInfo(Id id)
|
void InfoBar::globallySuppressInfo(Id id)
|
||||||
{
|
{
|
||||||
globallySuppressed.insert(id);
|
globallySuppressed.insert(id);
|
||||||
QStringList list;
|
writeGloballySuppressedToSettings();
|
||||||
foreach (Id i, globallySuppressed)
|
}
|
||||||
list << QLatin1String(i.name());
|
|
||||||
ICore::settings()->setValue(QLatin1String(C_SUPPRESSED_WARNINGS), list);
|
void InfoBar::globallyUnsuppressInfo(Id id)
|
||||||
|
{
|
||||||
|
globallySuppressed.remove(id);
|
||||||
|
writeGloballySuppressedToSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
void InfoBar::initializeGloballySuppressed()
|
void InfoBar::initializeGloballySuppressed()
|
||||||
@@ -148,12 +166,17 @@ bool InfoBar::anyGloballySuppressed()
|
|||||||
return !globallySuppressed.isEmpty();
|
return !globallySuppressed.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void InfoBar::writeGloballySuppressedToSettings()
|
||||||
|
{
|
||||||
|
QStringList list;
|
||||||
|
foreach (Id i, globallySuppressed)
|
||||||
|
list << QLatin1String(i.name());
|
||||||
|
ICore::settings()->setValue(QLatin1String(C_SUPPRESSED_WARNINGS), list);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
InfoBarDisplay::InfoBarDisplay(QObject *parent)
|
InfoBarDisplay::InfoBarDisplay(QObject *parent)
|
||||||
: QObject(parent)
|
: QObject(parent)
|
||||||
, m_infoBar(0)
|
|
||||||
, m_boxLayout(0)
|
|
||||||
, m_boxIndex(0)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -209,13 +232,43 @@ void InfoBarDisplay::update()
|
|||||||
infoWidget->setLineWidth(1);
|
infoWidget->setLineWidth(1);
|
||||||
infoWidget->setAutoFillBackground(true);
|
infoWidget->setAutoFillBackground(true);
|
||||||
|
|
||||||
QHBoxLayout *hbox = new QHBoxLayout(infoWidget);
|
QHBoxLayout *hbox = new QHBoxLayout;
|
||||||
hbox->setMargin(2);
|
hbox->setMargin(2);
|
||||||
|
|
||||||
|
auto *vbox = new QVBoxLayout(infoWidget);
|
||||||
|
vbox->setMargin(0);
|
||||||
|
vbox->addLayout(hbox);
|
||||||
|
|
||||||
QLabel *infoWidgetLabel = new QLabel(info.infoText);
|
QLabel *infoWidgetLabel = new QLabel(info.infoText);
|
||||||
infoWidgetLabel->setWordWrap(true);
|
infoWidgetLabel->setWordWrap(true);
|
||||||
hbox->addWidget(infoWidgetLabel);
|
hbox->addWidget(infoWidgetLabel);
|
||||||
|
|
||||||
|
if (info.m_detailsWidgetCreator) {
|
||||||
|
if (m_isShowingDetailsWidget) {
|
||||||
|
QWidget *detailsWidget = info.m_detailsWidgetCreator();
|
||||||
|
vbox->addWidget(detailsWidget);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto *showDetailsButton = new QToolButton;
|
||||||
|
showDetailsButton->setCheckable(true);
|
||||||
|
showDetailsButton->setChecked(m_isShowingDetailsWidget);
|
||||||
|
showDetailsButton->setText(tr("&Show Details"));
|
||||||
|
connect(showDetailsButton, &QToolButton::clicked, [this, vbox, info] (bool) {
|
||||||
|
QWidget *detailsWidget = vbox->count() == 2 ? vbox->itemAt(1)->widget() : nullptr;
|
||||||
|
if (!detailsWidget) {
|
||||||
|
detailsWidget = info.m_detailsWidgetCreator();
|
||||||
|
vbox->addWidget(detailsWidget);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_isShowingDetailsWidget = !m_isShowingDetailsWidget;
|
||||||
|
detailsWidget->setVisible(m_isShowingDetailsWidget);
|
||||||
|
});
|
||||||
|
|
||||||
|
hbox->addWidget(showDetailsButton);
|
||||||
|
} else {
|
||||||
|
m_isShowingDetailsWidget = false;
|
||||||
|
}
|
||||||
|
|
||||||
if (!info.buttonText.isEmpty()) {
|
if (!info.buttonText.isEmpty()) {
|
||||||
QToolButton *infoWidgetButton = new QToolButton;
|
QToolButton *infoWidgetButton = new QToolButton;
|
||||||
infoWidgetButton->setText(info.buttonText);
|
infoWidgetButton->setText(info.buttonText);
|
||||||
@@ -229,7 +282,9 @@ void InfoBarDisplay::update()
|
|||||||
if (info.globalSuppression == InfoBarEntry::GlobalSuppressionEnabled) {
|
if (info.globalSuppression == InfoBarEntry::GlobalSuppressionEnabled) {
|
||||||
infoWidgetSuppressButton = new QToolButton;
|
infoWidgetSuppressButton = new QToolButton;
|
||||||
infoWidgetSuppressButton->setText(tr("Do Not Show Again"));
|
infoWidgetSuppressButton->setText(tr("Do Not Show Again"));
|
||||||
connect(infoWidgetSuppressButton, &QAbstractButton::clicked, this, [this, id] {
|
connect(infoWidgetSuppressButton, &QAbstractButton::clicked, this, [this, info, id] {
|
||||||
|
if (info.m_suppressionButtonCallBack)
|
||||||
|
info.m_suppressionButtonCallBack();
|
||||||
m_infoBar->removeInfo(id);
|
m_infoBar->removeInfo(id);
|
||||||
InfoBar::globallySuppressInfo(id);
|
InfoBar::globallySuppressInfo(id);
|
||||||
});
|
});
|
||||||
@@ -245,12 +300,17 @@ void InfoBarDisplay::update()
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (info.cancelButtonText.isEmpty()) {
|
if (info.cancelButtonText.isEmpty()) {
|
||||||
infoWidgetCloseButton->setAutoRaise(true);
|
if (info.m_showDefaultCancelButton) {
|
||||||
infoWidgetCloseButton->setIcon(Utils::Icons::CLOSE_FOREGROUND.icon());
|
infoWidgetCloseButton->setAutoRaise(true);
|
||||||
infoWidgetCloseButton->setToolTip(tr("Close"));
|
infoWidgetCloseButton->setIcon(Utils::Icons::CLOSE_FOREGROUND.icon());
|
||||||
|
infoWidgetCloseButton->setToolTip(tr("Close"));
|
||||||
|
}
|
||||||
|
|
||||||
if (infoWidgetSuppressButton)
|
if (infoWidgetSuppressButton)
|
||||||
hbox->addWidget(infoWidgetSuppressButton);
|
hbox->addWidget(infoWidgetSuppressButton);
|
||||||
hbox->addWidget(infoWidgetCloseButton);
|
|
||||||
|
if (info.m_showDefaultCancelButton)
|
||||||
|
hbox->addWidget(infoWidgetCloseButton);
|
||||||
} else {
|
} else {
|
||||||
infoWidgetCloseButton->setText(info.cancelButtonText);
|
infoWidgetCloseButton->setText(info.cancelButtonText);
|
||||||
hbox->addWidget(infoWidgetCloseButton);
|
hbox->addWidget(infoWidgetCloseButton);
|
||||||
|
@@ -54,10 +54,15 @@ public:
|
|||||||
InfoBarEntry(Id _id, const QString &_infoText, GlobalSuppressionMode _globalSuppression = GlobalSuppressionDisabled);
|
InfoBarEntry(Id _id, const QString &_infoText, GlobalSuppressionMode _globalSuppression = GlobalSuppressionDisabled);
|
||||||
InfoBarEntry(const InfoBarEntry &other) { *this = other; }
|
InfoBarEntry(const InfoBarEntry &other) { *this = other; }
|
||||||
|
|
||||||
typedef std::function<void()> CallBack;
|
using CallBack = std::function<void()>;
|
||||||
void setCustomButtonInfo(const QString &_buttonText, CallBack callBack);
|
void setCustomButtonInfo(const QString &_buttonText, CallBack callBack);
|
||||||
void setCancelButtonInfo(CallBack callBack);
|
void setCancelButtonInfo(CallBack callBack);
|
||||||
void setCancelButtonInfo(const QString &_cancelButtonText, CallBack callBack);
|
void setCancelButtonInfo(const QString &_cancelButtonText, CallBack callBack);
|
||||||
|
void setSuppressionButtonInfo(CallBack callback);
|
||||||
|
void setShowDefaultCancelButton(bool yesno);
|
||||||
|
|
||||||
|
using DetailsWidgetCreator = std::function<QWidget*()>;
|
||||||
|
void setDetailsWidgetCreator(const DetailsWidgetCreator &creator);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Id id;
|
Id id;
|
||||||
@@ -66,7 +71,10 @@ private:
|
|||||||
CallBack m_buttonCallBack;
|
CallBack m_buttonCallBack;
|
||||||
QString cancelButtonText;
|
QString cancelButtonText;
|
||||||
CallBack m_cancelButtonCallBack;
|
CallBack m_cancelButtonCallBack;
|
||||||
|
CallBack m_suppressionButtonCallBack;
|
||||||
GlobalSuppressionMode globalSuppression;
|
GlobalSuppressionMode globalSuppression;
|
||||||
|
DetailsWidgetCreator m_detailsWidgetCreator;
|
||||||
|
bool m_showDefaultCancelButton = true;
|
||||||
friend class InfoBar;
|
friend class InfoBar;
|
||||||
friend class InfoBarDisplay;
|
friend class InfoBarDisplay;
|
||||||
};
|
};
|
||||||
@@ -84,6 +92,7 @@ public:
|
|||||||
void enableInfo(Id id);
|
void enableInfo(Id id);
|
||||||
void clear();
|
void clear();
|
||||||
static void globallySuppressInfo(Id id);
|
static void globallySuppressInfo(Id id);
|
||||||
|
static void globallyUnsuppressInfo(Id id);
|
||||||
static void initializeGloballySuppressed();
|
static void initializeGloballySuppressed();
|
||||||
static void clearGloballySuppressed();
|
static void clearGloballySuppressed();
|
||||||
static bool anyGloballySuppressed();
|
static bool anyGloballySuppressed();
|
||||||
@@ -91,6 +100,9 @@ public:
|
|||||||
signals:
|
signals:
|
||||||
void changed();
|
void changed();
|
||||||
|
|
||||||
|
private:
|
||||||
|
static void writeGloballySuppressedToSettings();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QList<InfoBarEntry> m_infoBarEntries;
|
QList<InfoBarEntry> m_infoBarEntries;
|
||||||
QSet<Id> m_suppressed;
|
QSet<Id> m_suppressed;
|
||||||
@@ -113,9 +125,10 @@ private:
|
|||||||
void widgetDestroyed();
|
void widgetDestroyed();
|
||||||
|
|
||||||
QList<QWidget *> m_infoWidgets;
|
QList<QWidget *> m_infoWidgets;
|
||||||
InfoBar *m_infoBar;
|
InfoBar *m_infoBar = nullptr;
|
||||||
QBoxLayout *m_boxLayout;
|
QBoxLayout *m_boxLayout = nullptr;
|
||||||
int m_boxIndex;
|
int m_boxIndex = 0;
|
||||||
|
bool m_isShowingDetailsWidget = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Core
|
} // namespace Core
|
||||||
|
@@ -44,6 +44,7 @@
|
|||||||
#include <coreplugin/actionmanager/actionmanager.h>
|
#include <coreplugin/actionmanager/actionmanager.h>
|
||||||
#include <coreplugin/editormanager/editormanager.h>
|
#include <coreplugin/editormanager/editormanager.h>
|
||||||
#include <coreplugin/editormanager/documentmodel.h>
|
#include <coreplugin/editormanager/documentmodel.h>
|
||||||
|
#include <coreplugin/infobar.h>
|
||||||
|
|
||||||
#include <cpptools/cppchecksymbols.h>
|
#include <cpptools/cppchecksymbols.h>
|
||||||
#include <cpptools/cppcodeformatter.h>
|
#include <cpptools/cppcodeformatter.h>
|
||||||
@@ -77,6 +78,7 @@
|
|||||||
#include <cplusplus/FastPreprocessor.h>
|
#include <cplusplus/FastPreprocessor.h>
|
||||||
#include <cplusplus/MatchingText.h>
|
#include <cplusplus/MatchingText.h>
|
||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
|
#include <utils/utilsicons.h>
|
||||||
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QAction>
|
#include <QAction>
|
||||||
@@ -126,9 +128,13 @@ public:
|
|||||||
QSharedPointer<FunctionDeclDefLink> m_declDefLink;
|
QSharedPointer<FunctionDeclDefLink> m_declDefLink;
|
||||||
|
|
||||||
QScopedPointer<FollowSymbolUnderCursor> m_followSymbolUnderCursor;
|
QScopedPointer<FollowSymbolUnderCursor> m_followSymbolUnderCursor;
|
||||||
QToolButton *m_preprocessorButton;
|
|
||||||
|
QToolButton *m_preprocessorButton = nullptr;
|
||||||
|
QToolButton *m_headerErrorsIndicatorButton = nullptr;
|
||||||
|
|
||||||
CppSelectionChanger m_cppSelectionChanger;
|
CppSelectionChanger m_cppSelectionChanger;
|
||||||
|
|
||||||
|
CppEditorWidget::HeaderErrorDiagnosticWidgetCreator m_headerErrorDiagnosticWidgetCreator;
|
||||||
};
|
};
|
||||||
|
|
||||||
CppEditorWidgetPrivate::CppEditorWidgetPrivate(CppEditorWidget *q)
|
CppEditorWidgetPrivate::CppEditorWidgetPrivate(CppEditorWidget *q)
|
||||||
@@ -139,7 +145,6 @@ CppEditorWidgetPrivate::CppEditorWidgetPrivate(CppEditorWidget *q)
|
|||||||
, m_useSelectionsUpdater(q)
|
, m_useSelectionsUpdater(q)
|
||||||
, m_declDefLinkFinder(new FunctionDeclDefLinkFinder(q))
|
, m_declDefLinkFinder(new FunctionDeclDefLinkFinder(q))
|
||||||
, m_followSymbolUnderCursor(new FollowSymbolUnderCursor(q))
|
, m_followSymbolUnderCursor(new FollowSymbolUnderCursor(q))
|
||||||
, m_preprocessorButton(0)
|
|
||||||
, m_cppSelectionChanger()
|
, m_cppSelectionChanger()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -224,7 +229,15 @@ void CppEditorWidget::finalizeInitialization()
|
|||||||
connect(cmd, &Command::keySequenceChanged, this, &CppEditorWidget::updatePreprocessorButtonTooltip);
|
connect(cmd, &Command::keySequenceChanged, this, &CppEditorWidget::updatePreprocessorButtonTooltip);
|
||||||
updatePreprocessorButtonTooltip();
|
updatePreprocessorButtonTooltip();
|
||||||
connect(d->m_preprocessorButton, &QAbstractButton::clicked, this, &CppEditorWidget::showPreProcessorWidget);
|
connect(d->m_preprocessorButton, &QAbstractButton::clicked, this, &CppEditorWidget::showPreProcessorWidget);
|
||||||
|
|
||||||
|
d->m_headerErrorsIndicatorButton = new QToolButton(this);
|
||||||
|
d->m_headerErrorsIndicatorButton->setIcon(Utils::Icons::WARNING_TOOLBAR.pixmap());
|
||||||
|
connect(d->m_headerErrorsIndicatorButton, &QAbstractButton::clicked,
|
||||||
|
this, &CppEditorWidget::showHeaderErrorInfoBar);
|
||||||
|
d->m_headerErrorsIndicatorButton->setEnabled(false);
|
||||||
|
|
||||||
insertExtraToolBarWidget(TextEditorWidget::Left, d->m_preprocessorButton);
|
insertExtraToolBarWidget(TextEditorWidget::Left, d->m_preprocessorButton);
|
||||||
|
insertExtraToolBarWidget(TextEditorWidget::Left, d->m_headerErrorsIndicatorButton);
|
||||||
insertExtraToolBarWidget(TextEditorWidget::Left, d->m_cppEditorOutline->widget());
|
insertExtraToolBarWidget(TextEditorWidget::Left, d->m_cppEditorOutline->widget());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -287,6 +300,7 @@ void CppEditorWidget::onCppDocumentUpdated()
|
|||||||
|
|
||||||
void CppEditorWidget::onCodeWarningsUpdated(unsigned revision,
|
void CppEditorWidget::onCodeWarningsUpdated(unsigned revision,
|
||||||
const QList<QTextEdit::ExtraSelection> selections,
|
const QList<QTextEdit::ExtraSelection> selections,
|
||||||
|
const HeaderErrorDiagnosticWidgetCreator &creator,
|
||||||
const TextEditor::RefactorMarkers &refactorMarkers)
|
const TextEditor::RefactorMarkers &refactorMarkers)
|
||||||
{
|
{
|
||||||
if (revision != documentRevision())
|
if (revision != documentRevision())
|
||||||
@@ -294,6 +308,9 @@ void CppEditorWidget::onCodeWarningsUpdated(unsigned revision,
|
|||||||
|
|
||||||
setExtraSelections(TextEditorWidget::CodeWarningsSelection, selections);
|
setExtraSelections(TextEditorWidget::CodeWarningsSelection, selections);
|
||||||
setRefactorMarkers(refactorMarkersWithoutClangMarkers() + refactorMarkers);
|
setRefactorMarkers(refactorMarkersWithoutClangMarkers() + refactorMarkers);
|
||||||
|
|
||||||
|
d->m_headerErrorDiagnosticWidgetCreator = creator;
|
||||||
|
updateHeaderErrorWidgets();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CppEditorWidget::onIfdefedOutBlocksUpdated(unsigned revision,
|
void CppEditorWidget::onIfdefedOutBlocksUpdated(unsigned revision,
|
||||||
@@ -304,6 +321,24 @@ void CppEditorWidget::onIfdefedOutBlocksUpdated(unsigned revision,
|
|||||||
setIfdefedOutBlocks(ifdefedOutBlocks);
|
setIfdefedOutBlocks(ifdefedOutBlocks);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CppEditorWidget::updateHeaderErrorWidgets()
|
||||||
|
{
|
||||||
|
const Id id(Constants::ERRORS_IN_HEADER_FILES);
|
||||||
|
InfoBar *infoBar = textDocument()->infoBar();
|
||||||
|
|
||||||
|
infoBar->removeInfo(id);
|
||||||
|
|
||||||
|
if (d->m_headerErrorDiagnosticWidgetCreator) {
|
||||||
|
if (infoBar->canInfoBeAdded(id)) {
|
||||||
|
addHeaderErrorInfoBarEntryAndHideIndicator();
|
||||||
|
} else {
|
||||||
|
d->m_headerErrorsIndicatorButton->setEnabled(true);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
d->m_headerErrorsIndicatorButton->setEnabled(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void CppEditorWidget::findUsages()
|
void CppEditorWidget::findUsages()
|
||||||
{
|
{
|
||||||
if (!d->m_modelManager)
|
if (!d->m_modelManager)
|
||||||
@@ -399,6 +434,25 @@ void CppEditorWidget::renameSymbolUnderCursorBuiltin()
|
|||||||
renameUsages(); // Rename non-local symbol or macro
|
renameUsages(); // Rename non-local symbol or macro
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CppEditorWidget::addHeaderErrorInfoBarEntryAndHideIndicator() const
|
||||||
|
{
|
||||||
|
InfoBarEntry info(Constants::ERRORS_IN_HEADER_FILES,
|
||||||
|
tr("<b>Warning</b>: The code model could not parse an included file, "
|
||||||
|
"which might lead to slow or incorrect code completion and "
|
||||||
|
"highlighting, for example."),
|
||||||
|
InfoBarEntry::GlobalSuppressionEnabled);
|
||||||
|
info.setDetailsWidgetCreator(d->m_headerErrorDiagnosticWidgetCreator);
|
||||||
|
info.setShowDefaultCancelButton(false);
|
||||||
|
info.setSuppressionButtonInfo([this](){
|
||||||
|
d->m_headerErrorsIndicatorButton->setEnabled(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
InfoBar *infoBar = textDocument()->infoBar();
|
||||||
|
infoBar->addInfo(info);
|
||||||
|
|
||||||
|
d->m_headerErrorsIndicatorButton->setEnabled(false);
|
||||||
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
QList<ProjectPart::Ptr> fetchProjectParts(CppTools::CppModelManager *modelManager,
|
QList<ProjectPart::Ptr> fetchProjectParts(CppTools::CppModelManager *modelManager,
|
||||||
@@ -970,5 +1024,14 @@ void CppEditorWidget::showPreProcessorWidget()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CppEditorWidget::showHeaderErrorInfoBar()
|
||||||
|
{
|
||||||
|
const Id id(Constants::ERRORS_IN_HEADER_FILES);
|
||||||
|
QTC_CHECK(!textDocument()->infoBar()->canInfoBeAdded(id));
|
||||||
|
|
||||||
|
InfoBar::globallyUnsuppressInfo(id);
|
||||||
|
addHeaderErrorInfoBarEntryAndHideIndicator();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
} // namespace CppEditor
|
} // namespace CppEditor
|
||||||
|
@@ -31,6 +31,10 @@
|
|||||||
|
|
||||||
#include <QScopedPointer>
|
#include <QScopedPointer>
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
class InfoBarEntry;
|
||||||
|
}
|
||||||
|
|
||||||
namespace CppTools {
|
namespace CppTools {
|
||||||
class CppEditorOutline;
|
class CppEditorOutline;
|
||||||
class RefactoringEngineInterface;
|
class RefactoringEngineInterface;
|
||||||
@@ -87,6 +91,7 @@ public:
|
|||||||
|
|
||||||
void switchDeclarationDefinition(bool inNextSplit);
|
void switchDeclarationDefinition(bool inNextSplit);
|
||||||
void showPreProcessorWidget();
|
void showPreProcessorWidget();
|
||||||
|
void showHeaderErrorInfoBar();
|
||||||
|
|
||||||
void findUsages();
|
void findUsages();
|
||||||
void renameSymbolUnderCursor();
|
void renameSymbolUnderCursor();
|
||||||
@@ -108,6 +113,9 @@ protected:
|
|||||||
|
|
||||||
void slotCodeStyleSettingsChanged(const QVariant &) override;
|
void slotCodeStyleSettingsChanged(const QVariant &) override;
|
||||||
|
|
||||||
|
public:
|
||||||
|
using HeaderErrorDiagnosticWidgetCreator = std::function<QWidget*()>;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void updateFunctionDeclDefLink();
|
void updateFunctionDeclDefLink();
|
||||||
void updateFunctionDeclDefLinkNow();
|
void updateFunctionDeclDefLinkNow();
|
||||||
@@ -118,10 +126,12 @@ private:
|
|||||||
|
|
||||||
void onCodeWarningsUpdated(unsigned revision,
|
void onCodeWarningsUpdated(unsigned revision,
|
||||||
const QList<QTextEdit::ExtraSelection> selections,
|
const QList<QTextEdit::ExtraSelection> selections,
|
||||||
|
const HeaderErrorDiagnosticWidgetCreator &creator,
|
||||||
const TextEditor::RefactorMarkers &refactorMarkers);
|
const TextEditor::RefactorMarkers &refactorMarkers);
|
||||||
void onIfdefedOutBlocksUpdated(unsigned revision,
|
void onIfdefedOutBlocksUpdated(unsigned revision,
|
||||||
const QList<TextEditor::BlockRange> ifdefedOutBlocks);
|
const QList<TextEditor::BlockRange> ifdefedOutBlocks);
|
||||||
|
|
||||||
|
void updateHeaderErrorWidgets();
|
||||||
void updateSemanticInfo(const CppTools::SemanticInfo &semanticInfo,
|
void updateSemanticInfo(const CppTools::SemanticInfo &semanticInfo,
|
||||||
bool updateUseSelectionSynchronously = false);
|
bool updateUseSelectionSynchronously = false);
|
||||||
void updatePreprocessorButtonTooltip();
|
void updatePreprocessorButtonTooltip();
|
||||||
@@ -140,6 +150,8 @@ private:
|
|||||||
void renameSymbolUnderCursorClang();
|
void renameSymbolUnderCursorClang();
|
||||||
void renameSymbolUnderCursorBuiltin();
|
void renameSymbolUnderCursorBuiltin();
|
||||||
|
|
||||||
|
void addHeaderErrorInfoBarEntryAndHideIndicator() const;
|
||||||
|
|
||||||
CppTools::ProjectPart *projectPart() const;
|
CppTools::ProjectPart *projectPart() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@@ -36,6 +36,7 @@ const char OPEN_DECLARATION_DEFINITION_IN_NEXT_SPLIT[] = "CppEditor.OpenDeclarat
|
|||||||
const char RENAME_SYMBOL_UNDER_CURSOR[] = "CppEditor.RenameSymbolUnderCursor";
|
const char RENAME_SYMBOL_UNDER_CURSOR[] = "CppEditor.RenameSymbolUnderCursor";
|
||||||
const char FIND_USAGES[] = "CppEditor.FindUsages";
|
const char FIND_USAGES[] = "CppEditor.FindUsages";
|
||||||
const char OPEN_PREPROCESSOR_DIALOG[] = "CppEditor.OpenPreprocessorDialog";
|
const char OPEN_PREPROCESSOR_DIALOG[] = "CppEditor.OpenPreprocessorDialog";
|
||||||
|
const char ERRORS_IN_HEADER_FILES[] = "CppEditor.ErrorsInHeaderFiles";
|
||||||
const char M_REFACTORING_MENU_INSERTION_POINT[] = "CppEditor.RefactorGroup";
|
const char M_REFACTORING_MENU_INSERTION_POINT[] = "CppEditor.RefactorGroup";
|
||||||
const char UPDATE_CODEMODEL[] = "CppEditor.UpdateCodeModel";
|
const char UPDATE_CODEMODEL[] = "CppEditor.UpdateCodeModel";
|
||||||
const char INSPECT_CPP_CODEMODEL[] = "CppEditor.InspectCppCodeModel";
|
const char INSPECT_CPP_CODEMODEL[] = "CppEditor.InspectCppCodeModel";
|
||||||
|
@@ -230,12 +230,14 @@ void CppEditorDocument::scheduleProcessDocument()
|
|||||||
{
|
{
|
||||||
m_processorRevision = document()->revision();
|
m_processorRevision = document()->revision();
|
||||||
m_processorTimer.start();
|
m_processorTimer.start();
|
||||||
|
processor()->editorDocumentTimerRestarted();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CppEditorDocument::processDocument()
|
void CppEditorDocument::processDocument()
|
||||||
{
|
{
|
||||||
if (processor()->isParserRunning() || m_processorRevision != contentsRevision()) {
|
if (processor()->isParserRunning() || m_processorRevision != contentsRevision()) {
|
||||||
m_processorTimer.start();
|
m_processorTimer.start();
|
||||||
|
processor()->editorDocumentTimerRestarted();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -59,9 +59,13 @@ public:
|
|||||||
const QByteArray &defines);
|
const QByteArray &defines);
|
||||||
void scheduleProcessDocument();
|
void scheduleProcessDocument();
|
||||||
|
|
||||||
|
public:
|
||||||
|
using HeaderErrorDiagnosticWidgetCreator = std::function<QWidget*()>;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void codeWarningsUpdated(unsigned contentsRevision,
|
void codeWarningsUpdated(unsigned contentsRevision,
|
||||||
const QList<QTextEdit::ExtraSelection> selections,
|
const QList<QTextEdit::ExtraSelection> selections,
|
||||||
|
const HeaderErrorDiagnosticWidgetCreator &creator,
|
||||||
const TextEditor::RefactorMarkers &refactorMarkers);
|
const TextEditor::RefactorMarkers &refactorMarkers);
|
||||||
|
|
||||||
void ifdefedOutBlocksUpdated(unsigned contentsRevision,
|
void ifdefedOutBlocksUpdated(unsigned contentsRevision,
|
||||||
|
@@ -67,6 +67,10 @@ void BaseEditorDocumentProcessor::addDiagnosticToolTipToLayout(uint, uint, QLayo
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BaseEditorDocumentProcessor::editorDocumentTimerRestarted()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
void BaseEditorDocumentProcessor::runParser(QFutureInterface<void> &future,
|
void BaseEditorDocumentProcessor::runParser(QFutureInterface<void> &future,
|
||||||
BaseEditorDocumentParser::Ptr parser,
|
BaseEditorDocumentParser::Ptr parser,
|
||||||
const WorkingCopy workingCopy)
|
const WorkingCopy workingCopy)
|
||||||
|
@@ -37,6 +37,8 @@
|
|||||||
|
|
||||||
#include <QTextEdit>
|
#include <QTextEdit>
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
namespace TextEditor {
|
namespace TextEditor {
|
||||||
class TextDocument;
|
class TextDocument;
|
||||||
class QuickFixOperations;
|
class QuickFixOperations;
|
||||||
@@ -67,10 +69,17 @@ public:
|
|||||||
virtual bool hasDiagnosticsAt(uint line, uint column) const;
|
virtual bool hasDiagnosticsAt(uint line, uint column) const;
|
||||||
virtual void addDiagnosticToolTipToLayout(uint line, uint column, QLayout *layout) const;
|
virtual void addDiagnosticToolTipToLayout(uint line, uint column, QLayout *layout) const;
|
||||||
|
|
||||||
|
virtual void editorDocumentTimerRestarted();
|
||||||
|
|
||||||
|
public:
|
||||||
|
using HeaderErrorDiagnosticWidgetCreator = std::function<QWidget*()>;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
|
||||||
// Signal interface to implement
|
// Signal interface to implement
|
||||||
void codeWarningsUpdated(unsigned revision,
|
void codeWarningsUpdated(unsigned revision,
|
||||||
const QList<QTextEdit::ExtraSelection> selections,
|
const QList<QTextEdit::ExtraSelection> selections,
|
||||||
|
const HeaderErrorDiagnosticWidgetCreator &creator,
|
||||||
const TextEditor::RefactorMarkers &refactorMarkers);
|
const TextEditor::RefactorMarkers &refactorMarkers);
|
||||||
|
|
||||||
void ifdefedOutBlocksUpdated(unsigned revision,
|
void ifdefedOutBlocksUpdated(unsigned revision,
|
||||||
|
@@ -310,7 +310,10 @@ void BuiltinEditorDocumentProcessor::onCodeWarningsUpdated(
|
|||||||
|
|
||||||
m_codeWarnings += toTextEditorSelections(codeWarnings, textDocument());
|
m_codeWarnings += toTextEditorSelections(codeWarnings, textDocument());
|
||||||
m_codeWarningsUpdated = true;
|
m_codeWarningsUpdated = true;
|
||||||
emit codeWarningsUpdated(revision(), m_codeWarnings, TextEditor::RefactorMarkers());
|
emit codeWarningsUpdated(revision(),
|
||||||
|
m_codeWarnings,
|
||||||
|
HeaderErrorDiagnosticWidgetCreator(),
|
||||||
|
TextEditor::RefactorMarkers());
|
||||||
}
|
}
|
||||||
|
|
||||||
SemanticInfo::Source BuiltinEditorDocumentProcessor::createSemanticInfoSource(bool force) const
|
SemanticInfo::Source BuiltinEditorDocumentProcessor::createSemanticInfoSource(bool force) const
|
||||||
|
@@ -622,25 +622,25 @@ void HelpPlugin::handleHelpRequest(const QUrl &url, HelpManager::HelpViewerLocat
|
|||||||
if (HelpViewer::launchWithExternalApp(url))
|
if (HelpViewer::launchWithExternalApp(url))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
QString address = url.toString();
|
|
||||||
if (!HelpManager::findFile(url).isValid()) {
|
if (!HelpManager::findFile(url).isValid()) {
|
||||||
|
const QString address = url.toString();
|
||||||
if (address.startsWith("qthelp://org.qt-project.")
|
if (address.startsWith("qthelp://org.qt-project.")
|
||||||
|| address.startsWith("qthelp://com.nokia.")
|
|| address.startsWith("qthelp://com.nokia.")
|
||||||
|| address.startsWith("qthelp://com.trolltech.")) {
|
|| address.startsWith("qthelp://com.trolltech.")) {
|
||||||
// local help not installed, resort to external web help
|
// local help not installed, resort to external web help
|
||||||
QString urlPrefix = "http://doc.qt.io/";
|
QString urlPrefix = "http://doc.qt.io/";
|
||||||
if (url.authority() == "org.qt-project.qtcreator")
|
if (url.authority() == "org.qt-project.qtcreator")
|
||||||
urlPrefix.append(QString::fromLatin1("qtcreator"));
|
urlPrefix.append(QString::fromLatin1("qtcreator"));
|
||||||
else
|
else
|
||||||
urlPrefix.append("qt-5");
|
urlPrefix.append("qt-5");
|
||||||
address = urlPrefix + address.mid(address.lastIndexOf(QLatin1Char('/')));
|
QDesktopServices::openUrl(QUrl(urlPrefix + address.mid(address.lastIndexOf(QLatin1Char('/')))));
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const QUrl newUrl(address);
|
|
||||||
HelpViewer *viewer = viewerForHelpViewerLocation(location);
|
HelpViewer *viewer = viewerForHelpViewerLocation(location);
|
||||||
QTC_ASSERT(viewer, return);
|
QTC_ASSERT(viewer, return);
|
||||||
viewer->setSource(newUrl);
|
viewer->setSource(url);
|
||||||
ICore::raiseWindow(viewer);
|
ICore::raiseWindow(viewer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -169,7 +169,7 @@ static QPoint flipPoint(const NSPoint &p)
|
|||||||
|
|
||||||
NSURL *resolvedURL = data.resolvedUrl.toNSURL();
|
NSURL *resolvedURL = data.resolvedUrl.toNSURL();
|
||||||
NSString *mimeType = data.mimeType.toNSString();
|
NSString *mimeType = data.mimeType.toNSString();
|
||||||
NSData *nsdata = QtMac::toNSData(data.data); // Qt 5.3 has this in QByteArray
|
NSData *nsdata = data.data.toNSData();
|
||||||
NSURLResponse *response = [[NSURLResponse alloc] initWithURL:resolvedURL
|
NSURLResponse *response = [[NSURLResponse alloc] initWithURL:resolvedURL
|
||||||
MIMEType:mimeType
|
MIMEType:mimeType
|
||||||
expectedContentLength:data.data.length()
|
expectedContentLength:data.data.length()
|
||||||
|
@@ -93,7 +93,8 @@ RemoteHelpFilter::RemoteHelpFilter()
|
|||||||
m_remoteUrls.append("https://www.bing.com/search?q=%1");
|
m_remoteUrls.append("https://www.bing.com/search?q=%1");
|
||||||
m_remoteUrls.append("https://www.google.com/search?q=%1");
|
m_remoteUrls.append("https://www.google.com/search?q=%1");
|
||||||
m_remoteUrls.append("https://search.yahoo.com/search?p=%1");
|
m_remoteUrls.append("https://search.yahoo.com/search?p=%1");
|
||||||
m_remoteUrls.append("https://www.cplusplus.com/reference/stl/%1");
|
m_remoteUrls.append("https://stackoverflow.com/search?q=%1");
|
||||||
|
m_remoteUrls.append("http://en.cppreference.com/mwiki/index.php?title=Special%3ASearch&search=%1");
|
||||||
m_remoteUrls.append("https://en.wikipedia.org/w/index.php?search=%1");
|
m_remoteUrls.append("https://en.wikipedia.org/w/index.php?search=%1");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -404,6 +404,7 @@ bool LineEditField::parseData(const QVariant &data, QString *errorMessage)
|
|||||||
|
|
||||||
QVariantMap tmp = data.toMap();
|
QVariantMap tmp = data.toMap();
|
||||||
|
|
||||||
|
m_isPassword = tmp.value("isPassword", false).toBool();
|
||||||
m_defaultText = JsonWizardFactory::localizedString(tmp.value(QLatin1String("trText")).toString());
|
m_defaultText = JsonWizardFactory::localizedString(tmp.value(QLatin1String("trText")).toString());
|
||||||
m_disabledText = JsonWizardFactory::localizedString(tmp.value(QLatin1String("trDisabledText")).toString());
|
m_disabledText = JsonWizardFactory::localizedString(tmp.value(QLatin1String("trDisabledText")).toString());
|
||||||
m_placeholderText = JsonWizardFactory::localizedString(tmp.value(QLatin1String("trPlaceholder")).toString());
|
m_placeholderText = JsonWizardFactory::localizedString(tmp.value(QLatin1String("trPlaceholder")).toString());
|
||||||
@@ -439,6 +440,8 @@ QWidget *LineEditField::createWidget(const QString &displayName, JsonFieldPage *
|
|||||||
if (!m_historyId.isEmpty())
|
if (!m_historyId.isEmpty())
|
||||||
w->setHistoryCompleter(m_historyId, m_restoreLastHistoryItem);
|
w->setHistoryCompleter(m_historyId, m_restoreLastHistoryItem);
|
||||||
|
|
||||||
|
w->setEchoMode(m_isPassword ? QLineEdit::Password : QLineEdit::Normal);
|
||||||
|
|
||||||
return w;
|
return w;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -105,6 +105,7 @@ private:
|
|||||||
bool m_isModified;
|
bool m_isModified;
|
||||||
bool m_isValidating;
|
bool m_isValidating;
|
||||||
bool m_restoreLastHistoryItem;
|
bool m_restoreLastHistoryItem;
|
||||||
|
bool m_isPassword;
|
||||||
QString m_placeholderText;
|
QString m_placeholderText;
|
||||||
QString m_defaultText;
|
QString m_defaultText;
|
||||||
QString m_disabledText;
|
QString m_disabledText;
|
||||||
|
@@ -93,6 +93,7 @@ void QtProjectParameters::writeProFile(QTextStream &str) const
|
|||||||
case ConsoleApp:
|
case ConsoleApp:
|
||||||
// Mac: Command line apps should not be bundles
|
// Mac: Command line apps should not be bundles
|
||||||
str << "CONFIG += console\nCONFIG -= app_bundle\n\n";
|
str << "CONFIG += console\nCONFIG -= app_bundle\n\n";
|
||||||
|
// fallthrough
|
||||||
case GuiApp:
|
case GuiApp:
|
||||||
str << "TEMPLATE = app\n";
|
str << "TEMPLATE = app\n";
|
||||||
break;
|
break;
|
||||||
|
@@ -102,6 +102,7 @@ const char *nameForStyle(TextStyle style)
|
|||||||
case C_WARNING_CONTEXT: return "WarningContext";
|
case C_WARNING_CONTEXT: return "WarningContext";
|
||||||
|
|
||||||
case C_DECLARATION: return "Declaration";
|
case C_DECLARATION: return "Declaration";
|
||||||
|
case C_OUTPUT_ARGUMENT: return "C_OUTPUT_ARGUMENT";
|
||||||
|
|
||||||
case C_LAST_STYLE_SENTINEL: return "LastStyleSentinel";
|
case C_LAST_STYLE_SENTINEL: return "LastStyleSentinel";
|
||||||
}
|
}
|
||||||
|
@@ -100,6 +100,7 @@ enum TextStyle : quint8 {
|
|||||||
C_ERROR_CONTEXT,
|
C_ERROR_CONTEXT,
|
||||||
|
|
||||||
C_DECLARATION,
|
C_DECLARATION,
|
||||||
|
C_OUTPUT_ARGUMENT,
|
||||||
|
|
||||||
C_LAST_STYLE_SENTINEL
|
C_LAST_STYLE_SENTINEL
|
||||||
};
|
};
|
||||||
|
@@ -313,6 +313,10 @@ TextEditorSettings::TextEditorSettings(QObject *parent)
|
|||||||
tr("Declaration"),
|
tr("Declaration"),
|
||||||
tr("Declaration of a function, variable, and so on."),
|
tr("Declaration of a function, variable, and so on."),
|
||||||
FormatDescription::ShowFontUnderlineAndRelativeControls);
|
FormatDescription::ShowFontUnderlineAndRelativeControls);
|
||||||
|
formatDescr.emplace_back(C_OUTPUT_ARGUMENT,
|
||||||
|
tr("Output Argument"),
|
||||||
|
tr("Writable arguments of a function call."),
|
||||||
|
FormatDescription::ShowFontUnderlineAndRelativeControls);
|
||||||
|
|
||||||
d->m_fontSettingsPage = new FontSettingsPage(formatDescr,
|
d->m_fontSettingsPage = new FontSettingsPage(formatDescr,
|
||||||
Constants::TEXT_EDITOR_FONT_SETTINGS,
|
Constants::TEXT_EDITOR_FONT_SETTINGS,
|
||||||
|
@@ -711,10 +711,11 @@ public:
|
|||||||
return m_tool->createRunControl(runConfiguration, mode);
|
return m_tool->createRunControl(runConfiguration, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
IRunConfigurationAspect *createRunConfigurationAspect(ProjectExplorer::RunConfiguration *rc) override
|
// Do not create an aspect, let the Callgrind tool create one and use that, too.
|
||||||
{
|
// IRunConfigurationAspect *createRunConfigurationAspect(ProjectExplorer::RunConfiguration *rc) override
|
||||||
return createValgrindRunConfigurationAspect(rc);
|
// {
|
||||||
}
|
// return createValgrindRunConfigurationAspect(rc);
|
||||||
|
// }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
MemcheckTool *m_tool;
|
MemcheckTool *m_tool;
|
||||||
|
@@ -64,6 +64,11 @@ public:
|
|||||||
return future;
|
return future;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void preventFinalization() override
|
||||||
|
{
|
||||||
|
m_futureWatcher.disconnect();
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Runner m_runner;
|
Runner m_runner;
|
||||||
QFutureWatcher<Result> m_futureWatcher;
|
QFutureWatcher<Result> m_futureWatcher;
|
||||||
|
37
src/tools/clangbackend/ipcsource/clangbackend_global.h
Normal file
37
src/tools/clangbackend/ipcsource/clangbackend_global.h
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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
|
||||||
|
|
||||||
|
namespace ClangBackEnd {
|
||||||
|
|
||||||
|
enum class PreferredTranslationUnit
|
||||||
|
{
|
||||||
|
RecentlyParsed,
|
||||||
|
PreviouslyParsed,
|
||||||
|
LastUninitialized,
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace ClangBackEnd
|
@@ -29,6 +29,7 @@ HEADERS += $$PWD/clangcodemodelserver.h \
|
|||||||
$$PWD/highlightingmarksiterator.h \
|
$$PWD/highlightingmarksiterator.h \
|
||||||
$$PWD/utf8positionfromlinecolumn.h \
|
$$PWD/utf8positionfromlinecolumn.h \
|
||||||
$$PWD/clangasyncjob.h \
|
$$PWD/clangasyncjob.h \
|
||||||
|
$$PWD/clangbackend_global.h \
|
||||||
$$PWD/clangcompletecodejob.h \
|
$$PWD/clangcompletecodejob.h \
|
||||||
$$PWD/clangcreateinitialdocumentpreamblejob.h \
|
$$PWD/clangcreateinitialdocumentpreamblejob.h \
|
||||||
$$PWD/clangfilepath.h \
|
$$PWD/clangfilepath.h \
|
||||||
@@ -41,7 +42,14 @@ HEADERS += $$PWD/clangcodemodelserver.h \
|
|||||||
$$PWD/clangtranslationunit.h \
|
$$PWD/clangtranslationunit.h \
|
||||||
$$PWD/clangunsavedfilesshallowarguments.h \
|
$$PWD/clangunsavedfilesshallowarguments.h \
|
||||||
$$PWD/clangupdatedocumentannotationsjob.h \
|
$$PWD/clangupdatedocumentannotationsjob.h \
|
||||||
$$PWD/clangexceptions.h
|
$$PWD/clangexceptions.h \
|
||||||
|
$$PWD/clangdocumentprocessor.h \
|
||||||
|
$$PWD/clangdocumentprocessors.h \
|
||||||
|
$$PWD/clangtranslationunits.h \
|
||||||
|
$$PWD/clangclock.h \
|
||||||
|
$$PWD/clangsupportivetranslationunitinitializer.h \
|
||||||
|
$$PWD/clangparsesupportivetranslationunitjob.h \
|
||||||
|
$$PWD/clangreparsesupportivetranslationunitjob.h \
|
||||||
|
|
||||||
SOURCES += $$PWD/clangcodemodelserver.cpp \
|
SOURCES += $$PWD/clangcodemodelserver.cpp \
|
||||||
$$PWD/codecompleter.cpp \
|
$$PWD/codecompleter.cpp \
|
||||||
@@ -80,4 +88,10 @@ SOURCES += $$PWD/clangcodemodelserver.cpp \
|
|||||||
$$PWD/clangtranslationunit.cpp \
|
$$PWD/clangtranslationunit.cpp \
|
||||||
$$PWD/clangunsavedfilesshallowarguments.cpp \
|
$$PWD/clangunsavedfilesshallowarguments.cpp \
|
||||||
$$PWD/clangupdatedocumentannotationsjob.cpp \
|
$$PWD/clangupdatedocumentannotationsjob.cpp \
|
||||||
$$PWD/clangexceptions.cpp
|
$$PWD/clangexceptions.cpp \
|
||||||
|
$$PWD/clangdocumentprocessor.cpp \
|
||||||
|
$$PWD/clangdocumentprocessors.cpp \
|
||||||
|
$$PWD/clangtranslationunits.cpp \
|
||||||
|
$$PWD/clangsupportivetranslationunitinitializer.cpp \
|
||||||
|
$$PWD/clangparsesupportivetranslationunitjob.cpp \
|
||||||
|
$$PWD/clangreparsesupportivetranslationunitjob.cpp \
|
||||||
|
36
src/tools/clangbackend/ipcsource/clangclock.h
Normal file
36
src/tools/clangbackend/ipcsource/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
|
@@ -27,6 +27,7 @@
|
|||||||
|
|
||||||
#include "clangdocuments.h"
|
#include "clangdocuments.h"
|
||||||
#include "clangfilesystemwatcher.h"
|
#include "clangfilesystemwatcher.h"
|
||||||
|
#include "clangtranslationunits.h"
|
||||||
#include "codecompleter.h"
|
#include "codecompleter.h"
|
||||||
#include "diagnosticset.h"
|
#include "diagnosticset.h"
|
||||||
#include "highlightingmarks.h"
|
#include "highlightingmarks.h"
|
||||||
@@ -126,10 +127,16 @@ void ClangCodeModelServer::updateTranslationUnitsForEditor(const UpdateTranslati
|
|||||||
try {
|
try {
|
||||||
const auto newerFileContainers = documents.newerFileContainers(message.fileContainers());
|
const auto newerFileContainers = documents.newerFileContainers(message.fileContainers());
|
||||||
if (newerFileContainers.size() > 0) {
|
if (newerFileContainers.size() > 0) {
|
||||||
documents.update(newerFileContainers);
|
const std::vector<Document> updateDocuments = documents.update(newerFileContainers);
|
||||||
unsavedFiles.createOrUpdate(newerFileContainers);
|
unsavedFiles.createOrUpdate(newerFileContainers);
|
||||||
|
|
||||||
updateDocumentAnnotationsTimer.start(updateDocumentAnnotationsTimeOutInMs);
|
// 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);
|
||||||
|
QTimer::singleShot(0, [this, updateDocuments](){
|
||||||
|
startInitializingSupportiveTranslationUnits(updateDocuments);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
} catch (const std::exception &exception) {
|
} catch (const std::exception &exception) {
|
||||||
qWarning() << "Error in ClangCodeModelServer::updateTranslationUnitsForEditor:" << exception.what();
|
qWarning() << "Error in ClangCodeModelServer::updateTranslationUnitsForEditor:" << exception.what();
|
||||||
@@ -141,6 +148,10 @@ void ClangCodeModelServer::unregisterTranslationUnitsForEditor(const ClangBackEn
|
|||||||
TIME_SCOPE_DURATION("ClangCodeModelServer::unregisterTranslationUnitsForEditor");
|
TIME_SCOPE_DURATION("ClangCodeModelServer::unregisterTranslationUnitsForEditor");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
for (const auto &fileContainer : message.fileContainers()) {
|
||||||
|
const Document &document = documents.document(fileContainer);
|
||||||
|
documentProcessors().remove(document);
|
||||||
|
}
|
||||||
documents.remove(message.fileContainers());
|
documents.remove(message.fileContainers());
|
||||||
unsavedFiles.remove(message.fileContainers());
|
unsavedFiles.remove(message.fileContainers());
|
||||||
} catch (const std::exception &exception) {
|
} catch (const std::exception &exception) {
|
||||||
@@ -211,8 +222,9 @@ void ClangCodeModelServer::completeCode(const ClangBackEnd::CompleteCodeMessage
|
|||||||
jobRequest.column = message.column();
|
jobRequest.column = message.column();
|
||||||
jobRequest.ticketNumber = message.ticketNumber();
|
jobRequest.ticketNumber = message.ticketNumber();
|
||||||
|
|
||||||
jobs().add(jobRequest);
|
DocumentProcessor processor = documentProcessors().processor(document);
|
||||||
jobs().process();
|
processor.addJob(jobRequest);
|
||||||
|
processor.process();
|
||||||
} catch (const std::exception &exception) {
|
} catch (const std::exception &exception) {
|
||||||
qWarning() << "Error in ClangCodeModelServer::completeCode:" << exception.what();
|
qWarning() << "Error in ClangCodeModelServer::completeCode:" << exception.what();
|
||||||
}
|
}
|
||||||
@@ -229,8 +241,9 @@ void ClangCodeModelServer::requestDocumentAnnotations(const RequestDocumentAnnot
|
|||||||
const JobRequest jobRequest = createJobRequest(document,
|
const JobRequest jobRequest = createJobRequest(document,
|
||||||
JobRequest::Type::RequestDocumentAnnotations);
|
JobRequest::Type::RequestDocumentAnnotations);
|
||||||
|
|
||||||
jobs().add(jobRequest);
|
DocumentProcessor processor = documentProcessors().processor(document);
|
||||||
jobs().process();
|
processor.addJob(jobRequest);
|
||||||
|
processor.process();
|
||||||
} catch (const std::exception &exception) {
|
} catch (const std::exception &exception) {
|
||||||
qWarning() << "Error in ClangCodeModelServer::requestDocumentAnnotations:" << exception.what();
|
qWarning() << "Error in ClangCodeModelServer::requestDocumentAnnotations:" << exception.what();
|
||||||
}
|
}
|
||||||
@@ -260,9 +273,14 @@ void ClangCodeModelServer::startDocumentAnnotationsTimerIfFileIsNotOpenAsDocumen
|
|||||||
updateDocumentAnnotationsTimer.start(0);
|
updateDocumentAnnotationsTimer.start(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
const Jobs &ClangCodeModelServer::jobsForTestOnly()
|
QList<Jobs::RunningJob> ClangCodeModelServer::runningJobsForTestsOnly()
|
||||||
{
|
{
|
||||||
return jobs();
|
return documentProcessors().runningJobs();
|
||||||
|
}
|
||||||
|
|
||||||
|
int ClangCodeModelServer::queueSizeForTestsOnly()
|
||||||
|
{
|
||||||
|
return documentProcessors().queueSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ClangCodeModelServer::isTimerRunningForTestOnly() const
|
bool ClangCodeModelServer::isTimerRunningForTestOnly() const
|
||||||
@@ -270,32 +288,55 @@ bool ClangCodeModelServer::isTimerRunningForTestOnly() const
|
|||||||
return updateDocumentAnnotationsTimer.isActive();
|
return updateDocumentAnnotationsTimer.isActive();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClangCodeModelServer::addJobRequestsForDirtyAndVisibleDocuments()
|
|
||||||
{
|
|
||||||
for (const auto &document : documents.documents()) {
|
|
||||||
if (document.isNeedingReparse() && document.isVisibleInEditor())
|
|
||||||
jobs().add(createJobRequest(document, JobRequest::Type::UpdateDocumentAnnotations));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClangCodeModelServer::processJobsForDirtyAndVisibleDocuments()
|
void ClangCodeModelServer::processJobsForDirtyAndVisibleDocuments()
|
||||||
{
|
{
|
||||||
addJobRequestsForDirtyAndVisibleDocuments();
|
for (const auto &document : documents.documents()) {
|
||||||
jobs().process();
|
if (document.isNeedingReparse() && document.isVisibleInEditor()) {
|
||||||
|
DocumentProcessor processor = documentProcessors().processor(document);
|
||||||
|
processor.addJob(createJobRequest(document,
|
||||||
|
JobRequest::Type::UpdateDocumentAnnotations,
|
||||||
|
PreferredTranslationUnit::PreviouslyParsed));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
documentProcessors().process();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClangCodeModelServer::processInitialJobsForDocuments(const std::vector<Document> &documents)
|
void ClangCodeModelServer::processInitialJobsForDocuments(const std::vector<Document> &documents)
|
||||||
{
|
{
|
||||||
for (const auto &document : documents) {
|
for (const auto &document : documents) {
|
||||||
jobs().add(createJobRequest(document, JobRequest::Type::UpdateDocumentAnnotations));
|
DocumentProcessor processor = documentProcessors().create(document);
|
||||||
jobs().add(createJobRequest(document, JobRequest::Type::CreateInitialDocumentPreamble));
|
const auto jobRequestCreator = [this](const Document &document,
|
||||||
}
|
JobRequest::Type jobRequestType,
|
||||||
|
PreferredTranslationUnit preferredTranslationUnit) {
|
||||||
|
return createJobRequest(document, jobRequestType, preferredTranslationUnit);
|
||||||
|
};
|
||||||
|
processor.setJobRequestCreator(jobRequestCreator);
|
||||||
|
|
||||||
jobs().process();
|
processor.addJob(createJobRequest(document, JobRequest::Type::UpdateDocumentAnnotations));
|
||||||
|
processor.addJob(createJobRequest(document, JobRequest::Type::CreateInitialDocumentPreamble));
|
||||||
|
processor.process();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
JobRequest ClangCodeModelServer::createJobRequest(const Document &document,
|
void ClangCodeModelServer::startInitializingSupportiveTranslationUnits(
|
||||||
JobRequest::Type type) const
|
const std::vector<Document> &documents)
|
||||||
|
{
|
||||||
|
for (const Document &document : documents) {
|
||||||
|
try {
|
||||||
|
DocumentProcessor processor = documentProcessors().processor(document);
|
||||||
|
if (!processor.hasSupportiveTranslationUnit())
|
||||||
|
processor.startInitializingSupportiveTranslationUnit();
|
||||||
|
} catch (const DocumentProcessorDoesNotExist &) {
|
||||||
|
// OK, document was already closed.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
JobRequest ClangCodeModelServer::createJobRequest(
|
||||||
|
const Document &document,
|
||||||
|
JobRequest::Type type,
|
||||||
|
PreferredTranslationUnit preferredTranslationUnit) const
|
||||||
{
|
{
|
||||||
JobRequest jobRequest;
|
JobRequest jobRequest;
|
||||||
jobRequest.type = type;
|
jobRequest.type = type;
|
||||||
@@ -304,6 +345,7 @@ JobRequest ClangCodeModelServer::createJobRequest(const Document &document,
|
|||||||
jobRequest.projectPartId = document.projectPartId();
|
jobRequest.projectPartId = document.projectPartId();
|
||||||
jobRequest.unsavedFilesChangeTimePoint = unsavedFiles.lastChangeTimePoint();
|
jobRequest.unsavedFilesChangeTimePoint = unsavedFiles.lastChangeTimePoint();
|
||||||
jobRequest.documentRevision = document.documentRevision();
|
jobRequest.documentRevision = document.documentRevision();
|
||||||
|
jobRequest.preferredTranslationUnit = preferredTranslationUnit;
|
||||||
const ProjectPart &projectPart = projects.project(document.projectPartId());
|
const ProjectPart &projectPart = projects.project(document.projectPartId());
|
||||||
jobRequest.projectChangeTimePoint = projectPart.lastChangeTimePoint();
|
jobRequest.projectChangeTimePoint = projectPart.lastChangeTimePoint();
|
||||||
|
|
||||||
@@ -315,16 +357,16 @@ void ClangCodeModelServer::setUpdateDocumentAnnotationsTimeOutInMsForTestsOnly(i
|
|||||||
updateDocumentAnnotationsTimeOutInMs = value;
|
updateDocumentAnnotationsTimeOutInMs = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
Jobs &ClangCodeModelServer::jobs()
|
DocumentProcessors &ClangCodeModelServer::documentProcessors()
|
||||||
{
|
{
|
||||||
if (!jobs_) {
|
if (!documentProcessors_) {
|
||||||
// Jobs needs a reference to the client, but the client is not known at
|
// DocumentProcessors needs a reference to the client, but the client
|
||||||
// construction time of ClangCodeModelServer, so construct Jobs in a
|
// is not known at construction time of ClangCodeModelServer, so
|
||||||
// lazy manner.
|
// construct DocumentProcessors in a lazy manner.
|
||||||
jobs_.reset(new Jobs(documents, unsavedFiles, projects, *client()));
|
documentProcessors_.reset(new DocumentProcessors(documents, unsavedFiles, projects, *client()));
|
||||||
}
|
}
|
||||||
|
|
||||||
return *jobs_.data();
|
return *documentProcessors_.data();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace ClangBackEnd
|
} // namespace ClangBackEnd
|
||||||
|
@@ -31,8 +31,9 @@
|
|||||||
#include "projects.h"
|
#include "projects.h"
|
||||||
#include "clangdocument.h"
|
#include "clangdocument.h"
|
||||||
#include "clangdocuments.h"
|
#include "clangdocuments.h"
|
||||||
|
#include "clangdocumentprocessors.h"
|
||||||
|
#include "clangjobrequest.h"
|
||||||
#include "unsavedfiles.h"
|
#include "unsavedfiles.h"
|
||||||
#include "clangjobs.h"
|
|
||||||
|
|
||||||
#include <utf8string.h>
|
#include <utf8string.h>
|
||||||
|
|
||||||
@@ -58,27 +59,33 @@ public:
|
|||||||
void updateVisibleTranslationUnits(const UpdateVisibleTranslationUnitsMessage &message) override;
|
void updateVisibleTranslationUnits(const UpdateVisibleTranslationUnitsMessage &message) override;
|
||||||
void requestDocumentAnnotations(const RequestDocumentAnnotationsMessage &message) override;
|
void requestDocumentAnnotations(const RequestDocumentAnnotationsMessage &message) override;
|
||||||
|
|
||||||
public /*for tests*/:
|
public: // for tests
|
||||||
const Documents &documentsForTestOnly() const;
|
const Documents &documentsForTestOnly() const;
|
||||||
const Jobs &jobsForTestOnly();
|
QList<Jobs::RunningJob> runningJobsForTestsOnly();
|
||||||
|
int queueSizeForTestsOnly();
|
||||||
bool isTimerRunningForTestOnly() const;
|
bool isTimerRunningForTestOnly() const;
|
||||||
void setUpdateDocumentAnnotationsTimeOutInMsForTestsOnly(int value);
|
void setUpdateDocumentAnnotationsTimeOutInMsForTestsOnly(int value);
|
||||||
|
DocumentProcessors &documentProcessors();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Jobs &jobs();
|
|
||||||
|
|
||||||
void startDocumentAnnotationsTimerIfFileIsNotOpenAsDocument(const Utf8String &filePath);
|
void startDocumentAnnotationsTimerIfFileIsNotOpenAsDocument(const Utf8String &filePath);
|
||||||
void addJobRequestsForDirtyAndVisibleDocuments();
|
void addJobRequestsForDirtyAndVisibleDocuments();
|
||||||
void processJobsForDirtyAndVisibleDocuments();
|
void processJobsForDirtyAndVisibleDocuments();
|
||||||
void processInitialJobsForDocuments(const std::vector<Document> &documents);
|
void processInitialJobsForDocuments(const std::vector<Document> &documents);
|
||||||
|
void startInitializingSupportiveTranslationUnits(const std::vector<Document> &documents);
|
||||||
|
|
||||||
JobRequest createJobRequest(const Document &document, JobRequest::Type type) const;
|
JobRequest createJobRequest(const Document &document,
|
||||||
|
JobRequest::Type type,
|
||||||
|
PreferredTranslationUnit preferredTranslationUnit
|
||||||
|
= PreferredTranslationUnit::RecentlyParsed) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ProjectParts projects;
|
ProjectParts projects;
|
||||||
UnsavedFiles unsavedFiles;
|
UnsavedFiles unsavedFiles;
|
||||||
Documents documents;
|
Documents documents;
|
||||||
QScopedPointer<Jobs> jobs_;
|
|
||||||
|
QScopedPointer<DocumentProcessors> documentProcessors_; // Delayed initialization
|
||||||
|
|
||||||
QTimer updateDocumentAnnotationsTimer;
|
QTimer updateDocumentAnnotationsTimer;
|
||||||
int updateDocumentAnnotationsTimeOutInMs;
|
int updateDocumentAnnotationsTimeOutInMs;
|
||||||
|
@@ -50,29 +50,28 @@ static CompleteCodeJob::AsyncResult runAsyncHelper(const TranslationUnit &transl
|
|||||||
return asyncResult;
|
return asyncResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CompleteCodeJob::prepareAsyncRun()
|
IAsyncJob::AsyncPrepareResult CompleteCodeJob::prepareAsyncRun()
|
||||||
{
|
{
|
||||||
const JobRequest jobRequest = context().jobRequest;
|
const JobRequest jobRequest = context().jobRequest;
|
||||||
QTC_ASSERT(jobRequest.type == JobRequest::Type::CompleteCode, return false);
|
QTC_ASSERT(jobRequest.type == JobRequest::Type::CompleteCode, return AsyncPrepareResult());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
m_pinnedDocument = context().documentForJobRequest();
|
m_pinnedDocument = context().documentForJobRequest();
|
||||||
|
|
||||||
const TranslationUnit translationUnit = m_pinnedDocument.translationUnit();
|
const TranslationUnit translationUnit
|
||||||
|
= m_pinnedDocument.translationUnit(jobRequest.preferredTranslationUnit);
|
||||||
const UnsavedFiles unsavedFiles = *context().unsavedFiles;
|
const UnsavedFiles unsavedFiles = *context().unsavedFiles;
|
||||||
const quint32 line = jobRequest.line;
|
const quint32 line = jobRequest.line;
|
||||||
const quint32 column = jobRequest.column;
|
const quint32 column = jobRequest.column;
|
||||||
setRunner([translationUnit, unsavedFiles, line, column]() {
|
setRunner([translationUnit, unsavedFiles, line, column]() {
|
||||||
return runAsyncHelper(translationUnit, unsavedFiles, line, column);
|
return runAsyncHelper(translationUnit, unsavedFiles, line, column);
|
||||||
});
|
});
|
||||||
|
return AsyncPrepareResult{translationUnit.id()};
|
||||||
|
|
||||||
} catch (const std::exception &exception) {
|
} catch (const std::exception &exception) {
|
||||||
qWarning() << "Error in CompleteCodeJob::prepareAsyncRun:" << exception.what();
|
qWarning() << "Error in CompleteCodeJob::prepareAsyncRun:" << exception.what();
|
||||||
return false;
|
return AsyncPrepareResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CompleteCodeJob::finalizeAsyncRun()
|
void CompleteCodeJob::finalizeAsyncRun()
|
||||||
|
@@ -43,7 +43,7 @@ class CompleteCodeJob : public AsyncJob<CompleteCodeJobResult>
|
|||||||
public:
|
public:
|
||||||
using AsyncResult = CompleteCodeJobResult;
|
using AsyncResult = CompleteCodeJobResult;
|
||||||
|
|
||||||
bool prepareAsyncRun() override;
|
AsyncPrepareResult prepareAsyncRun() override;
|
||||||
void finalizeAsyncRun() override;
|
void finalizeAsyncRun() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@@ -39,28 +39,28 @@ static void runAsyncHelper(const TranslationUnit &translationUnit,
|
|||||||
translationUnit.reparse(translationUnitUpdateInput);
|
translationUnit.reparse(translationUnitUpdateInput);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CreateInitialDocumentPreambleJob::prepareAsyncRun()
|
IAsyncJob::AsyncPrepareResult CreateInitialDocumentPreambleJob::prepareAsyncRun()
|
||||||
{
|
{
|
||||||
const JobRequest jobRequest = context().jobRequest;
|
const JobRequest jobRequest = context().jobRequest;
|
||||||
QTC_ASSERT(jobRequest.type == JobRequest::Type::CreateInitialDocumentPreamble, return false);
|
QTC_ASSERT(jobRequest.type == JobRequest::Type::CreateInitialDocumentPreamble, return AsyncPrepareResult());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
m_pinnedDocument = context().documentForJobRequest();
|
m_pinnedDocument = context().documentForJobRequest();
|
||||||
m_pinnedFileContainer = m_pinnedDocument.fileContainer();
|
m_pinnedFileContainer = m_pinnedDocument.fileContainer();
|
||||||
|
|
||||||
const TranslationUnit translationUnit = m_pinnedDocument.translationUnit();
|
const TranslationUnit translationUnit
|
||||||
|
= m_pinnedDocument.translationUnit(jobRequest.preferredTranslationUnit);
|
||||||
const TranslationUnitUpdateInput updateInput = m_pinnedDocument.createUpdateInput();
|
const TranslationUnitUpdateInput updateInput = m_pinnedDocument.createUpdateInput();
|
||||||
setRunner([translationUnit, updateInput]() {
|
setRunner([translationUnit, updateInput]() {
|
||||||
return runAsyncHelper(translationUnit, updateInput);
|
return runAsyncHelper(translationUnit, updateInput);
|
||||||
});
|
});
|
||||||
|
return AsyncPrepareResult{translationUnit.id()};
|
||||||
|
|
||||||
} catch (const std::exception &exception) {
|
} catch (const std::exception &exception) {
|
||||||
qWarning() << "Error in CreateInitialDocumentPreambleJob::prepareAsyncRun:"
|
qWarning() << "Error in CreateInitialDocumentPreambleJob::prepareAsyncRun:"
|
||||||
<< exception.what();
|
<< exception.what();
|
||||||
return false;
|
return AsyncPrepareResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CreateInitialDocumentPreambleJob::finalizeAsyncRun()
|
void CreateInitialDocumentPreambleJob::finalizeAsyncRun()
|
||||||
|
@@ -33,7 +33,7 @@ namespace ClangBackEnd {
|
|||||||
class CreateInitialDocumentPreambleJob : public AsyncJob<void>
|
class CreateInitialDocumentPreambleJob : public AsyncJob<void>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
bool prepareAsyncRun() override;
|
AsyncPrepareResult prepareAsyncRun() override;
|
||||||
void finalizeAsyncRun() override;
|
void finalizeAsyncRun() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@@ -32,6 +32,7 @@
|
|||||||
#include "projectpart.h"
|
#include "projectpart.h"
|
||||||
#include "clangexceptions.h"
|
#include "clangexceptions.h"
|
||||||
#include "clangtranslationunit.h"
|
#include "clangtranslationunit.h"
|
||||||
|
#include "clangtranslationunits.h"
|
||||||
#include "clangtranslationunitupdater.h"
|
#include "clangtranslationunitupdater.h"
|
||||||
#include "unsavedfiles.h"
|
#include "unsavedfiles.h"
|
||||||
#include "unsavedfile.h"
|
#include "unsavedfile.h"
|
||||||
@@ -62,15 +63,14 @@ public:
|
|||||||
const Utf8StringVector fileArguments;
|
const Utf8StringVector fileArguments;
|
||||||
|
|
||||||
ProjectPart projectPart;
|
ProjectPart projectPart;
|
||||||
time_point lastProjectPartChangeTimePoint;
|
TimePoint lastProjectPartChangeTimePoint;
|
||||||
|
|
||||||
CXTranslationUnit translationUnit = nullptr;
|
TranslationUnits translationUnits;
|
||||||
CXIndex index = nullptr;
|
|
||||||
|
|
||||||
QSet<Utf8String> dependedFilePaths;
|
QSet<Utf8String> dependedFilePaths;
|
||||||
|
|
||||||
uint documentRevision = 0;
|
uint documentRevision = 0;
|
||||||
time_point needsToBeReparsedChangeTimePoint;
|
TimePoint needsToBeReparsedChangeTimePoint;
|
||||||
bool hasParseOrReparseFailed = false;
|
bool hasParseOrReparseFailed = false;
|
||||||
bool needsToBeReparsed = false;
|
bool needsToBeReparsed = false;
|
||||||
bool isUsedByCurrentEditor = false;
|
bool isUsedByCurrentEditor = false;
|
||||||
@@ -85,16 +85,16 @@ DocumentData::DocumentData(const Utf8String &filePath,
|
|||||||
filePath(filePath),
|
filePath(filePath),
|
||||||
fileArguments(fileArguments),
|
fileArguments(fileArguments),
|
||||||
projectPart(projectPart),
|
projectPart(projectPart),
|
||||||
lastProjectPartChangeTimePoint(std::chrono::steady_clock::now()),
|
lastProjectPartChangeTimePoint(Clock::now()),
|
||||||
|
translationUnits(filePath),
|
||||||
needsToBeReparsedChangeTimePoint(lastProjectPartChangeTimePoint)
|
needsToBeReparsedChangeTimePoint(lastProjectPartChangeTimePoint)
|
||||||
{
|
{
|
||||||
dependedFilePaths.insert(filePath);
|
dependedFilePaths.insert(filePath);
|
||||||
|
translationUnits.createAndAppend();
|
||||||
}
|
}
|
||||||
|
|
||||||
DocumentData::~DocumentData()
|
DocumentData::~DocumentData()
|
||||||
{
|
{
|
||||||
clang_disposeTranslationUnit(translationUnit);
|
|
||||||
clang_disposeIndex(index);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Document::Document(const Utf8String &filePath,
|
Document::Document(const Utf8String &filePath,
|
||||||
@@ -183,7 +183,7 @@ const ProjectPart &Document::projectPart() const
|
|||||||
return d->projectPart;
|
return d->projectPart;
|
||||||
}
|
}
|
||||||
|
|
||||||
const time_point Document::lastProjectPartChangeTimePoint() const
|
const TimePoint Document::lastProjectPartChangeTimePoint() const
|
||||||
{
|
{
|
||||||
checkIfNull();
|
checkIfNull();
|
||||||
|
|
||||||
@@ -239,7 +239,7 @@ void Document::setIsVisibleInEditor(bool isVisibleInEditor)
|
|||||||
d->isVisibleInEditor = isVisibleInEditor;
|
d->isVisibleInEditor = isVisibleInEditor;
|
||||||
}
|
}
|
||||||
|
|
||||||
time_point Document::isNeededReparseChangeTimePoint() const
|
TimePoint Document::isNeededReparseChangeTimePoint() const
|
||||||
{
|
{
|
||||||
checkIfNull();
|
checkIfNull();
|
||||||
|
|
||||||
@@ -282,8 +282,13 @@ TranslationUnitUpdateInput Document::createUpdateInput() const
|
|||||||
|
|
||||||
TranslationUnitUpdater Document::createUpdater() const
|
TranslationUnitUpdater Document::createUpdater() const
|
||||||
{
|
{
|
||||||
|
TranslationUnit unit = translationUnit();
|
||||||
|
|
||||||
const TranslationUnitUpdateInput updateInput = createUpdateInput();
|
const TranslationUnitUpdateInput updateInput = createUpdateInput();
|
||||||
TranslationUnitUpdater updater(d->index, d->translationUnit, updateInput);
|
TranslationUnitUpdater updater(unit.id(),
|
||||||
|
unit.cxIndex(),
|
||||||
|
unit.cxTranslationUnit(),
|
||||||
|
updateInput);
|
||||||
|
|
||||||
return updater;
|
return updater;
|
||||||
}
|
}
|
||||||
@@ -304,9 +309,13 @@ void Document::incorporateUpdaterResult(const TranslationUnitUpdateResult &resul
|
|||||||
if (result.hasParsed())
|
if (result.hasParsed())
|
||||||
d->lastProjectPartChangeTimePoint = result.parseTimePoint;
|
d->lastProjectPartChangeTimePoint = result.parseTimePoint;
|
||||||
|
|
||||||
if (result.hasParsed() || result.hasReparsed())
|
if (result.hasParsed() || result.hasReparsed()) {
|
||||||
d->dependedFilePaths = result.dependedOnFilePaths;
|
d->dependedFilePaths = result.dependedOnFilePaths;
|
||||||
|
|
||||||
|
const TimePoint timePoint = qMax(result.parseTimePoint, result.reparseTimePoint);
|
||||||
|
d->translationUnits.updateParseTimePoint(result.translationUnitId, timePoint);
|
||||||
|
}
|
||||||
|
|
||||||
d->documents.addWatchedFiles(d->dependedFilePaths);
|
d->documents.addWatchedFiles(d->dependedFilePaths);
|
||||||
|
|
||||||
if (result.hasReparsed()
|
if (result.hasReparsed()
|
||||||
@@ -315,11 +324,16 @@ void Document::incorporateUpdaterResult(const TranslationUnitUpdateResult &resul
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TranslationUnit Document::translationUnit() const
|
TranslationUnit Document::translationUnit(PreferredTranslationUnit preferredTranslationUnit) const
|
||||||
{
|
{
|
||||||
checkIfNull();
|
checkIfNull();
|
||||||
|
|
||||||
return TranslationUnit(d->filePath, d->index, d->translationUnit);
|
return d->translationUnits.get(preferredTranslationUnit);
|
||||||
|
}
|
||||||
|
|
||||||
|
TranslationUnits &Document::translationUnits() const
|
||||||
|
{
|
||||||
|
return d->translationUnits;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Document::parse() const
|
void Document::parse() const
|
||||||
@@ -352,7 +366,7 @@ const QSet<Utf8String> Document::dependedFilePaths() const
|
|||||||
|
|
||||||
void Document::setDirty()
|
void Document::setDirty()
|
||||||
{
|
{
|
||||||
d->needsToBeReparsedChangeTimePoint = std::chrono::steady_clock::now();
|
d->needsToBeReparsedChangeTimePoint = Clock::now();
|
||||||
d->needsToBeReparsed = true;
|
d->needsToBeReparsed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -27,6 +27,7 @@
|
|||||||
|
|
||||||
#include "clangtranslationunitupdater.h"
|
#include "clangtranslationunitupdater.h"
|
||||||
|
|
||||||
|
#include "clangbackend_global.h"
|
||||||
#include "clangtranslationunit.h"
|
#include "clangtranslationunit.h"
|
||||||
|
|
||||||
#include <utf8stringvector.h>
|
#include <utf8stringvector.h>
|
||||||
@@ -36,7 +37,6 @@
|
|||||||
#include <QSet>
|
#include <QSet>
|
||||||
#include <QtGlobal>
|
#include <QtGlobal>
|
||||||
|
|
||||||
#include <chrono>
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
class Utf8String;
|
class Utf8String;
|
||||||
@@ -44,14 +44,13 @@ class Utf8String;
|
|||||||
namespace ClangBackEnd {
|
namespace ClangBackEnd {
|
||||||
|
|
||||||
class TranslationUnit;
|
class TranslationUnit;
|
||||||
|
class TranslationUnits;
|
||||||
class DocumentData;
|
class DocumentData;
|
||||||
class TranslationUnitUpdateResult;
|
class TranslationUnitUpdateResult;
|
||||||
class ProjectPart;
|
class ProjectPart;
|
||||||
class FileContainer;
|
class FileContainer;
|
||||||
class Documents;
|
class Documents;
|
||||||
|
|
||||||
using time_point = std::chrono::steady_clock::time_point;
|
|
||||||
|
|
||||||
class Document
|
class Document
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -85,7 +84,7 @@ public:
|
|||||||
|
|
||||||
Utf8String projectPartId() const;
|
Utf8String projectPartId() const;
|
||||||
const ProjectPart &projectPart() const;
|
const ProjectPart &projectPart() const;
|
||||||
const time_point lastProjectPartChangeTimePoint() const;
|
const TimePoint lastProjectPartChangeTimePoint() const;
|
||||||
bool isProjectPartOutdated() const;
|
bool isProjectPartOutdated() const;
|
||||||
|
|
||||||
uint documentRevision() const;
|
uint documentRevision() const;
|
||||||
@@ -104,7 +103,9 @@ public:
|
|||||||
TranslationUnitUpdateInput createUpdateInput() const;
|
TranslationUnitUpdateInput createUpdateInput() const;
|
||||||
void incorporateUpdaterResult(const TranslationUnitUpdateResult &result) const;
|
void incorporateUpdaterResult(const TranslationUnitUpdateResult &result) const;
|
||||||
|
|
||||||
TranslationUnit translationUnit() const;
|
TranslationUnit translationUnit(PreferredTranslationUnit preferredTranslationUnit
|
||||||
|
= PreferredTranslationUnit::RecentlyParsed) const;
|
||||||
|
TranslationUnits &translationUnits() const;
|
||||||
|
|
||||||
public: // for tests
|
public: // for tests
|
||||||
void parse() const;
|
void parse() const;
|
||||||
@@ -112,7 +113,7 @@ public: // for tests
|
|||||||
const QSet<Utf8String> dependedFilePaths() const;
|
const QSet<Utf8String> dependedFilePaths() const;
|
||||||
TranslationUnitUpdater createUpdater() const;
|
TranslationUnitUpdater createUpdater() const;
|
||||||
void setHasParseOrReparseFailed(bool hasFailed);
|
void setHasParseOrReparseFailed(bool hasFailed);
|
||||||
time_point isNeededReparseChangeTimePoint() const;
|
TimePoint isNeededReparseChangeTimePoint() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void setDirty();
|
void setDirty();
|
||||||
|
128
src/tools/clangbackend/ipcsource/clangdocumentprocessor.cpp
Normal file
128
src/tools/clangbackend/ipcsource/clangdocumentprocessor.cpp
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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/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;
|
||||||
|
JobRequestCreator jobRequestCreator;
|
||||||
|
};
|
||||||
|
|
||||||
|
DocumentProcessor::DocumentProcessor(const Document &document,
|
||||||
|
Documents &documents,
|
||||||
|
UnsavedFiles &unsavedFiles,
|
||||||
|
ProjectParts &projects,
|
||||||
|
ClangCodeModelClientInterface &client)
|
||||||
|
: d(std::make_shared<DocumentProcessorData>(document,
|
||||||
|
documents,
|
||||||
|
unsavedFiles,
|
||||||
|
projects,
|
||||||
|
client))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void DocumentProcessor::setJobRequestCreator(const JobRequestCreator &creator)
|
||||||
|
{
|
||||||
|
d->supportiveTranslationUnitInitializer.setJobRequestCreator(creator);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DocumentProcessor::addJob(const JobRequest &jobRequest)
|
||||||
|
{
|
||||||
|
d->jobs.add(jobRequest);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<Jobs::RunningJob> DocumentProcessor::runningJobs() const
|
||||||
|
{
|
||||||
|
return d->jobs.runningJobs();
|
||||||
|
}
|
||||||
|
|
||||||
|
int DocumentProcessor::queueSize() const
|
||||||
|
{
|
||||||
|
return d->jobs.queue().size();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace ClangBackEnd
|
71
src/tools/clangbackend/ipcsource/clangdocumentprocessor.h
Normal file
71
src/tools/clangbackend/ipcsource/clangdocumentprocessor.h
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.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#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);
|
||||||
|
|
||||||
|
void setJobRequestCreator(const JobRequestCreator &creator);
|
||||||
|
|
||||||
|
void addJob(const JobRequest &jobRequest);
|
||||||
|
JobRequests process();
|
||||||
|
|
||||||
|
Document document() const;
|
||||||
|
|
||||||
|
bool hasSupportiveTranslationUnit() const;
|
||||||
|
void startInitializingSupportiveTranslationUnit();
|
||||||
|
|
||||||
|
public: // for tests
|
||||||
|
bool isSupportiveTranslationUnitInitialized() const;
|
||||||
|
QList<Jobs::RunningJob> runningJobs() const;
|
||||||
|
int queueSize() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::shared_ptr<DocumentProcessorData> d;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace ClangBackEnd
|
113
src/tools/clangbackend/ipcsource/clangdocumentprocessors.cpp
Normal file
113
src/tools/clangbackend/ipcsource/clangdocumentprocessors.cpp
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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"
|
||||||
|
|
||||||
|
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.projectPartId()};
|
||||||
|
if (m_processors.contains(id))
|
||||||
|
throw DocumentProcessorAlreadyExists(document.filePath(), document.projectPartId());
|
||||||
|
|
||||||
|
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.projectPartId()};
|
||||||
|
|
||||||
|
const auto it = m_processors.find(id);
|
||||||
|
if (it == m_processors.end())
|
||||||
|
throw DocumentProcessorDoesNotExist(document.filePath(), document.projectPartId());
|
||||||
|
|
||||||
|
return *it;
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<DocumentProcessor> DocumentProcessors::processors() const
|
||||||
|
{
|
||||||
|
return m_processors.values();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DocumentProcessors::remove(const Document &document)
|
||||||
|
{
|
||||||
|
const DocumentId id{document.filePath(), document.projectPartId()};
|
||||||
|
|
||||||
|
const int itemsRemoved = m_processors.remove(id);
|
||||||
|
if (itemsRemoved != 1)
|
||||||
|
throw DocumentProcessorDoesNotExist(document.filePath(), document.projectPartId());
|
||||||
|
}
|
||||||
|
|
||||||
|
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/ipcsource/clangdocumentprocessors.h
Normal file
74
src/tools/clangbackend/ipcsource/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
|
@@ -68,14 +68,20 @@ std::vector<Document> Documents::create(const QVector<FileContainer> &fileContai
|
|||||||
return createdDocuments;
|
return createdDocuments;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Documents::update(const QVector<FileContainer> &fileContainers)
|
std::vector<Document> Documents::update(const QVector<FileContainer> &fileContainers)
|
||||||
{
|
{
|
||||||
checkIfDocumentsForFilePathsExist(fileContainers);
|
checkIfDocumentsForFilePathsExist(fileContainers);
|
||||||
|
|
||||||
|
std::vector<Document> createdDocuments;
|
||||||
|
|
||||||
for (const FileContainer &fileContainer : fileContainers) {
|
for (const FileContainer &fileContainer : fileContainers) {
|
||||||
updateDocument(fileContainer);
|
const std::vector<Document> documents = updateDocument(fileContainer);
|
||||||
|
createdDocuments.insert(createdDocuments.end(), documents.begin(), documents.end());
|
||||||
|
|
||||||
updateDocumentsWithChangedDependency(fileContainer.filePath());
|
updateDocumentsWithChangedDependency(fileContainer.filePath());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return createdDocuments;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool removeFromFileContainer(QVector<FileContainer> &fileContainers, const Document &document)
|
static bool removeFromFileContainer(QVector<FileContainer> &fileContainers, const Document &document)
|
||||||
@@ -205,12 +211,14 @@ Document Documents::createDocument(const FileContainer &fileContainer)
|
|||||||
return documents_.back();
|
return documents_.back();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Documents::updateDocument(const FileContainer &fileContainer)
|
std::vector<Document> Documents::updateDocument(const FileContainer &fileContainer)
|
||||||
{
|
{
|
||||||
const auto documents = findAllDocumentsWithFilePath(fileContainer.filePath());
|
const auto documents = findAllDocumentsWithFilePath(fileContainer.filePath());
|
||||||
|
|
||||||
for (auto document : documents)
|
for (auto document : documents)
|
||||||
document.setDocumentRevision(fileContainer.documentRevision());
|
document.setDocumentRevision(fileContainer.documentRevision());
|
||||||
|
|
||||||
|
return documents;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<Document>::iterator Documents::findDocument(const FileContainer &fileContainer)
|
std::vector<Document>::iterator Documents::findDocument(const FileContainer &fileContainer)
|
||||||
|
@@ -45,7 +45,7 @@ public:
|
|||||||
Documents(ProjectParts &projectParts, UnsavedFiles &unsavedFiles);
|
Documents(ProjectParts &projectParts, UnsavedFiles &unsavedFiles);
|
||||||
|
|
||||||
std::vector<Document> create(const QVector<FileContainer> &fileContainers);
|
std::vector<Document> create(const QVector<FileContainer> &fileContainers);
|
||||||
void update(const QVector<FileContainer> &fileContainers);
|
std::vector<Document> update(const QVector<FileContainer> &fileContainers);
|
||||||
void remove(const QVector<FileContainer> &fileContainers);
|
void remove(const QVector<FileContainer> &fileContainers);
|
||||||
|
|
||||||
void setUsedByCurrentEditor(const Utf8String &filePath);
|
void setUsedByCurrentEditor(const Utf8String &filePath);
|
||||||
@@ -72,7 +72,7 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
Document createDocument(const FileContainer &fileContainer);
|
Document createDocument(const FileContainer &fileContainer);
|
||||||
void updateDocument(const FileContainer &fileContainer);
|
std::vector<Document> updateDocument(const FileContainer &fileContainer);
|
||||||
std::vector<Document>::iterator findDocument(const FileContainer &fileContainer);
|
std::vector<Document>::iterator findDocument(const FileContainer &fileContainer);
|
||||||
std::vector<Document> findAllDocumentsWithFilePath(const Utf8String &filePath);
|
std::vector<Document> findAllDocumentsWithFilePath(const Utf8String &filePath);
|
||||||
std::vector<Document>::const_iterator findDocument(const Utf8String &filePath, const Utf8String &projectPartId) const;
|
std::vector<Document>::const_iterator findDocument(const Utf8String &filePath, const Utf8String &projectPartId) const;
|
||||||
|
@@ -74,4 +74,31 @@ DocumentIsNullException::DocumentIsNullException()
|
|||||||
m_info = Utf8String::fromUtf8("Tried to access a null Document!");
|
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
|
} // namespace ClangBackEnd
|
||||||
|
@@ -74,4 +74,24 @@ public:
|
|||||||
DocumentIsNullException();
|
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
|
} // namespace ClangBackEnd
|
||||||
|
@@ -27,6 +27,8 @@
|
|||||||
|
|
||||||
#include "clangcompletecodejob.h"
|
#include "clangcompletecodejob.h"
|
||||||
#include "clangcreateinitialdocumentpreamblejob.h"
|
#include "clangcreateinitialdocumentpreamblejob.h"
|
||||||
|
#include "clangparsesupportivetranslationunitjob.h"
|
||||||
|
#include "clangreparsesupportivetranslationunitjob.h"
|
||||||
#include "clangrequestdocumentannotationsjob.h"
|
#include "clangrequestdocumentannotationsjob.h"
|
||||||
#include "clangupdatedocumentannotationsjob.h"
|
#include "clangupdatedocumentannotationsjob.h"
|
||||||
|
|
||||||
@@ -39,6 +41,10 @@ IAsyncJob *IAsyncJob::create(JobRequest::Type type)
|
|||||||
switch (type) {
|
switch (type) {
|
||||||
case JobRequest::Type::UpdateDocumentAnnotations:
|
case JobRequest::Type::UpdateDocumentAnnotations:
|
||||||
return new UpdateDocumentAnnotationsJob();
|
return new UpdateDocumentAnnotationsJob();
|
||||||
|
case JobRequest::Type::ParseSupportiveTranslationUnit:
|
||||||
|
return new ParseSupportiveTranslationUnitJob();
|
||||||
|
case JobRequest::Type::ReparseSupportiveTranslationUnit:
|
||||||
|
return new ReparseSupportiveTranslationUnitJob();
|
||||||
case JobRequest::Type::CreateInitialDocumentPreamble:
|
case JobRequest::Type::CreateInitialDocumentPreamble:
|
||||||
return new CreateInitialDocumentPreambleJob();
|
return new CreateInitialDocumentPreambleJob();
|
||||||
case JobRequest::Type::CompleteCode:
|
case JobRequest::Type::CompleteCode:
|
||||||
|
@@ -41,6 +41,11 @@ class IAsyncJob
|
|||||||
public:
|
public:
|
||||||
static IAsyncJob *create(JobRequest::Type type);
|
static IAsyncJob *create(JobRequest::Type type);
|
||||||
|
|
||||||
|
struct AsyncPrepareResult {
|
||||||
|
operator bool() const { return !translationUnitId.isEmpty(); }
|
||||||
|
Utf8String translationUnitId;
|
||||||
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
IAsyncJob();
|
IAsyncJob();
|
||||||
virtual ~IAsyncJob();
|
virtual ~IAsyncJob();
|
||||||
@@ -52,10 +57,12 @@ public:
|
|||||||
FinishedHandler finishedHandler() const;
|
FinishedHandler finishedHandler() const;
|
||||||
void setFinishedHandler(const FinishedHandler &finishedHandler);
|
void setFinishedHandler(const FinishedHandler &finishedHandler);
|
||||||
|
|
||||||
virtual bool prepareAsyncRun() = 0;
|
virtual AsyncPrepareResult prepareAsyncRun() = 0;
|
||||||
virtual QFuture<void> runAsync() = 0;
|
virtual QFuture<void> runAsync() = 0;
|
||||||
virtual void finalizeAsyncRun() = 0;
|
virtual void finalizeAsyncRun() = 0;
|
||||||
|
|
||||||
|
virtual void preventFinalization() = 0;
|
||||||
|
|
||||||
public: // for tests
|
public: // for tests
|
||||||
bool isFinished() const;
|
bool isFinished() const;
|
||||||
void setIsFinished(bool isFinished);
|
void setIsFinished(bool isFinished);
|
||||||
|
@@ -27,6 +27,7 @@
|
|||||||
#include "clangjobqueue.h"
|
#include "clangjobqueue.h"
|
||||||
#include "clangdocument.h"
|
#include "clangdocument.h"
|
||||||
#include "clangdocuments.h"
|
#include "clangdocuments.h"
|
||||||
|
#include "clangtranslationunits.h"
|
||||||
#include "projects.h"
|
#include "projects.h"
|
||||||
#include "unsavedfiles.h"
|
#include "unsavedfiles.h"
|
||||||
|
|
||||||
@@ -40,11 +41,22 @@ JobQueue::JobQueue(Documents &documents, ProjectParts &projectParts)
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void JobQueue::add(const JobRequest &job)
|
bool JobQueue::add(const JobRequest &job)
|
||||||
{
|
{
|
||||||
qCDebug(jobsLog) << "Adding" << 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
qCDebug(jobsLog) << "Adding" << job;
|
||||||
m_queue.append(job);
|
m_queue.append(job);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int JobQueue::size() const
|
int JobQueue::size() const
|
||||||
@@ -164,50 +176,65 @@ void JobQueue::prioritizeRequests()
|
|||||||
JobRequests JobQueue::takeJobRequestsToRunNow()
|
JobRequests JobQueue::takeJobRequestsToRunNow()
|
||||||
{
|
{
|
||||||
JobRequests jobsToRun;
|
JobRequests jobsToRun;
|
||||||
QSet<DocumentId> documentsScheduledForThisRun;
|
using TranslationUnitIds = QSet<Utf8String>;
|
||||||
|
TranslationUnitIds translationUnitsScheduledForThisRun;
|
||||||
|
|
||||||
QMutableVectorIterator<JobRequest> i(m_queue);
|
QMutableVectorIterator<JobRequest> i(m_queue);
|
||||||
while (i.hasNext()) {
|
while (i.hasNext()) {
|
||||||
const JobRequest &jobRequest = i.next();
|
const JobRequest &request = i.next();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const Document &document
|
const Document &document = m_documents.document(request.filePath,
|
||||||
= m_documents.document(jobRequest.filePath,
|
request.projectPartId);
|
||||||
jobRequest.projectPartId);
|
|
||||||
const DocumentId documentId = DocumentId(jobRequest.filePath, jobRequest.projectPartId);
|
|
||||||
|
|
||||||
if (!document.isUsedByCurrentEditor() && !document.isVisibleInEditor())
|
if (!document.isUsedByCurrentEditor() && !document.isVisibleInEditor())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (documentsScheduledForThisRun.contains(documentId))
|
const Utf8String id = document.translationUnit(request.preferredTranslationUnit).id();
|
||||||
|
if (translationUnitsScheduledForThisRun.contains(id))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (isJobRunningForDocument(documentId))
|
if (isJobRunningForTranslationUnit(id))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
documentsScheduledForThisRun.insert(documentId);
|
translationUnitsScheduledForThisRun.insert(id);
|
||||||
jobsToRun += jobRequest;
|
jobsToRun += request;
|
||||||
i.remove();
|
i.remove();
|
||||||
} catch (const std::exception &exception) {
|
} catch (const std::exception &exception) {
|
||||||
qWarning() << "Error in Jobs::takeJobRequestsToRunNow for"
|
qWarning() << "Error in Jobs::takeJobRequestsToRunNow for"
|
||||||
<< jobRequest << ":" << exception.what();
|
<< request << ":" << exception.what();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return jobsToRun;
|
return jobsToRun;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool JobQueue::isJobRunningForDocument(const JobQueue::DocumentId &documentId)
|
bool JobQueue::isJobRunningForTranslationUnit(const Utf8String &translationUnitId)
|
||||||
{
|
{
|
||||||
if (m_isJobRunningHandler)
|
if (m_isJobRunningForTranslationUnitHandler)
|
||||||
return m_isJobRunningHandler(documentId.first, documentId.second);
|
return m_isJobRunningForTranslationUnitHandler(translationUnitId);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void JobQueue::setIsJobRunningHandler(const IsJobRunningHandler &isJobRunningHandler)
|
bool JobQueue::isJobRunningForJobRequest(const JobRequest &jobRequest)
|
||||||
{
|
{
|
||||||
m_isJobRunningHandler = isJobRunningHandler;
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
JobRequests JobQueue::queue() const
|
JobRequests JobQueue::queue() const
|
||||||
|
@@ -39,12 +39,17 @@ class JobQueue
|
|||||||
public:
|
public:
|
||||||
JobQueue(Documents &documents, ProjectParts &projects);
|
JobQueue(Documents &documents, ProjectParts &projects);
|
||||||
|
|
||||||
void add(const JobRequest &job);
|
bool add(const JobRequest &job);
|
||||||
|
|
||||||
JobRequests processQueue();
|
JobRequests processQueue();
|
||||||
|
|
||||||
using IsJobRunningHandler = std::function<bool(const Utf8String &, const Utf8String &)>;
|
using IsJobRunningForTranslationUnitHandler = std::function<bool(const Utf8String &)>;
|
||||||
void setIsJobRunningHandler(const IsJobRunningHandler &isJobRunningHandler);
|
void setIsJobRunningForTranslationUnitHandler(
|
||||||
|
const IsJobRunningForTranslationUnitHandler &isJobRunningHandler);
|
||||||
|
|
||||||
|
using IsJobRunningForJobRequestHandler = std::function<bool(const JobRequest &)>;
|
||||||
|
void setIsJobRunningForJobRequestHandler(
|
||||||
|
const IsJobRunningForJobRequestHandler &isJobRunningHandler);
|
||||||
|
|
||||||
public: // for tests
|
public: // for tests
|
||||||
JobRequests queue() const;
|
JobRequests queue() const;
|
||||||
@@ -52,8 +57,8 @@ public: // for tests
|
|||||||
void prioritizeRequests();
|
void prioritizeRequests();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
using DocumentId = QPair<Utf8String, Utf8String>;
|
bool isJobRunningForTranslationUnit(const Utf8String &translationUnitId);
|
||||||
bool isJobRunningForDocument(const DocumentId &documentId);
|
bool isJobRunningForJobRequest(const JobRequest &jobRequest);
|
||||||
JobRequests takeJobRequestsToRunNow();
|
JobRequests takeJobRequestsToRunNow();
|
||||||
void removeOutDatedRequests();
|
void removeOutDatedRequests();
|
||||||
bool isJobRequestOutDated(const JobRequest &jobRequest) const;
|
bool isJobRequestOutDated(const JobRequest &jobRequest) const;
|
||||||
@@ -62,7 +67,8 @@ private:
|
|||||||
Documents &m_documents;
|
Documents &m_documents;
|
||||||
ProjectParts &m_projectParts;
|
ProjectParts &m_projectParts;
|
||||||
|
|
||||||
IsJobRunningHandler m_isJobRunningHandler;
|
IsJobRunningForTranslationUnitHandler m_isJobRunningForTranslationUnitHandler;
|
||||||
|
IsJobRunningForJobRequestHandler m_isJobRunningForJobRequestHandler;
|
||||||
|
|
||||||
JobRequests m_queue;
|
JobRequests m_queue;
|
||||||
};
|
};
|
||||||
|
@@ -25,6 +25,8 @@
|
|||||||
|
|
||||||
#include "clangjobrequest.h"
|
#include "clangjobrequest.h"
|
||||||
|
|
||||||
|
#include <QFileInfo>
|
||||||
|
|
||||||
namespace ClangBackEnd {
|
namespace ClangBackEnd {
|
||||||
|
|
||||||
#define RETURN_TEXT_FOR_CASE(enumValue) case JobRequest::Type::enumValue: return #enumValue
|
#define RETURN_TEXT_FOR_CASE(enumValue) case JobRequest::Type::enumValue: return #enumValue
|
||||||
@@ -32,6 +34,8 @@ static const char *JobRequestTypeToText(JobRequest::Type type)
|
|||||||
{
|
{
|
||||||
switch (type) {
|
switch (type) {
|
||||||
RETURN_TEXT_FOR_CASE(UpdateDocumentAnnotations);
|
RETURN_TEXT_FOR_CASE(UpdateDocumentAnnotations);
|
||||||
|
RETURN_TEXT_FOR_CASE(ParseSupportiveTranslationUnit);
|
||||||
|
RETURN_TEXT_FOR_CASE(ReparseSupportiveTranslationUnit);
|
||||||
RETURN_TEXT_FOR_CASE(CreateInitialDocumentPreamble);
|
RETURN_TEXT_FOR_CASE(CreateInitialDocumentPreamble);
|
||||||
RETURN_TEXT_FOR_CASE(CompleteCode);
|
RETURN_TEXT_FOR_CASE(CompleteCode);
|
||||||
RETURN_TEXT_FOR_CASE(RequestDocumentAnnotations);
|
RETURN_TEXT_FOR_CASE(RequestDocumentAnnotations);
|
||||||
@@ -41,6 +45,19 @@ static const char *JobRequestTypeToText(JobRequest::Type type)
|
|||||||
}
|
}
|
||||||
#undef RETURN_TEXT_FOR_CASE
|
#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)
|
QDebug operator<<(QDebug debug, JobRequest::Type type)
|
||||||
{
|
{
|
||||||
debug << JobRequestTypeToText(type);
|
debug << JobRequestTypeToText(type);
|
||||||
@@ -53,12 +70,14 @@ QDebug operator<<(QDebug debug, const JobRequest &jobRequest)
|
|||||||
debug.nospace() << "Job<"
|
debug.nospace() << "Job<"
|
||||||
<< jobRequest.id
|
<< jobRequest.id
|
||||||
<< ","
|
<< ","
|
||||||
|
<< QFileInfo(jobRequest.filePath).fileName()
|
||||||
|
<< ","
|
||||||
<< JobRequestTypeToText(jobRequest.type)
|
<< JobRequestTypeToText(jobRequest.type)
|
||||||
<< ","
|
<< ","
|
||||||
<< jobRequest.filePath
|
<< preferredTranslationUnitToText(jobRequest.preferredTranslationUnit)
|
||||||
<< ">";
|
<< ">";
|
||||||
|
|
||||||
return debug;
|
return debug.space();
|
||||||
}
|
}
|
||||||
|
|
||||||
JobRequest::JobRequest()
|
JobRequest::JobRequest()
|
||||||
@@ -67,6 +86,23 @@ JobRequest::JobRequest()
|
|||||||
id = ++idCounter;
|
id = ++idCounter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool JobRequest::operator==(const JobRequest &other) const
|
||||||
|
{
|
||||||
|
return type == other.type
|
||||||
|
&& requirements == other.requirements
|
||||||
|
|
||||||
|
&& 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;
|
||||||
|
}
|
||||||
|
|
||||||
JobRequest::Requirements JobRequest::requirementsForType(Type type)
|
JobRequest::Requirements JobRequest::requirementsForType(Type type)
|
||||||
{
|
{
|
||||||
switch (type) {
|
switch (type) {
|
||||||
@@ -77,6 +113,8 @@ JobRequest::Requirements JobRequest::requirementsForType(Type type)
|
|||||||
|JobRequest::CurrentDocumentRevision);
|
|JobRequest::CurrentDocumentRevision);
|
||||||
case JobRequest::Type::CompleteCode:
|
case JobRequest::Type::CompleteCode:
|
||||||
case JobRequest::Type::CreateInitialDocumentPreamble:
|
case JobRequest::Type::CreateInitialDocumentPreamble:
|
||||||
|
case JobRequest::Type::ParseSupportiveTranslationUnit:
|
||||||
|
case JobRequest::Type::ReparseSupportiveTranslationUnit:
|
||||||
return JobRequest::Requirements(JobRequest::DocumentValid);
|
return JobRequest::Requirements(JobRequest::DocumentValid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -25,17 +25,20 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "clangbackend_global.h"
|
||||||
|
#include "clangclock.h"
|
||||||
|
|
||||||
#include <utf8string.h>
|
#include <utf8string.h>
|
||||||
|
|
||||||
#include <QFlags>
|
#include <QFlags>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QVector>
|
#include <QVector>
|
||||||
|
|
||||||
#include <chrono>
|
#include <functional>
|
||||||
|
|
||||||
namespace ClangBackEnd {
|
namespace ClangBackEnd {
|
||||||
|
|
||||||
using time_point = std::chrono::steady_clock::time_point;
|
class Document;
|
||||||
|
|
||||||
class JobRequest
|
class JobRequest
|
||||||
{
|
{
|
||||||
@@ -43,6 +46,10 @@ public:
|
|||||||
enum class Type {
|
enum class Type {
|
||||||
UpdateDocumentAnnotations,
|
UpdateDocumentAnnotations,
|
||||||
CreateInitialDocumentPreamble,
|
CreateInitialDocumentPreamble,
|
||||||
|
|
||||||
|
ParseSupportiveTranslationUnit,
|
||||||
|
ReparseSupportiveTranslationUnit,
|
||||||
|
|
||||||
CompleteCode,
|
CompleteCode,
|
||||||
RequestDocumentAnnotations,
|
RequestDocumentAnnotations,
|
||||||
};
|
};
|
||||||
@@ -64,6 +71,8 @@ public:
|
|||||||
|
|
||||||
JobRequest();
|
JobRequest();
|
||||||
|
|
||||||
|
bool operator==(const JobRequest &other) const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
quint64 id = 0;
|
quint64 id = 0;
|
||||||
Type type;
|
Type type;
|
||||||
@@ -72,9 +81,10 @@ public:
|
|||||||
// General
|
// General
|
||||||
Utf8String filePath;
|
Utf8String filePath;
|
||||||
Utf8String projectPartId;
|
Utf8String projectPartId;
|
||||||
time_point unsavedFilesChangeTimePoint;
|
TimePoint unsavedFilesChangeTimePoint;
|
||||||
time_point projectChangeTimePoint;
|
TimePoint projectChangeTimePoint;
|
||||||
uint documentRevision = 0;
|
uint documentRevision = 0;
|
||||||
|
PreferredTranslationUnit preferredTranslationUnit = PreferredTranslationUnit::RecentlyParsed;
|
||||||
|
|
||||||
// For code completion
|
// For code completion
|
||||||
quint32 line = 0;
|
quint32 line = 0;
|
||||||
@@ -83,6 +93,9 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
using JobRequests = QVector<JobRequest>;
|
using JobRequests = QVector<JobRequest>;
|
||||||
|
using JobRequestCreator = std::function<JobRequest(const Document &,
|
||||||
|
JobRequest::Type ,
|
||||||
|
PreferredTranslationUnit)>;
|
||||||
|
|
||||||
QDebug operator<<(QDebug debug, const JobRequest &jobRequest);
|
QDebug operator<<(QDebug debug, const JobRequest &jobRequest);
|
||||||
|
|
||||||
|
@@ -45,17 +45,25 @@ Jobs::Jobs(Documents &documents,
|
|||||||
, m_client(client)
|
, m_client(client)
|
||||||
, m_queue(documents, projectParts)
|
, m_queue(documents, projectParts)
|
||||||
{
|
{
|
||||||
m_queue.setIsJobRunningHandler([this](const Utf8String &filePath,
|
m_queue.setIsJobRunningForTranslationUnitHandler([this](const Utf8String &translationUnitId) {
|
||||||
const Utf8String &projectPartId) {
|
return isJobRunningForTranslationUnit(translationUnitId);
|
||||||
return isJobRunning(filePath, projectPartId);
|
});
|
||||||
|
m_queue.setIsJobRunningForJobRequestHandler([this](const JobRequest &jobRequest) {
|
||||||
|
return isJobRunningForJobRequest(jobRequest);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Jobs::~Jobs()
|
Jobs::~Jobs()
|
||||||
{
|
{
|
||||||
|
foreach (IAsyncJob *asyncJob, m_running.keys())
|
||||||
|
asyncJob->preventFinalization();
|
||||||
|
|
||||||
QFutureSynchronizer<void> waitForFinishedJobs;
|
QFutureSynchronizer<void> waitForFinishedJobs;
|
||||||
foreach (const RunningJob &runningJob, m_running.values())
|
foreach (const RunningJob &runningJob, m_running.values())
|
||||||
waitForFinishedJobs.addFuture(runningJob.future);
|
waitForFinishedJobs.addFuture(runningJob.future);
|
||||||
|
|
||||||
|
foreach (IAsyncJob *asyncJob, m_running.keys())
|
||||||
|
delete asyncJob;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Jobs::add(const JobRequest &job)
|
void Jobs::add(const JobRequest &job)
|
||||||
@@ -87,22 +95,25 @@ JobRequests Jobs::runJobs(const JobRequests &jobsRequests)
|
|||||||
|
|
||||||
bool Jobs::runJob(const JobRequest &jobRequest)
|
bool Jobs::runJob(const JobRequest &jobRequest)
|
||||||
{
|
{
|
||||||
if (IAsyncJob *asyncJob = IAsyncJob::create(jobRequest.type)) {
|
IAsyncJob *asyncJob = IAsyncJob::create(jobRequest.type);
|
||||||
JobContext context(jobRequest, &m_documents, &m_unsavedFiles, &m_client);
|
QTC_ASSERT(asyncJob, return false);
|
||||||
asyncJob->setContext(context);
|
|
||||||
|
|
||||||
if (asyncJob->prepareAsyncRun()) {
|
JobContext context(jobRequest, &m_documents, &m_unsavedFiles, &m_client);
|
||||||
qCDebug(jobsLog) << "Running" << jobRequest;
|
asyncJob->setContext(context);
|
||||||
|
|
||||||
asyncJob->setFinishedHandler([this](IAsyncJob *asyncJob){ onJobFinished(asyncJob); });
|
if (const IAsyncJob::AsyncPrepareResult prepareResult = asyncJob->prepareAsyncRun()) {
|
||||||
const QFuture<void> future = asyncJob->runAsync();
|
qCDebug(jobsLog) << "Running" << jobRequest
|
||||||
|
<< "with TranslationUnit" << prepareResult.translationUnitId;
|
||||||
|
|
||||||
m_running.insert(asyncJob, RunningJob{jobRequest, future});
|
asyncJob->setFinishedHandler([this](IAsyncJob *asyncJob){ onJobFinished(asyncJob); });
|
||||||
return true;
|
const QFuture<void> future = asyncJob->runAsync();
|
||||||
} else {
|
|
||||||
qCDebug(jobsLog) << "Preparation failed for " << jobRequest;
|
const RunningJob runningJob{jobRequest, prepareResult.translationUnitId, future};
|
||||||
delete asyncJob;
|
m_running.insert(asyncJob, runningJob);
|
||||||
}
|
return true;
|
||||||
|
} else {
|
||||||
|
qCDebug(jobsLog) << "Preparation failed for " << jobRequest;
|
||||||
|
delete asyncJob;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@@ -112,15 +123,25 @@ void Jobs::onJobFinished(IAsyncJob *asyncJob)
|
|||||||
{
|
{
|
||||||
qCDebug(jobsLog) << "Finishing" << asyncJob->context().jobRequest;
|
qCDebug(jobsLog) << "Finishing" << asyncJob->context().jobRequest;
|
||||||
|
|
||||||
|
if (m_jobFinishedCallback) {
|
||||||
|
const RunningJob runningJob = m_running.value(asyncJob);
|
||||||
|
m_jobFinishedCallback(runningJob);
|
||||||
|
}
|
||||||
|
|
||||||
m_running.remove(asyncJob);
|
m_running.remove(asyncJob);
|
||||||
delete asyncJob;
|
delete asyncJob;
|
||||||
|
|
||||||
process();
|
process();
|
||||||
}
|
}
|
||||||
|
|
||||||
int Jobs::runningJobs() const
|
void Jobs::setJobFinishedCallback(const JobFinishedCallback &jobFinishedCallback)
|
||||||
{
|
{
|
||||||
return m_running.size();
|
m_jobFinishedCallback = jobFinishedCallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<Jobs::RunningJob> Jobs::runningJobs() const
|
||||||
|
{
|
||||||
|
return m_running.values();
|
||||||
}
|
}
|
||||||
|
|
||||||
JobRequests Jobs::queue() const
|
JobRequests Jobs::queue() const
|
||||||
@@ -128,12 +149,19 @@ JobRequests Jobs::queue() const
|
|||||||
return m_queue.queue();
|
return m_queue.queue();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Jobs::isJobRunning(const Utf8String &filePath, const Utf8String &projectPartId) const
|
bool Jobs::isJobRunningForTranslationUnit(const Utf8String &translationUnitId) const
|
||||||
{
|
{
|
||||||
const auto hasJobRequest = [filePath, projectPartId](const RunningJob &runningJob) {
|
const auto hasTranslationUnitId = [translationUnitId](const RunningJob &runningJob) {
|
||||||
const JobRequest &jobRequest = runningJob.jobRequest;
|
return runningJob.translationUnitId == translationUnitId;
|
||||||
return filePath == jobRequest.filePath
|
};
|
||||||
&& projectPartId == jobRequest.projectPartId;
|
|
||||||
|
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);
|
return Utils::anyOf(m_running.values(), hasJobRequest);
|
||||||
|
@@ -31,6 +31,8 @@
|
|||||||
|
|
||||||
#include <QFuture>
|
#include <QFuture>
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
namespace ClangBackEnd {
|
namespace ClangBackEnd {
|
||||||
|
|
||||||
class ClangCodeModelClientInterface;
|
class ClangCodeModelClientInterface;
|
||||||
@@ -43,9 +45,12 @@ class Jobs
|
|||||||
public:
|
public:
|
||||||
struct RunningJob {
|
struct RunningJob {
|
||||||
JobRequest jobRequest;
|
JobRequest jobRequest;
|
||||||
|
Utf8String translationUnitId;
|
||||||
QFuture<void> future;
|
QFuture<void> future;
|
||||||
};
|
};
|
||||||
|
|
||||||
using RunningJobs = QHash<IAsyncJob *, RunningJob>;
|
using RunningJobs = QHash<IAsyncJob *, RunningJob>;
|
||||||
|
using JobFinishedCallback = std::function<void(RunningJob)>;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Jobs(Documents &documents,
|
Jobs(Documents &documents,
|
||||||
@@ -58,10 +63,13 @@ public:
|
|||||||
|
|
||||||
JobRequests process();
|
JobRequests process();
|
||||||
|
|
||||||
|
void setJobFinishedCallback(const JobFinishedCallback &jobFinishedCallback);
|
||||||
|
|
||||||
public /*for tests*/:
|
public /*for tests*/:
|
||||||
int runningJobs() const;
|
QList<RunningJob> runningJobs() const;
|
||||||
JobRequests queue() const;
|
JobRequests queue() const;
|
||||||
bool isJobRunning(const Utf8String &filePath, const Utf8String &projectPartId) const;
|
bool isJobRunningForTranslationUnit(const Utf8String &translationUnitId) const;
|
||||||
|
bool isJobRunningForJobRequest(const JobRequest &jobRequest) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
JobRequests runJobs(const JobRequests &jobRequest);
|
JobRequests runJobs(const JobRequests &jobRequest);
|
||||||
@@ -75,6 +83,7 @@ private:
|
|||||||
|
|
||||||
JobQueue m_queue;
|
JobQueue m_queue;
|
||||||
RunningJobs m_running;
|
RunningJobs m_running;
|
||||||
|
JobFinishedCallback m_jobFinishedCallback;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ClangBackEnd
|
} // namespace ClangBackEnd
|
||||||
|
@@ -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.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include "clangparsesupportivetranslationunitjob.h"
|
||||||
|
|
||||||
|
#include <clangbackendipc/clangbackendipcdebugutils.h>
|
||||||
|
|
||||||
|
#include <utils/qtcassert.h>
|
||||||
|
|
||||||
|
namespace ClangBackEnd {
|
||||||
|
|
||||||
|
static ParseSupportiveTranslationUnitJob::AsyncResult runAsyncHelper(
|
||||||
|
const TranslationUnit &translationUnit,
|
||||||
|
const TranslationUnitUpdateInput &translationUnitUpdateInput)
|
||||||
|
{
|
||||||
|
TIME_SCOPE_DURATION("ParseSupportiveTranslationUnitJob");
|
||||||
|
|
||||||
|
TranslationUnitUpdateInput updateInput = translationUnitUpdateInput;
|
||||||
|
updateInput.parseNeeded = true;
|
||||||
|
|
||||||
|
ParseSupportiveTranslationUnitJob::AsyncResult asyncResult;
|
||||||
|
asyncResult.updateResult = translationUnit.update(updateInput);
|
||||||
|
|
||||||
|
return asyncResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
IAsyncJob::AsyncPrepareResult ParseSupportiveTranslationUnitJob::prepareAsyncRun()
|
||||||
|
{
|
||||||
|
const JobRequest jobRequest = context().jobRequest;
|
||||||
|
QTC_ASSERT(jobRequest.type == JobRequest::Type::ParseSupportiveTranslationUnit, return AsyncPrepareResult());
|
||||||
|
|
||||||
|
try {
|
||||||
|
m_pinnedDocument = context().documentForJobRequest();
|
||||||
|
m_pinnedFileContainer = m_pinnedDocument.fileContainer();
|
||||||
|
|
||||||
|
const TranslationUnit translationUnit
|
||||||
|
= m_pinnedDocument.translationUnit(jobRequest.preferredTranslationUnit);
|
||||||
|
const TranslationUnitUpdateInput updateInput = m_pinnedDocument.createUpdateInput();
|
||||||
|
setRunner([translationUnit, updateInput]() {
|
||||||
|
return runAsyncHelper(translationUnit, updateInput);
|
||||||
|
});
|
||||||
|
return AsyncPrepareResult{translationUnit.id()};
|
||||||
|
|
||||||
|
} catch (const std::exception &exception) {
|
||||||
|
qWarning() << "Error in ParseForSupportiveTranslationUnitJob::prepareAsyncRun:"
|
||||||
|
<< exception.what();
|
||||||
|
return AsyncPrepareResult();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ParseSupportiveTranslationUnitJob::finalizeAsyncRun()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace ClangBackEnd
|
||||||
|
|
@@ -0,0 +1,51 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2016 The Qt Company Ltd.
|
||||||
|
** Contact: https://www.qt.io/licensing/
|
||||||
|
**
|
||||||
|
** This file is part of Qt Creator.
|
||||||
|
**
|
||||||
|
** Commercial License Usage
|
||||||
|
** Licensees holding valid commercial Qt licenses may use this file in
|
||||||
|
** accordance with the commercial license agreement provided with the
|
||||||
|
** Software or, alternatively, in accordance with the terms contained in
|
||||||
|
** a written agreement between you and The Qt Company. For licensing terms
|
||||||
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||||
|
** information use the contact form at https://www.qt.io/contact-us.
|
||||||
|
**
|
||||||
|
** GNU General Public License Usage
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU
|
||||||
|
** General Public License version 3 as published by the Free Software
|
||||||
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||||
|
** included in the packaging of this file. Please review the following
|
||||||
|
** information to ensure the GNU General Public License requirements will
|
||||||
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "clangasyncjob.h"
|
||||||
|
#include "clangdocument.h"
|
||||||
|
|
||||||
|
namespace ClangBackEnd {
|
||||||
|
|
||||||
|
struct ParseSupportiveTranslationUnitJobResult
|
||||||
|
{
|
||||||
|
TranslationUnitUpdateResult updateResult;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ParseSupportiveTranslationUnitJob : public AsyncJob<ParseSupportiveTranslationUnitJobResult>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using AsyncResult = ParseSupportiveTranslationUnitJobResult;
|
||||||
|
|
||||||
|
AsyncPrepareResult prepareAsyncRun() override;
|
||||||
|
void finalizeAsyncRun() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Document m_pinnedDocument;
|
||||||
|
FileContainer m_pinnedFileContainer;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace ClangBackEnd
|
@@ -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.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include "clangreparsesupportivetranslationunitjob.h"
|
||||||
|
|
||||||
|
#include <clangbackendipc/clangbackendipcdebugutils.h>
|
||||||
|
|
||||||
|
#include <utils/qtcassert.h>
|
||||||
|
|
||||||
|
namespace ClangBackEnd {
|
||||||
|
|
||||||
|
static ReparseSupportiveTranslationUnitJob::AsyncResult runAsyncHelper(
|
||||||
|
const TranslationUnit &translationUnit,
|
||||||
|
const TranslationUnitUpdateInput &translationUnitUpdateInput)
|
||||||
|
{
|
||||||
|
TIME_SCOPE_DURATION("ReparseSupportiveTranslationUnitJob");
|
||||||
|
|
||||||
|
TranslationUnitUpdateInput updateInput = translationUnitUpdateInput;
|
||||||
|
updateInput.reparseNeeded = true;
|
||||||
|
|
||||||
|
ReparseSupportiveTranslationUnitJob::AsyncResult asyncResult;
|
||||||
|
asyncResult.updateResult = translationUnit.reparse(updateInput);
|
||||||
|
|
||||||
|
return asyncResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
IAsyncJob::AsyncPrepareResult ReparseSupportiveTranslationUnitJob::prepareAsyncRun()
|
||||||
|
{
|
||||||
|
const JobRequest jobRequest = context().jobRequest;
|
||||||
|
QTC_ASSERT(jobRequest.type == JobRequest::Type::ReparseSupportiveTranslationUnit, return AsyncPrepareResult());
|
||||||
|
|
||||||
|
try {
|
||||||
|
m_pinnedDocument = context().documentForJobRequest();
|
||||||
|
m_pinnedFileContainer = m_pinnedDocument.fileContainer();
|
||||||
|
|
||||||
|
const TranslationUnit translationUnit
|
||||||
|
= m_pinnedDocument.translationUnit(jobRequest.preferredTranslationUnit);
|
||||||
|
const TranslationUnitUpdateInput updateInput = m_pinnedDocument.createUpdateInput();
|
||||||
|
setRunner([translationUnit, updateInput]() {
|
||||||
|
return runAsyncHelper(translationUnit, updateInput);
|
||||||
|
});
|
||||||
|
return AsyncPrepareResult{translationUnit.id()};
|
||||||
|
|
||||||
|
} catch (const std::exception &exception) {
|
||||||
|
qWarning() << "Error in ReparseSupportiveTranslationUnitJob::prepareAsyncRun:"
|
||||||
|
<< exception.what();
|
||||||
|
return AsyncPrepareResult();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReparseSupportiveTranslationUnitJob::finalizeAsyncRun()
|
||||||
|
{
|
||||||
|
if (!context().isOutdated()) {
|
||||||
|
const AsyncResult result = asyncResult();
|
||||||
|
m_pinnedDocument.incorporateUpdaterResult(result.updateResult);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace ClangBackEnd
|
||||||
|
|
@@ -0,0 +1,51 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2016 The Qt Company Ltd.
|
||||||
|
** Contact: https://www.qt.io/licensing/
|
||||||
|
**
|
||||||
|
** This file is part of Qt Creator.
|
||||||
|
**
|
||||||
|
** Commercial License Usage
|
||||||
|
** Licensees holding valid commercial Qt licenses may use this file in
|
||||||
|
** accordance with the commercial license agreement provided with the
|
||||||
|
** Software or, alternatively, in accordance with the terms contained in
|
||||||
|
** a written agreement between you and The Qt Company. For licensing terms
|
||||||
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||||
|
** information use the contact form at https://www.qt.io/contact-us.
|
||||||
|
**
|
||||||
|
** GNU General Public License Usage
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU
|
||||||
|
** General Public License version 3 as published by the Free Software
|
||||||
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||||
|
** included in the packaging of this file. Please review the following
|
||||||
|
** information to ensure the GNU General Public License requirements will
|
||||||
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "clangasyncjob.h"
|
||||||
|
#include "clangdocument.h"
|
||||||
|
|
||||||
|
namespace ClangBackEnd {
|
||||||
|
|
||||||
|
struct ReparseSupportiveTranslationUnitJobResult
|
||||||
|
{
|
||||||
|
TranslationUnitUpdateResult updateResult;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ReparseSupportiveTranslationUnitJob : public AsyncJob<ReparseSupportiveTranslationUnitJobResult>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using AsyncResult = ReparseSupportiveTranslationUnitJobResult;
|
||||||
|
|
||||||
|
AsyncPrepareResult prepareAsyncRun() override;
|
||||||
|
void finalizeAsyncRun() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Document m_pinnedDocument;
|
||||||
|
FileContainer m_pinnedFileContainer;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace ClangBackEnd
|
@@ -40,33 +40,35 @@ static RequestDocumentAnnotationsJob::AsyncResult runAsyncHelper(
|
|||||||
|
|
||||||
RequestDocumentAnnotationsJob::AsyncResult asyncResult;
|
RequestDocumentAnnotationsJob::AsyncResult asyncResult;
|
||||||
|
|
||||||
translationUnit.extractDocumentAnnotations(asyncResult.diagnostics,
|
translationUnit.extractDocumentAnnotations(asyncResult.firstHeaderErrorDiagnostic,
|
||||||
|
asyncResult.diagnostics,
|
||||||
asyncResult.highlightingMarks,
|
asyncResult.highlightingMarks,
|
||||||
asyncResult.skippedSourceRanges);
|
asyncResult.skippedSourceRanges);
|
||||||
|
|
||||||
return asyncResult;
|
return asyncResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RequestDocumentAnnotationsJob::prepareAsyncRun()
|
IAsyncJob::AsyncPrepareResult RequestDocumentAnnotationsJob::prepareAsyncRun()
|
||||||
{
|
{
|
||||||
const JobRequest jobRequest = context().jobRequest;
|
const JobRequest jobRequest = context().jobRequest;
|
||||||
QTC_ASSERT(jobRequest.type == JobRequest::Type::RequestDocumentAnnotations, return false);
|
QTC_ASSERT(jobRequest.type == JobRequest::Type::RequestDocumentAnnotations,
|
||||||
|
return AsyncPrepareResult());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
m_pinnedDocument = context().documentForJobRequest();
|
m_pinnedDocument = context().documentForJobRequest();
|
||||||
m_pinnedFileContainer = m_pinnedDocument.fileContainer();
|
m_pinnedFileContainer = m_pinnedDocument.fileContainer();
|
||||||
|
|
||||||
const TranslationUnit translationUnit = m_pinnedDocument.translationUnit();
|
const TranslationUnit translationUnit
|
||||||
|
= m_pinnedDocument.translationUnit(jobRequest.preferredTranslationUnit);
|
||||||
setRunner([translationUnit]() {
|
setRunner([translationUnit]() {
|
||||||
return runAsyncHelper(translationUnit);
|
return runAsyncHelper(translationUnit);
|
||||||
});
|
});
|
||||||
|
return AsyncPrepareResult{translationUnit.id()};
|
||||||
|
|
||||||
} catch (const std::exception &exception) {
|
} catch (const std::exception &exception) {
|
||||||
qWarning() << "Error in RequestDocumentAnnotationsJob::prepareAsyncRun:" << exception.what();
|
qWarning() << "Error in RequestDocumentAnnotationsJob::prepareAsyncRun:" << exception.what();
|
||||||
return false;
|
return AsyncPrepareResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RequestDocumentAnnotationsJob::finalizeAsyncRun()
|
void RequestDocumentAnnotationsJob::finalizeAsyncRun()
|
||||||
@@ -82,6 +84,7 @@ void RequestDocumentAnnotationsJob::sendAnnotations(
|
|||||||
{
|
{
|
||||||
const DocumentAnnotationsChangedMessage message(m_pinnedFileContainer,
|
const DocumentAnnotationsChangedMessage message(m_pinnedFileContainer,
|
||||||
result.diagnostics,
|
result.diagnostics,
|
||||||
|
result.firstHeaderErrorDiagnostic,
|
||||||
result.highlightingMarks,
|
result.highlightingMarks,
|
||||||
result.skippedSourceRanges);
|
result.skippedSourceRanges);
|
||||||
|
|
||||||
|
@@ -36,6 +36,7 @@ namespace ClangBackEnd {
|
|||||||
|
|
||||||
struct RequestDocumentAnnotationsJobResult
|
struct RequestDocumentAnnotationsJobResult
|
||||||
{
|
{
|
||||||
|
ClangBackEnd::DiagnosticContainer firstHeaderErrorDiagnostic;
|
||||||
QVector<ClangBackEnd::DiagnosticContainer> diagnostics;
|
QVector<ClangBackEnd::DiagnosticContainer> diagnostics;
|
||||||
QVector<HighlightingMarkContainer> highlightingMarks;
|
QVector<HighlightingMarkContainer> highlightingMarks;
|
||||||
QVector<SourceRangeContainer> skippedSourceRanges;
|
QVector<SourceRangeContainer> skippedSourceRanges;
|
||||||
@@ -46,7 +47,7 @@ class RequestDocumentAnnotationsJob : public AsyncJob<RequestDocumentAnnotations
|
|||||||
public:
|
public:
|
||||||
using AsyncResult = RequestDocumentAnnotationsJobResult;
|
using AsyncResult = RequestDocumentAnnotationsJobResult;
|
||||||
|
|
||||||
bool prepareAsyncRun() override;
|
AsyncPrepareResult prepareAsyncRun() override;
|
||||||
void finalizeAsyncRun() override;
|
void finalizeAsyncRun() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@@ -0,0 +1,141 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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 <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::setJobRequestCreator(const JobRequestCreator &creator)
|
||||||
|
{
|
||||||
|
m_jobRequestCreator = creator;
|
||||||
|
}
|
||||||
|
|
||||||
|
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.projectPartId())) {
|
||||||
|
m_state = State::Aborted;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SupportiveTranslationUnitInitializer::addJob(JobRequest::Type jobRequestType)
|
||||||
|
{
|
||||||
|
QTC_CHECK(m_jobRequestCreator);
|
||||||
|
|
||||||
|
const JobRequest jobRequest = m_jobRequestCreator(m_document,
|
||||||
|
jobRequestType,
|
||||||
|
PreferredTranslationUnit::LastUninitialized);
|
||||||
|
|
||||||
|
m_jobs.add(jobRequest);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SupportiveTranslationUnitInitializer::setState(const State &state)
|
||||||
|
{
|
||||||
|
m_state = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace ClangBackEnd
|
@@ -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.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include "clangdocument.h"
|
||||||
|
#include "clangjobrequest.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 setJobRequestCreator(const JobRequestCreator &creator);
|
||||||
|
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;
|
||||||
|
JobRequestCreator m_jobRequestCreator;
|
||||||
|
IsDocumentClosedChecker m_isDocumentClosedChecker;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace ClangBackEnd
|
@@ -38,10 +38,12 @@
|
|||||||
|
|
||||||
namespace ClangBackEnd {
|
namespace ClangBackEnd {
|
||||||
|
|
||||||
TranslationUnit::TranslationUnit(const Utf8String &filepath,
|
TranslationUnit::TranslationUnit(const Utf8String &id,
|
||||||
|
const Utf8String &filepath,
|
||||||
CXIndex &cxIndex,
|
CXIndex &cxIndex,
|
||||||
CXTranslationUnit &cxTranslationUnit)
|
CXTranslationUnit &cxTranslationUnit)
|
||||||
: m_filePath(filepath)
|
: m_id(id)
|
||||||
|
, m_filePath(filepath)
|
||||||
, m_cxIndex(cxIndex)
|
, m_cxIndex(cxIndex)
|
||||||
, m_cxTranslationUnit(cxTranslationUnit)
|
, m_cxTranslationUnit(cxTranslationUnit)
|
||||||
{
|
{
|
||||||
@@ -49,7 +51,12 @@ TranslationUnit::TranslationUnit(const Utf8String &filepath,
|
|||||||
|
|
||||||
bool TranslationUnit::isNull() const
|
bool TranslationUnit::isNull() const
|
||||||
{
|
{
|
||||||
return !m_cxTranslationUnit || !m_cxIndex || m_filePath.isEmpty();
|
return !m_cxTranslationUnit || !m_cxIndex || m_filePath.isEmpty() || m_id.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
Utf8String TranslationUnit::id() const
|
||||||
|
{
|
||||||
|
return m_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
Utf8String TranslationUnit::filePath() const
|
Utf8String TranslationUnit::filePath() const
|
||||||
@@ -70,7 +77,7 @@ CXTranslationUnit &TranslationUnit::cxTranslationUnit() const
|
|||||||
TranslationUnitUpdateResult TranslationUnit::update(
|
TranslationUnitUpdateResult TranslationUnit::update(
|
||||||
const TranslationUnitUpdateInput &parseInput) const
|
const TranslationUnitUpdateInput &parseInput) const
|
||||||
{
|
{
|
||||||
TranslationUnitUpdater updater(cxIndex(), cxTranslationUnit(), parseInput);
|
TranslationUnitUpdater updater(id(), cxIndex(), cxTranslationUnit(), parseInput);
|
||||||
|
|
||||||
return updater.update(TranslationUnitUpdater::UpdateMode::AsNeeded);
|
return updater.update(TranslationUnitUpdater::UpdateMode::AsNeeded);
|
||||||
}
|
}
|
||||||
@@ -78,7 +85,7 @@ TranslationUnitUpdateResult TranslationUnit::update(
|
|||||||
TranslationUnitUpdateResult TranslationUnit::parse(
|
TranslationUnitUpdateResult TranslationUnit::parse(
|
||||||
const TranslationUnitUpdateInput &parseInput) const
|
const TranslationUnitUpdateInput &parseInput) const
|
||||||
{
|
{
|
||||||
TranslationUnitUpdater updater(cxIndex(), cxTranslationUnit(), parseInput);
|
TranslationUnitUpdater updater(id(), cxIndex(), cxTranslationUnit(), parseInput);
|
||||||
|
|
||||||
return updater.update(TranslationUnitUpdater::UpdateMode::ParseIfNeeded);
|
return updater.update(TranslationUnitUpdater::UpdateMode::ParseIfNeeded);
|
||||||
}
|
}
|
||||||
@@ -86,7 +93,7 @@ TranslationUnitUpdateResult TranslationUnit::parse(
|
|||||||
TranslationUnitUpdateResult TranslationUnit::reparse(
|
TranslationUnitUpdateResult TranslationUnit::reparse(
|
||||||
const TranslationUnitUpdateInput &parseInput) const
|
const TranslationUnitUpdateInput &parseInput) const
|
||||||
{
|
{
|
||||||
TranslationUnitUpdater updater(cxIndex(), cxTranslationUnit(), parseInput);
|
TranslationUnitUpdater updater(id(), cxIndex(), cxTranslationUnit(), parseInput);
|
||||||
|
|
||||||
return updater.update(TranslationUnitUpdater::UpdateMode::ForceReparse);
|
return updater.update(TranslationUnitUpdater::UpdateMode::ForceReparse);
|
||||||
}
|
}
|
||||||
@@ -105,11 +112,12 @@ TranslationUnit::CodeCompletionResult TranslationUnit::complete(
|
|||||||
}
|
}
|
||||||
|
|
||||||
void TranslationUnit::extractDocumentAnnotations(
|
void TranslationUnit::extractDocumentAnnotations(
|
||||||
QVector<DiagnosticContainer> &diagnostics,
|
DiagnosticContainer &firstHeaderErrorDiagnostic,
|
||||||
|
QVector<DiagnosticContainer> &mainFileDiagnostics,
|
||||||
QVector<HighlightingMarkContainer> &highlightingMarks,
|
QVector<HighlightingMarkContainer> &highlightingMarks,
|
||||||
QVector<SourceRangeContainer> &skippedSourceRanges) const
|
QVector<SourceRangeContainer> &skippedSourceRanges) const
|
||||||
{
|
{
|
||||||
diagnostics = mainFileDiagnostics();
|
extractDiagnostics(firstHeaderErrorDiagnostic, mainFileDiagnostics);
|
||||||
highlightingMarks = this->highlightingMarks().toHighlightingMarksContainers();
|
highlightingMarks = this->highlightingMarks().toHighlightingMarksContainers();
|
||||||
skippedSourceRanges = this->skippedSourceRanges().toSourceRangeContainers();
|
skippedSourceRanges = this->skippedSourceRanges().toSourceRangeContainers();
|
||||||
}
|
}
|
||||||
@@ -119,15 +127,6 @@ DiagnosticSet TranslationUnit::diagnostics() const
|
|||||||
return DiagnosticSet(clang_getDiagnosticSetFromTU(m_cxTranslationUnit));
|
return DiagnosticSet(clang_getDiagnosticSetFromTU(m_cxTranslationUnit));
|
||||||
}
|
}
|
||||||
|
|
||||||
QVector<DiagnosticContainer> TranslationUnit::mainFileDiagnostics() const
|
|
||||||
{
|
|
||||||
const auto isMainFileDiagnostic = [this](const Diagnostic &diagnostic) {
|
|
||||||
return diagnostic.location().filePath() == m_filePath;
|
|
||||||
};
|
|
||||||
|
|
||||||
return diagnostics().toDiagnosticContainers(isMainFileDiagnostic);
|
|
||||||
}
|
|
||||||
|
|
||||||
SourceLocation TranslationUnit::sourceLocationAt(uint line,uint column) const
|
SourceLocation TranslationUnit::sourceLocationAt(uint line,uint column) const
|
||||||
{
|
{
|
||||||
return SourceLocation(m_cxTranslationUnit, m_filePath, line, column);
|
return SourceLocation(m_cxTranslationUnit, m_filePath, line, column);
|
||||||
@@ -186,4 +185,35 @@ SkippedSourceRanges TranslationUnit::skippedSourceRanges() const
|
|||||||
return SkippedSourceRanges(m_cxTranslationUnit, m_filePath.constData());
|
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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace ClangBackEnd
|
} // namespace ClangBackEnd
|
||||||
|
@@ -57,12 +57,15 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
TranslationUnit(const Utf8String &filePath,
|
TranslationUnit(const Utf8String &id,
|
||||||
|
const Utf8String &filePath,
|
||||||
CXIndex &cxIndex,
|
CXIndex &cxIndex,
|
||||||
CXTranslationUnit &cxTranslationUnit);
|
CXTranslationUnit &cxTranslationUnit);
|
||||||
|
|
||||||
bool isNull() const;
|
bool isNull() const;
|
||||||
|
|
||||||
|
Utf8String id() const;
|
||||||
|
|
||||||
Utf8String filePath() const;
|
Utf8String filePath() const;
|
||||||
CXIndex &cxIndex() const;
|
CXIndex &cxIndex() const;
|
||||||
CXTranslationUnit &cxTranslationUnit() const;
|
CXTranslationUnit &cxTranslationUnit() const;
|
||||||
@@ -73,12 +76,14 @@ public:
|
|||||||
|
|
||||||
CodeCompletionResult complete(UnsavedFiles &unsavedFiles, uint line, uint column) const;
|
CodeCompletionResult complete(UnsavedFiles &unsavedFiles, uint line, uint column) const;
|
||||||
|
|
||||||
void extractDocumentAnnotations(QVector<DiagnosticContainer> &diagnostics,
|
void extractDiagnostics(DiagnosticContainer &firstHeaderErrorDiagnostic,
|
||||||
|
QVector<DiagnosticContainer> &mainFileDiagnostics) const;
|
||||||
|
void extractDocumentAnnotations(DiagnosticContainer &firstHeaderErrorDiagnostic,
|
||||||
|
QVector<DiagnosticContainer> &mainFileDiagnostics,
|
||||||
QVector<HighlightingMarkContainer> &highlightingMarks,
|
QVector<HighlightingMarkContainer> &highlightingMarks,
|
||||||
QVector<SourceRangeContainer> &skippedSourceRanges) const;
|
QVector<SourceRangeContainer> &skippedSourceRanges) const;
|
||||||
|
|
||||||
DiagnosticSet diagnostics() const;
|
DiagnosticSet diagnostics() const;
|
||||||
QVector<DiagnosticContainer> mainFileDiagnostics() const;
|
|
||||||
|
|
||||||
SourceLocation sourceLocationAt(uint line, uint column) const;
|
SourceLocation sourceLocationAt(uint line, uint column) const;
|
||||||
SourceLocation sourceLocationAt(const Utf8String &filePath, uint line, uint column) const;
|
SourceLocation sourceLocationAt(const Utf8String &filePath, uint line, uint column) const;
|
||||||
@@ -94,6 +99,7 @@ public:
|
|||||||
SkippedSourceRanges skippedSourceRanges() const;
|
SkippedSourceRanges skippedSourceRanges() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
const Utf8String m_id;
|
||||||
const Utf8String m_filePath;
|
const Utf8String m_filePath;
|
||||||
CXIndex &m_cxIndex;
|
CXIndex &m_cxIndex;
|
||||||
CXTranslationUnit &m_cxTranslationUnit;
|
CXTranslationUnit &m_cxTranslationUnit;
|
||||||
|
150
src/tools/clangbackend/ipcsource/clangtranslationunits.cpp
Normal file
150
src/tools/clangbackend/ipcsource/clangtranslationunits.cpp
Normal file
@@ -0,0 +1,150 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
Q_LOGGING_CATEGORY(tuLog, "qtc.clangbackend.translationunits");
|
||||||
|
|
||||||
|
namespace ClangBackEnd {
|
||||||
|
|
||||||
|
TranslationUnits::TranslationUnits(const Utf8String &filePath)
|
||||||
|
: m_filePath(filePath)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
TranslationUnits::~TranslationUnits()
|
||||||
|
{
|
||||||
|
foreach (const TranslationUnitData &unit, m_tuDatas) {
|
||||||
|
clang_disposeTranslationUnit(unit.cxTranslationUnit);
|
||||||
|
clang_disposeIndex(unit.cxIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TranslationUnit TranslationUnits::createAndAppend()
|
||||||
|
{
|
||||||
|
const Utf8String id = Utf8String::fromByteArray(QUuid::createUuid().toByteArray());
|
||||||
|
qCDebug(tuLog) << "Creating TranslationUnit" << id << "for" << QFileInfo(m_filePath).fileName();
|
||||||
|
|
||||||
|
m_tuDatas.append(TranslationUnitData(id));
|
||||||
|
TranslationUnitData &translationUnitData = m_tuDatas.last();
|
||||||
|
|
||||||
|
return toTranslationUnit(translationUnitData);
|
||||||
|
}
|
||||||
|
|
||||||
|
TranslationUnit TranslationUnits::get(PreferredTranslationUnit type)
|
||||||
|
{
|
||||||
|
if (m_tuDatas.isEmpty())
|
||||||
|
throw TranslationUnitDoesNotExist(m_filePath);
|
||||||
|
|
||||||
|
if (m_tuDatas.size() == 1)
|
||||||
|
return toTranslationUnit(m_tuDatas.first());
|
||||||
|
|
||||||
|
if (areAllTranslationUnitsParsed())
|
||||||
|
return getPreferredTranslationUnit(type);
|
||||||
|
else if (type == PreferredTranslationUnit::LastUninitialized)
|
||||||
|
return toTranslationUnit(m_tuDatas.last());
|
||||||
|
|
||||||
|
return toTranslationUnit(m_tuDatas.first());
|
||||||
|
}
|
||||||
|
|
||||||
|
void TranslationUnits::updateParseTimePoint(const Utf8String &translationUnitId,
|
||||||
|
TimePoint timePoint)
|
||||||
|
{
|
||||||
|
TranslationUnitData &unit = findUnit(translationUnitId);
|
||||||
|
|
||||||
|
QTC_CHECK(timePoint != TimePoint());
|
||||||
|
unit.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_tuDatas, [](const TranslationUnitData &unit) {
|
||||||
|
return unit.parseTimePoint != TimePoint();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
int TranslationUnits::size() const
|
||||||
|
{
|
||||||
|
return m_tuDatas.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
TranslationUnit TranslationUnits::getPreferredTranslationUnit(PreferredTranslationUnit type)
|
||||||
|
{
|
||||||
|
using TuData = TranslationUnitData;
|
||||||
|
|
||||||
|
const auto lessThan = [](const TuData &a, const TuData &b) {
|
||||||
|
return a.parseTimePoint < b.parseTimePoint;
|
||||||
|
};
|
||||||
|
auto translationUnitData = type == PreferredTranslationUnit::RecentlyParsed
|
||||||
|
? std::max_element(m_tuDatas.begin(), m_tuDatas.end(), lessThan)
|
||||||
|
: std::min_element(m_tuDatas.begin(), m_tuDatas.end(), lessThan);
|
||||||
|
|
||||||
|
if (translationUnitData == m_tuDatas.end())
|
||||||
|
throw TranslationUnitDoesNotExist(m_filePath);
|
||||||
|
|
||||||
|
return toTranslationUnit(*translationUnitData);
|
||||||
|
}
|
||||||
|
|
||||||
|
TranslationUnits::TranslationUnitData &TranslationUnits::findUnit(
|
||||||
|
const Utf8String &translationUnitId)
|
||||||
|
{
|
||||||
|
for (TranslationUnitData &unit : m_tuDatas) {
|
||||||
|
if (translationUnitId == unit.id)
|
||||||
|
return unit;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw TranslationUnitDoesNotExist(m_filePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
TranslationUnit TranslationUnits::toTranslationUnit(TranslationUnits::TranslationUnitData &unit)
|
||||||
|
{
|
||||||
|
return TranslationUnit(unit.id,
|
||||||
|
m_filePath,
|
||||||
|
unit.cxIndex,
|
||||||
|
unit.cxTranslationUnit);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace ClangBackEnd
|
82
src/tools/clangbackend/ipcsource/clangtranslationunits.h
Normal file
82
src/tools/clangbackend/ipcsource/clangtranslationunits.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 "clangbackend_global.h"
|
||||||
|
#include "clangclock.h"
|
||||||
|
|
||||||
|
#include <utf8string.h>
|
||||||
|
|
||||||
|
#include <clang-c/Index.h>
|
||||||
|
|
||||||
|
#include <QList>
|
||||||
|
|
||||||
|
namespace ClangBackEnd {
|
||||||
|
|
||||||
|
class TranslationUnit;
|
||||||
|
|
||||||
|
class TranslationUnits
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
class TranslationUnitData {
|
||||||
|
public:
|
||||||
|
TranslationUnitData(const Utf8String &id)
|
||||||
|
: id(id)
|
||||||
|
{}
|
||||||
|
|
||||||
|
Utf8String id;
|
||||||
|
|
||||||
|
CXTranslationUnit cxTranslationUnit = nullptr;
|
||||||
|
CXIndex cxIndex = nullptr;
|
||||||
|
|
||||||
|
TimePoint parseTimePoint;
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
TranslationUnits(const Utf8String &filePath);
|
||||||
|
~TranslationUnits();
|
||||||
|
|
||||||
|
TranslationUnit createAndAppend();
|
||||||
|
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(TranslationUnitData &unit);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Utf8String m_filePath;
|
||||||
|
QList<TranslationUnitData> m_tuDatas;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace ClangBackEnd
|
@@ -40,13 +40,15 @@ static bool isVerboseModeEnabled()
|
|||||||
|
|
||||||
namespace ClangBackEnd {
|
namespace ClangBackEnd {
|
||||||
|
|
||||||
TranslationUnitUpdater::TranslationUnitUpdater(CXIndex &index,
|
TranslationUnitUpdater::TranslationUnitUpdater(const Utf8String translationUnitId,
|
||||||
|
CXIndex &index,
|
||||||
CXTranslationUnit &cxTranslationUnit,
|
CXTranslationUnit &cxTranslationUnit,
|
||||||
const TranslationUnitUpdateInput &updateData)
|
const TranslationUnitUpdateInput &updateData)
|
||||||
: m_cxIndex(index)
|
: m_cxIndex(index)
|
||||||
, m_cxTranslationUnit(cxTranslationUnit)
|
, m_cxTranslationUnit(cxTranslationUnit)
|
||||||
, m_in(updateData)
|
, m_in(updateData)
|
||||||
{
|
{
|
||||||
|
m_out.translationUnitId = translationUnitId;
|
||||||
}
|
}
|
||||||
|
|
||||||
TranslationUnitUpdateResult TranslationUnitUpdater::update(UpdateMode mode)
|
TranslationUnitUpdateResult TranslationUnitUpdater::update(UpdateMode mode)
|
||||||
@@ -122,7 +124,7 @@ void TranslationUnitUpdater::createTranslationUnitIfNeeded()
|
|||||||
|
|
||||||
if (parseWasSuccessful()) {
|
if (parseWasSuccessful()) {
|
||||||
updateIncludeFilePaths();
|
updateIncludeFilePaths();
|
||||||
m_out.parseTimePoint = std::chrono::steady_clock::now();
|
m_out.parseTimePoint = Clock::now();
|
||||||
} else {
|
} else {
|
||||||
qWarning() << "Parsing" << m_in.filePath << "failed:"
|
qWarning() << "Parsing" << m_in.filePath << "failed:"
|
||||||
<< errorCodeToText(m_parseErrorCode);
|
<< errorCodeToText(m_parseErrorCode);
|
||||||
@@ -151,7 +153,7 @@ void TranslationUnitUpdater::reparse()
|
|||||||
if (reparseWasSuccessful()) {
|
if (reparseWasSuccessful()) {
|
||||||
updateIncludeFilePaths();
|
updateIncludeFilePaths();
|
||||||
|
|
||||||
m_out.reparseTimePoint = std::chrono::steady_clock::now();
|
m_out.reparseTimePoint = Clock::now();
|
||||||
m_out.needsToBeReparsedChangeTimePoint = m_in.needsToBeReparsedChangeTimePoint;
|
m_out.needsToBeReparsedChangeTimePoint = m_in.needsToBeReparsedChangeTimePoint;
|
||||||
} else {
|
} else {
|
||||||
qWarning() << "Reparsing" << m_in.filePath << "failed:" << m_reparseErrorCode;
|
qWarning() << "Reparsing" << m_in.filePath << "failed:" << m_reparseErrorCode;
|
||||||
|
@@ -25,6 +25,8 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "clangclock.h"
|
||||||
|
|
||||||
#include "commandlinearguments.h"
|
#include "commandlinearguments.h"
|
||||||
#include "unsavedfiles.h"
|
#include "unsavedfiles.h"
|
||||||
#include "utf8stringvector.h"
|
#include "utf8stringvector.h"
|
||||||
@@ -33,18 +35,14 @@
|
|||||||
|
|
||||||
#include <QSet>
|
#include <QSet>
|
||||||
|
|
||||||
#include <chrono>
|
|
||||||
|
|
||||||
namespace ClangBackEnd {
|
namespace ClangBackEnd {
|
||||||
|
|
||||||
using time_point = std::chrono::steady_clock::time_point;
|
|
||||||
|
|
||||||
class TranslationUnitUpdateInput {
|
class TranslationUnitUpdateInput {
|
||||||
public:
|
public:
|
||||||
bool parseNeeded = false;
|
bool parseNeeded = false;
|
||||||
bool reparseNeeded = false;
|
bool reparseNeeded = false;
|
||||||
|
|
||||||
time_point needsToBeReparsedChangeTimePoint;
|
TimePoint needsToBeReparsedChangeTimePoint;
|
||||||
Utf8String filePath;
|
Utf8String filePath;
|
||||||
Utf8StringVector fileArguments;
|
Utf8StringVector fileArguments;
|
||||||
|
|
||||||
@@ -57,17 +55,18 @@ public:
|
|||||||
class TranslationUnitUpdateResult {
|
class TranslationUnitUpdateResult {
|
||||||
public:
|
public:
|
||||||
bool hasParsed() const
|
bool hasParsed() const
|
||||||
{ return parseTimePoint != time_point(); }
|
{ return parseTimePoint != TimePoint(); }
|
||||||
|
|
||||||
bool hasReparsed() const
|
bool hasReparsed() const
|
||||||
{ return reparseTimePoint != time_point(); }
|
{ return reparseTimePoint != TimePoint(); }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
bool hasParseOrReparseFailed = false;
|
Utf8String translationUnitId;
|
||||||
|
|
||||||
time_point parseTimePoint;
|
bool hasParseOrReparseFailed = false;
|
||||||
time_point reparseTimePoint;
|
TimePoint parseTimePoint;
|
||||||
time_point needsToBeReparsedChangeTimePoint;
|
TimePoint reparseTimePoint;
|
||||||
|
TimePoint needsToBeReparsedChangeTimePoint;
|
||||||
|
|
||||||
QSet<Utf8String> dependedOnFilePaths;
|
QSet<Utf8String> dependedOnFilePaths;
|
||||||
};
|
};
|
||||||
@@ -81,7 +80,8 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
TranslationUnitUpdater(CXIndex &index,
|
TranslationUnitUpdater(const Utf8String translationUnitId,
|
||||||
|
CXIndex &index,
|
||||||
CXTranslationUnit &cxTranslationUnit,
|
CXTranslationUnit &cxTranslationUnit,
|
||||||
const TranslationUnitUpdateInput &in);
|
const TranslationUnitUpdateInput &in);
|
||||||
|
|
||||||
|
@@ -69,7 +69,7 @@ bool Type::isReferencingConstant() const
|
|||||||
return (isPointer() || isLValueReference()) && pointeeType().isConstant();
|
return (isPointer() || isLValueReference()) && pointeeType().isConstant();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Type::isOutputParameter() const
|
bool Type::isOutputArgument() const
|
||||||
{
|
{
|
||||||
return (isPointer() || isLValueReference()) && !pointeeType().isConstant();
|
return (isPointer() || isLValueReference()) && !pointeeType().isConstant();
|
||||||
}
|
}
|
||||||
|
@@ -49,7 +49,7 @@ public:
|
|||||||
bool isConstantPointer() const;
|
bool isConstantPointer() const;
|
||||||
bool isLValueReference() const;
|
bool isLValueReference() const;
|
||||||
bool isReferencingConstant() const;
|
bool isReferencingConstant() const;
|
||||||
bool isOutputParameter() const;
|
bool isOutputArgument() const;
|
||||||
|
|
||||||
Utf8String utf8Spelling() const;
|
Utf8String utf8Spelling() const;
|
||||||
ClangString spelling() const;
|
ClangString spelling() const;
|
||||||
|
@@ -45,34 +45,36 @@ static UpdateDocumentAnnotationsJob::AsyncResult runAsyncHelper(
|
|||||||
asyncResult.updateResult = translationUnit.update(translationUnitUpdatInput);
|
asyncResult.updateResult = translationUnit.update(translationUnitUpdatInput);
|
||||||
|
|
||||||
// Collect
|
// Collect
|
||||||
translationUnit.extractDocumentAnnotations(asyncResult.diagnostics,
|
translationUnit.extractDocumentAnnotations(asyncResult.firstHeaderErrorDiagnostic,
|
||||||
|
asyncResult.diagnostics,
|
||||||
asyncResult.highlightingMarks,
|
asyncResult.highlightingMarks,
|
||||||
asyncResult.skippedSourceRanges);
|
asyncResult.skippedSourceRanges);
|
||||||
|
|
||||||
return asyncResult;
|
return asyncResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool UpdateDocumentAnnotationsJob::prepareAsyncRun()
|
IAsyncJob::AsyncPrepareResult UpdateDocumentAnnotationsJob::prepareAsyncRun()
|
||||||
{
|
{
|
||||||
const JobRequest jobRequest = context().jobRequest;
|
const JobRequest jobRequest = context().jobRequest;
|
||||||
QTC_ASSERT(jobRequest.type == JobRequest::Type::UpdateDocumentAnnotations, return false);
|
QTC_ASSERT(jobRequest.type == JobRequest::Type::UpdateDocumentAnnotations,
|
||||||
|
return AsyncPrepareResult());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
m_pinnedDocument = context().documentForJobRequest();
|
m_pinnedDocument = context().documentForJobRequest();
|
||||||
m_pinnedFileContainer = m_pinnedDocument.fileContainer();
|
m_pinnedFileContainer = m_pinnedDocument.fileContainer();
|
||||||
|
|
||||||
const TranslationUnit translationUnit = m_pinnedDocument.translationUnit();
|
const TranslationUnit translationUnit
|
||||||
|
= m_pinnedDocument.translationUnit(jobRequest.preferredTranslationUnit);
|
||||||
const TranslationUnitUpdateInput updateInput = m_pinnedDocument.createUpdateInput();
|
const TranslationUnitUpdateInput updateInput = m_pinnedDocument.createUpdateInput();
|
||||||
setRunner([translationUnit, updateInput]() {
|
setRunner([translationUnit, updateInput]() {
|
||||||
return runAsyncHelper(translationUnit, updateInput);
|
return runAsyncHelper(translationUnit, updateInput);
|
||||||
});
|
});
|
||||||
|
return AsyncPrepareResult{translationUnit.id()};
|
||||||
|
|
||||||
} catch (const std::exception &exception) {
|
} catch (const std::exception &exception) {
|
||||||
qWarning() << "Error in UpdateDocumentAnnotationsJob::prepareAsyncRun:" << exception.what();
|
qWarning() << "Error in UpdateDocumentAnnotationsJob::prepareAsyncRun:" << exception.what();
|
||||||
return false;
|
return AsyncPrepareResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdateDocumentAnnotationsJob::finalizeAsyncRun()
|
void UpdateDocumentAnnotationsJob::finalizeAsyncRun()
|
||||||
@@ -94,6 +96,7 @@ void UpdateDocumentAnnotationsJob::sendAnnotations(const AsyncResult &result)
|
|||||||
{
|
{
|
||||||
const DocumentAnnotationsChangedMessage message(m_pinnedFileContainer,
|
const DocumentAnnotationsChangedMessage message(m_pinnedFileContainer,
|
||||||
result.diagnostics,
|
result.diagnostics,
|
||||||
|
result.firstHeaderErrorDiagnostic,
|
||||||
result.highlightingMarks,
|
result.highlightingMarks,
|
||||||
result.skippedSourceRanges);
|
result.skippedSourceRanges);
|
||||||
|
|
||||||
|
@@ -39,6 +39,7 @@ struct UpdateDocumentAnnotationsJobResult
|
|||||||
{
|
{
|
||||||
TranslationUnitUpdateResult updateResult;
|
TranslationUnitUpdateResult updateResult;
|
||||||
|
|
||||||
|
ClangBackEnd::DiagnosticContainer firstHeaderErrorDiagnostic;
|
||||||
QVector<ClangBackEnd::DiagnosticContainer> diagnostics;
|
QVector<ClangBackEnd::DiagnosticContainer> diagnostics;
|
||||||
QVector<HighlightingMarkContainer> highlightingMarks;
|
QVector<HighlightingMarkContainer> highlightingMarks;
|
||||||
QVector<SourceRangeContainer> skippedSourceRanges;
|
QVector<SourceRangeContainer> skippedSourceRanges;
|
||||||
@@ -49,7 +50,7 @@ class UpdateDocumentAnnotationsJob : public AsyncJob<UpdateDocumentAnnotationsJo
|
|||||||
public:
|
public:
|
||||||
using AsyncResult = UpdateDocumentAnnotationsJobResult;
|
using AsyncResult = UpdateDocumentAnnotationsJobResult;
|
||||||
|
|
||||||
bool prepareAsyncRun() override;
|
AsyncPrepareResult prepareAsyncRun() override;
|
||||||
void finalizeAsyncRun() override;
|
void finalizeAsyncRun() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@@ -213,16 +213,32 @@ SourceLocation Cursor::sourceLocation() const
|
|||||||
return clang_getCursorLocation(cxCursor);
|
return clang_getCursorLocation(cxCursor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CXSourceLocation Cursor::cxSourceLocation() const
|
||||||
|
{
|
||||||
|
return clang_getCursorLocation(cxCursor);
|
||||||
|
}
|
||||||
|
|
||||||
SourceRange Cursor::sourceRange() const
|
SourceRange Cursor::sourceRange() const
|
||||||
{
|
{
|
||||||
return clang_getCursorExtent(cxCursor);
|
return clang_getCursorExtent(cxCursor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CXSourceRange Cursor::cxSourceRange() const
|
||||||
|
{
|
||||||
|
return clang_getCursorExtent(cxCursor);
|
||||||
|
}
|
||||||
|
|
||||||
SourceRange Cursor::commentRange() const
|
SourceRange Cursor::commentRange() const
|
||||||
{
|
{
|
||||||
return clang_Cursor_getCommentRange(cxCursor);
|
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
|
Cursor Cursor::definition() const
|
||||||
{
|
{
|
||||||
return clang_getCursorDefinition(cxCursor);
|
return clang_getCursorDefinition(cxCursor);
|
||||||
@@ -279,32 +295,42 @@ Cursor Cursor::argument(int index) const
|
|||||||
{
|
{
|
||||||
return clang_Cursor_getArgument(cxCursor, index);
|
return clang_Cursor_getArgument(cxCursor, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
void collectOutputArguments(const Cursor &callExpression,
|
|
||||||
std::vector<Cursor> &outputArguments)
|
bool isNotUnexposedLValueReference(const Cursor &argument, const Type &argumentType)
|
||||||
{
|
{
|
||||||
auto callExpressionType = callExpression.referenced().type();
|
return !(argument.isUnexposed() && argumentType.isLValueReference());
|
||||||
auto argumentCount = callExpression.argumentCount();
|
}
|
||||||
outputArguments.reserve(argumentCount);
|
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
for (int argumentIndex = 0; argumentIndex < argumentCount; ++argumentIndex) {
|
||||||
auto argument = callExpression.argument(argumentIndex);
|
const Cursor argument = this->argument(argumentIndex);
|
||||||
auto argumentType = callExpressionType.argument(argumentIndex);
|
const Type argumentType = callExpressionType.argument(argumentIndex);
|
||||||
|
|
||||||
if (!argument.isUnexposed() && argumentType.isOutputParameter())
|
if (isNotUnexposedLValueReference(argument, argumentType)
|
||||||
outputArguments.push_back(callExpression.argument(argumentIndex));
|
&& argumentType.isOutputArgument()) {
|
||||||
|
outputArgumentRanges.push_back(argument.cxSourceRange());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<Cursor> Cursor::outputArguments() const
|
std::vector<CXSourceRange> Cursor::outputArgumentRanges() const
|
||||||
{
|
{
|
||||||
std::vector<Cursor> outputArguments;
|
std::vector<CXSourceRange> outputArgumentRanges;
|
||||||
|
|
||||||
if (kind() == CXCursor_CallExpr)
|
collectOutputArgumentRangesTo(outputArgumentRanges);
|
||||||
collectOutputArguments(*this, outputArguments);
|
|
||||||
|
|
||||||
return outputArguments;
|
return outputArgumentRanges;
|
||||||
}
|
}
|
||||||
|
|
||||||
CXCursorKind Cursor::kind() const
|
CXCursorKind Cursor::kind() const
|
||||||
@@ -317,6 +343,11 @@ bool operator==(const Cursor &first, const Cursor &second)
|
|||||||
return clang_equalCursors(first.cxCursor, second.cxCursor);
|
return clang_equalCursors(first.cxCursor, second.cxCursor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool operator!=(const Cursor &first, const Cursor &second)
|
||||||
|
{
|
||||||
|
return !(first == second);
|
||||||
|
}
|
||||||
|
|
||||||
void PrintTo(CXCursorKind cursorKind, ::std::ostream *os)
|
void PrintTo(CXCursorKind cursorKind, ::std::ostream *os)
|
||||||
{
|
{
|
||||||
ClangString cursorKindSpelling(clang_getCursorKindSpelling(cursorKind));
|
ClangString cursorKindSpelling(clang_getCursorKindSpelling(cursorKind));
|
||||||
|
@@ -78,8 +78,11 @@ public:
|
|||||||
Type nonPointerTupe() const;
|
Type nonPointerTupe() const;
|
||||||
|
|
||||||
SourceLocation sourceLocation() const;
|
SourceLocation sourceLocation() const;
|
||||||
|
CXSourceLocation cxSourceLocation() const;
|
||||||
SourceRange sourceRange() const;
|
SourceRange sourceRange() const;
|
||||||
|
CXSourceRange cxSourceRange() const;
|
||||||
SourceRange commentRange() const;
|
SourceRange commentRange() const;
|
||||||
|
bool hasSameSourceLocationAs(const Cursor &other) const;
|
||||||
|
|
||||||
Cursor definition() const;
|
Cursor definition() const;
|
||||||
Cursor canonical() const;
|
Cursor canonical() const;
|
||||||
@@ -90,7 +93,9 @@ public:
|
|||||||
Cursor functionBaseDeclaration() const;
|
Cursor functionBaseDeclaration() const;
|
||||||
Cursor functionBase() const;
|
Cursor functionBase() const;
|
||||||
Cursor argument(int index) const;
|
Cursor argument(int index) const;
|
||||||
std::vector<Cursor> outputArguments() const;
|
void collectOutputArgumentRangesTo(
|
||||||
|
std::vector<CXSourceRange> &outputArgumentRanges) const;
|
||||||
|
std::vector<CXSourceRange> outputArgumentRanges() const;
|
||||||
|
|
||||||
CXCursorKind kind() const;
|
CXCursorKind kind() const;
|
||||||
|
|
||||||
@@ -114,6 +119,7 @@ void Cursor::visit(VisitorCallback visitorCallback) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool operator==(const Cursor &first, const Cursor &second);
|
bool operator==(const Cursor &first, const Cursor &second);
|
||||||
|
bool operator!=(const Cursor &first, const Cursor &second);
|
||||||
|
|
||||||
void PrintTo(CXCursorKind cursorKind, ::std::ostream *os);
|
void PrintTo(CXCursorKind cursorKind, ::std::ostream *os);
|
||||||
void PrintTo(const Cursor &cursor, ::std::ostream* os);
|
void PrintTo(const Cursor &cursor, ::std::ostream* os);
|
||||||
|
@@ -30,6 +30,7 @@
|
|||||||
#include "highlightingmark.h"
|
#include "highlightingmark.h"
|
||||||
#include "sourcelocation.h"
|
#include "sourcelocation.h"
|
||||||
#include "sourcerange.h"
|
#include "sourcerange.h"
|
||||||
|
#include "sourcerangecontainer.h"
|
||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
@@ -39,16 +40,19 @@
|
|||||||
namespace ClangBackEnd {
|
namespace ClangBackEnd {
|
||||||
|
|
||||||
HighlightingMark::HighlightingMark(const CXCursor &cxCursor,
|
HighlightingMark::HighlightingMark(const CXCursor &cxCursor,
|
||||||
CXToken *cxToken,
|
CXToken *cxToken,
|
||||||
CXTranslationUnit cxTranslationUnit)
|
CXTranslationUnit cxTranslationUnit,
|
||||||
|
std::vector<CXSourceRange> ¤tOutputArgumentRanges)
|
||||||
|
: currentOutputArgumentRanges(¤tOutputArgumentRanges),
|
||||||
|
originalCursor(cxCursor)
|
||||||
{
|
{
|
||||||
const SourceRange sourceRange = clang_getTokenExtent(cxTranslationUnit, *cxToken);
|
const SourceRange sourceRange = clang_getTokenExtent(cxTranslationUnit, *cxToken);
|
||||||
const auto start = sourceRange.start();
|
const auto start = sourceRange.start();
|
||||||
const auto end = sourceRange.end();
|
const auto end = sourceRange.end();
|
||||||
|
|
||||||
originalCursor = cxCursor;
|
|
||||||
line = start.line();
|
line = start.line();
|
||||||
column = start.column();
|
column = start.column();
|
||||||
|
offset = start.offset();
|
||||||
length = end.offset() - start.offset();
|
length = end.offset() - start.offset();
|
||||||
collectKinds(cxToken, originalCursor);
|
collectKinds(cxToken, originalCursor);
|
||||||
}
|
}
|
||||||
@@ -159,6 +163,17 @@ void HighlightingMark::variableKind(const Cursor &cursor)
|
|||||||
types.mainHighlightingType = HighlightingType::LocalVariable;
|
types.mainHighlightingType = HighlightingType::LocalVariable;
|
||||||
else
|
else
|
||||||
types.mainHighlightingType = HighlightingType::GlobalVariable;
|
types.mainHighlightingType = HighlightingType::GlobalVariable;
|
||||||
|
|
||||||
|
if (isOutputArgument())
|
||||||
|
types.mixinHighlightingTypes.push_back(HighlightingType::OutputArgument);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HighlightingMark::fieldKind(const Cursor &)
|
||||||
|
{
|
||||||
|
types.mainHighlightingType = HighlightingType::Field;
|
||||||
|
|
||||||
|
if (isOutputArgument())
|
||||||
|
types.mixinHighlightingTypes.push_back(HighlightingType::OutputArgument);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HighlightingMark::isVirtualMethodDeclarationOrDefinition(const Cursor &cursor) const
|
bool HighlightingMark::isVirtualMethodDeclarationOrDefinition(const Cursor &cursor) const
|
||||||
@@ -185,6 +200,68 @@ void HighlightingMark::addExtraTypeIfFirstPass(HighlightingType type,
|
|||||||
types.mixinHighlightingTypes.push_back(type);
|
types.mixinHighlightingTypes.push_back(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool HighlightingMark::isArgumentInCurrentOutputArgumentLocations() const
|
||||||
|
{
|
||||||
|
auto originalSourceLocation = originalCursor.cxSourceLocation();
|
||||||
|
|
||||||
|
const auto isNotSameOutputArgument = [&] (const CXSourceRange ¤tSourceRange) {
|
||||||
|
return !(originalSourceLocation.int_data >= currentSourceRange.begin_int_data
|
||||||
|
&& originalSourceLocation.int_data <= currentSourceRange.end_int_data);
|
||||||
|
};
|
||||||
|
|
||||||
|
auto partitionPoint = std::partition(currentOutputArgumentRanges->begin(),
|
||||||
|
currentOutputArgumentRanges->end(),
|
||||||
|
isNotSameOutputArgument);
|
||||||
|
|
||||||
|
bool isOutputArgument = partitionPoint != currentOutputArgumentRanges->end();
|
||||||
|
|
||||||
|
if (isOutputArgument)
|
||||||
|
currentOutputArgumentRanges->erase(partitionPoint, currentOutputArgumentRanges->end());
|
||||||
|
|
||||||
|
return isOutputArgument;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HighlightingMark::isOutputArgument() const
|
||||||
|
{
|
||||||
|
if (currentOutputArgumentRanges->empty())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return isArgumentInCurrentOutputArgumentLocations();
|
||||||
|
}
|
||||||
|
|
||||||
|
void HighlightingMark::collectOutputArguments(const Cursor &cursor)
|
||||||
|
{
|
||||||
|
cursor.collectOutputArgumentRangesTo(*currentOutputArgumentRanges);
|
||||||
|
filterOutPreviousOutputArguments();
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
uint getStart(CXSourceRange cxSourceRange)
|
||||||
|
{
|
||||||
|
CXSourceLocation startSourceLocation = clang_getRangeStart(cxSourceRange);
|
||||||
|
|
||||||
|
uint startOffset;
|
||||||
|
|
||||||
|
clang_getFileLocation(startSourceLocation, nullptr, nullptr, nullptr, &startOffset);
|
||||||
|
|
||||||
|
return startOffset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void HighlightingMark::filterOutPreviousOutputArguments()
|
||||||
|
{
|
||||||
|
auto isAfterLocation = [this] (CXSourceRange outputRange) {
|
||||||
|
return getStart(outputRange) > offset;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto precedingBegin = std::partition(currentOutputArgumentRanges->begin(),
|
||||||
|
currentOutputArgumentRanges->end(),
|
||||||
|
isAfterLocation);
|
||||||
|
|
||||||
|
currentOutputArgumentRanges->erase(precedingBegin, currentOutputArgumentRanges->end());
|
||||||
|
}
|
||||||
|
|
||||||
void HighlightingMark::functionKind(const Cursor &cursor, Recursion recursion)
|
void HighlightingMark::functionKind(const Cursor &cursor, Recursion recursion)
|
||||||
{
|
{
|
||||||
if (isRealDynamicCall(cursor) || isVirtualMethodDeclarationOrDefinition(cursor))
|
if (isRealDynamicCall(cursor) || isVirtualMethodDeclarationOrDefinition(cursor))
|
||||||
@@ -204,12 +281,13 @@ void HighlightingMark::identifierKind(const Cursor &cursor, Recursion recursion)
|
|||||||
case CXCursor_CallExpr:
|
case CXCursor_CallExpr:
|
||||||
case CXCursor_CXXMethod: functionKind(cursor, recursion); break;
|
case CXCursor_CXXMethod: functionKind(cursor, recursion); break;
|
||||||
case CXCursor_NonTypeTemplateParameter:
|
case CXCursor_NonTypeTemplateParameter:
|
||||||
case CXCursor_ParmDecl: types.mainHighlightingType = HighlightingType::LocalVariable; break;
|
case CXCursor_CompoundStmt: types.mainHighlightingType = HighlightingType::LocalVariable; break;
|
||||||
|
case CXCursor_ParmDecl:
|
||||||
case CXCursor_VarDecl: variableKind(cursor); break;
|
case CXCursor_VarDecl: variableKind(cursor); break;
|
||||||
case CXCursor_DeclRefExpr: identifierKind(cursor.referenced(), Recursion::RecursivePass); break;
|
case CXCursor_DeclRefExpr: identifierKind(cursor.referenced(), Recursion::RecursivePass); break;
|
||||||
case CXCursor_MemberRefExpr: memberReferenceKind(cursor); break;
|
case CXCursor_MemberRefExpr: memberReferenceKind(cursor); break;
|
||||||
case CXCursor_FieldDecl:
|
case CXCursor_FieldDecl:
|
||||||
case CXCursor_MemberRef:
|
case CXCursor_MemberRef: fieldKind(cursor); break;
|
||||||
case CXCursor_ObjCIvarDecl:
|
case CXCursor_ObjCIvarDecl:
|
||||||
case CXCursor_ObjCPropertyDecl:
|
case CXCursor_ObjCPropertyDecl:
|
||||||
case CXCursor_ObjCClassMethodDecl:
|
case CXCursor_ObjCClassMethodDecl:
|
||||||
@@ -282,15 +360,17 @@ HighlightingType operatorKind(const Cursor &cursor)
|
|||||||
return HighlightingType::Invalid;
|
return HighlightingType::Invalid;
|
||||||
}
|
}
|
||||||
|
|
||||||
HighlightingType punctationKind(const Cursor &cursor)
|
}
|
||||||
|
|
||||||
|
HighlightingType HighlightingMark::punctuationKind(const Cursor &cursor)
|
||||||
{
|
{
|
||||||
switch (cursor.kind()) {
|
switch (cursor.kind()) {
|
||||||
case CXCursor_DeclRefExpr: return operatorKind(cursor);
|
case CXCursor_DeclRefExpr: return operatorKind(cursor);
|
||||||
|
case CXCursor_CallExpr: collectOutputArguments(cursor);
|
||||||
default: return HighlightingType::Invalid;
|
default: return HighlightingType::Invalid;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
void HighlightingMark::collectKinds(CXToken *cxToken, const Cursor &cursor)
|
void HighlightingMark::collectKinds(CXToken *cxToken, const Cursor &cursor)
|
||||||
{
|
{
|
||||||
auto cxTokenKind = clang_getTokenKind(*cxToken);
|
auto cxTokenKind = clang_getTokenKind(*cxToken);
|
||||||
@@ -299,7 +379,7 @@ void HighlightingMark::collectKinds(CXToken *cxToken, const Cursor &cursor)
|
|||||||
|
|
||||||
switch (cxTokenKind) {
|
switch (cxTokenKind) {
|
||||||
case CXToken_Keyword: types.mainHighlightingType = HighlightingType::Keyword; break;
|
case CXToken_Keyword: types.mainHighlightingType = HighlightingType::Keyword; break;
|
||||||
case CXToken_Punctuation: types.mainHighlightingType = punctationKind(cursor); break;
|
case CXToken_Punctuation: types.mainHighlightingType = punctuationKind(cursor); break;
|
||||||
case CXToken_Identifier: identifierKind(cursor, Recursion::FirstPass); break;
|
case CXToken_Identifier: identifierKind(cursor, Recursion::FirstPass); break;
|
||||||
case CXToken_Comment: types.mainHighlightingType = HighlightingType::Comment; break;
|
case CXToken_Comment: types.mainHighlightingType = HighlightingType::Comment; break;
|
||||||
case CXToken_Literal: types.mainHighlightingType = literalKind(cursor); break;
|
case CXToken_Literal: types.mainHighlightingType = literalKind(cursor); break;
|
||||||
|
@@ -45,7 +45,10 @@ class HighlightingMark
|
|||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
HighlightingMark(const CXCursor &cxCursor, CXToken *cxToken, CXTranslationUnit cxTranslationUnit);
|
HighlightingMark(const CXCursor &cxCursor,
|
||||||
|
CXToken *cxToken,
|
||||||
|
CXTranslationUnit cxTranslationUnit,
|
||||||
|
std::vector<CXSourceRange> ¤tOutputArgumentRanges);
|
||||||
HighlightingMark(uint line, uint column, uint length, HighlightingTypes types);
|
HighlightingMark(uint line, uint column, uint length, HighlightingTypes types);
|
||||||
HighlightingMark(uint line, uint column, uint length, HighlightingType type);
|
HighlightingMark(uint line, uint column, uint length, HighlightingType type);
|
||||||
|
|
||||||
@@ -61,18 +64,26 @@ private:
|
|||||||
void identifierKind(const Cursor &cursor, Recursion recursion);
|
void identifierKind(const Cursor &cursor, Recursion recursion);
|
||||||
void referencedTypeKind(const Cursor &cursor);
|
void referencedTypeKind(const Cursor &cursor);
|
||||||
void variableKind(const Cursor &cursor);
|
void variableKind(const Cursor &cursor);
|
||||||
|
void fieldKind(const Cursor &cursor);
|
||||||
bool isVirtualMethodDeclarationOrDefinition(const Cursor &cursor) const;
|
bool isVirtualMethodDeclarationOrDefinition(const Cursor &cursor) const;
|
||||||
void functionKind(const Cursor &cursor, Recursion recursion);
|
void functionKind(const Cursor &cursor, Recursion recursion);
|
||||||
void memberReferenceKind(const Cursor &cursor);
|
void memberReferenceKind(const Cursor &cursor);
|
||||||
|
HighlightingType punctuationKind(const Cursor &cursor);
|
||||||
void collectKinds(CXToken *cxToken, const Cursor &cursor);
|
void collectKinds(CXToken *cxToken, const Cursor &cursor);
|
||||||
bool isRealDynamicCall(const Cursor &cursor) const;
|
bool isRealDynamicCall(const Cursor &cursor) const;
|
||||||
void addExtraTypeIfFirstPass(HighlightingType type, Recursion recursion);
|
void addExtraTypeIfFirstPass(HighlightingType type, Recursion recursion);
|
||||||
|
bool isOutputArgument() const;
|
||||||
|
void collectOutputArguments(const Cursor &cursor);
|
||||||
|
void filterOutPreviousOutputArguments();
|
||||||
|
bool isArgumentInCurrentOutputArgumentLocations() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
std::vector<CXSourceRange> *currentOutputArgumentRanges = nullptr;
|
||||||
Cursor originalCursor;
|
Cursor originalCursor;
|
||||||
uint line;
|
uint line;
|
||||||
uint column;
|
uint column;
|
||||||
uint length;
|
uint length;
|
||||||
|
uint offset = 0;
|
||||||
HighlightingTypes types;
|
HighlightingTypes types;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -47,12 +47,18 @@ HighlightingMarks::~HighlightingMarks()
|
|||||||
|
|
||||||
HighlightingMarks::const_iterator HighlightingMarks::begin() const
|
HighlightingMarks::const_iterator HighlightingMarks::begin() const
|
||||||
{
|
{
|
||||||
return const_iterator(cxCursor.cbegin(), cxToken, cxTranslationUnit);
|
return const_iterator(cxCursor.cbegin(),
|
||||||
|
cxToken,
|
||||||
|
cxTranslationUnit,
|
||||||
|
currentOutputArgumentRanges);
|
||||||
}
|
}
|
||||||
|
|
||||||
HighlightingMarks::const_iterator HighlightingMarks::end() const
|
HighlightingMarks::const_iterator HighlightingMarks::end() const
|
||||||
{
|
{
|
||||||
return const_iterator(cxCursor.cend(), cxToken + cxTokenCount, cxTranslationUnit);
|
return const_iterator(cxCursor.cend(),
|
||||||
|
cxToken + cxTokenCount,
|
||||||
|
cxTranslationUnit,
|
||||||
|
currentOutputArgumentRanges);
|
||||||
}
|
}
|
||||||
|
|
||||||
QVector<HighlightingMarkContainer> HighlightingMarks::toHighlightingMarksContainers() const
|
QVector<HighlightingMarkContainer> HighlightingMarks::toHighlightingMarksContainers() const
|
||||||
@@ -67,11 +73,19 @@ QVector<HighlightingMarkContainer> HighlightingMarks::toHighlightingMarksContain
|
|||||||
&& !highlightMark.hasMainType(HighlightingType::Comment);
|
&& !highlightMark.hasMainType(HighlightingType::Comment);
|
||||||
};
|
};
|
||||||
|
|
||||||
std::copy_if(begin(), end(), std::back_inserter(containers), isValidHighlightMark);
|
for (const HighlightingMark &highlightMark : *this) {
|
||||||
|
if (isValidHighlightMark(highlightMark))
|
||||||
|
containers.push_back(highlightMark);
|
||||||
|
}
|
||||||
|
|
||||||
return containers;
|
return containers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool HighlightingMarks::currentOutputArgumentRangesAreEmpty() const
|
||||||
|
{
|
||||||
|
return currentOutputArgumentRanges.empty();
|
||||||
|
}
|
||||||
|
|
||||||
bool HighlightingMarks::isEmpty() const
|
bool HighlightingMarks::isEmpty() const
|
||||||
{
|
{
|
||||||
return cxTokenCount == 0;
|
return cxTokenCount == 0;
|
||||||
@@ -89,7 +103,10 @@ uint HighlightingMarks::size() const
|
|||||||
|
|
||||||
HighlightingMark HighlightingMarks::operator[](size_t index) const
|
HighlightingMark HighlightingMarks::operator[](size_t index) const
|
||||||
{
|
{
|
||||||
return HighlightingMark(cxCursor[index], cxToken + index, cxTranslationUnit);
|
return HighlightingMark(cxCursor[index],
|
||||||
|
cxToken + index,
|
||||||
|
cxTranslationUnit,
|
||||||
|
currentOutputArgumentRanges);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace ClangBackEnd
|
} // 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