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
|
||||
case.
|
||||
|
||||
\li \c isPassword is a boolean value that specifies that the line edit
|
||||
contains a password, which will be masked.
|
||||
|
||||
\endlist
|
||||
|
||||
\section2 Path Chooser
|
||||
|
@@ -63,7 +63,8 @@ Module {
|
||||
"QT_CREATOR",
|
||||
'IDE_LIBRARY_BASENAME="' + libDirName + '"',
|
||||
"QT_NO_CAST_TO_ASCII",
|
||||
"QT_RESTRICTED_CAST_FROM_ASCII"
|
||||
"QT_RESTRICTED_CAST_FROM_ASCII",
|
||||
"QT_DISABLE_DEPRECATED_BEFORE=0x050600",
|
||||
].concat(testsEnabled ? ["WITH_TESTS"] : [])
|
||||
|
||||
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 += 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
|
||||
|
||||
unix {
|
||||
|
@@ -37,6 +37,7 @@ QDebug operator<<(QDebug debug, const DocumentAnnotationsChangedMessage &message
|
||||
debug.nospace() << "DocumentAnnotationsChangedMessage("
|
||||
<< message.fileContainer()
|
||||
<< ", " << message.diagnostics().size()
|
||||
<< ", " << !message.firstHeaderErrorDiagnostic().text().isEmpty()
|
||||
<< ", " << message.highlightingMarks().size()
|
||||
<< ", " << message.skippedPreprocessorRanges().size()
|
||||
<< ")";
|
||||
@@ -49,6 +50,7 @@ void PrintTo(const DocumentAnnotationsChangedMessage &message, ::std::ostream* o
|
||||
*os << "DocumentAnnotationsChangedMessage(";
|
||||
PrintTo(message.fileContainer(), os);
|
||||
*os << "," << message.diagnostics().size();
|
||||
*os << "," << !message.firstHeaderErrorDiagnostic().text().isEmpty();
|
||||
*os << "," << message.highlightingMarks().size();
|
||||
*os << "," << message.skippedPreprocessorRanges().size();
|
||||
*os << ")";
|
||||
|
@@ -41,10 +41,12 @@ public:
|
||||
DocumentAnnotationsChangedMessage() = default;
|
||||
DocumentAnnotationsChangedMessage(const FileContainer &fileContainer,
|
||||
const QVector<DiagnosticContainer> &diagnostics,
|
||||
const DiagnosticContainer &firstHeaderErrorDiagnostic_,
|
||||
const QVector<HighlightingMarkContainer> &highlightingMarks,
|
||||
const QVector<SourceRangeContainer> &skippedPreprocessorRanges)
|
||||
: fileContainer_(fileContainer),
|
||||
diagnostics_(diagnostics),
|
||||
firstHeaderErrorDiagnostic_(firstHeaderErrorDiagnostic_),
|
||||
highlightingMarks_(highlightingMarks),
|
||||
skippedPreprocessorRanges_(skippedPreprocessorRanges)
|
||||
{
|
||||
@@ -60,6 +62,11 @@ public:
|
||||
return diagnostics_;
|
||||
}
|
||||
|
||||
const DiagnosticContainer &firstHeaderErrorDiagnostic() const
|
||||
{
|
||||
return firstHeaderErrorDiagnostic_;
|
||||
}
|
||||
|
||||
const QVector<HighlightingMarkContainer> &highlightingMarks() const
|
||||
{
|
||||
return highlightingMarks_;
|
||||
@@ -74,6 +81,7 @@ public:
|
||||
{
|
||||
out << message.fileContainer_;
|
||||
out << message.diagnostics_;
|
||||
out << message.firstHeaderErrorDiagnostic_;
|
||||
out << message.highlightingMarks_;
|
||||
out << message.skippedPreprocessorRanges_;
|
||||
|
||||
@@ -84,6 +92,7 @@ public:
|
||||
{
|
||||
in >> message.fileContainer_;
|
||||
in >> message.diagnostics_;
|
||||
in >> message.firstHeaderErrorDiagnostic_;
|
||||
in >> message.highlightingMarks_;
|
||||
in >> message.skippedPreprocessorRanges_;
|
||||
|
||||
@@ -95,6 +104,7 @@ public:
|
||||
{
|
||||
return first.fileContainer_ == second.fileContainer_
|
||||
&& first.diagnostics_ == second.diagnostics_
|
||||
&& first.firstHeaderErrorDiagnostic_ == second.firstHeaderErrorDiagnostic_
|
||||
&& first.highlightingMarks_ == second.highlightingMarks_
|
||||
&& first.skippedPreprocessorRanges_ == second.skippedPreprocessorRanges_;
|
||||
}
|
||||
@@ -102,6 +112,7 @@ public:
|
||||
private:
|
||||
FileContainer fileContainer_;
|
||||
QVector<DiagnosticContainer> diagnostics_;
|
||||
DiagnosticContainer firstHeaderErrorDiagnostic_;
|
||||
QVector<HighlightingMarkContainer> highlightingMarks_;
|
||||
QVector<SourceRangeContainer> skippedPreprocessorRanges_;
|
||||
};
|
||||
|
@@ -32,6 +32,7 @@
|
||||
|
||||
#include <coreplugin/editormanager/editormanager.h>
|
||||
#include <coreplugin/icore.h>
|
||||
#include <coreplugin/messagemanager.h>
|
||||
|
||||
#include <cpptools/abstracteditorsupport.h>
|
||||
#include <cpptools/baseeditordocumentprocessor.h>
|
||||
@@ -68,6 +69,7 @@
|
||||
|
||||
#include <cplusplus/Icons.h>
|
||||
|
||||
#include <QDir>
|
||||
#include <QElapsedTimer>
|
||||
#include <QLoggingCategory>
|
||||
#include <QProcess>
|
||||
@@ -180,7 +182,9 @@ void IpcReceiver::documentAnnotationsChanged(const DocumentAnnotationsChangedMes
|
||||
const QString documentProjectPartId = CppTools::CppToolsBridge::projectPartIdForFile(filePath);
|
||||
if (projectPartId == documentProjectPartId) {
|
||||
const quint32 documentRevision = message.fileContainer().documentRevision();
|
||||
processor->updateCodeWarnings(message.diagnostics(), documentRevision);
|
||||
processor->updateCodeWarnings(message.diagnostics(),
|
||||
message.firstHeaderErrorDiagnostic(),
|
||||
documentRevision);
|
||||
processor->updateHighlighting(message.highlightingMarks(),
|
||||
message.skippedPreprocessorRanges(),
|
||||
documentRevision);
|
||||
@@ -304,10 +308,16 @@ public:
|
||||
void updateVisibleTranslationUnits(const UpdateVisibleTranslationUnitsMessage &) override {}
|
||||
};
|
||||
|
||||
enum { backEndStartTimeOutInMs = 10000 };
|
||||
|
||||
IpcCommunicator::IpcCommunicator()
|
||||
: m_connection(&m_ipcReceiver)
|
||||
, m_ipcSender(new DummyIpcSender)
|
||||
{
|
||||
m_backendStartTimeOut.setSingleShot(true);
|
||||
connect(&m_backendStartTimeOut, &QTimer::timeout,
|
||||
this, &IpcCommunicator::logStartTimeOut);
|
||||
|
||||
m_ipcReceiver.setAliveHandler([this]() { m_connection.resetProcessAliveTimer(); });
|
||||
|
||||
connect(Core::EditorManager::instance(), &Core::EditorManager::editorAboutToClose,
|
||||
@@ -326,8 +336,11 @@ IpcCommunicator::~IpcCommunicator()
|
||||
void IpcCommunicator::initializeBackend()
|
||||
{
|
||||
const QString clangBackEndProcessPath = backendProcessPath();
|
||||
if (!QFileInfo(clangBackEndProcessPath).exists()) {
|
||||
logExecutableDoesNotExist();
|
||||
return;
|
||||
}
|
||||
qCDebug(log) << "Starting" << clangBackEndProcessPath;
|
||||
QTC_ASSERT(QFileInfo(clangBackEndProcessPath).exists(), return);
|
||||
|
||||
m_connection.setProcessAliveTimerInterval(30 * 1000);
|
||||
m_connection.setProcessPath(clangBackEndProcessPath);
|
||||
@@ -338,6 +351,7 @@ void IpcCommunicator::initializeBackend()
|
||||
this, &IpcCommunicator::setupDummySender);
|
||||
|
||||
m_connection.startProcessAndConnectToServerAsynchronously();
|
||||
m_backendStartTimeOut.start(backEndStartTimeOutInMs);
|
||||
}
|
||||
|
||||
static QStringList projectPartOptions(const CppTools::ProjectPart::Ptr &projectPart)
|
||||
@@ -622,11 +636,11 @@ void IpcCommunicator::updateUnsavedFile(Core::IDocument *document)
|
||||
|
||||
void IpcCommunicator::onConnectedToBackend()
|
||||
{
|
||||
m_backendStartTimeOut.stop();
|
||||
|
||||
++m_connectedCount;
|
||||
if (m_connectedCount > 1) {
|
||||
qWarning("Clang back end finished unexpectedly, restarted.");
|
||||
qCDebug(log) << "Backend restarted, re-initializing with project data and unsaved files.";
|
||||
}
|
||||
if (m_connectedCount > 1)
|
||||
logRestartedDueToUnexpectedFinish();
|
||||
|
||||
m_ipcReceiver.deleteAndClearWaitingAssistProcessors();
|
||||
m_ipcSender.reset(new IpcSender(m_connection));
|
||||
@@ -645,6 +659,42 @@ void IpcCommunicator::setupDummySender()
|
||||
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()
|
||||
{
|
||||
registerFallbackProjectPart();
|
||||
|
@@ -171,12 +171,18 @@ private:
|
||||
void onDisconnectedFromBackend();
|
||||
void onEditorAboutToClose(Core::IEditor *editor);
|
||||
|
||||
void logExecutableDoesNotExist();
|
||||
void logRestartedDueToUnexpectedFinish();
|
||||
void logStartTimeOut();
|
||||
void logError(const QString &text);
|
||||
|
||||
void updateTranslationUnitVisiblity(const Utf8String ¤tEditorFilePath,
|
||||
const Utf8StringVector &visibleEditorsFilePaths);
|
||||
|
||||
private:
|
||||
IpcReceiver m_ipcReceiver;
|
||||
ClangBackEnd::ClangCodeModelConnectionClient m_connection;
|
||||
QTimer m_backendStartTimeOut;
|
||||
QScopedPointer<IpcSenderInterface> m_ipcSender;
|
||||
int m_connectedCount = 0;
|
||||
};
|
||||
|
@@ -41,6 +41,7 @@
|
||||
#include <utils/proxyaction.h>
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
#include <QFileInfo>
|
||||
#include <QTextBlock>
|
||||
|
||||
namespace {
|
||||
|
@@ -129,9 +129,10 @@ enum IndentType { IndentDiagnostic, DoNotIndentDiagnostic };
|
||||
|
||||
QWidget *createDiagnosticLabel(const ClangBackEnd::DiagnosticContainer &diagnostic,
|
||||
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 text = clickableLocation(mainFilePath, diagnostic.location())
|
||||
+ QStringLiteral(": ")
|
||||
@@ -159,15 +160,18 @@ class MainDiagnosticWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
MainDiagnosticWidget(const ClangBackEnd::DiagnosticContainer &diagnostic)
|
||||
MainDiagnosticWidget(const ClangBackEnd::DiagnosticContainer &diagnostic,
|
||||
const ClangCodeModel::Internal::DisplayHints &displayHints)
|
||||
{
|
||||
setContentsMargins(0, 0, 0, 0);
|
||||
auto *mainLayout = createLayout<QVBoxLayout>();
|
||||
|
||||
const ClangBackEnd::SourceLocationContainer location = diagnostic.location();
|
||||
|
||||
// Set up header row: category + responsible option
|
||||
if (displayHints.showMainDiagnosticHeader) {
|
||||
const QString category = diagnostic.category();
|
||||
const QString responsibleOption = diagnostic.enableOption();
|
||||
const ClangBackEnd::SourceLocationContainer location = diagnostic.location();
|
||||
|
||||
auto *headerLayout = createLayout<QHBoxLayout>();
|
||||
headerLayout->addWidget(new QLabel(wrapInBoldTags(category)), 1);
|
||||
@@ -175,9 +179,16 @@ public:
|
||||
auto *responsibleOptionLabel = new QLabel(wrapInColor(responsibleOption, "gray"));
|
||||
headerLayout->addWidget(responsibleOptionLabel, 0);
|
||||
mainLayout->addLayout(headerLayout);
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
@@ -186,26 +197,35 @@ public:
|
||||
void addChildrenToLayout(const QString &mainFilePath,
|
||||
const QVector<ClangBackEnd::DiagnosticContainer>::const_iterator first,
|
||||
const QVector<ClangBackEnd::DiagnosticContainer>::const_iterator last,
|
||||
bool enableClickableFixits,
|
||||
QLayout &boxLayout)
|
||||
{
|
||||
for (auto it = first; it != last; ++it)
|
||||
boxLayout.addWidget(createDiagnosticLabel(*it, mainFilePath, IndentDiagnostic));
|
||||
for (auto it = first; it != last; ++it) {
|
||||
boxLayout.addWidget(createDiagnosticLabel(*it,
|
||||
mainFilePath,
|
||||
IndentDiagnostic,
|
||||
enableClickableFixits));
|
||||
}
|
||||
}
|
||||
|
||||
void setupChildDiagnostics(const QString &mainFilePath,
|
||||
const QVector<ClangBackEnd::DiagnosticContainer> &diagnostics,
|
||||
bool enableClickableFixits,
|
||||
QLayout &boxLayout)
|
||||
{
|
||||
if (diagnostics.size() <= 10) {
|
||||
addChildrenToLayout(mainFilePath, diagnostics.begin(), diagnostics.end(), boxLayout);
|
||||
addChildrenToLayout(mainFilePath, diagnostics.begin(), diagnostics.end(),
|
||||
enableClickableFixits, boxLayout);
|
||||
} else {
|
||||
addChildrenToLayout(mainFilePath, diagnostics.begin(), diagnostics.begin() + 7, boxLayout);
|
||||
addChildrenToLayout(mainFilePath, diagnostics.begin(), diagnostics.begin() + 7,
|
||||
enableClickableFixits, boxLayout);
|
||||
|
||||
auto ellipsisLabel = new QLabel(QStringLiteral("..."));
|
||||
ellipsisLabel->setContentsMargins(childIndentationOnTheLeftInPixel, 0, 0, 0);
|
||||
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 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
|
||||
target->addWidget(new MainDiagnosticWidget(diagnostic));
|
||||
target->addWidget(new MainDiagnosticWidget(diagnostic, displayHints));
|
||||
|
||||
// Set up child rows for notes
|
||||
setupChildDiagnostics(diagnostic.location().filePath(), diagnostic.children(), *target);
|
||||
setupChildDiagnostics(diagnostic.location().filePath(),
|
||||
diagnostic.children(),
|
||||
displayHints.enableClickableFixits,
|
||||
*target);
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
|
@@ -34,7 +34,15 @@ QT_END_NAMESPACE
|
||||
namespace ClangCodeModel {
|
||||
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 ClangCodeModel
|
||||
|
@@ -57,6 +57,8 @@
|
||||
#include <utils/runextensions.h>
|
||||
|
||||
#include <QTextBlock>
|
||||
#include <QVBoxLayout>
|
||||
#include <QWidget>
|
||||
|
||||
namespace ClangCodeModel {
|
||||
namespace Internal {
|
||||
@@ -72,6 +74,11 @@ ClangEditorDocumentProcessor::ClangEditorDocumentProcessor(
|
||||
, m_semanticHighlighter(document)
|
||||
, 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
|
||||
// editor (widget) related features that are not yet implemented by the clang plugin.
|
||||
connect(&m_builtinProcessor, &CppTools::BuiltinEditorDocumentProcessor::cppDocumentUpdated,
|
||||
@@ -82,6 +89,8 @@ ClangEditorDocumentProcessor::ClangEditorDocumentProcessor(
|
||||
|
||||
ClangEditorDocumentProcessor::~ClangEditorDocumentProcessor()
|
||||
{
|
||||
m_updateTranslationUnitTimer.stop();
|
||||
|
||||
m_parserWatcher.cancel();
|
||||
m_parserWatcher.waitForFinished();
|
||||
|
||||
@@ -93,7 +102,7 @@ ClangEditorDocumentProcessor::~ClangEditorDocumentProcessor()
|
||||
|
||||
void ClangEditorDocumentProcessor::run()
|
||||
{
|
||||
updateTranslationUnitIfProjectPartExists();
|
||||
m_updateTranslationUnitTimer.start();
|
||||
|
||||
// Run clang parser
|
||||
disconnect(&m_parserWatcher, &QFutureWatcher<void>::finished,
|
||||
@@ -160,14 +169,21 @@ void ClangEditorDocumentProcessor::clearProjectPart()
|
||||
m_projectPart.clear();
|
||||
}
|
||||
|
||||
void ClangEditorDocumentProcessor::updateCodeWarnings(const QVector<ClangBackEnd::DiagnosticContainer> &diagnostics,
|
||||
void ClangEditorDocumentProcessor::updateCodeWarnings(
|
||||
const QVector<ClangBackEnd::DiagnosticContainer> &diagnostics,
|
||||
const ClangBackEnd::DiagnosticContainer &firstHeaderErrorDiagnostic,
|
||||
uint documentRevision)
|
||||
{
|
||||
if (documentRevision == revision()) {
|
||||
m_diagnosticManager.processNewDiagnostics(diagnostics);
|
||||
const auto codeWarnings = m_diagnosticManager.takeExtraSelections();
|
||||
const auto fixitAvailableMarkers = m_diagnosticManager.takeFixItAvailableMarkers();
|
||||
emit codeWarningsUpdated(revision(), codeWarnings, fixitAvailableMarkers);
|
||||
const auto creator = creatorForHeaderErrorDiagnosticWidget(firstHeaderErrorDiagnostic);
|
||||
|
||||
emit codeWarningsUpdated(revision(),
|
||||
codeWarnings,
|
||||
creator,
|
||||
fixitAvailableMarkers);
|
||||
}
|
||||
}
|
||||
namespace {
|
||||
@@ -251,6 +267,11 @@ void ClangEditorDocumentProcessor::addDiagnosticToolTipToLayout(uint line,
|
||||
addToolTipToLayout(diagnostic, target);
|
||||
}
|
||||
|
||||
void ClangEditorDocumentProcessor::editorDocumentTimerRestarted()
|
||||
{
|
||||
m_updateTranslationUnitTimer.stop(); // Wait for the next call to run().
|
||||
}
|
||||
|
||||
ClangBackEnd::FileContainer ClangEditorDocumentProcessor::fileContainerWithArguments() const
|
||||
{
|
||||
return fileContainerWithArguments(m_projectPart.data());
|
||||
@@ -321,6 +342,38 @@ void ClangEditorDocumentProcessor::requestDocumentAnnotations(const QString &pro
|
||||
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)
|
||||
{
|
||||
if (projectPart)
|
||||
|
@@ -32,6 +32,7 @@
|
||||
#include <cpptools/semantichighlighter.h>
|
||||
|
||||
#include <QFutureWatcher>
|
||||
#include <QTimer>
|
||||
|
||||
namespace ClangBackEnd {
|
||||
class DiagnosticContainer;
|
||||
@@ -67,6 +68,7 @@ public:
|
||||
void clearProjectPart();
|
||||
|
||||
void updateCodeWarnings(const QVector<ClangBackEnd::DiagnosticContainer> &diagnostics,
|
||||
const ClangBackEnd::DiagnosticContainer &firstHeaderErrorDiagnostic,
|
||||
uint documentRevision);
|
||||
void updateHighlighting(const QVector<ClangBackEnd::HighlightingMarkContainer> &highlightingMarks,
|
||||
const QVector<ClangBackEnd::SourceRangeContainer> &skippedPreprocessorRanges,
|
||||
@@ -78,6 +80,8 @@ public:
|
||||
bool hasDiagnosticsAt(uint line, uint column) const override;
|
||||
void addDiagnosticToolTipToLayout(uint line, uint column, QLayout *target) const override;
|
||||
|
||||
void editorDocumentTimerRestarted() override;
|
||||
|
||||
ClangBackEnd::FileContainer fileContainerWithArguments() const;
|
||||
|
||||
void clearDiagnosticsWithFixIts();
|
||||
@@ -93,6 +97,8 @@ private:
|
||||
void registerTranslationUnitForEditor(CppTools::ProjectPart *projectPart);
|
||||
void updateTranslationUnitIfProjectPartExists();
|
||||
void requestDocumentAnnotations(const QString &projectpartId);
|
||||
HeaderErrorDiagnosticWidgetCreator creatorForHeaderErrorDiagnosticWidget(
|
||||
const ClangBackEnd::DiagnosticContainer &firstHeaderErrorDiagnostic);
|
||||
ClangBackEnd::FileContainer fileContainerWithArguments(CppTools::ProjectPart *projectPart) const;
|
||||
ClangBackEnd::FileContainer fileContainerWithDocumentContent(const QString &projectpartId) const;
|
||||
|
||||
@@ -102,6 +108,7 @@ private:
|
||||
QSharedPointer<ClangEditorDocumentParser> m_parser;
|
||||
CppTools::ProjectPart::Ptr m_projectPart;
|
||||
QFutureWatcher<void> m_parserWatcher;
|
||||
QTimer m_updateTranslationUnitTimer;
|
||||
unsigned m_parserRevision;
|
||||
|
||||
CppTools::SemanticHighlighter m_semanticHighlighter;
|
||||
|
@@ -60,6 +60,8 @@ TextEditor::TextStyle toTextStyle(ClangBackEnd::HighlightingType type)
|
||||
return TextEditor::C_PREPROCESSOR;
|
||||
case HighlightingType::Declaration:
|
||||
return TextEditor::C_DECLARATION;
|
||||
case HighlightingType::OutputArgument:
|
||||
return TextEditor::C_OUTPUT_ARGUMENT;
|
||||
default:
|
||||
return TextEditor::C_TEXT; // never called
|
||||
}
|
||||
|
@@ -84,7 +84,7 @@ void ClangTextMark::setIcon(ClangBackEnd::DiagnosticSeverity severity)
|
||||
|
||||
bool ClangTextMark::addToolTipContent(QLayout *target)
|
||||
{
|
||||
Internal::addToolTipToLayout(m_diagnostic, target);
|
||||
Internal::addToolTipToLayout(m_diagnostic, target, Internal::DisplayHints());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@@ -36,12 +36,16 @@
|
||||
#include <coreplugin/messagemanager.h>
|
||||
#include <coreplugin/editormanager/editormanager.h>
|
||||
#include <coreplugin/progressmanager/progressmanager.h>
|
||||
#include <cpptools/projectpartbuilder.h>
|
||||
#include <projectexplorer/headerpath.h>
|
||||
#include <projectexplorer/kit.h>
|
||||
#include <projectexplorer/kitinformation.h>
|
||||
#include <projectexplorer/project.h>
|
||||
#include <projectexplorer/projectexplorerconstants.h>
|
||||
#include <projectexplorer/projectnodes.h>
|
||||
#include <projectexplorer/target.h>
|
||||
#include <projectexplorer/taskhub.h>
|
||||
#include <projectexplorer/toolchain.h>
|
||||
|
||||
#include <utils/algorithm.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!
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
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()
|
||||
{
|
||||
if (m_tempDir) // always throw away changes in the tmpdir!
|
||||
@@ -656,6 +794,7 @@ CMakeConfig BuildDirManager::parseConfiguration(const Utils::FileName &cacheFile
|
||||
}
|
||||
|
||||
QSet<QByteArray> advancedSet;
|
||||
QMap<QByteArray, QByteArray> valuesMap;
|
||||
QByteArray documentation;
|
||||
while (!cache.atEnd()) {
|
||||
const QByteArray line = trimCMakeCacheLine(cache.readLine());
|
||||
@@ -679,6 +818,8 @@ CMakeConfig BuildDirManager::parseConfiguration(const Utils::FileName &cacheFile
|
||||
|
||||
if (key.endsWith("-ADVANCED") && value == "1") {
|
||||
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 {
|
||||
CMakeConfigItem::Type t = fromByteArray(type);
|
||||
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) {
|
||||
CMakeConfigItem &item = result[i];
|
||||
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());
|
||||
|
@@ -45,6 +45,7 @@ QT_FORWARD_DECLARE_CLASS(QTemporaryDir);
|
||||
QT_FORWARD_DECLARE_CLASS(QFileSystemWatcher);
|
||||
|
||||
namespace Core { class IDocument; }
|
||||
namespace CppTools { class ProjectPartBuilder; }
|
||||
|
||||
namespace ProjectExplorer {
|
||||
class FileNode;
|
||||
@@ -80,6 +81,7 @@ public:
|
||||
bool persistCMakeState();
|
||||
|
||||
void generateProjectTree(CMakeProjectNode *root);
|
||||
QSet<Core::Id> updateCodeModel(CppTools::ProjectPartBuilder &ppBuilder);
|
||||
|
||||
QList<CMakeBuildTarget> buildTargets() const;
|
||||
CMakeConfig parsedConfiguration() const;
|
||||
@@ -117,6 +119,10 @@ private:
|
||||
void processCMakeOutput();
|
||||
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;
|
||||
|
||||
CMakeBuildConfiguration *m_buildConfiguration = nullptr;
|
||||
|
@@ -211,6 +211,11 @@ void CMakeBuildConfiguration::generateProjectTree(CMakeProjectNode *root) const
|
||||
return m_buildDirManager->generateProjectTree(root);
|
||||
}
|
||||
|
||||
QSet<Core::Id> CMakeBuildConfiguration::updateCodeModel(CppTools::ProjectPartBuilder &ppBuilder)
|
||||
{
|
||||
return m_buildDirManager->updateCodeModel(ppBuilder);
|
||||
}
|
||||
|
||||
FileName CMakeBuildConfiguration::shadowBuildDirectory(const FileName &projectFilePath,
|
||||
const Kit *k,
|
||||
const QString &bcName,
|
||||
@@ -240,6 +245,7 @@ QList<ConfigModel::DataItem> CMakeBuildConfiguration::completeCMakeConfiguration
|
||||
j.key = QString::fromUtf8(i.key);
|
||||
j.value = QString::fromUtf8(i.value);
|
||||
j.description = QString::fromUtf8(i.documentation);
|
||||
j.values = i.values;
|
||||
|
||||
j.isAdvanced = i.isAdvanced || i.type == CMakeConfigItem::INTERNAL;
|
||||
switch (i.type) {
|
||||
@@ -275,6 +281,7 @@ void CMakeBuildConfiguration::setCurrentCMakeConfiguration(const QList<ConfigMod
|
||||
ni.value = i.value.toUtf8();
|
||||
ni.documentation = i.description.toUtf8();
|
||||
ni.isAdvanced = i.isAdvanced;
|
||||
ni.values = i.values;
|
||||
switch (i.type) {
|
||||
case CMakeProjectManager::ConfigModel::DataItem::BOOLEAN:
|
||||
ni.type = CMakeConfigItem::BOOL;
|
||||
|
@@ -32,6 +32,7 @@
|
||||
#include <projectexplorer/buildconfiguration.h>
|
||||
#include <projectexplorer/abi.h>
|
||||
|
||||
namespace CppTools { class ProjectPartBuilder; }
|
||||
namespace ProjectExplorer { class ToolChain; }
|
||||
|
||||
namespace CMakeProjectManager {
|
||||
@@ -82,6 +83,7 @@ public:
|
||||
|
||||
QList<CMakeBuildTarget> buildTargets() const;
|
||||
void generateProjectTree(CMakeProjectNode *root) const;
|
||||
QSet<Core::Id> updateCodeModel(CppTools::ProjectPartBuilder &ppBuilder);
|
||||
|
||||
static Utils::FileName
|
||||
shadowBuildDirectory(const Utils::FileName &projectFilePath, const ProjectExplorer::Kit *k,
|
||||
|
@@ -26,6 +26,7 @@
|
||||
#include "cmakebuildsettingswidget.h"
|
||||
|
||||
#include "configmodel.h"
|
||||
#include "configmodelitemdelegate.h"
|
||||
#include "cmakeproject.h"
|
||||
#include "cmakebuildconfiguration.h"
|
||||
|
||||
@@ -140,6 +141,7 @@ CMakeBuildSettingsWidget::CMakeBuildSettingsWidget(CMakeBuildConfiguration *bc)
|
||||
m_configView->setSelectionBehavior(QAbstractItemView::SelectItems);
|
||||
m_configView->setFrameShape(QFrame::NoFrame);
|
||||
m_configView->hideColumn(2); // Hide isAdvanced column
|
||||
m_configView->setItemDelegate(new ConfigModelItemDelegate(m_configView));
|
||||
QFrame *findWrapper = Core::ItemViewFind::createSearchableWrapper(m_configView, Core::ItemViewFind::LightColored);
|
||||
findWrapper->setFrameStyle(QFrame::StyledPanel);
|
||||
|
||||
|
@@ -42,7 +42,7 @@ CMakeConfigItem::CMakeConfigItem() = default;
|
||||
|
||||
CMakeConfigItem::CMakeConfigItem(const CMakeConfigItem &other) :
|
||||
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,
|
||||
|
@@ -61,6 +61,7 @@ public:
|
||||
bool isAdvanced = false;
|
||||
QByteArray value; // converted to string as needed
|
||||
QByteArray documentation;
|
||||
QStringList values;
|
||||
};
|
||||
using CMakeConfig = QList<CMakeConfigItem>;
|
||||
|
||||
|
@@ -94,102 +94,6 @@ CMakeProject::~CMakeProject()
|
||||
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()
|
||||
{
|
||||
auto cmakeBc = qobject_cast<CMakeBuildConfiguration *>(sender());
|
||||
@@ -225,39 +129,11 @@ void CMakeProject::updateProjectData()
|
||||
activeQtVersion = CppTools::ProjectPart::Qt5;
|
||||
}
|
||||
|
||||
const FileName sysroot = SysRootKitInformation::sysRoot(k);
|
||||
|
||||
ppBuilder.setQtVersion(activeQtVersion);
|
||||
|
||||
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 += 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);
|
||||
}
|
||||
const QSet<Core::Id> languages = cmakeBc->updateCodeModel(ppBuilder);
|
||||
for (const auto &lid : languages)
|
||||
setProjectLanguage(lid, true);
|
||||
|
||||
m_codeModelFuture.cancel();
|
||||
pinfo.finish();
|
||||
|
@@ -120,9 +120,6 @@ private:
|
||||
QStringList filesGeneratedFrom(const QString &sourceFile) const final;
|
||||
void updateTargetRunConfigurations(ProjectExplorer::Target *t);
|
||||
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;
|
||||
|
||||
|
@@ -28,7 +28,8 @@ HEADERS = builddirmanager.h \
|
||||
cmakebuildsettingswidget.h \
|
||||
cmakeindenter.h \
|
||||
cmakeautocompleter.h \
|
||||
configmodel.h
|
||||
configmodel.h \
|
||||
configmodelitemdelegate.h
|
||||
|
||||
SOURCES = builddirmanager.cpp \
|
||||
cmakebuildstep.cpp \
|
||||
@@ -54,6 +55,7 @@ SOURCES = builddirmanager.cpp \
|
||||
cmakebuildsettingswidget.cpp \
|
||||
cmakeindenter.cpp \
|
||||
cmakeautocompleter.cpp \
|
||||
configmodel.cpp
|
||||
configmodel.cpp \
|
||||
configmodelitemdelegate.cpp
|
||||
|
||||
RESOURCES += cmakeproject.qrc
|
||||
|
@@ -71,6 +71,8 @@ QtcPlugin {
|
||||
"cmakeautocompleter.h",
|
||||
"cmakeautocompleter.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()];
|
||||
|
||||
if (index.column() < 2) {
|
||||
switch (role) {
|
||||
case ItemTypeRole:
|
||||
return item.type;
|
||||
case ItemValuesRole:
|
||||
return item.values;
|
||||
}
|
||||
}
|
||||
|
||||
switch (index.column()) {
|
||||
case 0:
|
||||
switch (role) {
|
||||
@@ -97,8 +106,6 @@ QVariant ConfigModel::data(const QModelIndex &index, int role) const
|
||||
return item.key;
|
||||
case Qt::ToolTipRole:
|
||||
return item.description;
|
||||
case Qt::UserRole:
|
||||
return item.type;
|
||||
case Qt::FontRole: {
|
||||
QFont font;
|
||||
font.setItalic(item.isCMakeChanged);
|
||||
@@ -126,8 +133,6 @@ QVariant ConfigModel::data(const QModelIndex &index, int role) const
|
||||
}
|
||||
case Qt::ToolTipRole:
|
||||
return item.description;
|
||||
case Qt::UserRole:
|
||||
return item.type;
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
@@ -209,13 +214,15 @@ QVariant ConfigModel::headerData(int section, Qt::Orientation orientation, int r
|
||||
void ConfigModel::appendConfiguration(const QString &key,
|
||||
const QString &value,
|
||||
const ConfigModel::DataItem::Type type,
|
||||
const QString &description)
|
||||
const QString &description,
|
||||
const QStringList &values)
|
||||
{
|
||||
DataItem item;
|
||||
item.key = key;
|
||||
item.type = type;
|
||||
item.value = value;
|
||||
item.description = description;
|
||||
item.values = values;
|
||||
|
||||
InternalDataItem internalItem(item);
|
||||
internalItem.isUserNew = true;
|
||||
|
@@ -34,6 +34,11 @@ class ConfigModel : public QAbstractTableModel
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum Roles {
|
||||
ItemTypeRole = Qt::UserRole,
|
||||
ItemValuesRole
|
||||
};
|
||||
|
||||
class DataItem {
|
||||
public:
|
||||
enum Type { BOOLEAN, FILE, DIRECTORY, STRING, UNKNOWN};
|
||||
@@ -43,6 +48,7 @@ public:
|
||||
bool isAdvanced = false;
|
||||
QString value;
|
||||
QString description;
|
||||
QStringList values;
|
||||
};
|
||||
|
||||
explicit ConfigModel(QObject *parent = nullptr);
|
||||
@@ -58,7 +64,8 @@ public:
|
||||
void appendConfiguration(const QString &key,
|
||||
const QString &value = QString(),
|
||||
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 flush();
|
||||
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 <QHBoxLayout>
|
||||
#include <QVBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QToolButton>
|
||||
|
||||
@@ -67,6 +68,20 @@ void InfoBarEntry::setCancelButtonInfo(const QString &_cancelButtonText, CallBac
|
||||
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)
|
||||
{
|
||||
@@ -124,10 +139,13 @@ void InfoBar::clear()
|
||||
void InfoBar::globallySuppressInfo(Id id)
|
||||
{
|
||||
globallySuppressed.insert(id);
|
||||
QStringList list;
|
||||
foreach (Id i, globallySuppressed)
|
||||
list << QLatin1String(i.name());
|
||||
ICore::settings()->setValue(QLatin1String(C_SUPPRESSED_WARNINGS), list);
|
||||
writeGloballySuppressedToSettings();
|
||||
}
|
||||
|
||||
void InfoBar::globallyUnsuppressInfo(Id id)
|
||||
{
|
||||
globallySuppressed.remove(id);
|
||||
writeGloballySuppressedToSettings();
|
||||
}
|
||||
|
||||
void InfoBar::initializeGloballySuppressed()
|
||||
@@ -148,12 +166,17 @@ bool InfoBar::anyGloballySuppressed()
|
||||
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)
|
||||
: QObject(parent)
|
||||
, m_infoBar(0)
|
||||
, m_boxLayout(0)
|
||||
, m_boxIndex(0)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -209,13 +232,43 @@ void InfoBarDisplay::update()
|
||||
infoWidget->setLineWidth(1);
|
||||
infoWidget->setAutoFillBackground(true);
|
||||
|
||||
QHBoxLayout *hbox = new QHBoxLayout(infoWidget);
|
||||
QHBoxLayout *hbox = new QHBoxLayout;
|
||||
hbox->setMargin(2);
|
||||
|
||||
auto *vbox = new QVBoxLayout(infoWidget);
|
||||
vbox->setMargin(0);
|
||||
vbox->addLayout(hbox);
|
||||
|
||||
QLabel *infoWidgetLabel = new QLabel(info.infoText);
|
||||
infoWidgetLabel->setWordWrap(true);
|
||||
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()) {
|
||||
QToolButton *infoWidgetButton = new QToolButton;
|
||||
infoWidgetButton->setText(info.buttonText);
|
||||
@@ -229,7 +282,9 @@ void InfoBarDisplay::update()
|
||||
if (info.globalSuppression == InfoBarEntry::GlobalSuppressionEnabled) {
|
||||
infoWidgetSuppressButton = new QToolButton;
|
||||
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);
|
||||
InfoBar::globallySuppressInfo(id);
|
||||
});
|
||||
@@ -245,11 +300,16 @@ void InfoBarDisplay::update()
|
||||
});
|
||||
|
||||
if (info.cancelButtonText.isEmpty()) {
|
||||
if (info.m_showDefaultCancelButton) {
|
||||
infoWidgetCloseButton->setAutoRaise(true);
|
||||
infoWidgetCloseButton->setIcon(Utils::Icons::CLOSE_FOREGROUND.icon());
|
||||
infoWidgetCloseButton->setToolTip(tr("Close"));
|
||||
}
|
||||
|
||||
if (infoWidgetSuppressButton)
|
||||
hbox->addWidget(infoWidgetSuppressButton);
|
||||
|
||||
if (info.m_showDefaultCancelButton)
|
||||
hbox->addWidget(infoWidgetCloseButton);
|
||||
} else {
|
||||
infoWidgetCloseButton->setText(info.cancelButtonText);
|
||||
|
@@ -54,10 +54,15 @@ public:
|
||||
InfoBarEntry(Id _id, const QString &_infoText, GlobalSuppressionMode _globalSuppression = GlobalSuppressionDisabled);
|
||||
InfoBarEntry(const InfoBarEntry &other) { *this = other; }
|
||||
|
||||
typedef std::function<void()> CallBack;
|
||||
using CallBack = std::function<void()>;
|
||||
void setCustomButtonInfo(const QString &_buttonText, CallBack callBack);
|
||||
void setCancelButtonInfo(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:
|
||||
Id id;
|
||||
@@ -66,7 +71,10 @@ private:
|
||||
CallBack m_buttonCallBack;
|
||||
QString cancelButtonText;
|
||||
CallBack m_cancelButtonCallBack;
|
||||
CallBack m_suppressionButtonCallBack;
|
||||
GlobalSuppressionMode globalSuppression;
|
||||
DetailsWidgetCreator m_detailsWidgetCreator;
|
||||
bool m_showDefaultCancelButton = true;
|
||||
friend class InfoBar;
|
||||
friend class InfoBarDisplay;
|
||||
};
|
||||
@@ -84,6 +92,7 @@ public:
|
||||
void enableInfo(Id id);
|
||||
void clear();
|
||||
static void globallySuppressInfo(Id id);
|
||||
static void globallyUnsuppressInfo(Id id);
|
||||
static void initializeGloballySuppressed();
|
||||
static void clearGloballySuppressed();
|
||||
static bool anyGloballySuppressed();
|
||||
@@ -91,6 +100,9 @@ public:
|
||||
signals:
|
||||
void changed();
|
||||
|
||||
private:
|
||||
static void writeGloballySuppressedToSettings();
|
||||
|
||||
private:
|
||||
QList<InfoBarEntry> m_infoBarEntries;
|
||||
QSet<Id> m_suppressed;
|
||||
@@ -113,9 +125,10 @@ private:
|
||||
void widgetDestroyed();
|
||||
|
||||
QList<QWidget *> m_infoWidgets;
|
||||
InfoBar *m_infoBar;
|
||||
QBoxLayout *m_boxLayout;
|
||||
int m_boxIndex;
|
||||
InfoBar *m_infoBar = nullptr;
|
||||
QBoxLayout *m_boxLayout = nullptr;
|
||||
int m_boxIndex = 0;
|
||||
bool m_isShowingDetailsWidget = false;
|
||||
};
|
||||
|
||||
} // namespace Core
|
||||
|
@@ -44,6 +44,7 @@
|
||||
#include <coreplugin/actionmanager/actionmanager.h>
|
||||
#include <coreplugin/editormanager/editormanager.h>
|
||||
#include <coreplugin/editormanager/documentmodel.h>
|
||||
#include <coreplugin/infobar.h>
|
||||
|
||||
#include <cpptools/cppchecksymbols.h>
|
||||
#include <cpptools/cppcodeformatter.h>
|
||||
@@ -77,6 +78,7 @@
|
||||
#include <cplusplus/FastPreprocessor.h>
|
||||
#include <cplusplus/MatchingText.h>
|
||||
#include <utils/qtcassert.h>
|
||||
#include <utils/utilsicons.h>
|
||||
|
||||
#include <QApplication>
|
||||
#include <QAction>
|
||||
@@ -126,9 +128,13 @@ public:
|
||||
QSharedPointer<FunctionDeclDefLink> m_declDefLink;
|
||||
|
||||
QScopedPointer<FollowSymbolUnderCursor> m_followSymbolUnderCursor;
|
||||
QToolButton *m_preprocessorButton;
|
||||
|
||||
QToolButton *m_preprocessorButton = nullptr;
|
||||
QToolButton *m_headerErrorsIndicatorButton = nullptr;
|
||||
|
||||
CppSelectionChanger m_cppSelectionChanger;
|
||||
|
||||
CppEditorWidget::HeaderErrorDiagnosticWidgetCreator m_headerErrorDiagnosticWidgetCreator;
|
||||
};
|
||||
|
||||
CppEditorWidgetPrivate::CppEditorWidgetPrivate(CppEditorWidget *q)
|
||||
@@ -139,7 +145,6 @@ CppEditorWidgetPrivate::CppEditorWidgetPrivate(CppEditorWidget *q)
|
||||
, m_useSelectionsUpdater(q)
|
||||
, m_declDefLinkFinder(new FunctionDeclDefLinkFinder(q))
|
||||
, m_followSymbolUnderCursor(new FollowSymbolUnderCursor(q))
|
||||
, m_preprocessorButton(0)
|
||||
, m_cppSelectionChanger()
|
||||
{
|
||||
}
|
||||
@@ -224,7 +229,15 @@ void CppEditorWidget::finalizeInitialization()
|
||||
connect(cmd, &Command::keySequenceChanged, this, &CppEditorWidget::updatePreprocessorButtonTooltip);
|
||||
updatePreprocessorButtonTooltip();
|
||||
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_headerErrorsIndicatorButton);
|
||||
insertExtraToolBarWidget(TextEditorWidget::Left, d->m_cppEditorOutline->widget());
|
||||
}
|
||||
|
||||
@@ -287,6 +300,7 @@ void CppEditorWidget::onCppDocumentUpdated()
|
||||
|
||||
void CppEditorWidget::onCodeWarningsUpdated(unsigned revision,
|
||||
const QList<QTextEdit::ExtraSelection> selections,
|
||||
const HeaderErrorDiagnosticWidgetCreator &creator,
|
||||
const TextEditor::RefactorMarkers &refactorMarkers)
|
||||
{
|
||||
if (revision != documentRevision())
|
||||
@@ -294,6 +308,9 @@ void CppEditorWidget::onCodeWarningsUpdated(unsigned revision,
|
||||
|
||||
setExtraSelections(TextEditorWidget::CodeWarningsSelection, selections);
|
||||
setRefactorMarkers(refactorMarkersWithoutClangMarkers() + refactorMarkers);
|
||||
|
||||
d->m_headerErrorDiagnosticWidgetCreator = creator;
|
||||
updateHeaderErrorWidgets();
|
||||
}
|
||||
|
||||
void CppEditorWidget::onIfdefedOutBlocksUpdated(unsigned revision,
|
||||
@@ -304,6 +321,24 @@ void CppEditorWidget::onIfdefedOutBlocksUpdated(unsigned revision,
|
||||
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()
|
||||
{
|
||||
if (!d->m_modelManager)
|
||||
@@ -399,6 +434,25 @@ void CppEditorWidget::renameSymbolUnderCursorBuiltin()
|
||||
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 {
|
||||
|
||||
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 CppEditor
|
||||
|
@@ -31,6 +31,10 @@
|
||||
|
||||
#include <QScopedPointer>
|
||||
|
||||
namespace Core {
|
||||
class InfoBarEntry;
|
||||
}
|
||||
|
||||
namespace CppTools {
|
||||
class CppEditorOutline;
|
||||
class RefactoringEngineInterface;
|
||||
@@ -87,6 +91,7 @@ public:
|
||||
|
||||
void switchDeclarationDefinition(bool inNextSplit);
|
||||
void showPreProcessorWidget();
|
||||
void showHeaderErrorInfoBar();
|
||||
|
||||
void findUsages();
|
||||
void renameSymbolUnderCursor();
|
||||
@@ -108,6 +113,9 @@ protected:
|
||||
|
||||
void slotCodeStyleSettingsChanged(const QVariant &) override;
|
||||
|
||||
public:
|
||||
using HeaderErrorDiagnosticWidgetCreator = std::function<QWidget*()>;
|
||||
|
||||
private:
|
||||
void updateFunctionDeclDefLink();
|
||||
void updateFunctionDeclDefLinkNow();
|
||||
@@ -118,10 +126,12 @@ private:
|
||||
|
||||
void onCodeWarningsUpdated(unsigned revision,
|
||||
const QList<QTextEdit::ExtraSelection> selections,
|
||||
const HeaderErrorDiagnosticWidgetCreator &creator,
|
||||
const TextEditor::RefactorMarkers &refactorMarkers);
|
||||
void onIfdefedOutBlocksUpdated(unsigned revision,
|
||||
const QList<TextEditor::BlockRange> ifdefedOutBlocks);
|
||||
|
||||
void updateHeaderErrorWidgets();
|
||||
void updateSemanticInfo(const CppTools::SemanticInfo &semanticInfo,
|
||||
bool updateUseSelectionSynchronously = false);
|
||||
void updatePreprocessorButtonTooltip();
|
||||
@@ -140,6 +150,8 @@ private:
|
||||
void renameSymbolUnderCursorClang();
|
||||
void renameSymbolUnderCursorBuiltin();
|
||||
|
||||
void addHeaderErrorInfoBarEntryAndHideIndicator() const;
|
||||
|
||||
CppTools::ProjectPart *projectPart() const;
|
||||
|
||||
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 FIND_USAGES[] = "CppEditor.FindUsages";
|
||||
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 UPDATE_CODEMODEL[] = "CppEditor.UpdateCodeModel";
|
||||
const char INSPECT_CPP_CODEMODEL[] = "CppEditor.InspectCppCodeModel";
|
||||
|
@@ -230,12 +230,14 @@ void CppEditorDocument::scheduleProcessDocument()
|
||||
{
|
||||
m_processorRevision = document()->revision();
|
||||
m_processorTimer.start();
|
||||
processor()->editorDocumentTimerRestarted();
|
||||
}
|
||||
|
||||
void CppEditorDocument::processDocument()
|
||||
{
|
||||
if (processor()->isParserRunning() || m_processorRevision != contentsRevision()) {
|
||||
m_processorTimer.start();
|
||||
processor()->editorDocumentTimerRestarted();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@@ -59,9 +59,13 @@ public:
|
||||
const QByteArray &defines);
|
||||
void scheduleProcessDocument();
|
||||
|
||||
public:
|
||||
using HeaderErrorDiagnosticWidgetCreator = std::function<QWidget*()>;
|
||||
|
||||
signals:
|
||||
void codeWarningsUpdated(unsigned contentsRevision,
|
||||
const QList<QTextEdit::ExtraSelection> selections,
|
||||
const HeaderErrorDiagnosticWidgetCreator &creator,
|
||||
const TextEditor::RefactorMarkers &refactorMarkers);
|
||||
|
||||
void ifdefedOutBlocksUpdated(unsigned contentsRevision,
|
||||
|
@@ -67,6 +67,10 @@ void BaseEditorDocumentProcessor::addDiagnosticToolTipToLayout(uint, uint, QLayo
|
||||
{
|
||||
}
|
||||
|
||||
void BaseEditorDocumentProcessor::editorDocumentTimerRestarted()
|
||||
{
|
||||
}
|
||||
|
||||
void BaseEditorDocumentProcessor::runParser(QFutureInterface<void> &future,
|
||||
BaseEditorDocumentParser::Ptr parser,
|
||||
const WorkingCopy workingCopy)
|
||||
|
@@ -37,6 +37,8 @@
|
||||
|
||||
#include <QTextEdit>
|
||||
|
||||
#include <functional>
|
||||
|
||||
namespace TextEditor {
|
||||
class TextDocument;
|
||||
class QuickFixOperations;
|
||||
@@ -67,10 +69,17 @@ public:
|
||||
virtual bool hasDiagnosticsAt(uint line, uint column) const;
|
||||
virtual void addDiagnosticToolTipToLayout(uint line, uint column, QLayout *layout) const;
|
||||
|
||||
virtual void editorDocumentTimerRestarted();
|
||||
|
||||
public:
|
||||
using HeaderErrorDiagnosticWidgetCreator = std::function<QWidget*()>;
|
||||
|
||||
signals:
|
||||
|
||||
// Signal interface to implement
|
||||
void codeWarningsUpdated(unsigned revision,
|
||||
const QList<QTextEdit::ExtraSelection> selections,
|
||||
const HeaderErrorDiagnosticWidgetCreator &creator,
|
||||
const TextEditor::RefactorMarkers &refactorMarkers);
|
||||
|
||||
void ifdefedOutBlocksUpdated(unsigned revision,
|
||||
|
@@ -310,7 +310,10 @@ void BuiltinEditorDocumentProcessor::onCodeWarningsUpdated(
|
||||
|
||||
m_codeWarnings += toTextEditorSelections(codeWarnings, textDocument());
|
||||
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
|
||||
|
@@ -622,8 +622,8 @@ void HelpPlugin::handleHelpRequest(const QUrl &url, HelpManager::HelpViewerLocat
|
||||
if (HelpViewer::launchWithExternalApp(url))
|
||||
return;
|
||||
|
||||
QString address = url.toString();
|
||||
if (!HelpManager::findFile(url).isValid()) {
|
||||
const QString address = url.toString();
|
||||
if (address.startsWith("qthelp://org.qt-project.")
|
||||
|| address.startsWith("qthelp://com.nokia.")
|
||||
|| address.startsWith("qthelp://com.trolltech.")) {
|
||||
@@ -633,14 +633,14 @@ void HelpPlugin::handleHelpRequest(const QUrl &url, HelpManager::HelpViewerLocat
|
||||
urlPrefix.append(QString::fromLatin1("qtcreator"));
|
||||
else
|
||||
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);
|
||||
QTC_ASSERT(viewer, return);
|
||||
viewer->setSource(newUrl);
|
||||
viewer->setSource(url);
|
||||
ICore::raiseWindow(viewer);
|
||||
}
|
||||
|
||||
|
@@ -169,7 +169,7 @@ static QPoint flipPoint(const NSPoint &p)
|
||||
|
||||
NSURL *resolvedURL = data.resolvedUrl.toNSURL();
|
||||
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
|
||||
MIMEType:mimeType
|
||||
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.google.com/search?q=%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");
|
||||
}
|
||||
|
||||
|
@@ -404,6 +404,7 @@ bool LineEditField::parseData(const QVariant &data, QString *errorMessage)
|
||||
|
||||
QVariantMap tmp = data.toMap();
|
||||
|
||||
m_isPassword = tmp.value("isPassword", false).toBool();
|
||||
m_defaultText = JsonWizardFactory::localizedString(tmp.value(QLatin1String("trText")).toString());
|
||||
m_disabledText = JsonWizardFactory::localizedString(tmp.value(QLatin1String("trDisabledText")).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())
|
||||
w->setHistoryCompleter(m_historyId, m_restoreLastHistoryItem);
|
||||
|
||||
w->setEchoMode(m_isPassword ? QLineEdit::Password : QLineEdit::Normal);
|
||||
|
||||
return w;
|
||||
}
|
||||
|
||||
|
@@ -105,6 +105,7 @@ private:
|
||||
bool m_isModified;
|
||||
bool m_isValidating;
|
||||
bool m_restoreLastHistoryItem;
|
||||
bool m_isPassword;
|
||||
QString m_placeholderText;
|
||||
QString m_defaultText;
|
||||
QString m_disabledText;
|
||||
|
@@ -93,6 +93,7 @@ void QtProjectParameters::writeProFile(QTextStream &str) const
|
||||
case ConsoleApp:
|
||||
// Mac: Command line apps should not be bundles
|
||||
str << "CONFIG += console\nCONFIG -= app_bundle\n\n";
|
||||
// fallthrough
|
||||
case GuiApp:
|
||||
str << "TEMPLATE = app\n";
|
||||
break;
|
||||
|
@@ -102,6 +102,7 @@ const char *nameForStyle(TextStyle style)
|
||||
case C_WARNING_CONTEXT: return "WarningContext";
|
||||
|
||||
case C_DECLARATION: return "Declaration";
|
||||
case C_OUTPUT_ARGUMENT: return "C_OUTPUT_ARGUMENT";
|
||||
|
||||
case C_LAST_STYLE_SENTINEL: return "LastStyleSentinel";
|
||||
}
|
||||
|
@@ -100,6 +100,7 @@ enum TextStyle : quint8 {
|
||||
C_ERROR_CONTEXT,
|
||||
|
||||
C_DECLARATION,
|
||||
C_OUTPUT_ARGUMENT,
|
||||
|
||||
C_LAST_STYLE_SENTINEL
|
||||
};
|
||||
|
@@ -313,6 +313,10 @@ TextEditorSettings::TextEditorSettings(QObject *parent)
|
||||
tr("Declaration"),
|
||||
tr("Declaration of a function, variable, and so on."),
|
||||
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,
|
||||
Constants::TEXT_EDITOR_FONT_SETTINGS,
|
||||
|
@@ -711,10 +711,11 @@ public:
|
||||
return m_tool->createRunControl(runConfiguration, mode);
|
||||
}
|
||||
|
||||
IRunConfigurationAspect *createRunConfigurationAspect(ProjectExplorer::RunConfiguration *rc) override
|
||||
{
|
||||
return createValgrindRunConfigurationAspect(rc);
|
||||
}
|
||||
// Do not create an aspect, let the Callgrind tool create one and use that, too.
|
||||
// IRunConfigurationAspect *createRunConfigurationAspect(ProjectExplorer::RunConfiguration *rc) override
|
||||
// {
|
||||
// return createValgrindRunConfigurationAspect(rc);
|
||||
// }
|
||||
|
||||
public:
|
||||
MemcheckTool *m_tool;
|
||||
|
@@ -64,6 +64,11 @@ public:
|
||||
return future;
|
||||
}
|
||||
|
||||
void preventFinalization() override
|
||||
{
|
||||
m_futureWatcher.disconnect();
|
||||
}
|
||||
|
||||
private:
|
||||
Runner m_runner;
|
||||
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/utf8positionfromlinecolumn.h \
|
||||
$$PWD/clangasyncjob.h \
|
||||
$$PWD/clangbackend_global.h \
|
||||
$$PWD/clangcompletecodejob.h \
|
||||
$$PWD/clangcreateinitialdocumentpreamblejob.h \
|
||||
$$PWD/clangfilepath.h \
|
||||
@@ -41,7 +42,14 @@ HEADERS += $$PWD/clangcodemodelserver.h \
|
||||
$$PWD/clangtranslationunit.h \
|
||||
$$PWD/clangunsavedfilesshallowarguments.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 \
|
||||
$$PWD/codecompleter.cpp \
|
||||
@@ -80,4 +88,10 @@ SOURCES += $$PWD/clangcodemodelserver.cpp \
|
||||
$$PWD/clangtranslationunit.cpp \
|
||||
$$PWD/clangunsavedfilesshallowarguments.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 "clangfilesystemwatcher.h"
|
||||
#include "clangtranslationunits.h"
|
||||
#include "codecompleter.h"
|
||||
#include "diagnosticset.h"
|
||||
#include "highlightingmarks.h"
|
||||
@@ -126,10 +127,16 @@ void ClangCodeModelServer::updateTranslationUnitsForEditor(const UpdateTranslati
|
||||
try {
|
||||
const auto newerFileContainers = documents.newerFileContainers(message.fileContainers());
|
||||
if (newerFileContainers.size() > 0) {
|
||||
documents.update(newerFileContainers);
|
||||
const std::vector<Document> updateDocuments = documents.update(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) {
|
||||
qWarning() << "Error in ClangCodeModelServer::updateTranslationUnitsForEditor:" << exception.what();
|
||||
@@ -141,6 +148,10 @@ void ClangCodeModelServer::unregisterTranslationUnitsForEditor(const ClangBackEn
|
||||
TIME_SCOPE_DURATION("ClangCodeModelServer::unregisterTranslationUnitsForEditor");
|
||||
|
||||
try {
|
||||
for (const auto &fileContainer : message.fileContainers()) {
|
||||
const Document &document = documents.document(fileContainer);
|
||||
documentProcessors().remove(document);
|
||||
}
|
||||
documents.remove(message.fileContainers());
|
||||
unsavedFiles.remove(message.fileContainers());
|
||||
} catch (const std::exception &exception) {
|
||||
@@ -211,8 +222,9 @@ void ClangCodeModelServer::completeCode(const ClangBackEnd::CompleteCodeMessage
|
||||
jobRequest.column = message.column();
|
||||
jobRequest.ticketNumber = message.ticketNumber();
|
||||
|
||||
jobs().add(jobRequest);
|
||||
jobs().process();
|
||||
DocumentProcessor processor = documentProcessors().processor(document);
|
||||
processor.addJob(jobRequest);
|
||||
processor.process();
|
||||
} catch (const std::exception &exception) {
|
||||
qWarning() << "Error in ClangCodeModelServer::completeCode:" << exception.what();
|
||||
}
|
||||
@@ -229,8 +241,9 @@ void ClangCodeModelServer::requestDocumentAnnotations(const RequestDocumentAnnot
|
||||
const JobRequest jobRequest = createJobRequest(document,
|
||||
JobRequest::Type::RequestDocumentAnnotations);
|
||||
|
||||
jobs().add(jobRequest);
|
||||
jobs().process();
|
||||
DocumentProcessor processor = documentProcessors().processor(document);
|
||||
processor.addJob(jobRequest);
|
||||
processor.process();
|
||||
} catch (const std::exception &exception) {
|
||||
qWarning() << "Error in ClangCodeModelServer::requestDocumentAnnotations:" << exception.what();
|
||||
}
|
||||
@@ -260,9 +273,14 @@ void ClangCodeModelServer::startDocumentAnnotationsTimerIfFileIsNotOpenAsDocumen
|
||||
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
|
||||
@@ -270,32 +288,55 @@ bool ClangCodeModelServer::isTimerRunningForTestOnly() const
|
||||
return updateDocumentAnnotationsTimer.isActive();
|
||||
}
|
||||
|
||||
void ClangCodeModelServer::addJobRequestsForDirtyAndVisibleDocuments()
|
||||
void ClangCodeModelServer::processJobsForDirtyAndVisibleDocuments()
|
||||
{
|
||||
for (const auto &document : documents.documents()) {
|
||||
if (document.isNeedingReparse() && document.isVisibleInEditor())
|
||||
jobs().add(createJobRequest(document, JobRequest::Type::UpdateDocumentAnnotations));
|
||||
if (document.isNeedingReparse() && document.isVisibleInEditor()) {
|
||||
DocumentProcessor processor = documentProcessors().processor(document);
|
||||
processor.addJob(createJobRequest(document,
|
||||
JobRequest::Type::UpdateDocumentAnnotations,
|
||||
PreferredTranslationUnit::PreviouslyParsed));
|
||||
}
|
||||
}
|
||||
|
||||
void ClangCodeModelServer::processJobsForDirtyAndVisibleDocuments()
|
||||
{
|
||||
addJobRequestsForDirtyAndVisibleDocuments();
|
||||
jobs().process();
|
||||
documentProcessors().process();
|
||||
}
|
||||
|
||||
void ClangCodeModelServer::processInitialJobsForDocuments(const std::vector<Document> &documents)
|
||||
{
|
||||
for (const auto &document : documents) {
|
||||
jobs().add(createJobRequest(document, JobRequest::Type::UpdateDocumentAnnotations));
|
||||
jobs().add(createJobRequest(document, JobRequest::Type::CreateInitialDocumentPreamble));
|
||||
DocumentProcessor processor = documentProcessors().create(document);
|
||||
const auto jobRequestCreator = [this](const Document &document,
|
||||
JobRequest::Type jobRequestType,
|
||||
PreferredTranslationUnit preferredTranslationUnit) {
|
||||
return createJobRequest(document, jobRequestType, preferredTranslationUnit);
|
||||
};
|
||||
processor.setJobRequestCreator(jobRequestCreator);
|
||||
|
||||
processor.addJob(createJobRequest(document, JobRequest::Type::UpdateDocumentAnnotations));
|
||||
processor.addJob(createJobRequest(document, JobRequest::Type::CreateInitialDocumentPreamble));
|
||||
processor.process();
|
||||
}
|
||||
}
|
||||
|
||||
jobs().process();
|
||||
void ClangCodeModelServer::startInitializingSupportiveTranslationUnits(
|
||||
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) const
|
||||
JobRequest ClangCodeModelServer::createJobRequest(
|
||||
const Document &document,
|
||||
JobRequest::Type type,
|
||||
PreferredTranslationUnit preferredTranslationUnit) const
|
||||
{
|
||||
JobRequest jobRequest;
|
||||
jobRequest.type = type;
|
||||
@@ -304,6 +345,7 @@ JobRequest ClangCodeModelServer::createJobRequest(const Document &document,
|
||||
jobRequest.projectPartId = document.projectPartId();
|
||||
jobRequest.unsavedFilesChangeTimePoint = unsavedFiles.lastChangeTimePoint();
|
||||
jobRequest.documentRevision = document.documentRevision();
|
||||
jobRequest.preferredTranslationUnit = preferredTranslationUnit;
|
||||
const ProjectPart &projectPart = projects.project(document.projectPartId());
|
||||
jobRequest.projectChangeTimePoint = projectPart.lastChangeTimePoint();
|
||||
|
||||
@@ -315,16 +357,16 @@ void ClangCodeModelServer::setUpdateDocumentAnnotationsTimeOutInMsForTestsOnly(i
|
||||
updateDocumentAnnotationsTimeOutInMs = value;
|
||||
}
|
||||
|
||||
Jobs &ClangCodeModelServer::jobs()
|
||||
DocumentProcessors &ClangCodeModelServer::documentProcessors()
|
||||
{
|
||||
if (!jobs_) {
|
||||
// Jobs needs a reference to the client, but the client is not known at
|
||||
// construction time of ClangCodeModelServer, so construct Jobs in a
|
||||
// lazy manner.
|
||||
jobs_.reset(new Jobs(documents, unsavedFiles, projects, *client()));
|
||||
if (!documentProcessors_) {
|
||||
// DocumentProcessors needs a reference to the client, but the client
|
||||
// is not known at construction time of ClangCodeModelServer, so
|
||||
// construct DocumentProcessors in a lazy manner.
|
||||
documentProcessors_.reset(new DocumentProcessors(documents, unsavedFiles, projects, *client()));
|
||||
}
|
||||
|
||||
return *jobs_.data();
|
||||
return *documentProcessors_.data();
|
||||
}
|
||||
|
||||
} // namespace ClangBackEnd
|
||||
|
@@ -31,8 +31,9 @@
|
||||
#include "projects.h"
|
||||
#include "clangdocument.h"
|
||||
#include "clangdocuments.h"
|
||||
#include "clangdocumentprocessors.h"
|
||||
#include "clangjobrequest.h"
|
||||
#include "unsavedfiles.h"
|
||||
#include "clangjobs.h"
|
||||
|
||||
#include <utf8string.h>
|
||||
|
||||
@@ -58,27 +59,33 @@ public:
|
||||
void updateVisibleTranslationUnits(const UpdateVisibleTranslationUnitsMessage &message) override;
|
||||
void requestDocumentAnnotations(const RequestDocumentAnnotationsMessage &message) override;
|
||||
|
||||
public /*for tests*/:
|
||||
public: // for tests
|
||||
const Documents &documentsForTestOnly() const;
|
||||
const Jobs &jobsForTestOnly();
|
||||
QList<Jobs::RunningJob> runningJobsForTestsOnly();
|
||||
int queueSizeForTestsOnly();
|
||||
bool isTimerRunningForTestOnly() const;
|
||||
void setUpdateDocumentAnnotationsTimeOutInMsForTestsOnly(int value);
|
||||
DocumentProcessors &documentProcessors();
|
||||
|
||||
private:
|
||||
Jobs &jobs();
|
||||
|
||||
void startDocumentAnnotationsTimerIfFileIsNotOpenAsDocument(const Utf8String &filePath);
|
||||
void addJobRequestsForDirtyAndVisibleDocuments();
|
||||
void processJobsForDirtyAndVisibleDocuments();
|
||||
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:
|
||||
ProjectParts projects;
|
||||
UnsavedFiles unsavedFiles;
|
||||
Documents documents;
|
||||
QScopedPointer<Jobs> jobs_;
|
||||
|
||||
QScopedPointer<DocumentProcessors> documentProcessors_; // Delayed initialization
|
||||
|
||||
QTimer updateDocumentAnnotationsTimer;
|
||||
int updateDocumentAnnotationsTimeOutInMs;
|
||||
|
@@ -50,29 +50,28 @@ static CompleteCodeJob::AsyncResult runAsyncHelper(const TranslationUnit &transl
|
||||
return asyncResult;
|
||||
}
|
||||
|
||||
bool CompleteCodeJob::prepareAsyncRun()
|
||||
IAsyncJob::AsyncPrepareResult CompleteCodeJob::prepareAsyncRun()
|
||||
{
|
||||
const JobRequest jobRequest = context().jobRequest;
|
||||
QTC_ASSERT(jobRequest.type == JobRequest::Type::CompleteCode, return false);
|
||||
QTC_ASSERT(jobRequest.type == JobRequest::Type::CompleteCode, return AsyncPrepareResult());
|
||||
|
||||
try {
|
||||
m_pinnedDocument = context().documentForJobRequest();
|
||||
|
||||
const TranslationUnit translationUnit = m_pinnedDocument.translationUnit();
|
||||
const TranslationUnit translationUnit
|
||||
= m_pinnedDocument.translationUnit(jobRequest.preferredTranslationUnit);
|
||||
const UnsavedFiles unsavedFiles = *context().unsavedFiles;
|
||||
const quint32 line = jobRequest.line;
|
||||
const quint32 column = jobRequest.column;
|
||||
setRunner([translationUnit, unsavedFiles, line, column]() {
|
||||
return runAsyncHelper(translationUnit, unsavedFiles, line, column);
|
||||
});
|
||||
|
||||
return AsyncPrepareResult{translationUnit.id()};
|
||||
|
||||
} catch (const std::exception &exception) {
|
||||
qWarning() << "Error in CompleteCodeJob::prepareAsyncRun:" << exception.what();
|
||||
return false;
|
||||
return AsyncPrepareResult();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CompleteCodeJob::finalizeAsyncRun()
|
||||
|
@@ -43,7 +43,7 @@ class CompleteCodeJob : public AsyncJob<CompleteCodeJobResult>
|
||||
public:
|
||||
using AsyncResult = CompleteCodeJobResult;
|
||||
|
||||
bool prepareAsyncRun() override;
|
||||
AsyncPrepareResult prepareAsyncRun() override;
|
||||
void finalizeAsyncRun() override;
|
||||
|
||||
private:
|
||||
|
@@ -39,28 +39,28 @@ static void runAsyncHelper(const TranslationUnit &translationUnit,
|
||||
translationUnit.reparse(translationUnitUpdateInput);
|
||||
}
|
||||
|
||||
bool CreateInitialDocumentPreambleJob::prepareAsyncRun()
|
||||
IAsyncJob::AsyncPrepareResult CreateInitialDocumentPreambleJob::prepareAsyncRun()
|
||||
{
|
||||
const JobRequest jobRequest = context().jobRequest;
|
||||
QTC_ASSERT(jobRequest.type == JobRequest::Type::CreateInitialDocumentPreamble, return false);
|
||||
QTC_ASSERT(jobRequest.type == JobRequest::Type::CreateInitialDocumentPreamble, return AsyncPrepareResult());
|
||||
|
||||
try {
|
||||
m_pinnedDocument = context().documentForJobRequest();
|
||||
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();
|
||||
setRunner([translationUnit, updateInput]() {
|
||||
return runAsyncHelper(translationUnit, updateInput);
|
||||
});
|
||||
return AsyncPrepareResult{translationUnit.id()};
|
||||
|
||||
} catch (const std::exception &exception) {
|
||||
qWarning() << "Error in CreateInitialDocumentPreambleJob::prepareAsyncRun:"
|
||||
<< exception.what();
|
||||
return false;
|
||||
return AsyncPrepareResult();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CreateInitialDocumentPreambleJob::finalizeAsyncRun()
|
||||
|
@@ -33,7 +33,7 @@ namespace ClangBackEnd {
|
||||
class CreateInitialDocumentPreambleJob : public AsyncJob<void>
|
||||
{
|
||||
public:
|
||||
bool prepareAsyncRun() override;
|
||||
AsyncPrepareResult prepareAsyncRun() override;
|
||||
void finalizeAsyncRun() override;
|
||||
|
||||
private:
|
||||
|
@@ -32,6 +32,7 @@
|
||||
#include "projectpart.h"
|
||||
#include "clangexceptions.h"
|
||||
#include "clangtranslationunit.h"
|
||||
#include "clangtranslationunits.h"
|
||||
#include "clangtranslationunitupdater.h"
|
||||
#include "unsavedfiles.h"
|
||||
#include "unsavedfile.h"
|
||||
@@ -62,15 +63,14 @@ public:
|
||||
const Utf8StringVector fileArguments;
|
||||
|
||||
ProjectPart projectPart;
|
||||
time_point lastProjectPartChangeTimePoint;
|
||||
TimePoint lastProjectPartChangeTimePoint;
|
||||
|
||||
CXTranslationUnit translationUnit = nullptr;
|
||||
CXIndex index = nullptr;
|
||||
TranslationUnits translationUnits;
|
||||
|
||||
QSet<Utf8String> dependedFilePaths;
|
||||
|
||||
uint documentRevision = 0;
|
||||
time_point needsToBeReparsedChangeTimePoint;
|
||||
TimePoint needsToBeReparsedChangeTimePoint;
|
||||
bool hasParseOrReparseFailed = false;
|
||||
bool needsToBeReparsed = false;
|
||||
bool isUsedByCurrentEditor = false;
|
||||
@@ -85,16 +85,16 @@ DocumentData::DocumentData(const Utf8String &filePath,
|
||||
filePath(filePath),
|
||||
fileArguments(fileArguments),
|
||||
projectPart(projectPart),
|
||||
lastProjectPartChangeTimePoint(std::chrono::steady_clock::now()),
|
||||
lastProjectPartChangeTimePoint(Clock::now()),
|
||||
translationUnits(filePath),
|
||||
needsToBeReparsedChangeTimePoint(lastProjectPartChangeTimePoint)
|
||||
{
|
||||
dependedFilePaths.insert(filePath);
|
||||
translationUnits.createAndAppend();
|
||||
}
|
||||
|
||||
DocumentData::~DocumentData()
|
||||
{
|
||||
clang_disposeTranslationUnit(translationUnit);
|
||||
clang_disposeIndex(index);
|
||||
}
|
||||
|
||||
Document::Document(const Utf8String &filePath,
|
||||
@@ -183,7 +183,7 @@ const ProjectPart &Document::projectPart() const
|
||||
return d->projectPart;
|
||||
}
|
||||
|
||||
const time_point Document::lastProjectPartChangeTimePoint() const
|
||||
const TimePoint Document::lastProjectPartChangeTimePoint() const
|
||||
{
|
||||
checkIfNull();
|
||||
|
||||
@@ -239,7 +239,7 @@ void Document::setIsVisibleInEditor(bool isVisibleInEditor)
|
||||
d->isVisibleInEditor = isVisibleInEditor;
|
||||
}
|
||||
|
||||
time_point Document::isNeededReparseChangeTimePoint() const
|
||||
TimePoint Document::isNeededReparseChangeTimePoint() const
|
||||
{
|
||||
checkIfNull();
|
||||
|
||||
@@ -282,8 +282,13 @@ TranslationUnitUpdateInput Document::createUpdateInput() const
|
||||
|
||||
TranslationUnitUpdater Document::createUpdater() const
|
||||
{
|
||||
TranslationUnit unit = translationUnit();
|
||||
|
||||
const TranslationUnitUpdateInput updateInput = createUpdateInput();
|
||||
TranslationUnitUpdater updater(d->index, d->translationUnit, updateInput);
|
||||
TranslationUnitUpdater updater(unit.id(),
|
||||
unit.cxIndex(),
|
||||
unit.cxTranslationUnit(),
|
||||
updateInput);
|
||||
|
||||
return updater;
|
||||
}
|
||||
@@ -304,9 +309,13 @@ void Document::incorporateUpdaterResult(const TranslationUnitUpdateResult &resul
|
||||
if (result.hasParsed())
|
||||
d->lastProjectPartChangeTimePoint = result.parseTimePoint;
|
||||
|
||||
if (result.hasParsed() || result.hasReparsed())
|
||||
if (result.hasParsed() || result.hasReparsed()) {
|
||||
d->dependedFilePaths = result.dependedOnFilePaths;
|
||||
|
||||
const TimePoint timePoint = qMax(result.parseTimePoint, result.reparseTimePoint);
|
||||
d->translationUnits.updateParseTimePoint(result.translationUnitId, timePoint);
|
||||
}
|
||||
|
||||
d->documents.addWatchedFiles(d->dependedFilePaths);
|
||||
|
||||
if (result.hasReparsed()
|
||||
@@ -315,11 +324,16 @@ void Document::incorporateUpdaterResult(const TranslationUnitUpdateResult &resul
|
||||
}
|
||||
}
|
||||
|
||||
TranslationUnit Document::translationUnit() const
|
||||
TranslationUnit Document::translationUnit(PreferredTranslationUnit preferredTranslationUnit) const
|
||||
{
|
||||
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
|
||||
@@ -352,7 +366,7 @@ const QSet<Utf8String> Document::dependedFilePaths() const
|
||||
|
||||
void Document::setDirty()
|
||||
{
|
||||
d->needsToBeReparsedChangeTimePoint = std::chrono::steady_clock::now();
|
||||
d->needsToBeReparsedChangeTimePoint = Clock::now();
|
||||
d->needsToBeReparsed = true;
|
||||
}
|
||||
|
||||
|
@@ -27,6 +27,7 @@
|
||||
|
||||
#include "clangtranslationunitupdater.h"
|
||||
|
||||
#include "clangbackend_global.h"
|
||||
#include "clangtranslationunit.h"
|
||||
|
||||
#include <utf8stringvector.h>
|
||||
@@ -36,7 +37,6 @@
|
||||
#include <QSet>
|
||||
#include <QtGlobal>
|
||||
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
|
||||
class Utf8String;
|
||||
@@ -44,14 +44,13 @@ class Utf8String;
|
||||
namespace ClangBackEnd {
|
||||
|
||||
class TranslationUnit;
|
||||
class TranslationUnits;
|
||||
class DocumentData;
|
||||
class TranslationUnitUpdateResult;
|
||||
class ProjectPart;
|
||||
class FileContainer;
|
||||
class Documents;
|
||||
|
||||
using time_point = std::chrono::steady_clock::time_point;
|
||||
|
||||
class Document
|
||||
{
|
||||
public:
|
||||
@@ -85,7 +84,7 @@ public:
|
||||
|
||||
Utf8String projectPartId() const;
|
||||
const ProjectPart &projectPart() const;
|
||||
const time_point lastProjectPartChangeTimePoint() const;
|
||||
const TimePoint lastProjectPartChangeTimePoint() const;
|
||||
bool isProjectPartOutdated() const;
|
||||
|
||||
uint documentRevision() const;
|
||||
@@ -104,7 +103,9 @@ public:
|
||||
TranslationUnitUpdateInput createUpdateInput() const;
|
||||
void incorporateUpdaterResult(const TranslationUnitUpdateResult &result) const;
|
||||
|
||||
TranslationUnit translationUnit() const;
|
||||
TranslationUnit translationUnit(PreferredTranslationUnit preferredTranslationUnit
|
||||
= PreferredTranslationUnit::RecentlyParsed) const;
|
||||
TranslationUnits &translationUnits() const;
|
||||
|
||||
public: // for tests
|
||||
void parse() const;
|
||||
@@ -112,7 +113,7 @@ public: // for tests
|
||||
const QSet<Utf8String> dependedFilePaths() const;
|
||||
TranslationUnitUpdater createUpdater() const;
|
||||
void setHasParseOrReparseFailed(bool hasFailed);
|
||||
time_point isNeededReparseChangeTimePoint() const;
|
||||
TimePoint isNeededReparseChangeTimePoint() const;
|
||||
|
||||
private:
|
||||
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;
|
||||
}
|
||||
|
||||
void Documents::update(const QVector<FileContainer> &fileContainers)
|
||||
std::vector<Document> Documents::update(const QVector<FileContainer> &fileContainers)
|
||||
{
|
||||
checkIfDocumentsForFilePathsExist(fileContainers);
|
||||
|
||||
std::vector<Document> createdDocuments;
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
return createdDocuments;
|
||||
}
|
||||
|
||||
static bool removeFromFileContainer(QVector<FileContainer> &fileContainers, const Document &document)
|
||||
@@ -205,12 +211,14 @@ Document Documents::createDocument(const FileContainer &fileContainer)
|
||||
return documents_.back();
|
||||
}
|
||||
|
||||
void Documents::updateDocument(const FileContainer &fileContainer)
|
||||
std::vector<Document> Documents::updateDocument(const FileContainer &fileContainer)
|
||||
{
|
||||
const auto documents = findAllDocumentsWithFilePath(fileContainer.filePath());
|
||||
|
||||
for (auto document : documents)
|
||||
document.setDocumentRevision(fileContainer.documentRevision());
|
||||
|
||||
return documents;
|
||||
}
|
||||
|
||||
std::vector<Document>::iterator Documents::findDocument(const FileContainer &fileContainer)
|
||||
|
@@ -45,7 +45,7 @@ public:
|
||||
Documents(ProjectParts &projectParts, UnsavedFiles &unsavedFiles);
|
||||
|
||||
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 setUsedByCurrentEditor(const Utf8String &filePath);
|
||||
@@ -72,7 +72,7 @@ public:
|
||||
|
||||
private:
|
||||
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> findAllDocumentsWithFilePath(const Utf8String &filePath);
|
||||
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!");
|
||||
}
|
||||
|
||||
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
|
||||
|
@@ -74,4 +74,24 @@ public:
|
||||
DocumentIsNullException();
|
||||
};
|
||||
|
||||
class DocumentProcessorAlreadyExists : public ClangBaseException
|
||||
{
|
||||
public:
|
||||
DocumentProcessorAlreadyExists(const Utf8String &filePath,
|
||||
const Utf8String &projectPartId);
|
||||
};
|
||||
|
||||
class DocumentProcessorDoesNotExist : public ClangBaseException
|
||||
{
|
||||
public:
|
||||
DocumentProcessorDoesNotExist(const Utf8String &filePath,
|
||||
const Utf8String &projectPartId);
|
||||
};
|
||||
|
||||
class TranslationUnitDoesNotExist : public ClangBaseException
|
||||
{
|
||||
public:
|
||||
TranslationUnitDoesNotExist(const Utf8String &filePath);
|
||||
};
|
||||
|
||||
} // namespace ClangBackEnd
|
||||
|
@@ -27,6 +27,8 @@
|
||||
|
||||
#include "clangcompletecodejob.h"
|
||||
#include "clangcreateinitialdocumentpreamblejob.h"
|
||||
#include "clangparsesupportivetranslationunitjob.h"
|
||||
#include "clangreparsesupportivetranslationunitjob.h"
|
||||
#include "clangrequestdocumentannotationsjob.h"
|
||||
#include "clangupdatedocumentannotationsjob.h"
|
||||
|
||||
@@ -39,6 +41,10 @@ IAsyncJob *IAsyncJob::create(JobRequest::Type type)
|
||||
switch (type) {
|
||||
case JobRequest::Type::UpdateDocumentAnnotations:
|
||||
return new UpdateDocumentAnnotationsJob();
|
||||
case JobRequest::Type::ParseSupportiveTranslationUnit:
|
||||
return new ParseSupportiveTranslationUnitJob();
|
||||
case JobRequest::Type::ReparseSupportiveTranslationUnit:
|
||||
return new ReparseSupportiveTranslationUnitJob();
|
||||
case JobRequest::Type::CreateInitialDocumentPreamble:
|
||||
return new CreateInitialDocumentPreambleJob();
|
||||
case JobRequest::Type::CompleteCode:
|
||||
|
@@ -41,6 +41,11 @@ class IAsyncJob
|
||||
public:
|
||||
static IAsyncJob *create(JobRequest::Type type);
|
||||
|
||||
struct AsyncPrepareResult {
|
||||
operator bool() const { return !translationUnitId.isEmpty(); }
|
||||
Utf8String translationUnitId;
|
||||
};
|
||||
|
||||
public:
|
||||
IAsyncJob();
|
||||
virtual ~IAsyncJob();
|
||||
@@ -52,10 +57,12 @@ public:
|
||||
FinishedHandler finishedHandler() const;
|
||||
void setFinishedHandler(const FinishedHandler &finishedHandler);
|
||||
|
||||
virtual bool prepareAsyncRun() = 0;
|
||||
virtual AsyncPrepareResult prepareAsyncRun() = 0;
|
||||
virtual QFuture<void> runAsync() = 0;
|
||||
virtual void finalizeAsyncRun() = 0;
|
||||
|
||||
virtual void preventFinalization() = 0;
|
||||
|
||||
public: // for tests
|
||||
bool isFinished() const;
|
||||
void setIsFinished(bool isFinished);
|
||||
|
@@ -27,6 +27,7 @@
|
||||
#include "clangjobqueue.h"
|
||||
#include "clangdocument.h"
|
||||
#include "clangdocuments.h"
|
||||
#include "clangtranslationunits.h"
|
||||
#include "projects.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);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int JobQueue::size() const
|
||||
@@ -164,50 +176,65 @@ void JobQueue::prioritizeRequests()
|
||||
JobRequests JobQueue::takeJobRequestsToRunNow()
|
||||
{
|
||||
JobRequests jobsToRun;
|
||||
QSet<DocumentId> documentsScheduledForThisRun;
|
||||
using TranslationUnitIds = QSet<Utf8String>;
|
||||
TranslationUnitIds translationUnitsScheduledForThisRun;
|
||||
|
||||
QMutableVectorIterator<JobRequest> i(m_queue);
|
||||
while (i.hasNext()) {
|
||||
const JobRequest &jobRequest = i.next();
|
||||
const JobRequest &request = i.next();
|
||||
|
||||
try {
|
||||
const Document &document
|
||||
= m_documents.document(jobRequest.filePath,
|
||||
jobRequest.projectPartId);
|
||||
const DocumentId documentId = DocumentId(jobRequest.filePath, jobRequest.projectPartId);
|
||||
const Document &document = m_documents.document(request.filePath,
|
||||
request.projectPartId);
|
||||
|
||||
if (!document.isUsedByCurrentEditor() && !document.isVisibleInEditor())
|
||||
continue;
|
||||
|
||||
if (documentsScheduledForThisRun.contains(documentId))
|
||||
const Utf8String id = document.translationUnit(request.preferredTranslationUnit).id();
|
||||
if (translationUnitsScheduledForThisRun.contains(id))
|
||||
continue;
|
||||
|
||||
if (isJobRunningForDocument(documentId))
|
||||
if (isJobRunningForTranslationUnit(id))
|
||||
continue;
|
||||
|
||||
documentsScheduledForThisRun.insert(documentId);
|
||||
jobsToRun += jobRequest;
|
||||
translationUnitsScheduledForThisRun.insert(id);
|
||||
jobsToRun += request;
|
||||
i.remove();
|
||||
} catch (const std::exception &exception) {
|
||||
qWarning() << "Error in Jobs::takeJobRequestsToRunNow for"
|
||||
<< jobRequest << ":" << exception.what();
|
||||
<< request << ":" << exception.what();
|
||||
}
|
||||
}
|
||||
|
||||
return jobsToRun;
|
||||
}
|
||||
|
||||
bool JobQueue::isJobRunningForDocument(const JobQueue::DocumentId &documentId)
|
||||
bool JobQueue::isJobRunningForTranslationUnit(const Utf8String &translationUnitId)
|
||||
{
|
||||
if (m_isJobRunningHandler)
|
||||
return m_isJobRunningHandler(documentId.first, documentId.second);
|
||||
if (m_isJobRunningForTranslationUnitHandler)
|
||||
return m_isJobRunningForTranslationUnitHandler(translationUnitId);
|
||||
|
||||
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
|
||||
|
@@ -39,12 +39,17 @@ class JobQueue
|
||||
public:
|
||||
JobQueue(Documents &documents, ProjectParts &projects);
|
||||
|
||||
void add(const JobRequest &job);
|
||||
bool add(const JobRequest &job);
|
||||
|
||||
JobRequests processQueue();
|
||||
|
||||
using IsJobRunningHandler = std::function<bool(const Utf8String &, const Utf8String &)>;
|
||||
void setIsJobRunningHandler(const IsJobRunningHandler &isJobRunningHandler);
|
||||
using IsJobRunningForTranslationUnitHandler = std::function<bool(const Utf8String &)>;
|
||||
void setIsJobRunningForTranslationUnitHandler(
|
||||
const IsJobRunningForTranslationUnitHandler &isJobRunningHandler);
|
||||
|
||||
using IsJobRunningForJobRequestHandler = std::function<bool(const JobRequest &)>;
|
||||
void setIsJobRunningForJobRequestHandler(
|
||||
const IsJobRunningForJobRequestHandler &isJobRunningHandler);
|
||||
|
||||
public: // for tests
|
||||
JobRequests queue() const;
|
||||
@@ -52,8 +57,8 @@ public: // for tests
|
||||
void prioritizeRequests();
|
||||
|
||||
private:
|
||||
using DocumentId = QPair<Utf8String, Utf8String>;
|
||||
bool isJobRunningForDocument(const DocumentId &documentId);
|
||||
bool isJobRunningForTranslationUnit(const Utf8String &translationUnitId);
|
||||
bool isJobRunningForJobRequest(const JobRequest &jobRequest);
|
||||
JobRequests takeJobRequestsToRunNow();
|
||||
void removeOutDatedRequests();
|
||||
bool isJobRequestOutDated(const JobRequest &jobRequest) const;
|
||||
@@ -62,7 +67,8 @@ private:
|
||||
Documents &m_documents;
|
||||
ProjectParts &m_projectParts;
|
||||
|
||||
IsJobRunningHandler m_isJobRunningHandler;
|
||||
IsJobRunningForTranslationUnitHandler m_isJobRunningForTranslationUnitHandler;
|
||||
IsJobRunningForJobRequestHandler m_isJobRunningForJobRequestHandler;
|
||||
|
||||
JobRequests m_queue;
|
||||
};
|
||||
|
@@ -25,6 +25,8 @@
|
||||
|
||||
#include "clangjobrequest.h"
|
||||
|
||||
#include <QFileInfo>
|
||||
|
||||
namespace ClangBackEnd {
|
||||
|
||||
#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) {
|
||||
RETURN_TEXT_FOR_CASE(UpdateDocumentAnnotations);
|
||||
RETURN_TEXT_FOR_CASE(ParseSupportiveTranslationUnit);
|
||||
RETURN_TEXT_FOR_CASE(ReparseSupportiveTranslationUnit);
|
||||
RETURN_TEXT_FOR_CASE(CreateInitialDocumentPreamble);
|
||||
RETURN_TEXT_FOR_CASE(CompleteCode);
|
||||
RETURN_TEXT_FOR_CASE(RequestDocumentAnnotations);
|
||||
@@ -41,6 +45,19 @@ static const char *JobRequestTypeToText(JobRequest::Type type)
|
||||
}
|
||||
#undef RETURN_TEXT_FOR_CASE
|
||||
|
||||
#define RETURN_TEXT_FOR_CASE(enumValue) case PreferredTranslationUnit::enumValue: return #enumValue
|
||||
const char *preferredTranslationUnitToText(PreferredTranslationUnit type)
|
||||
{
|
||||
switch (type) {
|
||||
RETURN_TEXT_FOR_CASE(RecentlyParsed);
|
||||
RETURN_TEXT_FOR_CASE(PreviouslyParsed);
|
||||
RETURN_TEXT_FOR_CASE(LastUninitialized);
|
||||
}
|
||||
|
||||
return "UnhandledPreferredTranslationUnitType";
|
||||
}
|
||||
#undef RETURN_TEXT_FOR_CASE
|
||||
|
||||
QDebug operator<<(QDebug debug, JobRequest::Type type)
|
||||
{
|
||||
debug << JobRequestTypeToText(type);
|
||||
@@ -53,12 +70,14 @@ QDebug operator<<(QDebug debug, const JobRequest &jobRequest)
|
||||
debug.nospace() << "Job<"
|
||||
<< jobRequest.id
|
||||
<< ","
|
||||
<< QFileInfo(jobRequest.filePath).fileName()
|
||||
<< ","
|
||||
<< JobRequestTypeToText(jobRequest.type)
|
||||
<< ","
|
||||
<< jobRequest.filePath
|
||||
<< preferredTranslationUnitToText(jobRequest.preferredTranslationUnit)
|
||||
<< ">";
|
||||
|
||||
return debug;
|
||||
return debug.space();
|
||||
}
|
||||
|
||||
JobRequest::JobRequest()
|
||||
@@ -67,6 +86,23 @@ JobRequest::JobRequest()
|
||||
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)
|
||||
{
|
||||
switch (type) {
|
||||
@@ -77,6 +113,8 @@ JobRequest::Requirements JobRequest::requirementsForType(Type type)
|
||||
|JobRequest::CurrentDocumentRevision);
|
||||
case JobRequest::Type::CompleteCode:
|
||||
case JobRequest::Type::CreateInitialDocumentPreamble:
|
||||
case JobRequest::Type::ParseSupportiveTranslationUnit:
|
||||
case JobRequest::Type::ReparseSupportiveTranslationUnit:
|
||||
return JobRequest::Requirements(JobRequest::DocumentValid);
|
||||
}
|
||||
|
||||
|
@@ -25,17 +25,20 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "clangbackend_global.h"
|
||||
#include "clangclock.h"
|
||||
|
||||
#include <utf8string.h>
|
||||
|
||||
#include <QFlags>
|
||||
#include <QDebug>
|
||||
#include <QVector>
|
||||
|
||||
#include <chrono>
|
||||
#include <functional>
|
||||
|
||||
namespace ClangBackEnd {
|
||||
|
||||
using time_point = std::chrono::steady_clock::time_point;
|
||||
class Document;
|
||||
|
||||
class JobRequest
|
||||
{
|
||||
@@ -43,6 +46,10 @@ public:
|
||||
enum class Type {
|
||||
UpdateDocumentAnnotations,
|
||||
CreateInitialDocumentPreamble,
|
||||
|
||||
ParseSupportiveTranslationUnit,
|
||||
ReparseSupportiveTranslationUnit,
|
||||
|
||||
CompleteCode,
|
||||
RequestDocumentAnnotations,
|
||||
};
|
||||
@@ -64,6 +71,8 @@ public:
|
||||
|
||||
JobRequest();
|
||||
|
||||
bool operator==(const JobRequest &other) const;
|
||||
|
||||
public:
|
||||
quint64 id = 0;
|
||||
Type type;
|
||||
@@ -72,9 +81,10 @@ public:
|
||||
// General
|
||||
Utf8String filePath;
|
||||
Utf8String projectPartId;
|
||||
time_point unsavedFilesChangeTimePoint;
|
||||
time_point projectChangeTimePoint;
|
||||
TimePoint unsavedFilesChangeTimePoint;
|
||||
TimePoint projectChangeTimePoint;
|
||||
uint documentRevision = 0;
|
||||
PreferredTranslationUnit preferredTranslationUnit = PreferredTranslationUnit::RecentlyParsed;
|
||||
|
||||
// For code completion
|
||||
quint32 line = 0;
|
||||
@@ -83,6 +93,9 @@ public:
|
||||
};
|
||||
|
||||
using JobRequests = QVector<JobRequest>;
|
||||
using JobRequestCreator = std::function<JobRequest(const Document &,
|
||||
JobRequest::Type ,
|
||||
PreferredTranslationUnit)>;
|
||||
|
||||
QDebug operator<<(QDebug debug, const JobRequest &jobRequest);
|
||||
|
||||
|
@@ -45,17 +45,25 @@ Jobs::Jobs(Documents &documents,
|
||||
, m_client(client)
|
||||
, m_queue(documents, projectParts)
|
||||
{
|
||||
m_queue.setIsJobRunningHandler([this](const Utf8String &filePath,
|
||||
const Utf8String &projectPartId) {
|
||||
return isJobRunning(filePath, projectPartId);
|
||||
m_queue.setIsJobRunningForTranslationUnitHandler([this](const Utf8String &translationUnitId) {
|
||||
return isJobRunningForTranslationUnit(translationUnitId);
|
||||
});
|
||||
m_queue.setIsJobRunningForJobRequestHandler([this](const JobRequest &jobRequest) {
|
||||
return isJobRunningForJobRequest(jobRequest);
|
||||
});
|
||||
}
|
||||
|
||||
Jobs::~Jobs()
|
||||
{
|
||||
foreach (IAsyncJob *asyncJob, m_running.keys())
|
||||
asyncJob->preventFinalization();
|
||||
|
||||
QFutureSynchronizer<void> waitForFinishedJobs;
|
||||
foreach (const RunningJob &runningJob, m_running.values())
|
||||
waitForFinishedJobs.addFuture(runningJob.future);
|
||||
|
||||
foreach (IAsyncJob *asyncJob, m_running.keys())
|
||||
delete asyncJob;
|
||||
}
|
||||
|
||||
void Jobs::add(const JobRequest &job)
|
||||
@@ -87,23 +95,26 @@ JobRequests Jobs::runJobs(const JobRequests &jobsRequests)
|
||||
|
||||
bool Jobs::runJob(const JobRequest &jobRequest)
|
||||
{
|
||||
if (IAsyncJob *asyncJob = IAsyncJob::create(jobRequest.type)) {
|
||||
IAsyncJob *asyncJob = IAsyncJob::create(jobRequest.type);
|
||||
QTC_ASSERT(asyncJob, return false);
|
||||
|
||||
JobContext context(jobRequest, &m_documents, &m_unsavedFiles, &m_client);
|
||||
asyncJob->setContext(context);
|
||||
|
||||
if (asyncJob->prepareAsyncRun()) {
|
||||
qCDebug(jobsLog) << "Running" << jobRequest;
|
||||
if (const IAsyncJob::AsyncPrepareResult prepareResult = asyncJob->prepareAsyncRun()) {
|
||||
qCDebug(jobsLog) << "Running" << jobRequest
|
||||
<< "with TranslationUnit" << prepareResult.translationUnitId;
|
||||
|
||||
asyncJob->setFinishedHandler([this](IAsyncJob *asyncJob){ onJobFinished(asyncJob); });
|
||||
const QFuture<void> future = asyncJob->runAsync();
|
||||
|
||||
m_running.insert(asyncJob, RunningJob{jobRequest, future});
|
||||
const RunningJob runningJob{jobRequest, prepareResult.translationUnitId, future};
|
||||
m_running.insert(asyncJob, runningJob);
|
||||
return true;
|
||||
} else {
|
||||
qCDebug(jobsLog) << "Preparation failed for " << jobRequest;
|
||||
delete asyncJob;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -112,15 +123,25 @@ void Jobs::onJobFinished(IAsyncJob *asyncJob)
|
||||
{
|
||||
qCDebug(jobsLog) << "Finishing" << asyncJob->context().jobRequest;
|
||||
|
||||
if (m_jobFinishedCallback) {
|
||||
const RunningJob runningJob = m_running.value(asyncJob);
|
||||
m_jobFinishedCallback(runningJob);
|
||||
}
|
||||
|
||||
m_running.remove(asyncJob);
|
||||
delete asyncJob;
|
||||
|
||||
process();
|
||||
}
|
||||
|
||||
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
|
||||
@@ -128,12 +149,19 @@ JobRequests Jobs::queue() const
|
||||
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 JobRequest &jobRequest = runningJob.jobRequest;
|
||||
return filePath == jobRequest.filePath
|
||||
&& projectPartId == jobRequest.projectPartId;
|
||||
const auto hasTranslationUnitId = [translationUnitId](const RunningJob &runningJob) {
|
||||
return runningJob.translationUnitId == translationUnitId;
|
||||
};
|
||||
|
||||
return Utils::anyOf(m_running.values(), hasTranslationUnitId);
|
||||
}
|
||||
|
||||
bool Jobs::isJobRunningForJobRequest(const JobRequest &jobRequest) const
|
||||
{
|
||||
const auto hasJobRequest = [jobRequest](const RunningJob &runningJob) {
|
||||
return runningJob.jobRequest == jobRequest;
|
||||
};
|
||||
|
||||
return Utils::anyOf(m_running.values(), hasJobRequest);
|
||||
|
@@ -31,6 +31,8 @@
|
||||
|
||||
#include <QFuture>
|
||||
|
||||
#include <functional>
|
||||
|
||||
namespace ClangBackEnd {
|
||||
|
||||
class ClangCodeModelClientInterface;
|
||||
@@ -43,9 +45,12 @@ class Jobs
|
||||
public:
|
||||
struct RunningJob {
|
||||
JobRequest jobRequest;
|
||||
Utf8String translationUnitId;
|
||||
QFuture<void> future;
|
||||
};
|
||||
|
||||
using RunningJobs = QHash<IAsyncJob *, RunningJob>;
|
||||
using JobFinishedCallback = std::function<void(RunningJob)>;
|
||||
|
||||
public:
|
||||
Jobs(Documents &documents,
|
||||
@@ -58,10 +63,13 @@ public:
|
||||
|
||||
JobRequests process();
|
||||
|
||||
void setJobFinishedCallback(const JobFinishedCallback &jobFinishedCallback);
|
||||
|
||||
public /*for tests*/:
|
||||
int runningJobs() const;
|
||||
QList<RunningJob> runningJobs() 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:
|
||||
JobRequests runJobs(const JobRequests &jobRequest);
|
||||
@@ -75,6 +83,7 @@ private:
|
||||
|
||||
JobQueue m_queue;
|
||||
RunningJobs m_running;
|
||||
JobFinishedCallback m_jobFinishedCallback;
|
||||
};
|
||||
|
||||
} // 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;
|
||||
|
||||
translationUnit.extractDocumentAnnotations(asyncResult.diagnostics,
|
||||
translationUnit.extractDocumentAnnotations(asyncResult.firstHeaderErrorDiagnostic,
|
||||
asyncResult.diagnostics,
|
||||
asyncResult.highlightingMarks,
|
||||
asyncResult.skippedSourceRanges);
|
||||
|
||||
return asyncResult;
|
||||
}
|
||||
|
||||
bool RequestDocumentAnnotationsJob::prepareAsyncRun()
|
||||
IAsyncJob::AsyncPrepareResult RequestDocumentAnnotationsJob::prepareAsyncRun()
|
||||
{
|
||||
const JobRequest jobRequest = context().jobRequest;
|
||||
QTC_ASSERT(jobRequest.type == JobRequest::Type::RequestDocumentAnnotations, return false);
|
||||
QTC_ASSERT(jobRequest.type == JobRequest::Type::RequestDocumentAnnotations,
|
||||
return AsyncPrepareResult());
|
||||
|
||||
try {
|
||||
m_pinnedDocument = context().documentForJobRequest();
|
||||
m_pinnedFileContainer = m_pinnedDocument.fileContainer();
|
||||
|
||||
const TranslationUnit translationUnit = m_pinnedDocument.translationUnit();
|
||||
const TranslationUnit translationUnit
|
||||
= m_pinnedDocument.translationUnit(jobRequest.preferredTranslationUnit);
|
||||
setRunner([translationUnit]() {
|
||||
return runAsyncHelper(translationUnit);
|
||||
});
|
||||
return AsyncPrepareResult{translationUnit.id()};
|
||||
|
||||
} catch (const std::exception &exception) {
|
||||
qWarning() << "Error in RequestDocumentAnnotationsJob::prepareAsyncRun:" << exception.what();
|
||||
return false;
|
||||
return AsyncPrepareResult();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void RequestDocumentAnnotationsJob::finalizeAsyncRun()
|
||||
@@ -82,6 +84,7 @@ void RequestDocumentAnnotationsJob::sendAnnotations(
|
||||
{
|
||||
const DocumentAnnotationsChangedMessage message(m_pinnedFileContainer,
|
||||
result.diagnostics,
|
||||
result.firstHeaderErrorDiagnostic,
|
||||
result.highlightingMarks,
|
||||
result.skippedSourceRanges);
|
||||
|
||||
|
@@ -36,6 +36,7 @@ namespace ClangBackEnd {
|
||||
|
||||
struct RequestDocumentAnnotationsJobResult
|
||||
{
|
||||
ClangBackEnd::DiagnosticContainer firstHeaderErrorDiagnostic;
|
||||
QVector<ClangBackEnd::DiagnosticContainer> diagnostics;
|
||||
QVector<HighlightingMarkContainer> highlightingMarks;
|
||||
QVector<SourceRangeContainer> skippedSourceRanges;
|
||||
@@ -46,7 +47,7 @@ class RequestDocumentAnnotationsJob : public AsyncJob<RequestDocumentAnnotations
|
||||
public:
|
||||
using AsyncResult = RequestDocumentAnnotationsJobResult;
|
||||
|
||||
bool prepareAsyncRun() override;
|
||||
AsyncPrepareResult prepareAsyncRun() override;
|
||||
void finalizeAsyncRun() override;
|
||||
|
||||
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 {
|
||||
|
||||
TranslationUnit::TranslationUnit(const Utf8String &filepath,
|
||||
TranslationUnit::TranslationUnit(const Utf8String &id,
|
||||
const Utf8String &filepath,
|
||||
CXIndex &cxIndex,
|
||||
CXTranslationUnit &cxTranslationUnit)
|
||||
: m_filePath(filepath)
|
||||
: m_id(id)
|
||||
, m_filePath(filepath)
|
||||
, m_cxIndex(cxIndex)
|
||||
, m_cxTranslationUnit(cxTranslationUnit)
|
||||
{
|
||||
@@ -49,7 +51,12 @@ TranslationUnit::TranslationUnit(const Utf8String &filepath,
|
||||
|
||||
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
|
||||
@@ -70,7 +77,7 @@ CXTranslationUnit &TranslationUnit::cxTranslationUnit() const
|
||||
TranslationUnitUpdateResult TranslationUnit::update(
|
||||
const TranslationUnitUpdateInput &parseInput) const
|
||||
{
|
||||
TranslationUnitUpdater updater(cxIndex(), cxTranslationUnit(), parseInput);
|
||||
TranslationUnitUpdater updater(id(), cxIndex(), cxTranslationUnit(), parseInput);
|
||||
|
||||
return updater.update(TranslationUnitUpdater::UpdateMode::AsNeeded);
|
||||
}
|
||||
@@ -78,7 +85,7 @@ TranslationUnitUpdateResult TranslationUnit::update(
|
||||
TranslationUnitUpdateResult TranslationUnit::parse(
|
||||
const TranslationUnitUpdateInput &parseInput) const
|
||||
{
|
||||
TranslationUnitUpdater updater(cxIndex(), cxTranslationUnit(), parseInput);
|
||||
TranslationUnitUpdater updater(id(), cxIndex(), cxTranslationUnit(), parseInput);
|
||||
|
||||
return updater.update(TranslationUnitUpdater::UpdateMode::ParseIfNeeded);
|
||||
}
|
||||
@@ -86,7 +93,7 @@ TranslationUnitUpdateResult TranslationUnit::parse(
|
||||
TranslationUnitUpdateResult TranslationUnit::reparse(
|
||||
const TranslationUnitUpdateInput &parseInput) const
|
||||
{
|
||||
TranslationUnitUpdater updater(cxIndex(), cxTranslationUnit(), parseInput);
|
||||
TranslationUnitUpdater updater(id(), cxIndex(), cxTranslationUnit(), parseInput);
|
||||
|
||||
return updater.update(TranslationUnitUpdater::UpdateMode::ForceReparse);
|
||||
}
|
||||
@@ -105,11 +112,12 @@ TranslationUnit::CodeCompletionResult TranslationUnit::complete(
|
||||
}
|
||||
|
||||
void TranslationUnit::extractDocumentAnnotations(
|
||||
QVector<DiagnosticContainer> &diagnostics,
|
||||
DiagnosticContainer &firstHeaderErrorDiagnostic,
|
||||
QVector<DiagnosticContainer> &mainFileDiagnostics,
|
||||
QVector<HighlightingMarkContainer> &highlightingMarks,
|
||||
QVector<SourceRangeContainer> &skippedSourceRanges) const
|
||||
{
|
||||
diagnostics = mainFileDiagnostics();
|
||||
extractDiagnostics(firstHeaderErrorDiagnostic, mainFileDiagnostics);
|
||||
highlightingMarks = this->highlightingMarks().toHighlightingMarksContainers();
|
||||
skippedSourceRanges = this->skippedSourceRanges().toSourceRangeContainers();
|
||||
}
|
||||
@@ -119,15 +127,6 @@ DiagnosticSet TranslationUnit::diagnostics() const
|
||||
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
|
||||
{
|
||||
return SourceLocation(m_cxTranslationUnit, m_filePath, line, column);
|
||||
@@ -186,4 +185,35 @@ SkippedSourceRanges TranslationUnit::skippedSourceRanges() const
|
||||
return SkippedSourceRanges(m_cxTranslationUnit, m_filePath.constData());
|
||||
}
|
||||
|
||||
static bool isMainFileDiagnostic(const Utf8String &mainFilePath, const Diagnostic &diagnostic)
|
||||
{
|
||||
return diagnostic.location().filePath() == mainFilePath;
|
||||
}
|
||||
|
||||
static bool isHeaderErrorDiagnostic(const Utf8String &mainFilePath, const Diagnostic &diagnostic)
|
||||
{
|
||||
const bool isCritical = diagnostic.severity() == DiagnosticSeverity::Error
|
||||
|| diagnostic.severity() == DiagnosticSeverity::Fatal;
|
||||
return isCritical && diagnostic.location().filePath() != mainFilePath;
|
||||
}
|
||||
|
||||
void TranslationUnit::extractDiagnostics(DiagnosticContainer &firstHeaderErrorDiagnostic,
|
||||
QVector<DiagnosticContainer> &mainFileDiagnostics) const
|
||||
{
|
||||
mainFileDiagnostics.clear();
|
||||
mainFileDiagnostics.reserve(int(diagnostics().size()));
|
||||
|
||||
bool hasFirstHeaderErrorDiagnostic = false;
|
||||
|
||||
for (const Diagnostic &diagnostic : diagnostics()) {
|
||||
if (!hasFirstHeaderErrorDiagnostic && isHeaderErrorDiagnostic(m_filePath, diagnostic)) {
|
||||
hasFirstHeaderErrorDiagnostic = true;
|
||||
firstHeaderErrorDiagnostic = diagnostic.toDiagnosticContainer();
|
||||
}
|
||||
|
||||
if (isMainFileDiagnostic(m_filePath, diagnostic))
|
||||
mainFileDiagnostics.push_back(diagnostic.toDiagnosticContainer());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ClangBackEnd
|
||||
|
@@ -57,12 +57,15 @@ public:
|
||||
};
|
||||
|
||||
public:
|
||||
TranslationUnit(const Utf8String &filePath,
|
||||
TranslationUnit(const Utf8String &id,
|
||||
const Utf8String &filePath,
|
||||
CXIndex &cxIndex,
|
||||
CXTranslationUnit &cxTranslationUnit);
|
||||
|
||||
bool isNull() const;
|
||||
|
||||
Utf8String id() const;
|
||||
|
||||
Utf8String filePath() const;
|
||||
CXIndex &cxIndex() const;
|
||||
CXTranslationUnit &cxTranslationUnit() const;
|
||||
@@ -73,12 +76,14 @@ public:
|
||||
|
||||
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<SourceRangeContainer> &skippedSourceRanges) const;
|
||||
|
||||
DiagnosticSet diagnostics() const;
|
||||
QVector<DiagnosticContainer> mainFileDiagnostics() const;
|
||||
|
||||
SourceLocation sourceLocationAt(uint line, uint column) const;
|
||||
SourceLocation sourceLocationAt(const Utf8String &filePath, uint line, uint column) const;
|
||||
@@ -94,6 +99,7 @@ public:
|
||||
SkippedSourceRanges skippedSourceRanges() const;
|
||||
|
||||
private:
|
||||
const Utf8String m_id;
|
||||
const Utf8String m_filePath;
|
||||
CXIndex &m_cxIndex;
|
||||
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 {
|
||||
|
||||
TranslationUnitUpdater::TranslationUnitUpdater(CXIndex &index,
|
||||
TranslationUnitUpdater::TranslationUnitUpdater(const Utf8String translationUnitId,
|
||||
CXIndex &index,
|
||||
CXTranslationUnit &cxTranslationUnit,
|
||||
const TranslationUnitUpdateInput &updateData)
|
||||
: m_cxIndex(index)
|
||||
, m_cxTranslationUnit(cxTranslationUnit)
|
||||
, m_in(updateData)
|
||||
{
|
||||
m_out.translationUnitId = translationUnitId;
|
||||
}
|
||||
|
||||
TranslationUnitUpdateResult TranslationUnitUpdater::update(UpdateMode mode)
|
||||
@@ -122,7 +124,7 @@ void TranslationUnitUpdater::createTranslationUnitIfNeeded()
|
||||
|
||||
if (parseWasSuccessful()) {
|
||||
updateIncludeFilePaths();
|
||||
m_out.parseTimePoint = std::chrono::steady_clock::now();
|
||||
m_out.parseTimePoint = Clock::now();
|
||||
} else {
|
||||
qWarning() << "Parsing" << m_in.filePath << "failed:"
|
||||
<< errorCodeToText(m_parseErrorCode);
|
||||
@@ -151,7 +153,7 @@ void TranslationUnitUpdater::reparse()
|
||||
if (reparseWasSuccessful()) {
|
||||
updateIncludeFilePaths();
|
||||
|
||||
m_out.reparseTimePoint = std::chrono::steady_clock::now();
|
||||
m_out.reparseTimePoint = Clock::now();
|
||||
m_out.needsToBeReparsedChangeTimePoint = m_in.needsToBeReparsedChangeTimePoint;
|
||||
} else {
|
||||
qWarning() << "Reparsing" << m_in.filePath << "failed:" << m_reparseErrorCode;
|
||||
|
@@ -25,6 +25,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "clangclock.h"
|
||||
|
||||
#include "commandlinearguments.h"
|
||||
#include "unsavedfiles.h"
|
||||
#include "utf8stringvector.h"
|
||||
@@ -33,18 +35,14 @@
|
||||
|
||||
#include <QSet>
|
||||
|
||||
#include <chrono>
|
||||
|
||||
namespace ClangBackEnd {
|
||||
|
||||
using time_point = std::chrono::steady_clock::time_point;
|
||||
|
||||
class TranslationUnitUpdateInput {
|
||||
public:
|
||||
bool parseNeeded = false;
|
||||
bool reparseNeeded = false;
|
||||
|
||||
time_point needsToBeReparsedChangeTimePoint;
|
||||
TimePoint needsToBeReparsedChangeTimePoint;
|
||||
Utf8String filePath;
|
||||
Utf8StringVector fileArguments;
|
||||
|
||||
@@ -57,17 +55,18 @@ public:
|
||||
class TranslationUnitUpdateResult {
|
||||
public:
|
||||
bool hasParsed() const
|
||||
{ return parseTimePoint != time_point(); }
|
||||
{ return parseTimePoint != TimePoint(); }
|
||||
|
||||
bool hasReparsed() const
|
||||
{ return reparseTimePoint != time_point(); }
|
||||
{ return reparseTimePoint != TimePoint(); }
|
||||
|
||||
public:
|
||||
bool hasParseOrReparseFailed = false;
|
||||
Utf8String translationUnitId;
|
||||
|
||||
time_point parseTimePoint;
|
||||
time_point reparseTimePoint;
|
||||
time_point needsToBeReparsedChangeTimePoint;
|
||||
bool hasParseOrReparseFailed = false;
|
||||
TimePoint parseTimePoint;
|
||||
TimePoint reparseTimePoint;
|
||||
TimePoint needsToBeReparsedChangeTimePoint;
|
||||
|
||||
QSet<Utf8String> dependedOnFilePaths;
|
||||
};
|
||||
@@ -81,7 +80,8 @@ public:
|
||||
};
|
||||
|
||||
public:
|
||||
TranslationUnitUpdater(CXIndex &index,
|
||||
TranslationUnitUpdater(const Utf8String translationUnitId,
|
||||
CXIndex &index,
|
||||
CXTranslationUnit &cxTranslationUnit,
|
||||
const TranslationUnitUpdateInput &in);
|
||||
|
||||
|
@@ -69,7 +69,7 @@ bool Type::isReferencingConstant() const
|
||||
return (isPointer() || isLValueReference()) && pointeeType().isConstant();
|
||||
}
|
||||
|
||||
bool Type::isOutputParameter() const
|
||||
bool Type::isOutputArgument() const
|
||||
{
|
||||
return (isPointer() || isLValueReference()) && !pointeeType().isConstant();
|
||||
}
|
||||
|
@@ -49,7 +49,7 @@ public:
|
||||
bool isConstantPointer() const;
|
||||
bool isLValueReference() const;
|
||||
bool isReferencingConstant() const;
|
||||
bool isOutputParameter() const;
|
||||
bool isOutputArgument() const;
|
||||
|
||||
Utf8String utf8Spelling() const;
|
||||
ClangString spelling() const;
|
||||
|
@@ -45,34 +45,36 @@ static UpdateDocumentAnnotationsJob::AsyncResult runAsyncHelper(
|
||||
asyncResult.updateResult = translationUnit.update(translationUnitUpdatInput);
|
||||
|
||||
// Collect
|
||||
translationUnit.extractDocumentAnnotations(asyncResult.diagnostics,
|
||||
translationUnit.extractDocumentAnnotations(asyncResult.firstHeaderErrorDiagnostic,
|
||||
asyncResult.diagnostics,
|
||||
asyncResult.highlightingMarks,
|
||||
asyncResult.skippedSourceRanges);
|
||||
|
||||
return asyncResult;
|
||||
}
|
||||
|
||||
bool UpdateDocumentAnnotationsJob::prepareAsyncRun()
|
||||
IAsyncJob::AsyncPrepareResult UpdateDocumentAnnotationsJob::prepareAsyncRun()
|
||||
{
|
||||
const JobRequest jobRequest = context().jobRequest;
|
||||
QTC_ASSERT(jobRequest.type == JobRequest::Type::UpdateDocumentAnnotations, return false);
|
||||
QTC_ASSERT(jobRequest.type == JobRequest::Type::UpdateDocumentAnnotations,
|
||||
return AsyncPrepareResult());
|
||||
|
||||
try {
|
||||
m_pinnedDocument = context().documentForJobRequest();
|
||||
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();
|
||||
setRunner([translationUnit, updateInput]() {
|
||||
return runAsyncHelper(translationUnit, updateInput);
|
||||
});
|
||||
return AsyncPrepareResult{translationUnit.id()};
|
||||
|
||||
} catch (const std::exception &exception) {
|
||||
qWarning() << "Error in UpdateDocumentAnnotationsJob::prepareAsyncRun:" << exception.what();
|
||||
return false;
|
||||
return AsyncPrepareResult();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void UpdateDocumentAnnotationsJob::finalizeAsyncRun()
|
||||
@@ -94,6 +96,7 @@ void UpdateDocumentAnnotationsJob::sendAnnotations(const AsyncResult &result)
|
||||
{
|
||||
const DocumentAnnotationsChangedMessage message(m_pinnedFileContainer,
|
||||
result.diagnostics,
|
||||
result.firstHeaderErrorDiagnostic,
|
||||
result.highlightingMarks,
|
||||
result.skippedSourceRanges);
|
||||
|
||||
|
@@ -39,6 +39,7 @@ struct UpdateDocumentAnnotationsJobResult
|
||||
{
|
||||
TranslationUnitUpdateResult updateResult;
|
||||
|
||||
ClangBackEnd::DiagnosticContainer firstHeaderErrorDiagnostic;
|
||||
QVector<ClangBackEnd::DiagnosticContainer> diagnostics;
|
||||
QVector<HighlightingMarkContainer> highlightingMarks;
|
||||
QVector<SourceRangeContainer> skippedSourceRanges;
|
||||
@@ -49,7 +50,7 @@ class UpdateDocumentAnnotationsJob : public AsyncJob<UpdateDocumentAnnotationsJo
|
||||
public:
|
||||
using AsyncResult = UpdateDocumentAnnotationsJobResult;
|
||||
|
||||
bool prepareAsyncRun() override;
|
||||
AsyncPrepareResult prepareAsyncRun() override;
|
||||
void finalizeAsyncRun() override;
|
||||
|
||||
private:
|
||||
|
@@ -213,16 +213,32 @@ SourceLocation Cursor::sourceLocation() const
|
||||
return clang_getCursorLocation(cxCursor);
|
||||
}
|
||||
|
||||
CXSourceLocation Cursor::cxSourceLocation() const
|
||||
{
|
||||
return clang_getCursorLocation(cxCursor);
|
||||
}
|
||||
|
||||
SourceRange Cursor::sourceRange() const
|
||||
{
|
||||
return clang_getCursorExtent(cxCursor);
|
||||
}
|
||||
|
||||
CXSourceRange Cursor::cxSourceRange() const
|
||||
{
|
||||
return clang_getCursorExtent(cxCursor);
|
||||
}
|
||||
|
||||
SourceRange Cursor::commentRange() const
|
||||
{
|
||||
return clang_Cursor_getCommentRange(cxCursor);
|
||||
}
|
||||
|
||||
bool Cursor::hasSameSourceLocationAs(const Cursor &other) const
|
||||
{
|
||||
return clang_equalLocations(clang_getCursorLocation(cxCursor),
|
||||
clang_getCursorLocation(other.cxCursor));
|
||||
}
|
||||
|
||||
Cursor Cursor::definition() const
|
||||
{
|
||||
return clang_getCursorDefinition(cxCursor);
|
||||
@@ -279,32 +295,42 @@ Cursor Cursor::argument(int index) const
|
||||
{
|
||||
return clang_Cursor_getArgument(cxCursor, index);
|
||||
}
|
||||
|
||||
namespace {
|
||||
void collectOutputArguments(const Cursor &callExpression,
|
||||
std::vector<Cursor> &outputArguments)
|
||||
|
||||
bool isNotUnexposedLValueReference(const Cursor &argument, const Type &argumentType)
|
||||
{
|
||||
auto callExpressionType = callExpression.referenced().type();
|
||||
auto argumentCount = callExpression.argumentCount();
|
||||
outputArguments.reserve(argumentCount);
|
||||
return !(argument.isUnexposed() && argumentType.isLValueReference());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void Cursor::collectOutputArgumentRangesTo(std::vector<CXSourceRange> &outputArgumentRanges) const
|
||||
{
|
||||
const Type callExpressionType = referenced().type();
|
||||
const int argumentCount = this->argumentCount();
|
||||
const std::size_t maxSize = std::size_t(std::max(0, argumentCount))
|
||||
+ outputArgumentRanges.size();
|
||||
outputArgumentRanges.reserve(maxSize);
|
||||
|
||||
for (int argumentIndex = 0; argumentIndex < argumentCount; ++argumentIndex) {
|
||||
auto argument = callExpression.argument(argumentIndex);
|
||||
auto argumentType = callExpressionType.argument(argumentIndex);
|
||||
const Cursor argument = this->argument(argumentIndex);
|
||||
const Type argumentType = callExpressionType.argument(argumentIndex);
|
||||
|
||||
if (!argument.isUnexposed() && argumentType.isOutputParameter())
|
||||
outputArguments.push_back(callExpression.argument(argumentIndex));
|
||||
if (isNotUnexposedLValueReference(argument, argumentType)
|
||||
&& 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)
|
||||
collectOutputArguments(*this, outputArguments);
|
||||
collectOutputArgumentRangesTo(outputArgumentRanges);
|
||||
|
||||
return outputArguments;
|
||||
return outputArgumentRanges;
|
||||
}
|
||||
|
||||
CXCursorKind Cursor::kind() const
|
||||
@@ -317,6 +343,11 @@ bool operator==(const Cursor &first, const Cursor &second)
|
||||
return clang_equalCursors(first.cxCursor, second.cxCursor);
|
||||
}
|
||||
|
||||
bool operator!=(const Cursor &first, const Cursor &second)
|
||||
{
|
||||
return !(first == second);
|
||||
}
|
||||
|
||||
void PrintTo(CXCursorKind cursorKind, ::std::ostream *os)
|
||||
{
|
||||
ClangString cursorKindSpelling(clang_getCursorKindSpelling(cursorKind));
|
||||
|
@@ -78,8 +78,11 @@ public:
|
||||
Type nonPointerTupe() const;
|
||||
|
||||
SourceLocation sourceLocation() const;
|
||||
CXSourceLocation cxSourceLocation() const;
|
||||
SourceRange sourceRange() const;
|
||||
CXSourceRange cxSourceRange() const;
|
||||
SourceRange commentRange() const;
|
||||
bool hasSameSourceLocationAs(const Cursor &other) const;
|
||||
|
||||
Cursor definition() const;
|
||||
Cursor canonical() const;
|
||||
@@ -90,7 +93,9 @@ public:
|
||||
Cursor functionBaseDeclaration() const;
|
||||
Cursor functionBase() 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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
void PrintTo(CXCursorKind cursorKind, ::std::ostream *os);
|
||||
void PrintTo(const Cursor &cursor, ::std::ostream* os);
|
||||
|
@@ -30,6 +30,7 @@
|
||||
#include "highlightingmark.h"
|
||||
#include "sourcelocation.h"
|
||||
#include "sourcerange.h"
|
||||
#include "sourcerangecontainer.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <ostream>
|
||||
@@ -40,15 +41,18 @@ namespace ClangBackEnd {
|
||||
|
||||
HighlightingMark::HighlightingMark(const CXCursor &cxCursor,
|
||||
CXToken *cxToken,
|
||||
CXTranslationUnit cxTranslationUnit)
|
||||
CXTranslationUnit cxTranslationUnit,
|
||||
std::vector<CXSourceRange> ¤tOutputArgumentRanges)
|
||||
: currentOutputArgumentRanges(¤tOutputArgumentRanges),
|
||||
originalCursor(cxCursor)
|
||||
{
|
||||
const SourceRange sourceRange = clang_getTokenExtent(cxTranslationUnit, *cxToken);
|
||||
const auto start = sourceRange.start();
|
||||
const auto end = sourceRange.end();
|
||||
|
||||
originalCursor = cxCursor;
|
||||
line = start.line();
|
||||
column = start.column();
|
||||
offset = start.offset();
|
||||
length = end.offset() - start.offset();
|
||||
collectKinds(cxToken, originalCursor);
|
||||
}
|
||||
@@ -159,6 +163,17 @@ void HighlightingMark::variableKind(const Cursor &cursor)
|
||||
types.mainHighlightingType = HighlightingType::LocalVariable;
|
||||
else
|
||||
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
|
||||
@@ -185,6 +200,68 @@ void HighlightingMark::addExtraTypeIfFirstPass(HighlightingType 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)
|
||||
{
|
||||
if (isRealDynamicCall(cursor) || isVirtualMethodDeclarationOrDefinition(cursor))
|
||||
@@ -204,12 +281,13 @@ void HighlightingMark::identifierKind(const Cursor &cursor, Recursion recursion)
|
||||
case CXCursor_CallExpr:
|
||||
case CXCursor_CXXMethod: functionKind(cursor, recursion); break;
|
||||
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_DeclRefExpr: identifierKind(cursor.referenced(), Recursion::RecursivePass); break;
|
||||
case CXCursor_MemberRefExpr: memberReferenceKind(cursor); break;
|
||||
case CXCursor_FieldDecl:
|
||||
case CXCursor_MemberRef:
|
||||
case CXCursor_MemberRef: fieldKind(cursor); break;
|
||||
case CXCursor_ObjCIvarDecl:
|
||||
case CXCursor_ObjCPropertyDecl:
|
||||
case CXCursor_ObjCClassMethodDecl:
|
||||
@@ -282,15 +360,17 @@ HighlightingType operatorKind(const Cursor &cursor)
|
||||
return HighlightingType::Invalid;
|
||||
}
|
||||
|
||||
HighlightingType punctationKind(const Cursor &cursor)
|
||||
}
|
||||
|
||||
HighlightingType HighlightingMark::punctuationKind(const Cursor &cursor)
|
||||
{
|
||||
switch (cursor.kind()) {
|
||||
case CXCursor_DeclRefExpr: return operatorKind(cursor);
|
||||
case CXCursor_CallExpr: collectOutputArguments(cursor);
|
||||
default: return HighlightingType::Invalid;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
void HighlightingMark::collectKinds(CXToken *cxToken, const Cursor &cursor)
|
||||
{
|
||||
auto cxTokenKind = clang_getTokenKind(*cxToken);
|
||||
@@ -299,7 +379,7 @@ void HighlightingMark::collectKinds(CXToken *cxToken, const Cursor &cursor)
|
||||
|
||||
switch (cxTokenKind) {
|
||||
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_Comment: types.mainHighlightingType = HighlightingType::Comment; break;
|
||||
case CXToken_Literal: types.mainHighlightingType = literalKind(cursor); break;
|
||||
|
@@ -45,7 +45,10 @@ class HighlightingMark
|
||||
};
|
||||
|
||||
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, HighlightingType type);
|
||||
|
||||
@@ -61,18 +64,26 @@ private:
|
||||
void identifierKind(const Cursor &cursor, Recursion recursion);
|
||||
void referencedTypeKind(const Cursor &cursor);
|
||||
void variableKind(const Cursor &cursor);
|
||||
void fieldKind(const Cursor &cursor);
|
||||
bool isVirtualMethodDeclarationOrDefinition(const Cursor &cursor) const;
|
||||
void functionKind(const Cursor &cursor, Recursion recursion);
|
||||
void memberReferenceKind(const Cursor &cursor);
|
||||
HighlightingType punctuationKind(const Cursor &cursor);
|
||||
void collectKinds(CXToken *cxToken, const Cursor &cursor);
|
||||
bool isRealDynamicCall(const Cursor &cursor) const;
|
||||
void addExtraTypeIfFirstPass(HighlightingType type, Recursion recursion);
|
||||
bool isOutputArgument() const;
|
||||
void collectOutputArguments(const Cursor &cursor);
|
||||
void filterOutPreviousOutputArguments();
|
||||
bool isArgumentInCurrentOutputArgumentLocations() const;
|
||||
|
||||
private:
|
||||
std::vector<CXSourceRange> *currentOutputArgumentRanges = nullptr;
|
||||
Cursor originalCursor;
|
||||
uint line;
|
||||
uint column;
|
||||
uint length;
|
||||
uint offset = 0;
|
||||
HighlightingTypes types;
|
||||
};
|
||||
|
||||
|
@@ -47,12 +47,18 @@ HighlightingMarks::~HighlightingMarks()
|
||||
|
||||
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
|
||||
{
|
||||
return const_iterator(cxCursor.cend(), cxToken + cxTokenCount, cxTranslationUnit);
|
||||
return const_iterator(cxCursor.cend(),
|
||||
cxToken + cxTokenCount,
|
||||
cxTranslationUnit,
|
||||
currentOutputArgumentRanges);
|
||||
}
|
||||
|
||||
QVector<HighlightingMarkContainer> HighlightingMarks::toHighlightingMarksContainers() const
|
||||
@@ -67,11 +73,19 @@ QVector<HighlightingMarkContainer> HighlightingMarks::toHighlightingMarksContain
|
||||
&& !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;
|
||||
}
|
||||
|
||||
bool HighlightingMarks::currentOutputArgumentRangesAreEmpty() const
|
||||
{
|
||||
return currentOutputArgumentRanges.empty();
|
||||
}
|
||||
|
||||
bool HighlightingMarks::isEmpty() const
|
||||
{
|
||||
return cxTokenCount == 0;
|
||||
@@ -89,7 +103,10 @@ uint HighlightingMarks::size() 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
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user