diff --git a/src/libs/clangbackendipc/codecompletion.h b/src/libs/clangbackendipc/codecompletion.h index 4b9b2ed7c21..bd63115da09 100644 --- a/src/libs/clangbackendipc/codecompletion.h +++ b/src/libs/clangbackendipc/codecompletion.h @@ -208,6 +208,6 @@ private: CMBIPC_EXPORT QDebug operator<<(QDebug debug, CodeCompletion::Kind kind); -std::ostream &operator<<(std::ostream &os, const CodeCompletion::Kind kind); -std::ostream &operator<<(std::ostream &os, const CodeCompletion::Availability availability); +CMBIPC_EXPORT std::ostream &operator<<(std::ostream &os, const CodeCompletion::Kind kind); +CMBIPC_EXPORT std::ostream &operator<<(std::ostream &os, const CodeCompletion::Availability availability); } // namespace ClangBackEnd diff --git a/src/libs/qmldebug/qmldebugclient.cpp b/src/libs/qmldebug/qmldebugclient.cpp index a1ac4ecddf2..597281ab258 100644 --- a/src/libs/qmldebug/qmldebugclient.cpp +++ b/src/libs/qmldebug/qmldebugclient.cpp @@ -365,7 +365,7 @@ void QmlDebugConnection::connectToHost(const QString &hostName, quint16 port) }); connect(socket, &QAbstractSocket::connected, this, &QmlDebugConnection::socketConnected); connect(socket, &QAbstractSocket::disconnected, this, &QmlDebugConnection::socketDisconnected); - socket->connectToHost(hostName, port); + socket->connectToHost(hostName.isEmpty() ? QString("localhost") : hostName, port); } void QmlDebugConnection::startLocalServer(const QString &fileName) diff --git a/src/libs/utils/wizard.cpp b/src/libs/utils/wizard.cpp index aea1adc3064..7829744314f 100644 --- a/src/libs/utils/wizard.cpp +++ b/src/libs/utils/wizard.cpp @@ -430,6 +430,7 @@ void Wizard::showVariables() auto label = new QLabel(result); label->setWordWrap(true); + label->setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::TextSelectableByKeyboard); scrollArea->setWidget(label); layout->addWidget(scrollArea); diff --git a/src/libs/utils/wizardpage.cpp b/src/libs/utils/wizardpage.cpp index ff342665e5b..42cb46ba4dd 100644 --- a/src/libs/utils/wizardpage.cpp +++ b/src/libs/utils/wizardpage.cpp @@ -55,14 +55,18 @@ void WizardPage::pageWasAdded() void WizardPage::registerFieldWithName(const QString &name, QWidget *widget, const char *property, const char *changedSignal) +{ + registerFieldName(name); + registerField(name, widget, property, changedSignal); +} + +void WizardPage::registerFieldName(const QString &name) { Wizard *wiz = qobject_cast(wizard()); if (wiz) wiz->registerFieldName(name); else m_toRegister.insert(name); - - registerField(name, widget, property, changedSignal); } bool WizardPage::handleReject() diff --git a/src/libs/utils/wizardpage.h b/src/libs/utils/wizardpage.h index c9f9a462eca..16944668ea1 100644 --- a/src/libs/utils/wizardpage.h +++ b/src/libs/utils/wizardpage.h @@ -54,6 +54,8 @@ signals: void reportError(const QString &errorMessage); private: + void registerFieldName(const QString &name); + QSet m_toRegister; }; diff --git a/src/plugins/android/android.pro b/src/plugins/android/android.pro index 6ef13cc781a..702bb4d7cf7 100644 --- a/src/plugins/android/android.pro +++ b/src/plugins/android/android.pro @@ -12,7 +12,6 @@ HEADERS += \ androidmanager.h \ androidrunconfiguration.h \ androidruncontrol.h \ - androidrunfactories.h \ androidsettingspage.h \ androidsettingswidget.h \ androidtoolchain.h \ @@ -58,7 +57,6 @@ SOURCES += \ androidmanager.cpp \ androidrunconfiguration.cpp \ androidruncontrol.cpp \ - androidrunfactories.cpp \ androidsettingspage.cpp \ androidsettingswidget.cpp \ androidtoolchain.cpp \ diff --git a/src/plugins/android/android.qbs b/src/plugins/android/android.qbs index 5e5d5a45742..fcc2e9e52ee 100644 --- a/src/plugins/android/android.qbs +++ b/src/plugins/android/android.qbs @@ -83,8 +83,6 @@ Project { "androidrunconfigurationwidget.ui", "androidruncontrol.cpp", "androidruncontrol.h", - "androidrunfactories.cpp", - "androidrunfactories.h", "androidrunnable.cpp", "androidrunnable.h", "androidrunner.cpp", diff --git a/src/plugins/android/androidanalyzesupport.cpp b/src/plugins/android/androidanalyzesupport.cpp index 38d84d48630..eaea7196ba9 100644 --- a/src/plugins/android/androidanalyzesupport.cpp +++ b/src/plugins/android/androidanalyzesupport.cpp @@ -24,66 +24,37 @@ ****************************************************************************/ #include "androidanalyzesupport.h" - #include "androidrunner.h" -#include "androidmanager.h" -#include - -#include -#include -#include - -#include - -using namespace Debugger; using namespace ProjectExplorer; namespace Android { namespace Internal { -AndroidAnalyzeSupport::AndroidAnalyzeSupport(RunControl *runControl) +AndroidQmlProfilerSupport::AndroidQmlProfilerSupport(RunControl *runControl) : RunWorker(runControl) { - setDisplayName("AndroidAnalyzeSupport"); - - RunConfiguration *runConfig = runControl->runConfiguration(); - runControl->setDisplayName(AndroidManager::packageName(runConfig->target())); - runControl->setConnection(UrlConnection::localHostWithoutPort()); + setDisplayName("AndroidQmlProfilerSupport"); auto runner = new AndroidRunner(runControl); + addDependency(runner); - connect(runControl, &RunControl::finished, runner, [runner] { runner->stop(); }); + auto profiler = runControl->createWorker(runControl->runMode()); + profiler->addDependency(this); - connect(runControl, &RunControl::starting, runner, [runner] { runner->start(); }); + connect(runner, &AndroidRunner::qmlServerReady, [this, runner, profiler](const QUrl &server) { + profiler->recordData("QmlServerUrl", server); + reportStarted(); + }); +} - connect(&m_outputParser, &QmlDebug::QmlOutputParser::waitingForConnectionOnPort, this, - [this, runControl](Utils::Port) { - runControl->notifyRemoteSetupDone(m_qmlPort); - }); +void AndroidQmlProfilerSupport::start() +{ +} -// connect(runner, &AndroidRunner::handleRemoteProcessStarted, this, -// [this](Utils::Port, Utils::Port qmlPort) { -// m_qmlPort = qmlPort; -// }); - -// connect(runner, &AndroidRunner::handleRemoteProcessFinished, this, -// [this, runControl](const QString &errorMsg) { -// runControl->notifyRemoteFinished(); -// appendMessage(errorMsg, Utils::NormalMessageFormat); -// }); - - connect(runner, &AndroidRunner::remoteErrorOutput, this, - [this, runControl](const QString &msg) { - appendMessage(msg, Utils::StdErrFormatSameLine); - m_outputParser.processOutput(msg); - }); - - connect(runner, &AndroidRunner::remoteOutput, this, - [this, runControl](const QString &msg) { - appendMessage(msg, Utils::StdOutFormatSameLine); - m_outputParser.processOutput(msg); - }); +void AndroidQmlProfilerSupport::stop() +{ + reportStopped(); } } // namespace Internal diff --git a/src/plugins/android/androidanalyzesupport.h b/src/plugins/android/androidanalyzesupport.h index c9ceb45146c..b788bf40a6b 100644 --- a/src/plugins/android/androidanalyzesupport.h +++ b/src/plugins/android/androidanalyzesupport.h @@ -25,25 +25,21 @@ #pragma once -#include "androidrunconfiguration.h" - #include -#include - namespace Android { namespace Internal { -class AndroidAnalyzeSupport : public ProjectExplorer::RunWorker +class AndroidQmlProfilerSupport : public ProjectExplorer::RunWorker { Q_OBJECT public: - explicit AndroidAnalyzeSupport(ProjectExplorer::RunControl *runControl); + explicit AndroidQmlProfilerSupport(ProjectExplorer::RunControl *runControl); private: - QmlDebug::QmlOutputParser m_outputParser; - Utils::Port m_qmlPort; + void start() override; + void stop() override; }; } // namespace Internal diff --git a/src/plugins/android/androiddevice.cpp b/src/plugins/android/androiddevice.cpp index c3717ed6fdc..23c5716ff21 100644 --- a/src/plugins/android/androiddevice.cpp +++ b/src/plugins/android/androiddevice.cpp @@ -94,6 +94,11 @@ DeviceProcessSignalOperation::Ptr AndroidDevice::signalOperation() const return DeviceProcessSignalOperation::Ptr(new AndroidSignalOperation()); } +Utils::OsType AndroidDevice::osType() const +{ + return Utils::OsTypeOtherUnix; +} + IDevice::Ptr AndroidDevice::clone() const { return IDevice::Ptr(new AndroidDevice(*this)); diff --git a/src/plugins/android/androiddevice.h b/src/plugins/android/androiddevice.h index f050b445373..3a59e297981 100644 --- a/src/plugins/android/androiddevice.h +++ b/src/plugins/android/androiddevice.h @@ -44,6 +44,7 @@ public: void executeAction(Core::Id actionId, QWidget *parent = 0) override; bool canAutoDetectPorts() const override; ProjectExplorer::DeviceProcessSignalOperation::Ptr signalOperation() const override; + Utils::OsType osType() const override; ProjectExplorer::IDevice::Ptr clone() const override; ProjectExplorer::Connection toolControlChannel(const ControlChannelHint &) const override; diff --git a/src/plugins/android/androidplugin.cpp b/src/plugins/android/androidplugin.cpp index 5619958ac11..e2636cd4548 100644 --- a/src/plugins/android/androidplugin.cpp +++ b/src/plugins/android/androidplugin.cpp @@ -25,22 +25,26 @@ #include "androidplugin.h" -#include "androidconstants.h" +#include "androidanalyzesupport.h" #include "androidconfigurations.h" +#include "androidconstants.h" +#include "androiddebugsupport.h" +#include "androiddeployconfiguration.h" #include "androiddeployqtstep.h" #include "androiddevice.h" #include "androiddevicefactory.h" -#include "androidmanager.h" -#include "androidrunfactories.h" -#include "androidsettingspage.h" -#include "androidtoolchain.h" -#include "androidqtversionfactory.h" -#include "androiddeployconfiguration.h" #include "androidgdbserverkitinformation.h" +#include "androidmanager.h" #include "androidmanifesteditorfactory.h" #include "androidpotentialkit.h" +#include "androidqtversionfactory.h" +#include "androidrunconfiguration.h" +#include "androidruncontrol.h" +#include "androidsettingspage.h" +#include "androidtoolchain.h" #include "javacompletionassistprovider.h" #include "javaeditor.h" + #ifdef HAVE_QBS # include "androidqbspropertyprovider.h" #endif @@ -55,6 +59,8 @@ #include using namespace ProjectExplorer; +using namespace ProjectExplorer::Constants; +using namespace Android::Internal; namespace Android { @@ -66,9 +72,13 @@ bool AndroidPlugin::initialize(const QStringList &arguments, QString *errorMessa Q_UNUSED(arguments); Q_UNUSED(errorMessage); + RunControl::registerWorker(NORMAL_RUN_MODE); + RunControl::registerWorker(DEBUG_RUN_MODE); + RunControl::registerWorker(DEBUG_RUN_MODE_WITH_BREAK_ON_MAIN); + RunControl::registerWorker(QML_PROFILER_RUN_MODE); + new AndroidConfigurations(this); - addAutoReleasedObject(new Internal::AndroidRunControlFactory); addAutoReleasedObject(new Internal::AndroidDeployQtStepFactory); addAutoReleasedObject(new Internal::AndroidSettingsPage); addAutoReleasedObject(new Internal::AndroidQtVersionFactory); diff --git a/src/plugins/android/androidrunfactories.cpp b/src/plugins/android/androidrunfactories.cpp deleted file mode 100644 index 7d4e4a79452..00000000000 --- a/src/plugins/android/androidrunfactories.cpp +++ /dev/null @@ -1,84 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 BogDan Vatra -** 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 "androidrunfactories.h" - -#include "androidconstants.h" -#include "androiddebugsupport.h" -#include "androidanalyzesupport.h" -#include "androidrunconfiguration.h" -#include "androidruncontrol.h" -#include "androidmanager.h" - -#include - -using namespace ProjectExplorer; - -namespace Android { -namespace Internal { - -AndroidRunControlFactory::AndroidRunControlFactory(QObject *parent) - : IRunControlFactory(parent) -{ -} - -bool AndroidRunControlFactory::canRun(RunConfiguration *runConfiguration, Core::Id mode) const -{ - if (mode != ProjectExplorer::Constants::NORMAL_RUN_MODE - && mode != ProjectExplorer::Constants::DEBUG_RUN_MODE - && mode != ProjectExplorer::Constants::DEBUG_RUN_MODE_WITH_BREAK_ON_MAIN - && mode != ProjectExplorer::Constants::QML_PROFILER_RUN_MODE) { - return false; - } - return qobject_cast(runConfiguration); -} - -RunControl *AndroidRunControlFactory::create(RunConfiguration *runConfig, Core::Id mode, QString *) -{ - Q_ASSERT(canRun(runConfig, mode)); - if (mode == ProjectExplorer::Constants::NORMAL_RUN_MODE) { - auto runControl = new RunControl(runConfig, mode); - (void) new AndroidRunSupport(runControl); - return runControl; - } - if (mode == ProjectExplorer::Constants::DEBUG_RUN_MODE - || mode == ProjectExplorer::Constants::DEBUG_RUN_MODE_WITH_BREAK_ON_MAIN) { - auto runControl = new RunControl(runConfig, mode); - (void) new AndroidDebugSupport(runControl); - return runControl; - } - if (mode == ProjectExplorer::Constants::QML_PROFILER_RUN_MODE) { - auto runControl = new RunControl(runConfig, mode); - auto profiler = runControl->createWorker(mode); - auto profilee = new AndroidAnalyzeSupport(runControl); - profiler->addDependency(profilee); - return runControl; - } - QTC_CHECK(false); // The other run modes are not supported - return 0; -} - -} // namespace Internal -} // namespace Android diff --git a/src/plugins/android/androidrunfactories.h b/src/plugins/android/androidrunfactories.h deleted file mode 100644 index 5556b44f487..00000000000 --- a/src/plugins/android/androidrunfactories.h +++ /dev/null @@ -1,56 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 BogDan Vatra -** 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 "android_global.h" -#include - - -namespace ProjectExplorer { -class RunControl; -class RunConfigWidget; -class Target; -class Node; -} // namespace ProjectExplorer - -namespace Android { -namespace Internal { - -class AndroidRunControlFactory : public ProjectExplorer::IRunControlFactory -{ - Q_OBJECT - -public: - explicit AndroidRunControlFactory(QObject *parent = 0); - - bool canRun(ProjectExplorer::RunConfiguration *runConfiguration, - Core::Id mode) const override; - ProjectExplorer::RunControl *create(ProjectExplorer::RunConfiguration *runConfiguration, - Core::Id mode, QString *errorMessage) override; -}; - -} // namespace Internal -} // namespace Android diff --git a/src/plugins/android/androidrunner.cpp b/src/plugins/android/androidrunner.cpp index f6d4ce20325..4a62e028fe9 100644 --- a/src/plugins/android/androidrunner.cpp +++ b/src/plugins/android/androidrunner.cpp @@ -34,6 +34,7 @@ #include "androidavdmanager.h" #include +#include #include #include #include @@ -632,7 +633,7 @@ void AndroidRunnerWorker::onProcessIdChanged(qint64 pid) // Don't write to m_psProc from a different thread QTC_ASSERT(QThread::currentThread() == thread(), return); m_processPID = pid; - if (m_processPID == -1) { + if (pid == -1) { emit remoteProcessFinished(QLatin1String("\n\n") + tr("\"%1\" died.") .arg(m_packageName)); // App died/killed. Reset log and monitor processes. @@ -714,6 +715,9 @@ AndroidRunner::AndroidRunner(RunControl *runControl) connect(m_worker.data(), &AndroidRunnerWorker::remoteErrorOutput, this, &AndroidRunner::remoteErrorOutput); + connect(&m_outputParser, &QmlDebug::QmlOutputParser::waitingForConnectionOnPort, + this, &AndroidRunner::qmlServerPortReady); + m_thread.start(); } @@ -749,14 +753,28 @@ void AndroidRunner::stop() emit asyncStop(m_androidRunnable); } +void AndroidRunner::qmlServerPortReady(Port port) +{ + // FIXME: Note that the passed is nonsense, as the port is on the + // device side. It only happens to work since we redirect + // host port n to target port n via adb. + QUrl serverUrl; + serverUrl.setPort(port.number()); + emit qmlServerReady(serverUrl); +} + void AndroidRunner::remoteOutput(const QString &output) { + Core::MessageManager::write("LOGCAT: " + output, Core::MessageManager::Silent); appendMessage(output, Utils::StdOutFormatSameLine); + m_outputParser.processOutput(output); } void AndroidRunner::remoteErrorOutput(const QString &output) { + Core::MessageManager::write("LOGCAT: " + output, Core::MessageManager::Silent); appendMessage(output, Utils::StdErrFormatSameLine); + m_outputParser.processOutput(output); } void AndroidRunner::handleRemoteProcessStarted(Utils::Port gdbServerPort, Utils::Port qmlServerPort, int pid) @@ -770,6 +788,8 @@ void AndroidRunner::handleRemoteProcessStarted(Utils::Port gdbServerPort, Utils: void AndroidRunner::handleRemoteProcessFinished(const QString &errString) { appendMessage(errString, Utils::DebugFormat); + if (runControl()->isRunning()) + runControl()->initiateStop(); reportStopped(); } diff --git a/src/plugins/android/androidrunner.h b/src/plugins/android/androidrunner.h index 9c5f3dd7814..cf24d8423bf 100644 --- a/src/plugins/android/androidrunner.h +++ b/src/plugins/android/androidrunner.h @@ -30,6 +30,7 @@ #include #include +#include #include #include @@ -62,18 +63,20 @@ public: void start() override; void stop() override; - virtual void remoteOutput(const QString &output); - virtual void remoteErrorOutput(const QString &output); - signals: void asyncStart(const AndroidRunnable &runnable); void asyncStop(const AndroidRunnable &runnable); void remoteDebuggerRunning(); + void qmlServerReady(const QUrl &serverUrl); void adbParametersChanged(const QString &packageName, const QStringList &selector); void avdDetected(); private: + void qmlServerPortReady(Utils::Port port); + void remoteOutput(const QString &output); + void remoteErrorOutput(const QString &output); + void gotRemoteOutput(const QString &output); void handleRemoteProcessStarted(Utils::Port gdbServerPort, Utils::Port qmlServerPort, int pid); void handleRemoteProcessFinished(const QString &errString = QString()); void checkAVD(); @@ -88,6 +91,7 @@ private: Utils::Port m_gdbServerPort; Utils::Port m_qmlServerPort; Utils::ProcessHandle m_pid; + QmlDebug::QmlOutputParser m_outputParser; }; } // namespace Internal diff --git a/src/plugins/autotest/gtest/gtesttreeitem.cpp b/src/plugins/autotest/gtest/gtesttreeitem.cpp index 5e2766cb30d..b9308a4e737 100644 --- a/src/plugins/autotest/gtest/gtesttreeitem.cpp +++ b/src/plugins/autotest/gtest/gtesttreeitem.cpp @@ -57,6 +57,7 @@ QVariant GTestTreeItem::data(int column, int role) const } case Qt::CheckStateRole: switch (type()) { + case Root: case TestCase: case TestFunctionOrSet: return checked(); diff --git a/src/plugins/autotest/qtest/qttesttreeitem.cpp b/src/plugins/autotest/qtest/qttesttreeitem.cpp index 2b4ad6d6c2d..48fa4a9de9e 100644 --- a/src/plugins/autotest/qtest/qttesttreeitem.cpp +++ b/src/plugins/autotest/qtest/qttesttreeitem.cpp @@ -49,7 +49,6 @@ QVariant QtTestTreeItem::data(int column, int role) const return QVariant(name() + nameSuffix()); case Qt::CheckStateRole: switch (type()) { - case Root: case TestDataFunction: case TestSpecialFunction: return QVariant(); diff --git a/src/plugins/autotest/quick/quicktesttreeitem.cpp b/src/plugins/autotest/quick/quicktesttreeitem.cpp index 5576f97b09f..c4de28c6915 100644 --- a/src/plugins/autotest/quick/quicktesttreeitem.cpp +++ b/src/plugins/autotest/quick/quicktesttreeitem.cpp @@ -50,7 +50,6 @@ QVariant QuickTestTreeItem::data(int column, int role) const break; case Qt::CheckStateRole: switch (type()) { - case Root: case TestDataFunction: case TestSpecialFunction: case TestDataTag: diff --git a/src/plugins/autotest/testtreeitem.cpp b/src/plugins/autotest/testtreeitem.cpp index 7f1992ae583..3bfa4400c5e 100644 --- a/src/plugins/autotest/testtreeitem.cpp +++ b/src/plugins/autotest/testtreeitem.cpp @@ -42,7 +42,8 @@ TestTreeItem::TestTreeItem(const QString &name, const QString &filePath, Type ty m_filePath(filePath), m_type(type) { - m_checked = (m_type == TestCase || m_type == TestFunctionOrSet) ? Qt::Checked : Qt::Unchecked; + m_checked = (m_type == TestCase || m_type == TestFunctionOrSet || m_type == Root) + ? Qt::Checked : Qt::Unchecked; } static QIcon testTreeIcon(TestTreeItem::Type type) @@ -103,7 +104,7 @@ Qt::ItemFlags TestTreeItem::flags(int /*column*/) const static const Qt::ItemFlags defaultFlags = Qt::ItemIsEnabled | Qt::ItemIsSelectable; switch (m_type) { case Root: - return Qt::ItemIsEnabled; + return Qt::ItemIsEnabled | Qt::ItemIsAutoTristate | Qt::ItemIsUserCheckable; case TestCase: return defaultFlags | Qt::ItemIsAutoTristate | Qt::ItemIsUserCheckable; case TestFunctionOrSet: @@ -161,13 +162,14 @@ void TestTreeItem::setChecked(const Qt::CheckState checkState) parent->revalidateCheckState(); break; } + case Root: case TestFunctionOrSet: case TestCase: { Qt::CheckState usedState = (checkState == Qt::Unchecked ? Qt::Unchecked : Qt::Checked); for (int row = 0, count = childCount(); row < count; ++row) childItem(row)->setChecked(usedState); m_checked = usedState; - if (m_type == TestFunctionOrSet) { + if (m_type != Root) { if (auto parent = parentItem()) parent->revalidateCheckState(); } @@ -181,6 +183,7 @@ void TestTreeItem::setChecked(const Qt::CheckState checkState) Qt::CheckState TestTreeItem::checked() const { switch (m_type) { + case Root: case TestCase: case TestFunctionOrSet: case TestDataTag: @@ -295,7 +298,7 @@ QSet TestTreeItem::internalTargets() const void TestTreeItem::revalidateCheckState() { const Type ttiType = type(); - if (ttiType != TestCase && ttiType != TestFunctionOrSet) + if (ttiType != TestCase && ttiType != TestFunctionOrSet && ttiType != Root) return; if (childCount() == 0) // can this happen? (we're calling revalidateCS() on parentItem() return; @@ -317,13 +320,13 @@ void TestTreeItem::revalidateCheckState() foundPartiallyChecked |= (child->checked() == Qt::PartiallyChecked); if (foundPartiallyChecked || (foundChecked && foundUnchecked)) { m_checked = Qt::PartiallyChecked; - if (ttiType == TestFunctionOrSet) + if (ttiType == TestFunctionOrSet || ttiType == TestCase) parentItem()->revalidateCheckState(); return; } } m_checked = (foundUnchecked ? Qt::Unchecked : Qt::Checked); - if (ttiType == TestFunctionOrSet) + if (ttiType == TestFunctionOrSet || ttiType == TestCase) parentItem()->revalidateCheckState(); } diff --git a/src/plugins/autotest/testtreeitem.h b/src/plugins/autotest/testtreeitem.h index 530a105e275..2c2c728a2c7 100644 --- a/src/plugins/autotest/testtreeitem.h +++ b/src/plugins/autotest/testtreeitem.h @@ -135,6 +135,8 @@ private: unsigned m_column = 0; QString m_proFile; Status m_status = NewlyAdded; + + friend class TestTreeModel; // grant access to (private) revalidateCheckState() }; class TestCodeLocationAndType diff --git a/src/plugins/autotest/testtreemodel.cpp b/src/plugins/autotest/testtreemodel.cpp index d3cba6c76d1..cd27377b071 100644 --- a/src/plugins/autotest/testtreemodel.cpp +++ b/src/plugins/autotest/testtreemodel.cpp @@ -110,6 +110,7 @@ bool TestTreeModel::setData(const QModelIndex &index, const QVariant &value, int emit dataChanged(index, index); if (role == Qt::CheckStateRole) { switch (item->type()) { + case TestTreeItem::Root: case TestTreeItem::TestCase: if (item->childCount() > 0) emit dataChanged(index.child(0, 0), index.child(item->childCount() - 1, 0)); @@ -228,6 +229,7 @@ bool TestTreeModel::sweepChildren(TestTreeItem *item) if (child->type() != TestTreeItem::Root && child->markedForRemoval()) { destroyItem(child); + item->revalidateCheckState(); hasChanged = true; } else if (child->hasChildren()) { hasChanged |= sweepChildren(child); @@ -266,6 +268,12 @@ void TestTreeModel::handleParseResult(const TestParseResult *result, TestTreeIte TestTreeItem *newItem = result->createTestTreeItem(); QTC_ASSERT(newItem, return); parentNode->appendChild(newItem); + // new items are checked by default - revalidation of parents might be necessary + if (parentNode->checked() != Qt::Checked) { + parentNode->revalidateCheckState(); + const QModelIndex &idx = indexForItem(parentNode); + emit dataChanged(idx, idx); + } } void TestTreeModel::removeAllTestItems() diff --git a/src/plugins/autotest/testtreeview.cpp b/src/plugins/autotest/testtreeview.cpp index 9cd20644f83..a6bbe91b909 100644 --- a/src/plugins/autotest/testtreeview.cpp +++ b/src/plugins/autotest/testtreeview.cpp @@ -82,6 +82,10 @@ void TestTreeView::changeCheckStateAll(const Qt::CheckState checkState) item->setChecked(checkState); } } + if (count == 0) { + if (auto item = static_cast(currentRootIndex.internalPointer())) + item->setChecked(checkState); + } emit dataChanged(currentRootIndex, last); } } diff --git a/src/plugins/baremetal/baremetaldevice.cpp b/src/plugins/baremetal/baremetaldevice.cpp index b0e2c20db35..7852011fb5e 100644 --- a/src/plugins/baremetal/baremetaldevice.cpp +++ b/src/plugins/baremetal/baremetaldevice.cpp @@ -176,6 +176,11 @@ void BareMetalDevice::executeAction(Core::Id actionId, QWidget *parent) Q_UNUSED(parent); } +Utils::OsType BareMetalDevice::osType() const +{ + return Utils::OsTypeOther; +} + DeviceProcess *BareMetalDevice::createProcess(QObject *parent) const { return new GdbServerProviderProcess(sharedFromThis(), parent); diff --git a/src/plugins/baremetal/baremetaldevice.h b/src/plugins/baremetal/baremetaldevice.h index a82cdfea0e6..1a2fdbe8c5d 100644 --- a/src/plugins/baremetal/baremetaldevice.h +++ b/src/plugins/baremetal/baremetaldevice.h @@ -50,6 +50,7 @@ public: QList actionIds() const override; QString displayNameForActionId(Core::Id actionId) const override; void executeAction(Core::Id actionId, QWidget *parent) override; + Utils::OsType osType() const override; ProjectExplorer::IDevice::Ptr clone() const override; ProjectExplorer::DeviceProcessSignalOperation::Ptr signalOperation() const override; diff --git a/src/plugins/bookmarks/bookmark.cpp b/src/plugins/bookmarks/bookmark.cpp index 8834ccab00b..dd8f71fb03e 100644 --- a/src/plugins/bookmarks/bookmark.cpp +++ b/src/plugins/bookmarks/bookmark.cpp @@ -50,6 +50,16 @@ void Bookmark::removedFromEditor() m_manager->deleteBookmark(this); } +bool Bookmark::isDraggable() const +{ + return true; +} + +void Bookmark::dragToLine(int lineNumber) +{ + move(lineNumber); +} + void Bookmark::updateLineNumber(int line) { if (line != lineNumber()) { @@ -63,6 +73,7 @@ void Bookmark::move(int line) if (line != lineNumber()) { TextMark::move(line); m_manager->updateBookmark(this); + updateMarker(); } } @@ -84,6 +95,8 @@ void Bookmark::updateFileName(const QString &fileName) void Bookmark::setNote(const QString ¬e) { setToolTip(note); + setLineAnnotation(note); + updateMarker(); } void Bookmark::updateNote(const QString ¬e) diff --git a/src/plugins/bookmarks/bookmark.h b/src/plugins/bookmarks/bookmark.h index 6d818946ff3..ad9a1d7f53d 100644 --- a/src/plugins/bookmarks/bookmark.h +++ b/src/plugins/bookmarks/bookmark.h @@ -43,6 +43,9 @@ public: void updateFileName(const QString &fileName) override; void removedFromEditor() override; + bool isDraggable() const override; + void dragToLine(int lineNumber) override; + void setNote(const QString ¬e); void updateNote(const QString ¬e); diff --git a/src/plugins/clangcodemodel/clangbackendipcintegration.cpp b/src/plugins/clangcodemodel/clangbackendipcintegration.cpp index 8dd45907de3..5ff5b1aa7e5 100644 --- a/src/plugins/clangcodemodel/clangbackendipcintegration.cpp +++ b/src/plugins/clangcodemodel/clangbackendipcintegration.cpp @@ -248,9 +248,9 @@ void IpcReceiver::references(const ReferencesMessage &message) QTC_CHECK(futureInterface != QFutureInterface()); if (futureInterface.isCanceled()) - return; // A new request was issued making this one outdated. + return; // Editor document closed or a new request was issued making this result outdated. - QTC_CHECK(entry.textDocument); + QTC_ASSERT(entry.textDocument, return); futureInterface.reportResult(toCursorInfo(*entry.textDocument, message)); futureInterface.reportFinished(); } diff --git a/src/plugins/clangcodemodel/clangbackendipcintegration.h b/src/plugins/clangcodemodel/clangbackendipcintegration.h index e3842b2a26d..57a07e8097d 100644 --- a/src/plugins/clangcodemodel/clangbackendipcintegration.h +++ b/src/plugins/clangcodemodel/clangbackendipcintegration.h @@ -35,6 +35,7 @@ #include #include +#include #include #include #include @@ -102,7 +103,7 @@ private: : futureInterface(futureInterface) , textDocument(textDocument) {} QFutureInterface futureInterface; - QTextDocument *textDocument = nullptr; + QPointer textDocument; }; QHash m_referencesTable; }; diff --git a/src/plugins/clangcodemodel/clangtextmark.cpp b/src/plugins/clangcodemodel/clangtextmark.cpp index c066db538ad..1e53bce06e2 100644 --- a/src/plugins/clangcodemodel/clangtextmark.cpp +++ b/src/plugins/clangcodemodel/clangtextmark.cpp @@ -79,6 +79,7 @@ ClangTextMark::ClangTextMark(const QString &fileName, setPriority(warning ? TextEditor::TextMark::NormalPriority : TextEditor::TextMark::HighPriority); setIcon(diagnostic.severity()); + setLineAnnotation(diagnostic.text().toString()); } void ClangTextMark::setIcon(ClangBackEnd::DiagnosticSeverity severity) @@ -96,7 +97,7 @@ void ClangTextMark::setIcon(ClangBackEnd::DiagnosticSeverity severity) TextMark::setIcon(errorIcon); } -bool ClangTextMark::addToolTipContent(QLayout *target) +bool ClangTextMark::addToolTipContent(QLayout *target) const { using Internal::ClangDiagnosticWidget; diff --git a/src/plugins/clangcodemodel/clangtextmark.h b/src/plugins/clangcodemodel/clangtextmark.h index 6b504c69143..f1a1b9078ba 100644 --- a/src/plugins/clangcodemodel/clangtextmark.h +++ b/src/plugins/clangcodemodel/clangtextmark.h @@ -45,7 +45,7 @@ public: private: void setIcon(ClangBackEnd::DiagnosticSeverity severity); - bool addToolTipContent(QLayout *target) override; + bool addToolTipContent(QLayout *target) const override; void removedFromEditor() override; private: diff --git a/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp b/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp index 4bc51dd42ec..ff2a3d2c9a6 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp @@ -193,9 +193,8 @@ bool CMakeBuildStep::init(QList &earlierSteps) CMakeTool *tool = CMakeKitInformation::cmakeTool(target()->kit()); if (!tool || !tool->isValid()) { emit addTask(Task(Task::Error, - QCoreApplication::translate("CMakeProjectManager::CMakeBuildStep", - "Qt Creator needs a CMake Tool set up to build. " - "Configure a CMake Tool in the kit options."), + tr("Qt Creator needs a CMake Tool set up to build. " + "Configure a CMake Tool in the kit options."), Utils::FileName(), -1, ProjectExplorer::Constants::TASK_CATEGORY_BUILDSYSTEM)); canInit = false; @@ -218,6 +217,22 @@ bool CMakeBuildStep::init(QList &earlierSteps) return false; } + // Warn if doing out-of-source builds with a CMakeCache.txt is the source directory + const Utils::FileName projectDirectory = bc->target()->project()->projectDirectory(); + if (bc->buildDirectory() != projectDirectory) { + Utils::FileName cmc = projectDirectory; + cmc.appendPath("CMakeCache.txt"); + if (cmc.exists()) { + emit addTask(Task(Task::Warning, + tr("There is a CMakeCache.txt file in \"%1\", which suggest an " + "in-source build was done before. You are now building in \"%2\", " + "and the CMakeCache.txt file might confuse CMake.") + .arg(projectDirectory.toUserOutput(), bc->buildDirectory().toUserOutput()), + Utils::FileName(), -1, + ProjectExplorer::Constants::TASK_CATEGORY_BUILDSYSTEM)); + } + } + QString arguments = allArguments(rc); setIgnoreReturnValue(m_buildTarget == CMakeBuildStep::cleanTarget()); diff --git a/src/plugins/cppeditor/cpphoverhandler.cpp b/src/plugins/cppeditor/cpphoverhandler.cpp index 3f0ee1fdc4d..75b5913f17b 100644 --- a/src/plugins/cppeditor/cpphoverhandler.cpp +++ b/src/plugins/cppeditor/cpphoverhandler.cpp @@ -97,7 +97,7 @@ void CppHoverHandler::identifyMatch(TextEditorWidget *editorWidget, int pos) m_positionForEditorDocumentProcessor = -1; if (editorDocumentProcessorHasDiagnosticAt(editorWidget, pos)) { - setIsDiagnosticTooltip(true); + setPriority(Priority_Diagnostic); m_positionForEditorDocumentProcessor = pos; } else if (!editorWidget->extraSelectionTooltip(pos).isEmpty()) { setToolTip(editorWidget->extraSelectionTooltip(pos)); @@ -110,12 +110,14 @@ void CppHoverHandler::identifyMatch(TextEditorWidget *editorWidget, int pos) evaluator.execute(); if (evaluator.hasDiagnosis()) { setToolTip(evaluator.diagnosis()); - setIsDiagnosticTooltip(true); + setPriority(Priority_Diagnostic); } if (evaluator.identifiedCppElement()) { const QSharedPointer &cppElement = evaluator.cppElement(); - if (!isDiagnosticTooltip()) + if (priority() != Priority_Diagnostic) { setToolTip(cppElement->tooltip); + setPriority(cppElement->tooltip.isEmpty() ? Priority_None : Priority_Tooltip); + } QStringList candidates = cppElement->helpIdCandidates; candidates.removeDuplicates(); foreach (const QString &helpId, candidates) { @@ -143,7 +145,7 @@ void CppHoverHandler::decorateToolTip() if (Qt::mightBeRichText(toolTip())) setToolTip(toolTip().toHtmlEscaped()); - if (isDiagnosticTooltip()) + if (priority() != Priority_Diagnostic) return; const HelpItem &help = lastHelpItemIdentified(); diff --git a/src/plugins/cppeditor/cppuseselectionsupdater.cpp b/src/plugins/cppeditor/cppuseselectionsupdater.cpp index 217a58fa1d2..5e03ebbe2de 100644 --- a/src/plugins/cppeditor/cppuseselectionsupdater.cpp +++ b/src/plugins/cppeditor/cppuseselectionsupdater.cpp @@ -29,6 +29,7 @@ #include "cppeditordocument.h" #include +#include #include #include @@ -49,6 +50,12 @@ CppUseSelectionsUpdater::CppUseSelectionsUpdater(TextEditor::TextEditorWidget *e connect(&m_timer, &QTimer::timeout, this, [this]() { update(); }); } +CppUseSelectionsUpdater::~CppUseSelectionsUpdater() +{ + if (m_runnerWatcher) + m_runnerWatcher->cancel(); +} + void CppUseSelectionsUpdater::scheduleUpdate() { m_timer.start(); @@ -59,23 +66,6 @@ void CppUseSelectionsUpdater::abortSchedule() m_timer.stop(); } -static QTextCursor cursorAtWordStart(const QTextCursor &textCursor) -{ - const int originalPosition = textCursor.position(); - QTextCursor cursor(textCursor); - cursor.movePosition(QTextCursor::StartOfWord); - const int wordStartPosition = cursor.position(); - - if (originalPosition == wordStartPosition) { - // Cursor is not on an identifier, check whether we are right after one. - const QChar c = textCursor.document()->characterAt(originalPosition - 1); - if (CppTools::isValidIdentifierChar(c)) - cursor.movePosition(QTextCursor::PreviousWord); - } - - return cursor; -} - void CppUseSelectionsUpdater::update(CallType callType) { auto *cppEditorWidget = qobject_cast(m_editorWidget); @@ -86,7 +76,7 @@ void CppUseSelectionsUpdater::update(CallType callType) CppTools::CursorInfoParams params; params.semanticInfo = cppEditorWidget->semanticInfo(); - params.textCursor = cursorAtWordStart(cppEditorWidget->textCursor()); + params.textCursor = TextEditor::Convenience::wordStartCursor(cppEditorWidget->textCursor()); if (callType == Asynchronous) { if (isSameIdentifierAsBefore(params.textCursor)) @@ -144,8 +134,10 @@ void CppUseSelectionsUpdater::onFindUsesFinished() return; if (m_runnerRevision != m_editorWidget->document()->revision()) return; - if (m_runnerWordStartPosition != cursorAtWordStart(m_editorWidget->textCursor()).position()) + if (m_runnerWordStartPosition + != TextEditor::Convenience::wordStartCursor(m_editorWidget->textCursor()).position()) { return; + } processResults(m_runnerWatcher->result()); diff --git a/src/plugins/cppeditor/cppuseselectionsupdater.h b/src/plugins/cppeditor/cppuseselectionsupdater.h index b2474362850..478a816f980 100644 --- a/src/plugins/cppeditor/cppuseselectionsupdater.h +++ b/src/plugins/cppeditor/cppuseselectionsupdater.h @@ -44,6 +44,7 @@ class CppUseSelectionsUpdater : public QObject public: explicit CppUseSelectionsUpdater(TextEditor::TextEditorWidget *editorWidget); + ~CppUseSelectionsUpdater(); void scheduleUpdate(); void abortSchedule(); diff --git a/src/plugins/cppeditor/resourcepreviewhoverhandler.h b/src/plugins/cppeditor/resourcepreviewhoverhandler.h index 7f10db83d87..2ccb261c2a8 100644 --- a/src/plugins/cppeditor/resourcepreviewhoverhandler.h +++ b/src/plugins/cppeditor/resourcepreviewhoverhandler.h @@ -34,8 +34,6 @@ namespace Internal { class ResourcePreviewHoverHandler : public TextEditor::BaseHoverHandler { -public: - private: void identifyMatch(TextEditor::TextEditorWidget *editorWidget, int pos) override; void operateTooltip(TextEditor::TextEditorWidget *editorWidget, const QPoint &point) override; diff --git a/src/plugins/debugger/analyzer/startremotedialog.cpp b/src/plugins/debugger/analyzer/startremotedialog.cpp index 89b03b8f2d8..13dcf456a42 100644 --- a/src/plugins/debugger/analyzer/startremotedialog.cpp +++ b/src/plugins/debugger/analyzer/startremotedialog.cpp @@ -128,19 +128,11 @@ void StartRemoteDialog::validate() d->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(valid); } -QUrl StartRemoteDialog::serverUrl() const -{ - QUrl url; - Kit *kit = d->kitChooser->currentKit(); - IDevice::ConstPtr device = DeviceKitInformation::device(kit); - url.setHost(device->sshParameters().host); - url.setPort(device->sshParameters().port); - return url; -} - StandardRunnable StartRemoteDialog::runnable() const { + Kit *kit = d->kitChooser->currentKit(); StandardRunnable r; + r.device = DeviceKitInformation::device(kit); r.executable = d->executable->text(); r.commandLineArguments = d->arguments->text(); r.workingDirectory = d->workingDirectory->text(); diff --git a/src/plugins/debugger/analyzer/startremotedialog.h b/src/plugins/debugger/analyzer/startremotedialog.h index 91e61873162..1a9df377fa4 100644 --- a/src/plugins/debugger/analyzer/startremotedialog.h +++ b/src/plugins/debugger/analyzer/startremotedialog.h @@ -28,7 +28,6 @@ #include #include -#include namespace ProjectExplorer { class StandardRunnable; } @@ -44,7 +43,6 @@ public: explicit StartRemoteDialog(QWidget *parent = 0); ~StartRemoteDialog() override; - QUrl serverUrl() const; ProjectExplorer::StandardRunnable runnable() const; private: diff --git a/src/plugins/debugger/debuggerruncontrol.cpp b/src/plugins/debugger/debuggerruncontrol.cpp index ebb839fc907..2195708fd9f 100644 --- a/src/plugins/debugger/debuggerruncontrol.cpp +++ b/src/plugins/debugger/debuggerruncontrol.cpp @@ -468,12 +468,24 @@ static DebuggerRunConfigurationAspect *debuggerAspect(const RunControl *runContr return runControl->runConfiguration()->extraAspect(); } +static bool cppDebugging(const RunControl *runControl) +{ + auto aspect = debuggerAspect(runControl); + return aspect ? aspect->useCppDebugger() : true; // For cases like valgrind-with-gdb. +} + +static bool qmlDebugging(const RunControl *runControl) +{ + auto aspect = debuggerAspect(runControl); + return aspect ? aspect->useCppDebugger() : false; // For cases like valgrind-with-gdb. +} + /// DebuggerRunTool DebuggerRunTool::DebuggerRunTool(RunControl *runControl) : RunWorker(runControl), - m_isCppDebugging(debuggerAspect(runControl)->useCppDebugger()), - m_isQmlDebugging(debuggerAspect(runControl)->useQmlDebugger()) + m_isCppDebugging(cppDebugging(runControl)), + m_isQmlDebugging(qmlDebugging(runControl)) { setDisplayName("DebuggerRunTool"); } diff --git a/src/plugins/diffeditor/diffutils.cpp b/src/plugins/diffeditor/diffutils.cpp index a7e6b322197..87931329160 100644 --- a/src/plugins/diffeditor/diffutils.cpp +++ b/src/plugins/diffeditor/diffutils.cpp @@ -582,7 +582,7 @@ static QList readLines(QStringRef patch, break; } - Diff diffToBeAdded(command, line.mid(1) + newLine); + Diff diffToBeAdded(command, line.mid(1).toString() + newLine); if (!diffList.isEmpty() && diffList.last().command == command) diffList.last().text.append(diffToBeAdded.text); diff --git a/src/plugins/git/branchdialog.cpp b/src/plugins/git/branchdialog.cpp index eb71c73531a..8b7e5b1ccc1 100644 --- a/src/plugins/git/branchdialog.cpp +++ b/src/plugins/git/branchdialog.cpp @@ -66,6 +66,8 @@ BranchDialog::BranchDialog(QWidget *parent) : m_ui->includeOldCheckBox->setToolTip( tr("Include branches and tags that have not been active for %n days.", 0, Constants::OBSOLETE_COMMIT_AGE_IN_DAYS)); + m_ui->includeTagsCheckBox->setChecked(GitPlugin::client()->settings().boolValue( + GitSettings::showTagsKey)); connect(m_ui->refreshButton, &QAbstractButton::clicked, this, &BranchDialog::refreshCurrentRepository); connect(m_ui->addButton, &QAbstractButton::clicked, this, &BranchDialog::add); @@ -83,6 +85,10 @@ BranchDialog::BranchDialog(QWidget *parent) : m_model->setOldBranchesIncluded(value); refreshCurrentRepository(); }); + connect(m_ui->includeTagsCheckBox, &QCheckBox::toggled, this, [this](bool value) { + GitPlugin::client()->settings().setValue(GitSettings::showTagsKey, value); + refreshCurrentRepository(); + }); m_ui->branchView->setModel(m_model); m_ui->branchView->setFocus(); diff --git a/src/plugins/git/branchdialog.ui b/src/plugins/git/branchdialog.ui index 2ea2a762ecf..5335fecedbe 100644 --- a/src/plugins/git/branchdialog.ui +++ b/src/plugins/git/branchdialog.ui @@ -65,6 +65,13 @@ + + + + Include ta&gs + + + diff --git a/src/plugins/git/settingspage.cpp b/src/plugins/git/settingspage.cpp index 24ccf66ab5b..1f28de70f0f 100644 --- a/src/plugins/git/settingspage.cpp +++ b/src/plugins/git/settingspage.cpp @@ -76,7 +76,6 @@ VcsBaseClientSettings SettingsPageWidget::settings() const rc.setValue(GitSettings::logCountKey, m_ui.logCountSpinBox->value()); rc.setValue(GitSettings::timeoutKey, m_ui.timeoutSpinBox->value()); rc.setValue(GitSettings::pullRebaseKey, m_ui.pullRebaseCheckBox->isChecked()); - rc.setValue(GitSettings::showTagsKey, m_ui.showTagsCheckBox->isChecked()); rc.setValue(GitSettings::winSetHomeEnvironmentKey, m_ui.winHomeCheckBox->isChecked()); rc.setValue(GitSettings::gitkOptionsKey, m_ui.gitkOptionsLineEdit->text().trimmed()); rc.setValue(GitSettings::repositoryBrowserCmd, m_ui.repBrowserCommandPathChooser->path().trimmed()); @@ -90,7 +89,6 @@ void SettingsPageWidget::setSettings(const VcsBaseClientSettings &s) m_ui.logCountSpinBox->setValue(s.intValue(GitSettings::logCountKey)); m_ui.timeoutSpinBox->setValue(s.intValue(GitSettings::timeoutKey)); m_ui.pullRebaseCheckBox->setChecked(s.boolValue(GitSettings::pullRebaseKey)); - m_ui.showTagsCheckBox->setChecked(s.boolValue(GitSettings::showTagsKey)); m_ui.winHomeCheckBox->setChecked(s.boolValue(GitSettings::winSetHomeEnvironmentKey)); m_ui.gitkOptionsLineEdit->setText(s.stringValue(GitSettings::gitkOptionsKey)); m_ui.repBrowserCommandPathChooser->setPath(s.stringValue(GitSettings::repositoryBrowserCmd)); diff --git a/src/plugins/git/settingspage.ui b/src/plugins/git/settingspage.ui index 88ad0106892..86c95e02bfc 100644 --- a/src/plugins/git/settingspage.ui +++ b/src/plugins/git/settingspage.ui @@ -7,7 +7,7 @@ 0 0 705 - 427 + 403 @@ -123,13 +123,6 @@ - - - - Show tags in Branches dialog - - - @@ -214,7 +207,6 @@ logCountSpinBox timeoutSpinBox pullRebaseCheckBox - showTagsCheckBox gitkOptionsLineEdit diff --git a/src/plugins/glsleditor/glsleditor.cpp b/src/plugins/glsleditor/glsleditor.cpp index 5160828b4bb..feb283f02a9 100644 --- a/src/plugins/glsleditor/glsleditor.cpp +++ b/src/plugins/glsleditor/glsleditor.cpp @@ -27,7 +27,6 @@ #include "glsleditorconstants.h" #include "glsleditorplugin.h" #include "glslhighlighter.h" -#include "glslhoverhandler.h" #include "glslautocompleter.h" #include "glslcompletionassist.h" #include "glslindenter.h" @@ -332,8 +331,6 @@ GlslEditorFactory::GlslEditorFactory() setEditorActionHandlers(TextEditorActionHandler::Format | TextEditorActionHandler::UnCommentSelection | TextEditorActionHandler::UnCollapseAll); - - addHoverHandler(new GlslHoverHandler); } } // namespace Internal diff --git a/src/plugins/glsleditor/glsleditor.pro b/src/plugins/glsleditor/glsleditor.pro index 8f588ecb566..5abc1069702 100644 --- a/src/plugins/glsleditor/glsleditor.pro +++ b/src/plugins/glsleditor/glsleditor.pro @@ -10,7 +10,6 @@ glsleditorplugin.h \ glslhighlighter.h \ glslautocompleter.h \ glslindenter.h \ -glslhoverhandler.h \ glslcompletionassist.h SOURCES += \ @@ -19,7 +18,6 @@ glsleditorplugin.cpp \ glslhighlighter.cpp \ glslautocompleter.cpp \ glslindenter.cpp \ -glslhoverhandler.cpp \ glslcompletionassist.cpp RESOURCES += glsleditor.qrc diff --git a/src/plugins/glsleditor/glsleditor.qbs b/src/plugins/glsleditor/glsleditor.qbs index 1d5003de46d..23f7b4f4293 100644 --- a/src/plugins/glsleditor/glsleditor.qbs +++ b/src/plugins/glsleditor/glsleditor.qbs @@ -25,8 +25,6 @@ QtcPlugin { "glsleditorplugin.h", "glslhighlighter.cpp", "glslhighlighter.h", - "glslhoverhandler.cpp", - "glslhoverhandler.h", "glslindenter.cpp", "glslindenter.h", ] diff --git a/src/plugins/glsleditor/glslhoverhandler.cpp b/src/plugins/glsleditor/glslhoverhandler.cpp deleted file mode 100644 index 305852f0742..00000000000 --- a/src/plugins/glsleditor/glslhoverhandler.cpp +++ /dev/null @@ -1,45 +0,0 @@ -/**************************************************************************** -** -** 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 "glslhoverhandler.h" -#include "glsleditor.h" - -namespace GlslEditor { -namespace Internal { - -void GlslHoverHandler::identifyMatch(TextEditor::TextEditorWidget *editorWidget, int pos) -{ - if (!editorWidget->extraSelectionTooltip(pos).isEmpty()) - setToolTip(editorWidget->extraSelectionTooltip(pos)); -} - -void GlslHoverHandler::decorateToolTip() -{ - if (Qt::mightBeRichText(toolTip())) - setToolTip(toolTip().toHtmlEscaped()); -} - -} // namespace Internal -} // namespace GlslEditor diff --git a/src/plugins/glsleditor/glslhoverhandler.h b/src/plugins/glsleditor/glslhoverhandler.h deleted file mode 100644 index 5d1f29067e1..00000000000 --- a/src/plugins/glsleditor/glslhoverhandler.h +++ /dev/null @@ -1,44 +0,0 @@ -/**************************************************************************** -** -** 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 - -namespace GlslEditor { -namespace Internal { - -class GlslHoverHandler : public TextEditor::BaseHoverHandler -{ -public: - GlslHoverHandler() {} - -private: - void identifyMatch(TextEditor::TextEditorWidget *editorWidget, int pos) override; - void decorateToolTip() override; -}; - -} // namespace Internal -} // namespace GlslEditor diff --git a/src/plugins/ios/iosdevice.cpp b/src/plugins/ios/iosdevice.cpp index 4945b4cd0a7..00dd86b64c3 100644 --- a/src/plugins/ios/iosdevice.cpp +++ b/src/plugins/ios/iosdevice.cpp @@ -213,6 +213,11 @@ bool IosDevice::canAutoDetectPorts() const return true; } +Utils::OsType IosDevice::osType() const +{ + return Utils::OsTypeMac; +} + // IosDeviceManager diff --git a/src/plugins/ios/iosdevice.h b/src/plugins/ios/iosdevice.h index e2dd5cafd56..e0b7b4024bd 100644 --- a/src/plugins/ios/iosdevice.h +++ b/src/plugins/ios/iosdevice.h @@ -68,6 +68,7 @@ public: QString osVersion() const; Utils::Port nextPort() const; bool canAutoDetectPorts() const override; + Utils::OsType osType() const override; static QString name(); diff --git a/src/plugins/ios/iossimulator.cpp b/src/plugins/ios/iossimulator.cpp index 3f41bd84c13..681fe27f55d 100644 --- a/src/plugins/ios/iossimulator.cpp +++ b/src/plugins/ios/iossimulator.cpp @@ -154,6 +154,11 @@ bool IosSimulator::canAutoDetectPorts() const return true; } +Utils::OsType IosSimulator::osType() const +{ + return Utils::OsTypeMac; +} + IosSimulator::ConstPtr IosKitInformation::simulator(Kit *kit) { if (!kit) diff --git a/src/plugins/ios/iossimulator.h b/src/plugins/ios/iossimulator.h index b661821a3d0..ecbf2de776b 100644 --- a/src/plugins/ios/iossimulator.h +++ b/src/plugins/ios/iossimulator.h @@ -77,6 +77,7 @@ public: QVariantMap toMap() const override; Utils::Port nextPort() const; bool canAutoDetectPorts() const override; + Utils::OsType osType() const override; ProjectExplorer::IDevice::Ptr clone() const override; protected: diff --git a/src/plugins/projectexplorer/devicesupport/desktopdevice.cpp b/src/plugins/projectexplorer/devicesupport/desktopdevice.cpp index 400548bd12b..3c494afd7d9 100644 --- a/src/plugins/projectexplorer/devicesupport/desktopdevice.cpp +++ b/src/plugins/projectexplorer/devicesupport/desktopdevice.cpp @@ -142,6 +142,11 @@ Connection DesktopDevice::toolControlChannel(const ControlChannelHint &) const return HostName("localhost"); } +Utils::OsType DesktopDevice::osType() const +{ + return Utils::HostOsInfo::hostOs(); +} + IDevice::Ptr DesktopDevice::clone() const { return Ptr(new DesktopDevice(*this)); diff --git a/src/plugins/projectexplorer/devicesupport/desktopdevice.h b/src/plugins/projectexplorer/devicesupport/desktopdevice.h index 752bd20075f..80731edad31 100644 --- a/src/plugins/projectexplorer/devicesupport/desktopdevice.h +++ b/src/plugins/projectexplorer/devicesupport/desktopdevice.h @@ -53,6 +53,7 @@ public: DeviceProcessSignalOperation::Ptr signalOperation() const override; DeviceEnvironmentFetcher::Ptr environmentFetcher() const override; Connection toolControlChannel(const ControlChannelHint &) const override; + Utils::OsType osType() const override; IDevice::Ptr clone() const override; diff --git a/src/plugins/projectexplorer/devicesupport/devicemanager.cpp b/src/plugins/projectexplorer/devicesupport/devicemanager.cpp index 39b17a6444d..2d1e161d2cc 100644 --- a/src/plugins/projectexplorer/devicesupport/devicemanager.cpp +++ b/src/plugins/projectexplorer/devicesupport/devicemanager.cpp @@ -441,6 +441,7 @@ private: { return DeviceProcessSignalOperation::Ptr(); } + Utils::OsType osType() const override { return Utils::HostOsInfo::hostOs(); } }; void ProjectExplorerPlugin::testDeviceManager() diff --git a/src/plugins/projectexplorer/devicesupport/idevice.cpp b/src/plugins/projectexplorer/devicesupport/idevice.cpp index e4cc56c4278..d4f0f87576a 100644 --- a/src/plugins/projectexplorer/devicesupport/idevice.cpp +++ b/src/plugins/projectexplorer/devicesupport/idevice.cpp @@ -278,6 +278,11 @@ DeviceTester *IDevice::createDeviceTester() const return 0; } +Utils::OsType IDevice::osType() const +{ + return Utils::OsTypeOther; +} + DeviceProcess *IDevice::createProcess(QObject * /* parent */) const { QTC_CHECK(false); diff --git a/src/plugins/projectexplorer/devicesupport/idevice.h b/src/plugins/projectexplorer/devicesupport/idevice.h index a93a0298213..2f5270b7ea0 100644 --- a/src/plugins/projectexplorer/devicesupport/idevice.h +++ b/src/plugins/projectexplorer/devicesupport/idevice.h @@ -28,6 +28,7 @@ #include "../projectexplorer_export.h" #include +#include #include #include @@ -160,6 +161,7 @@ public: virtual DeviceProcessList *createProcessListModel(QObject *parent = 0) const; virtual bool hasDeviceTester() const { return false; } virtual DeviceTester *createDeviceTester() const; + virtual Utils::OsType osType() const; virtual bool canCreateProcess() const { return false; } virtual DeviceProcess *createProcess(QObject *parent) const; diff --git a/src/plugins/projectexplorer/runconfiguration.cpp b/src/plugins/projectexplorer/runconfiguration.cpp index 76f4dbcffec..338681ce854 100644 --- a/src/plugins/projectexplorer/runconfiguration.cpp +++ b/src/plugins/projectexplorer/runconfiguration.cpp @@ -44,6 +44,7 @@ #include #include +#include #include #include @@ -1178,7 +1179,7 @@ void RunControlPrivate::setState(RunControlState newState) void RunControlPrivate::debugMessage(const QString &msg) { - //q->appendMessage(msg + '\n', Utils::DebugFormat); + Core::MessageManager::write(msg, Core::MessageManager::Silent); qCDebug(statesLog()) << msg; } diff --git a/src/plugins/projectexplorer/runconfiguration.h b/src/plugins/projectexplorer/runconfiguration.h index a1f48e904c0..4d7f927f81b 100644 --- a/src/plugins/projectexplorer/runconfiguration.h +++ b/src/plugins/projectexplorer/runconfiguration.h @@ -523,7 +523,6 @@ signals: void appendMessageRequested(ProjectExplorer::RunControl *runControl, const QString &msg, Utils::OutputFormat format); void aboutToStart(); - void starting(); void started(); void finished(); void applicationProcessHandleChanged(QPrivateSignal); // Use setApplicationProcessHandle diff --git a/src/plugins/qmakeandroidsupport/qmakeandroidrunfactories.h b/src/plugins/qmakeandroidsupport/qmakeandroidrunfactories.h index 03c6702631a..0580e0f0171 100644 --- a/src/plugins/qmakeandroidsupport/qmakeandroidrunfactories.h +++ b/src/plugins/qmakeandroidsupport/qmakeandroidrunfactories.h @@ -25,13 +25,10 @@ #pragma once -#include #include #include namespace ProjectExplorer { -class RunControl; -class RunConfigWidget; class Target; class Node; } // namespace ProjectExplorer diff --git a/src/plugins/qmakeprojectmanager/profilehoverhandler.h b/src/plugins/qmakeprojectmanager/profilehoverhandler.h index 7f067b345b1..2fa1fb250e0 100644 --- a/src/plugins/qmakeprojectmanager/profilehoverhandler.h +++ b/src/plugins/qmakeprojectmanager/profilehoverhandler.h @@ -37,14 +37,9 @@ namespace Internal { class ProFileHoverHandler : public TextEditor::BaseHoverHandler { - Q_OBJECT - public: explicit ProFileHoverHandler(const TextEditor::Keywords &keywords); -signals: - void creatorHelpRequested(const QUrl &url); - private: void identifyMatch(TextEditor::TextEditorWidget *editorWidget, int pos) override; void identifyQMakeKeyword(const QString &text, int pos); diff --git a/src/plugins/qmljseditor/qmljshoverhandler.h b/src/plugins/qmljseditor/qmljshoverhandler.h index e9f2d80ec80..fde05c7e4a6 100644 --- a/src/plugins/qmljseditor/qmljshoverhandler.h +++ b/src/plugins/qmljseditor/qmljshoverhandler.h @@ -29,6 +29,7 @@ #include #include +#include QT_BEGIN_NAMESPACE template class QList; @@ -49,7 +50,7 @@ class QmlJSEditorWidget; class QmlJSHoverHandler : public TextEditor::BaseHoverHandler { - Q_OBJECT + Q_DECLARE_TR_FUNCTIONS(QmlJSHoverHandler) public: QmlJSHoverHandler(); diff --git a/src/plugins/qmlprofiler/qmlprofilerruncontrol.cpp b/src/plugins/qmlprofiler/qmlprofilerruncontrol.cpp index f84b435fe1c..4525b72e11e 100644 --- a/src/plugins/qmlprofiler/qmlprofilerruncontrol.cpp +++ b/src/plugins/qmlprofiler/qmlprofilerruncontrol.cpp @@ -114,7 +114,7 @@ void QmlProfilerRunner::start() QUrl serverUrl = this->serverUrl(); if (serverUrl.port() != -1) { - auto clientManager = Internal::QmlProfilerTool::clientManager(); + QmlProfilerClientManager *clientManager = Internal::QmlProfilerTool::clientManager(); clientManager->setServerUrl(serverUrl); clientManager->connectToTcpServer(); } @@ -149,6 +149,7 @@ void QmlProfilerRunner::stop() } break; } + reportStopped(); } void QmlProfilerRunner::notifyRemoteFinished() @@ -232,6 +233,7 @@ void QmlProfilerRunner::notifyRemoteSetupDone(Utils::Port port) auto clientManager = Internal::QmlProfilerTool::clientManager(); clientManager->setServerUrl(serverUrl); clientManager->connectToTcpServer(); + reportStarted(); } } diff --git a/src/plugins/qmlprofiler/qmlprofilertextmark.cpp b/src/plugins/qmlprofiler/qmlprofilertextmark.cpp index a0bdaed6cc1..bbc0bf3fc0b 100644 --- a/src/plugins/qmlprofiler/qmlprofilertextmark.cpp +++ b/src/plugins/qmlprofiler/qmlprofilertextmark.cpp @@ -44,7 +44,7 @@ void QmlProfilerTextMark::addTypeId(int typeId) m_typeIds.append(typeId); } -void QmlProfilerTextMark::paint(QPainter *painter, const QRect &paintRect) const +void QmlProfilerTextMark::paintIcon(QPainter *painter, const QRect &paintRect) const { painter->save(); painter->setPen(Qt::black); @@ -108,7 +108,7 @@ void QmlProfilerTextMarkModel::createMarks(QmlProfilerTool *tool, const QString } } -bool QmlProfilerTextMark::addToolTipContent(QLayout *target) +bool QmlProfilerTextMark::addToolTipContent(QLayout *target) const { QGridLayout *layout = new QGridLayout; layout->setHorizontalSpacing(10); diff --git a/src/plugins/qmlprofiler/qmlprofilertextmark.h b/src/plugins/qmlprofiler/qmlprofilertextmark.h index b3772aea134..894e5fc5178 100644 --- a/src/plugins/qmlprofiler/qmlprofilertextmark.h +++ b/src/plugins/qmlprofiler/qmlprofilertextmark.h @@ -37,10 +37,10 @@ public: QmlProfilerTextMark(QmlProfilerTool *tool, int typeId, const QString &fileName, int lineNumber); void addTypeId(int typeId); - void paint(QPainter *painter, const QRect &rect) const override; + void paintIcon(QPainter *painter, const QRect &rect) const override; void clicked() override; bool isClickable() const override { return true; } - bool addToolTipContent(QLayout *target) override; + bool addToolTipContent(QLayout *target) const override; private: QmlProfilerTool *m_tool; diff --git a/src/plugins/qnx/qnxdevice.cpp b/src/plugins/qnx/qnxdevice.cpp index 26275bb3b88..994f74a8392 100644 --- a/src/plugins/qnx/qnxdevice.cpp +++ b/src/plugins/qnx/qnxdevice.cpp @@ -122,6 +122,11 @@ QString QnxDevice::displayType() const return tr("QNX"); } +OsType QnxDevice::osType() const +{ + return OsTypeOtherUnix; +} + int QnxDevice::qnxVersion() const { if (m_versionNumber == 0) diff --git a/src/plugins/qnx/qnxdevice.h b/src/plugins/qnx/qnxdevice.h index eac1802a80f..3c5ae0965b2 100644 --- a/src/plugins/qnx/qnxdevice.h +++ b/src/plugins/qnx/qnxdevice.h @@ -56,6 +56,7 @@ public: void executeAction(Core::Id actionId, QWidget *parent) override; QString displayType() const override; + Utils::OsType osType() const override; int qnxVersion() const; diff --git a/src/plugins/remotelinux/linuxdevice.cpp b/src/plugins/remotelinux/linuxdevice.cpp index c3ad42f3b27..1e6fe89993a 100644 --- a/src/plugins/remotelinux/linuxdevice.cpp +++ b/src/plugins/remotelinux/linuxdevice.cpp @@ -203,6 +203,11 @@ void LinuxDevice::executeAction(Core::Id actionId, QWidget *parent) delete d; } +Utils::OsType LinuxDevice::osType() const +{ + return Utils::OsTypeLinux; +} + LinuxDevice::LinuxDevice(const QString &name, Core::Id type, MachineType machineType, Origin origin, Core::Id id) : IDevice(type, origin, machineType, id) diff --git a/src/plugins/remotelinux/linuxdevice.h b/src/plugins/remotelinux/linuxdevice.h index f9469abeb50..5b1a764aef0 100644 --- a/src/plugins/remotelinux/linuxdevice.h +++ b/src/plugins/remotelinux/linuxdevice.h @@ -54,6 +54,7 @@ public: QList actionIds() const; QString displayNameForActionId(Core::Id actionId) const; void executeAction(Core::Id actionId, QWidget *parent); + Utils::OsType osType() const override; ProjectExplorer::IDevice::Ptr clone() const; bool canCreateProcess() const { return true; } diff --git a/src/plugins/texteditor/basehoverhandler.cpp b/src/plugins/texteditor/basehoverhandler.cpp index 5e2ffac50f9..56ad0c0ddb8 100644 --- a/src/plugins/texteditor/basehoverhandler.cpp +++ b/src/plugins/texteditor/basehoverhandler.cpp @@ -26,27 +26,17 @@ #include "basehoverhandler.h" #include "texteditor.h" -#include #include -#include - -using namespace Core; - namespace TextEditor { -BaseHoverHandler::BaseHoverHandler() : m_diagnosticTooltip(false), m_priority(-1) -{ -} - BaseHoverHandler::~BaseHoverHandler() {} -void BaseHoverHandler::showToolTip(TextEditorWidget *widget, const QPoint &point, int pos) +void BaseHoverHandler::showToolTip(TextEditorWidget *widget, const QPoint &point, bool decorate) { - widget->setContextHelpId(QString()); - - process(widget, pos); + if (decorate) + decorateToolTip(); operateTooltip(widget, point); } @@ -64,9 +54,6 @@ int BaseHoverHandler::priority() const if (m_priority >= 0) return m_priority; - if (isDiagnosticTooltip()) - return Priority_Diagnostic; - if (lastHelpItemIdentified().isValid()) return Priority_Help; @@ -103,21 +90,6 @@ const QString &BaseHoverHandler::toolTip() const return m_toolTip; } -void BaseHoverHandler::appendToolTip(const QString &extension) -{ - m_toolTip.append(extension); -} - -void BaseHoverHandler::setIsDiagnosticTooltip(bool isDiagnosticTooltip) -{ - m_diagnosticTooltip = isDiagnosticTooltip; -} - -bool BaseHoverHandler::isDiagnosticTooltip() const -{ - return m_diagnosticTooltip; -} - void BaseHoverHandler::setLastHelpItemIdentified(const HelpItem &help) { m_lastHelpItemIdentified = help; @@ -128,19 +100,13 @@ const HelpItem &BaseHoverHandler::lastHelpItemIdentified() const return m_lastHelpItemIdentified; } -void BaseHoverHandler::clear() +void BaseHoverHandler::process(TextEditorWidget *widget, int pos) { - m_diagnosticTooltip = false; m_toolTip.clear(); m_priority = -1; m_lastHelpItemIdentified = HelpItem(); -} -void BaseHoverHandler::process(TextEditorWidget *widget, int pos) -{ - clear(); identifyMatch(widget, pos); - decorateToolTip(); } void BaseHoverHandler::identifyMatch(TextEditorWidget *editorWidget, int pos) @@ -155,11 +121,11 @@ void BaseHoverHandler::decorateToolTip() if (Qt::mightBeRichText(toolTip())) setToolTip(toolTip().toHtmlEscaped()); - if (!isDiagnosticTooltip() && lastHelpItemIdentified().isValid()) { + if (priority() != Priority_Diagnostic && lastHelpItemIdentified().isValid()) { const QString &contents = lastHelpItemIdentified().extractContent(false); if (!contents.isEmpty()) { - setToolTip(toolTip().toHtmlEscaped()); - appendToolTip(contents); + m_toolTip = toolTip().toHtmlEscaped(); + m_toolTip.append(contents); } } } diff --git a/src/plugins/texteditor/basehoverhandler.h b/src/plugins/texteditor/basehoverhandler.h index 7a5334e3a8e..44dfc61e922 100644 --- a/src/plugins/texteditor/basehoverhandler.h +++ b/src/plugins/texteditor/basehoverhandler.h @@ -28,43 +28,25 @@ #include "texteditor_global.h" #include "helpitem.h" -#include - -namespace Core { class IEditor; } +QT_BEGIN_NAMESPACE +class QPoint; +QT_END_NAMESPACE namespace TextEditor { -class BaseTextEditor; class TextEditorWidget; -class TEXTEDITOR_EXPORT BaseHoverHandler : public QObject +class TEXTEDITOR_EXPORT BaseHoverHandler { - Q_OBJECT - public: - BaseHoverHandler(); - ~BaseHoverHandler(); + virtual ~BaseHoverHandler(); QString contextHelpId(TextEditorWidget *widget, int pos); - int checkToolTip(TextEditorWidget *widget, int pos); - void showToolTip(TextEditorWidget *widget, const QPoint &point, int pos); - int priority() const; + int checkToolTip(TextEditorWidget *widget, int pos); + void showToolTip(TextEditorWidget *widget, const QPoint &point, bool decorate = true); protected: - void setToolTip(const QString &tooltip); - void appendToolTip(const QString &extension); - const QString &toolTip() const; - - void setIsDiagnosticTooltip(bool isDiagnosticTooltip); - bool isDiagnosticTooltip() const; - - void setLastHelpItemIdentified(const HelpItem &help); - const HelpItem &lastHelpItemIdentified() const; - - virtual void decorateToolTip(); - virtual void operateTooltip(TextEditorWidget *editorWidget, const QPoint &point); - enum { Priority_None = 0, Priority_Tooltip = 5, @@ -72,16 +54,24 @@ protected: Priority_Diagnostic = 20 }; void setPriority(int priority); -private: - void clear(); - void process(TextEditorWidget *widget, int pos); + int priority() const; + + void setToolTip(const QString &tooltip); + const QString &toolTip() const; + + void setLastHelpItemIdentified(const HelpItem &help); + const HelpItem &lastHelpItemIdentified() const; virtual void identifyMatch(TextEditorWidget *editorWidget, int pos); + virtual void decorateToolTip(); + virtual void operateTooltip(TextEditorWidget *editorWidget, const QPoint &point); + +private: + void process(TextEditorWidget *widget, int pos); - bool m_diagnosticTooltip; QString m_toolTip; HelpItem m_lastHelpItemIdentified; - int m_priority; + int m_priority = -1; }; } // namespace TextEditor diff --git a/src/plugins/texteditor/colorpreviewhoverhandler.h b/src/plugins/texteditor/colorpreviewhoverhandler.h index 2e956027dcc..8677bf009a2 100644 --- a/src/plugins/texteditor/colorpreviewhoverhandler.h +++ b/src/plugins/texteditor/colorpreviewhoverhandler.h @@ -38,9 +38,6 @@ class TextEditorWidget; class TEXTEDITOR_EXPORT ColorPreviewHoverHandler : public BaseHoverHandler { - Q_OBJECT -public: - private: void identifyMatch(TextEditorWidget *editorWidget, int pos) override; void operateTooltip(TextEditorWidget *editorWidget, const QPoint &point) override; diff --git a/src/plugins/texteditor/convenience.cpp b/src/plugins/texteditor/convenience.cpp index 22dcb99e9ba..8ee92147ddc 100644 --- a/src/plugins/texteditor/convenience.cpp +++ b/src/plugins/texteditor/convenience.cpp @@ -86,5 +86,31 @@ QTextCursor flippedCursor(const QTextCursor &cursor) return flipped; } +static bool isValidIdentifierChar(const QChar &c) +{ + return c.isLetter() + || c.isNumber() + || c == QLatin1Char('_') + || c.isHighSurrogate() + || c.isLowSurrogate(); +} + +QTextCursor wordStartCursor(const QTextCursor &textCursor) +{ + const int originalPosition = textCursor.position(); + QTextCursor cursor(textCursor); + cursor.movePosition(QTextCursor::StartOfWord); + const int wordStartPosition = cursor.position(); + + if (originalPosition == wordStartPosition) { + // Cursor is not on an identifier, check whether we are right after one. + const QChar c = textCursor.document()->characterAt(originalPosition - 1); + if (isValidIdentifierChar(c)) + cursor.movePosition(QTextCursor::PreviousWord); + } + + return cursor; +} + } // Util } // TextEditor diff --git a/src/plugins/texteditor/convenience.h b/src/plugins/texteditor/convenience.h index 5cbff33bef1..e4f5f0480bc 100644 --- a/src/plugins/texteditor/convenience.h +++ b/src/plugins/texteditor/convenience.h @@ -47,5 +47,7 @@ TEXTEDITOR_EXPORT QTextCursor selectAt(QTextCursor textCursor, uint line, uint c TEXTEDITOR_EXPORT QTextCursor flippedCursor(const QTextCursor &cursor); +TEXTEDITOR_EXPORT QTextCursor wordStartCursor(const QTextCursor &cursor); + } // Util } // TextEditor diff --git a/src/plugins/texteditor/displaysettings.cpp b/src/plugins/texteditor/displaysettings.cpp index d15cf52dcad..196b9434c2f 100644 --- a/src/plugins/texteditor/displaysettings.cpp +++ b/src/plugins/texteditor/displaysettings.cpp @@ -44,6 +44,7 @@ static const char displayFileEncodingKey[] = "DisplayFileEncoding"; static const char scrollBarHighlightsKey[] = "ScrollBarHighlights"; static const char animateNavigationWithinFileKey[] = "AnimateNavigationWithinFile"; static const char animateWithinFileTimeMaxKey[] = "AnimateWithinFileTimeMax"; +static const char displayAnnotationsKey[] = "DisplayAnnotations"; static const char groupPostfix[] = "DisplaySettings"; namespace TextEditor { @@ -69,6 +70,7 @@ void DisplaySettings::toSettings(const QString &category, QSettings *s) const s->setValue(QLatin1String(displayFileEncodingKey), m_displayFileEncoding); s->setValue(QLatin1String(scrollBarHighlightsKey), m_scrollBarHighlights); s->setValue(QLatin1String(animateNavigationWithinFileKey), m_animateNavigationWithinFile); + s->setValue(QLatin1String(displayAnnotationsKey), m_displayAnnotations); s->endGroup(); } @@ -97,6 +99,7 @@ void DisplaySettings::fromSettings(const QString &category, const QSettings *s) m_scrollBarHighlights = s->value(group + QLatin1String(scrollBarHighlightsKey), m_scrollBarHighlights).toBool(); m_animateNavigationWithinFile = s->value(group + QLatin1String(animateNavigationWithinFileKey), m_animateNavigationWithinFile).toBool(); m_animateWithinFileTimeMax = s->value(group + QLatin1String(animateWithinFileTimeMaxKey), m_animateWithinFileTimeMax).toInt(); + m_displayAnnotations = s->value(group + QLatin1String(displayAnnotationsKey), m_displayAnnotations).toBool(); } bool DisplaySettings::equals(const DisplaySettings &ds) const @@ -118,6 +121,7 @@ bool DisplaySettings::equals(const DisplaySettings &ds) const && m_scrollBarHighlights == ds.m_scrollBarHighlights && m_animateNavigationWithinFile == ds.m_animateNavigationWithinFile && m_animateWithinFileTimeMax == ds.m_animateWithinFileTimeMax + && m_displayAnnotations == ds.m_displayAnnotations ; } diff --git a/src/plugins/texteditor/displaysettings.h b/src/plugins/texteditor/displaysettings.h index fabebd96d8c..a37343bb486 100644 --- a/src/plugins/texteditor/displaysettings.h +++ b/src/plugins/texteditor/displaysettings.h @@ -58,6 +58,7 @@ public: bool m_scrollBarHighlights = true; bool m_animateNavigationWithinFile = false; int m_animateWithinFileTimeMax = 333; // read only setting + bool m_displayAnnotations = true; bool equals(const DisplaySettings &ds) const; }; diff --git a/src/plugins/texteditor/displaysettingspage.cpp b/src/plugins/texteditor/displaysettingspage.cpp index 147fa970804..7ae27e11d73 100644 --- a/src/plugins/texteditor/displaysettingspage.cpp +++ b/src/plugins/texteditor/displaysettingspage.cpp @@ -119,6 +119,7 @@ void DisplaySettingsPage::settingsFromUI(DisplaySettings &displaySettings, displaySettings.m_displayFileEncoding = d->m_page->displayFileEncoding->isChecked(); displaySettings.m_scrollBarHighlights = d->m_page->scrollBarHighlights->isChecked(); displaySettings.m_animateNavigationWithinFile = d->m_page->animateNavigationWithinFile->isChecked(); + displaySettings.m_displayAnnotations = d->m_page->displayAnnotations->isChecked(); } void DisplaySettingsPage::settingsToUI() @@ -142,6 +143,7 @@ void DisplaySettingsPage::settingsToUI() d->m_page->displayFileEncoding->setChecked(displaySettings.m_displayFileEncoding); d->m_page->scrollBarHighlights->setChecked(displaySettings.m_scrollBarHighlights); d->m_page->animateNavigationWithinFile->setChecked(displaySettings.m_animateNavigationWithinFile); + d->m_page->displayAnnotations->setChecked(displaySettings.m_displayAnnotations); } const DisplaySettings &DisplaySettingsPage::displaySettings() const diff --git a/src/plugins/texteditor/displaysettingspage.ui b/src/plugins/texteditor/displaysettingspage.ui index b91965a192c..1663840272e 100644 --- a/src/plugins/texteditor/displaysettingspage.ui +++ b/src/plugins/texteditor/displaysettingspage.ui @@ -80,17 +80,10 @@ Display - - + + - Display &folding markers - - - - - - - Center &cursor on scroll + &Highlight matching parentheses @@ -101,20 +94,6 @@ - - - - Auto-fold first &comment - - - - - - - &Animate matching parentheses - - - @@ -129,6 +108,20 @@ + + + + Auto-fold first &comment + + + + + + + &Animate matching parentheses + + + @@ -143,6 +136,13 @@ + + + + Center &cursor on scroll + + + @@ -153,17 +153,17 @@ - - + + - &Highlight matching parentheses + Display &folding markers - - + + - Mark &text changes + Animate navigation within file @@ -174,10 +174,17 @@ - - + + - Animate navigation within file + Mark &text changes + + + + + + + Display annotations behind lines @@ -197,12 +204,14 @@ centerOnScroll autoFoldFirstComment scrollBarHighlights + displayAnnotations highlightCurrentLine highlightBlocks animateMatchingParentheses highlightMatchingParentheses openLinksInNextSplit displayFileEncoding + animateNavigationWithinFile diff --git a/src/plugins/texteditor/textdocument.cpp b/src/plugins/texteditor/textdocument.cpp index f146507e4c0..7c53c812962 100644 --- a/src/plugins/texteditor/textdocument.cpp +++ b/src/plugins/texteditor/textdocument.cpp @@ -845,6 +845,13 @@ void TextDocument::modificationChanged(bool modified) emit changed(); } +void TextDocument::updateLayout() const +{ + auto documentLayout = qobject_cast(d->m_document.documentLayout()); + QTC_ASSERT(documentLayout, return); + documentLayout->requestUpdate(); +} + TextMarks TextDocument::marks() const { return d->m_marksCache; @@ -953,6 +960,7 @@ void TextDocument::removeMark(TextMark *mark) removeMarkFromMarksCache(mark); mark->setBaseTextDocument(0); + updateLayout(); } void TextDocument::updateMark(TextMark *mark) @@ -964,9 +972,7 @@ void TextDocument::updateMark(TextMark *mark) userData->removeMark(mark); userData->addMark(mark); } - auto documentLayout = qobject_cast(d->m_document.documentLayout()); - QTC_ASSERT(documentLayout, return); - documentLayout->requestUpdate(); + updateLayout(); } void TextDocument::moveMark(TextMark *mark, int previousLine) diff --git a/src/plugins/texteditor/textdocument.h b/src/plugins/texteditor/textdocument.h index 38719dd8486..63c1f78a421 100644 --- a/src/plugins/texteditor/textdocument.h +++ b/src/plugins/texteditor/textdocument.h @@ -154,6 +154,7 @@ private: void cleanWhitespace(QTextCursor &cursor, bool cleanIndentation, bool inEntireDocument); void ensureFinalNewLine(QTextCursor &cursor); void modificationChanged(bool modified); + void updateLayout() const; TextDocumentPrivate *d; }; diff --git a/src/plugins/texteditor/texteditor.cpp b/src/plugins/texteditor/texteditor.cpp index e1652a8241e..aa794ad63ce 100644 --- a/src/plugins/texteditor/texteditor.cpp +++ b/src/plugins/texteditor/texteditor.cpp @@ -73,6 +73,8 @@ #include #include #include +#include +#include #include #include #include @@ -278,6 +280,7 @@ public: bool expanded, bool active, bool hovered) const; + void drawLineAnnotation(QPainter &painter, const QTextBlock &block); void toggleBlockVisible(const QTextBlock &block); QRect foldBox(); @@ -296,6 +299,7 @@ public: bool camelCaseLeft(QTextCursor &cursor, QTextCursor::MoveMode mode); void processTooltipRequest(const QTextCursor &c); + bool processAnnotaionTooltipRequest(const QTextBlock &block, const QPoint &pos) const; void transformSelection(TransformationMethod method); void transformBlockSelection(TransformationMethod method); @@ -383,6 +387,13 @@ public: bool snippetCheckCursor(const QTextCursor &cursor); void snippetTabOrBacktab(bool forward); + struct AnnotationRect + { + QRectF rect; + const TextMark *mark; + }; + QMap> m_annotationRects; + RefactorOverlay *m_refactorOverlay = nullptr; QString m_contextHelpId; @@ -457,6 +468,26 @@ public: CodeAssistant m_codeAssistant; bool m_assistRelevantContentAdded = false; + + struct LastHoverHandlerInfo { + LastHoverHandlerInfo() = default; + LastHoverHandlerInfo(BaseHoverHandler *handler, int documentRevision, int cursorPosition) + : handler(handler) + , documentRevision(documentRevision) + , cursorPosition(cursorPosition) + {} + + bool applies(int documentRevision, int cursorPosition) const + { + return handler + && documentRevision == this->documentRevision + && cursorPosition == this->cursorPosition; + } + + BaseHoverHandler *handler = nullptr; + int documentRevision = -1; + int cursorPosition = -1; + } m_lastHoverHandlerInfo; QList m_hoverHandlers; // Not owned QPointer m_navigationAnimation; @@ -470,7 +501,8 @@ public: bool m_skipAutoCompletedText = true; bool m_removeAutoCompletedText = true; bool m_keepAutoCompletionHighlight = false; - QTextCursor m_autoCompleteHighlightPos; + QList m_autoCompleteHighlightPos; + void updateAutoCompleteHighlight(); int m_cursorBlockNumber = -1; int m_blockCount = 0; @@ -943,6 +975,21 @@ int TextEditorWidgetPrivate::visualIndent(const QTextBlock &block) const return 0; } +void TextEditorWidgetPrivate::updateAutoCompleteHighlight() +{ + const QTextCharFormat &matchFormat + = q->textDocument()->fontSettings().toTextCharFormat(C_PARENTHESES); + + QList extraSelections; + for (QTextCursor cursor : Utils::asConst(m_autoCompleteHighlightPos)) { + QTextEdit::ExtraSelection sel; + sel.cursor = cursor; + sel.format.setBackground(matchFormat.background()); + extraSelections.append(sel); + } + q->setExtraSelections(TextEditorWidget::AutoCompleteSelection, extraSelections); +} + void TextEditorWidget::selectEncoding() { TextDocument *doc = d->m_document.data(); @@ -2366,8 +2413,10 @@ void TextEditorWidget::keyPressEvent(QKeyEvent *e) QTextCursor cursor = textCursor(); QString autoText; if (!inOverwriteMode) { - autoText = autoCompleter()->autoComplete(cursor, eventText, - d->m_skipAutoCompletedText && cursor == d->m_autoCompleteHighlightPos); + const bool skipChar = d->m_skipAutoCompletedText + && !d->m_autoCompleteHighlightPos.isEmpty() + && cursor == d->m_autoCompleteHighlightPos.last(); + autoText = autoCompleter()->autoComplete(cursor, eventText, skipChar); } const bool cursorWithinSnippet = d->snippetCheckCursor(cursor); @@ -3132,6 +3181,15 @@ void TextEditorWidgetPrivate::processTooltipRequest(const QTextCursor &c) return; } + // Does the last handler still applies? + const int documentRevision = m_document->document()->revision(); + const int cursorPosition = Convenience::wordStartCursor(c).position(); + if (m_lastHoverHandlerInfo.applies(documentRevision, cursorPosition)) { + m_lastHoverHandlerInfo.handler->showToolTip(q, toolTipPoint, /*decorate=*/ false); + return; + } + + // Determine best handler int highestPriority = -1; BaseHoverHandler *highest = 0; foreach (BaseHoverHandler *handler, m_hoverHandlers) { @@ -3142,8 +3200,47 @@ void TextEditorWidgetPrivate::processTooltipRequest(const QTextCursor &c) } } - if (highest) - highest->showToolTip(q, toolTipPoint, c.position()); + // Let the best handler show the tooltip + if (highest) { + m_lastHoverHandlerInfo = LastHoverHandlerInfo{highest, documentRevision, cursorPosition}; + highest->showToolTip(q, toolTipPoint); + } +} + +bool TextEditorWidgetPrivate::processAnnotaionTooltipRequest(const QTextBlock &block, + const QPoint &pos) const +{ + TextBlockUserData *blockUserData = TextDocumentLayout::testUserData(block); + if (!blockUserData) + return false; + + for (const AnnotationRect &annotationRect : m_annotationRects[block.blockNumber()]) { + if (annotationRect.rect.contains(pos)) { + auto layout = new QGridLayout; + layout->setContentsMargins(0, 0, 0, 0); + layout->setSpacing(2); + annotationRect.mark->addToToolTipLayout(layout); + TextMarks marks = blockUserData->marks(); + if (marks.size() > 1) { + QFrame* separator = new QFrame(); + separator->setFrameShape(QFrame::HLine); + layout->addWidget(separator, 2, 0, 1, layout->columnCount()); + layout->addWidget(new QLabel(tr("Other annotations:")), 3, 0, 1, + layout->columnCount()); + + Utils::sort(marks, [](const TextMark* mark1, const TextMark* mark2){ + return mark1->priority() > mark2->priority(); + }); + for (const TextMark *mark : Utils::asConst(marks)) { + if (mark != annotationRect.mark) + mark->addToToolTipLayout(layout); + } + } + ToolTip::show(q->mapToGlobal(pos), layout, q); + return true; + } + } + return false; } bool TextEditorWidget::viewportEvent(QEvent *event) @@ -3173,10 +3270,14 @@ bool TextEditorWidget::viewportEvent(QEvent *event) QTC_CHECK(line.isValid()); // Only handle tool tip for text cursor if mouse is within the block for the text cursor, // and not if the mouse is e.g. in the empty space behind a short line. - if (line.isValid() - && pos.x() <= blockBoundingGeometry(block).left() + line.naturalTextRect().right()) { - d->processTooltipRequest(tc); - return true; + if (line.isValid()) { + if (pos.x() <= blockBoundingGeometry(block).left() + line.naturalTextRect().right()) { + d->processTooltipRequest(tc); + return true; + } else if (d->processAnnotaionTooltipRequest(block, pos)) { + return true; + } + ToolTip::hide(); } } return QPlainTextEdit::viewportEvent(event); @@ -3613,6 +3714,52 @@ static QTextLayout::FormatRange createBlockCursorCharFormatRange(int pos, const return o; } +void TextEditorWidgetPrivate::drawLineAnnotation(QPainter &painter, const QTextBlock &block) +{ + if (!m_displaySettings.m_displayAnnotations) + return; + + TextBlockUserData *blockUserData = TextDocumentLayout::testUserData(block); + if (!blockUserData) + return; + + TextMarks marks = blockUserData->marks(); + if (marks.isEmpty()) + return; + + const QTextLayout *layout = block.layout(); + const int lineCount = layout->lineCount(); + if (lineCount < 1) + return; + const QTextLine line = layout->lineAt(lineCount - 1); + const QPointF contentOffset = q->contentOffset(); + const qreal top = q->blockBoundingGeometry(block).translated(contentOffset).top(); + const QRectF lineRect = + line.naturalTextRect().translated(contentOffset.x(), top).adjusted(0, 0, -1, -1); + + Utils::sort(marks, [](const TextMark* mark1, const TextMark* mark2){ + return mark1->priority() > mark2->priority(); + }); + + constexpr qreal itemOffset = 10; + qreal x = lineRect.right() + itemOffset; + + const RefactorMarkers refactorMarkers = m_refactorOverlay->markers(); + for (auto refactorMark : refactorMarkers) { + if (refactorMark.cursor.block() == block) + x = qMax(x, refactorMark.rect.right() + itemOffset); + } + + for (const TextMark *mark : marks) { + QRectF annotationRect(x, lineRect.top(), q->viewport()->width() - x, lineRect.height()); + if (annotationRect.width() <= 0) + break; + mark->paintAnnotation(&painter, &annotationRect, q->fontMetrics()); + x += annotationRect.width() + itemOffset; + m_annotationRects[block.blockNumber()].append({annotationRect, mark}); + } +} + void TextEditorWidget::paintEvent(QPaintEvent *e) { // draw backgrond to the right of the wrap column before everything else @@ -3738,6 +3885,7 @@ void TextEditorWidget::paintEvent(QPaintEvent *e) int cursor_cpos = 0; QPen cursor_pen; + d->m_annotationRects.clear(); d->m_searchResultOverlay->clear(); if (!d->m_searchExpr.isEmpty()) { // first pass for the search result overlays @@ -4253,6 +4401,7 @@ void TextEditorWidget::paintEvent(QPaintEvent *e) painter.restore(); } } + d->drawLineAnnotation(painter, block); block = nextVisibleBlock; top = bottom; @@ -4538,7 +4687,7 @@ void TextEditorWidget::extraAreaPaintEvent(QPaintEvent *e) const int height = fmLineSpacing - 1; const int width = int(.5 + height * mark->widthFactor()); const QRect r(xoffset, top, width, height); - mark->paint(&painter, r); + mark->paintIcon(&painter, r); xoffset += 2; } } @@ -4732,13 +4881,17 @@ void TextEditorWidgetPrivate::updateHighlights() } } - if (m_highlightAutoComplete && !m_autoCompleteHighlightPos.isNull()) { + if (m_highlightAutoComplete && !m_autoCompleteHighlightPos.isEmpty()) { QTimer::singleShot(0, this, [this](){ - if ((!m_keepAutoCompletionHighlight && !q->hasFocus()) - || m_autoCompleteHighlightPos != q->textCursor()) { - q->setExtraSelections(TextEditorWidget::AutoCompleteSelection, - QList()); // clear - m_autoCompleteHighlightPos = QTextCursor(); + const QTextCursor &cursor = q->textCursor(); + auto popAutoCompletion = [&]() { + return !m_autoCompleteHighlightPos.isEmpty() + && m_autoCompleteHighlightPos.last() != cursor; + }; + if (!m_keepAutoCompletionHighlight && !q->hasFocus() && popAutoCompletion()) { + while (popAutoCompletion()) + m_autoCompleteHighlightPos.pop_back(); + updateAutoCompleteHighlight(); } }); } @@ -5405,8 +5558,11 @@ void TextEditorWidgetPrivate::handleBackspaceKey() const TabSettings &tabSettings = m_document->tabSettings(); const TypingSettings &typingSettings = m_document->typingSettings(); - if (typingSettings.m_autoIndent && (m_autoCompleteHighlightPos == cursor) - && m_removeAutoCompletedText && m_autoCompleter->autoBackspace(cursor)) { + if (typingSettings.m_autoIndent + && !m_autoCompleteHighlightPos.isEmpty() + && (m_autoCompleteHighlightPos.last() == cursor) + && m_removeAutoCompletedText + && m_autoCompleter->autoBackspace(cursor)) { return; } @@ -6082,25 +6238,14 @@ void TextEditorWidgetPrivate::_q_highlightBlocks() void TextEditorWidgetPrivate::autocompleterHighlight(const QTextCursor &cursor) { - QList extraSelections; if ((!m_animateAutoComplete && !m_highlightAutoComplete) || q->isReadOnly() || !cursor.hasSelection()) { - q->setExtraSelections(TextEditorWidget::AutoCompleteSelection, extraSelections); // clear - return; - } - - const QTextCharFormat &matchFormat - = q->textDocument()->fontSettings().toTextCharFormat(C_AUTOCOMPLETE); - - if (m_highlightAutoComplete) { - QTextEdit::ExtraSelection sel; - sel.cursor = cursor; - sel.format.setBackground(matchFormat.background()); - extraSelections.append(sel); - m_autoCompleteHighlightPos = cursor; - m_autoCompleteHighlightPos.movePosition(QTextCursor::PreviousCharacter); - } - if (m_animateAutoComplete) { + m_autoCompleteHighlightPos.clear(); + } else if (m_highlightAutoComplete) { + m_autoCompleteHighlightPos.push_back(cursor); + } else if (m_animateAutoComplete) { + const QTextCharFormat &matchFormat + = q->textDocument()->fontSettings().toTextCharFormat(C_AUTOCOMPLETE); cancelCurrentAnimations();// one animation is enough QPalette pal; pal.setBrush(QPalette::Text, matchFormat.foreground()); @@ -6110,7 +6255,7 @@ void TextEditorWidgetPrivate::autocompleterHighlight(const QTextCursor &cursor) connect(m_autocompleteAnimator.data(), &TextEditorAnimator::updateRequest, this, &TextEditorWidgetPrivate::_q_animateUpdate); } - q->setExtraSelections(TextEditorWidget::AutoCompleteSelection, extraSelections); + updateAutoCompleteHighlight(); } void TextEditorWidgetPrivate::updateAnimator(QPointer animator, @@ -8060,7 +8205,11 @@ IEditor *BaseTextEditor::duplicate() return 0; } - } // namespace TextEditor +uint qHash(const QColor &color) +{ + return color.rgba(); +} + #include "texteditor.moc" diff --git a/src/plugins/texteditor/texteditor.h b/src/plugins/texteditor/texteditor.h index 841324891c6..1613de4ed02 100644 --- a/src/plugins/texteditor/texteditor.h +++ b/src/plugins/texteditor/texteditor.h @@ -672,4 +672,6 @@ private: } // namespace TextEditor +uint qHash(const QColor &color); + Q_DECLARE_METATYPE(TextEditor::TextEditorWidget::Link) diff --git a/src/plugins/texteditor/textmark.cpp b/src/plugins/texteditor/textmark.cpp index 975cc7a41c5..15939a3f44d 100644 --- a/src/plugins/texteditor/textmark.cpp +++ b/src/plugins/texteditor/textmark.cpp @@ -33,6 +33,7 @@ #include #include +#include using namespace Core; using namespace Utils; @@ -57,6 +58,24 @@ private: QHash > m_marks; }; +class AnnotationColors +{ +public: + static AnnotationColors &getAnnotationColors(const QColor &markColor, + const QColor &backgroundColor); + +public: + using SourceColors = QPair; + QColor rectColor; + QColor textColor; + +private: + static double clipHsl(double value); + +private: + static QHash m_colorCache; +}; + TextMarkRegistry *m_instance = nullptr; TextMark::TextMark(const QString &fileName, int lineNumber, Id category, double widthFactor) @@ -99,11 +118,49 @@ int TextMark::lineNumber() const return m_lineNumber; } -void TextMark::paint(QPainter *painter, const QRect &rect) const +void TextMark::paintIcon(QPainter *painter, const QRect &rect) const { m_icon.paint(painter, rect, Qt::AlignCenter); } +void TextMark::paintAnnotation(QPainter *painter, + QRectF *annotationRect, + const QFontMetrics &fm) const +{ + QString text = lineAnnotation(); + if (text.isEmpty()) + return; + + const bool drawIcon = !m_icon.isNull(); + int textWidth = fm.width(text); + constexpr qreal margin = 1; + const qreal iconHeight = annotationRect->height() - 2 * margin; + const qreal iconWidth = iconHeight * m_widthFactor + 2 * margin; + qreal annotationWidth = (drawIcon ? textWidth + iconWidth : textWidth) + margin; + if (annotationRect->left() + annotationWidth > annotationRect->right()) { + textWidth = int(annotationRect->width() - (drawIcon ? iconWidth + margin : margin)); + text = fm.elidedText(text, Qt::ElideRight, textWidth); + annotationWidth = annotationRect->width(); + } + const QColor markColor = m_hasColor ? Utils::creatorTheme()->color(m_color).toHsl() + : painter->pen().color(); + const AnnotationColors &colors = + AnnotationColors::getAnnotationColors(markColor, painter->background().color()); + + painter->save(); + annotationRect->setWidth(annotationWidth); + painter->setPen(colors.rectColor); + painter->setBrush(colors.rectColor); + painter->drawRect(*annotationRect); + painter->setPen(colors.textColor); + if (drawIcon) { + paintIcon(painter, annotationRect->adjusted( + margin, margin, -(textWidth + 2 * margin), -margin).toAlignedRect()); + } + painter->drawText(annotationRect->adjusted(iconWidth, 0, 0, 0), Qt::AlignLeft, text); + painter->restore(); +} + void TextMark::updateLineNumber(int lineNumber) { m_lineNumber = lineNumber; @@ -176,7 +233,7 @@ void TextMark::dragToLine(int lineNumber) Q_UNUSED(lineNumber); } -void TextMark::addToToolTipLayout(QGridLayout *target) +void TextMark::addToToolTipLayout(QGridLayout *target) const { auto *contentLayout = new QVBoxLayout; addToolTipContent(contentLayout); @@ -191,7 +248,7 @@ void TextMark::addToToolTipLayout(QGridLayout *target) } } -bool TextMark::addToolTipContent(QLayout *target) +bool TextMark::addToolTipContent(QLayout *target) const { QString text = m_toolTip; if (text.isEmpty()) { @@ -304,6 +361,33 @@ void TextMarkRegistry::allDocumentsRenamed(const QString &oldName, const QString mark->updateFileName(newName); } +QHash AnnotationColors::m_colorCache; + +AnnotationColors &AnnotationColors::getAnnotationColors(const QColor &markColor, + const QColor &backgroundColor) +{ + AnnotationColors &colors = m_colorCache[{markColor, backgroundColor}]; + if (!colors.rectColor.isValid() || !colors.textColor.isValid()) { + const double backgroundSaturation = clipHsl(markColor.hslSaturationF() / 2); + const double backgroundLightness = clipHsl(backgroundColor.lightnessF()); + const double foregroundLightness = clipHsl(backgroundLightness > 0.5 + ? backgroundLightness - 0.5 + : backgroundLightness + 0.5); + colors.rectColor.setHslF(markColor.hslHueF(), + backgroundSaturation, + backgroundLightness); + colors.textColor.setHslF(markColor.hslHueF(), + markColor.hslSaturationF(), + foregroundLightness); + } + return colors; +} + +double AnnotationColors::clipHsl(double value) +{ + return std::max(0.15, std::min(0.85, value)); +} + } // namespace TextEditor #include "textmark.moc" diff --git a/src/plugins/texteditor/textmark.h b/src/plugins/texteditor/textmark.h index 162ac2f7943..89d3d96e023 100644 --- a/src/plugins/texteditor/textmark.h +++ b/src/plugins/texteditor/textmark.h @@ -63,7 +63,8 @@ public: QString fileName() const; int lineNumber() const; - virtual void paint(QPainter *painter, const QRect &rect) const; + virtual void paintIcon(QPainter *painter, const QRect &rect) const; + virtual void paintAnnotation(QPainter *painter, QRectF *annotationRect, const QFontMetrics &fm) const; /// called if the filename of the document changed virtual void updateFileName(const QString &fileName); virtual void updateLineNumber(int lineNumber); @@ -74,8 +75,8 @@ public: virtual void clicked(); virtual bool isDraggable() const; virtual void dragToLine(int lineNumber); - void addToToolTipLayout(QGridLayout *target); - virtual bool addToolTipContent(QLayout *target); + void addToToolTipLayout(QGridLayout *target) const; + virtual bool addToolTipContent(QLayout *target) const; void setIcon(const QIcon &icon) { m_icon = icon; } const QIcon &icon() const { return m_icon; } @@ -99,6 +100,9 @@ public: TextDocument *baseTextDocument() const { return m_baseTextDocument; } void setBaseTextDocument(TextDocument *baseTextDocument) { m_baseTextDocument = baseTextDocument; } + QString lineAnnotation() const { return m_lineAnnotation; } + void setLineAnnotation(const QString &lineAnnotation) { m_lineAnnotation = lineAnnotation; } + QString toolTip() const { return m_toolTip; } void setToolTip(const QString &toolTip) { m_toolTip = toolTip; } @@ -115,6 +119,7 @@ private: bool m_hasColor = false; Core::Id m_category; double m_widthFactor = 1.0; + QString m_lineAnnotation; QString m_toolTip; QString m_defaultToolTip; }; diff --git a/src/plugins/valgrind/callgrind/callgrindcontroller.cpp b/src/plugins/valgrind/callgrind/callgrindcontroller.cpp index faf1c980b4d..5bc4b2515d0 100644 --- a/src/plugins/valgrind/callgrind/callgrindcontroller.cpp +++ b/src/plugins/valgrind/callgrind/callgrindcontroller.cpp @@ -24,28 +24,31 @@ ****************************************************************************/ #include "callgrindcontroller.h" -#include "../valgrindprocess.h" + +#include +#include + +#include +#include +#include +#include +#include #include #include - -#include -#include -#include -#include +#include #define CALLGRIND_CONTROL_DEBUG 0 -const QLatin1String CALLGRIND_CONTROL_BINARY("callgrind_control"); +using namespace ProjectExplorer; +using namespace Utils; namespace Valgrind { namespace Callgrind { -CallgrindController::CallgrindController(QObject *parent) - : QObject(parent) - , m_process(0) - , m_valgrindProc(0) - , m_lastOption(Unknown) +const QLatin1String CALLGRIND_CONTROL_BINARY("callgrind_control"); + +CallgrindController::CallgrindController() { } @@ -54,7 +57,7 @@ CallgrindController::~CallgrindController() cleanupTempFile(); } -QString toOptionString(CallgrindController::Option option) +static QString toOptionString(CallgrindController::Option option) { /* callgrind_control help from v3.9.0 @@ -86,23 +89,15 @@ QString toOptionString(CallgrindController::Option option) void CallgrindController::run(Option option) { - if (m_process) { + if (m_controllerProcess) { emit statusMessage(tr("Previous command has not yet finished.")); return; } - QTC_ASSERT(m_valgrindProc, return); - - m_process = new ValgrindProcess(m_valgrindProc->device(), this); - - connect(m_process, &ValgrindProcess::finished, - this, &CallgrindController::processFinished); - connect(m_process, &ValgrindProcess::error, - this, &CallgrindController::processError); // save back current running operation m_lastOption = option; - const QString optionString = toOptionString(option); + m_controllerProcess = new ApplicationLauncher; switch (option) { case CallgrindController::Dump: @@ -122,31 +117,49 @@ void CallgrindController::run(Option option) } #if CALLGRIND_CONTROL_DEBUG - m_process->setProcessChannelMode(QProcess::ForwardedChannels); + m_controllerProcess->setProcessChannelMode(QProcess::ForwardedChannels); #endif - const int pid = Utils::HostOsInfo::isWindowsHost() ? 0 : m_valgrindProc->pid(); - m_process->setValgrindExecutable(CALLGRIND_CONTROL_BINARY); - m_process->setValgrindArguments(QStringList() << optionString << QString::number(pid)); - m_process->run(ProjectExplorer::ApplicationLauncher::Gui); + connect(m_controllerProcess, &ApplicationLauncher::processExited, + this, &CallgrindController::controllerProcessFinished); + connect(m_controllerProcess, &ApplicationLauncher::error, + this, &CallgrindController::handleControllerProcessError); + connect(m_controllerProcess, &ApplicationLauncher::finished, + this, &CallgrindController::controllerProcessClosed); + + StandardRunnable controller = m_valgrindRunnable; + controller.executable = CALLGRIND_CONTROL_BINARY; + controller.runMode = ApplicationLauncher::Gui; + controller.commandLineArguments = QString("%1 %2").arg(toOptionString(option)).arg(m_pid); + + if (!m_valgrindRunnable.device + || m_valgrindRunnable.device->type() == ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE) + m_controllerProcess->start(controller); + else + m_controllerProcess->start(controller, m_valgrindRunnable.device); } -void CallgrindController::processError(QProcess::ProcessError) +void CallgrindController::setValgrindPid(qint64 pid) { - QTC_ASSERT(m_process, return); - const QString error = m_process->errorString(); + m_pid = pid; +} + +void CallgrindController::handleControllerProcessError(QProcess::ProcessError) +{ + QTC_ASSERT(m_controllerProcess, return); + const QString error = m_controllerProcess->errorString(); emit statusMessage(tr("An error occurred while trying to run %1: %2").arg(CALLGRIND_CONTROL_BINARY).arg(error)); - m_process->deleteLater(); - m_process = 0; + m_controllerProcess->deleteLater(); + m_controllerProcess = nullptr; } -void CallgrindController::processFinished(int rc, QProcess::ExitStatus status) +void CallgrindController::controllerProcessFinished(int rc, QProcess::ExitStatus status) { - QTC_ASSERT(m_process, return); - const QString error = m_process->errorString(); + QTC_ASSERT(m_controllerProcess, return); + const QString error = m_controllerProcess->errorString(); - m_process->deleteLater(); // Called directly from finished() signal in m_process - m_process = 0; + m_controllerProcess->deleteLater(); // Called directly from finished() signal in m_process + m_controllerProcess = nullptr; if (rc != 0 || status != QProcess::NormalExit) { qWarning() << "Controller exited abnormally:" << error; @@ -175,32 +188,43 @@ void CallgrindController::processFinished(int rc, QProcess::ExitStatus status) m_lastOption = Unknown; } -void CallgrindController::setValgrindProcess(ValgrindProcess *proc) +void CallgrindController::controllerProcessClosed(bool success) { - m_valgrindProc = proc; + Q_UNUSED(success); + // QTC_ASSERT(m_remote.m_process, return); + +// m_remote.m_errorString = m_remote.m_process->errorString(); +// if (status == QSsh::SshRemoteProcess::FailedToStart) { +// m_remote.m_error = QProcess::FailedToStart; +// emit ValgrindProcessX::error(QProcess::FailedToStart); +// } else if (status == QSsh::SshRemoteProcess::NormalExit) { +// emit finished(m_remote.m_process->exitCode(), QProcess::NormalExit); +// } else if (status == QSsh::SshRemoteProcess::CrashExit) { +// m_remote.m_error = QProcess::Crashed; +// emit finished(m_remote.m_process->exitCode(), QProcess::CrashExit); +// } + controllerProcessFinished(0, QProcess::NormalExit); } void CallgrindController::getLocalDataFile() { - QTC_ASSERT(m_valgrindProc, return); - // we look for callgrind.out.PID, but there may be updated ones called ~.PID.NUM - QString baseFileName = QString::fromLatin1("callgrind.out.%1"). - arg(m_valgrindProc->pid()); - const QString workingDir = m_valgrindProc->workingDirectory(); + const QString baseFileName = QString("callgrind.out.%1").arg(m_pid); + const QString workingDir = m_valgrindRunnable.workingDirectory; // first, set the to-be-parsed file to callgrind.out.PID - QString fileName = workingDir.isEmpty() ? baseFileName : (workingDir + QLatin1Char('/') + baseFileName); + QString fileName = workingDir.isEmpty() ? baseFileName : (workingDir + '/' + baseFileName); - if (!m_valgrindProc->isLocal()) { - ///TODO: error handling - emit statusMessage(tr("Downloading remote profile data...")); - m_ssh = m_valgrindProc->connection(); - // if there are files like callgrind.out.PID.NUM, set it to the most recent one of those - QString cmd = QString::fromLatin1("ls -t %1* | head -n 1").arg(fileName); - m_findRemoteFile = m_ssh->createRemoteProcess(cmd.toUtf8()); - connect(m_findRemoteFile.data(), &QSsh::SshRemoteProcess::readyReadStandardOutput, - this, &CallgrindController::foundRemoteFile); - m_findRemoteFile->start(); + if (m_valgrindRunnable.device + && m_valgrindRunnable.device->type() != ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE) { +// ///TODO: error handling +// emit statusMessage(tr("Downloading remote profile data...")); +// m_ssh = m_valgrindProc->connection(); +// // if there are files like callgrind.out.PID.NUM, set it to the most recent one of those +// QString cmd = QString::fromLatin1("ls -t %1* | head -n 1").arg(fileName); +// m_findRemoteFile = m_ssh->createRemoteProcess(cmd.toUtf8()); +// connect(m_findRemoteFile.data(), &QSsh::SshRemoteProcess::readyReadStandardOutput, +// this, &CallgrindController::foundRemoteFile); +// m_findRemoteFile->start(); } else { QDir dir(workingDir, QString::fromLatin1("%1.*").arg(baseFileName), QDir::Time); QStringList outputFiles = dir.entryList(); @@ -254,5 +278,11 @@ void CallgrindController::cleanupTempFile() m_tempDataFile.clear(); } +void CallgrindController::setValgrindRunnable(const Runnable &runnable) +{ + QTC_ASSERT(runnable.is(), return); + m_valgrindRunnable = runnable.as(); +} + } // namespace Callgrind } // namespace Valgrind diff --git a/src/plugins/valgrind/callgrind/callgrindcontroller.h b/src/plugins/valgrind/callgrind/callgrindcontroller.h index a1e06fe4456..50e4490adf8 100644 --- a/src/plugins/valgrind/callgrind/callgrindcontroller.h +++ b/src/plugins/valgrind/callgrind/callgrindcontroller.h @@ -25,18 +25,15 @@ #pragma once -#include - -#include - -#include #include #include +#include + +#include + +#include namespace Valgrind { - -class ValgrindProcess; - namespace Callgrind { class CallgrindController : public QObject @@ -49,16 +46,14 @@ public: Unknown, Dump, ResetEventCounters, - Pause, UnPause + Pause, + UnPause }; - explicit CallgrindController(QObject *parent = 0); - virtual ~CallgrindController(); + CallgrindController(); + ~CallgrindController() override; - void run(Valgrind::Callgrind::CallgrindController::Option option); - - void setValgrindProcess(ValgrindProcess *process); - ValgrindProcess *valgrindProcess() { return m_valgrindProc; } + void run(Option option); /** * Make data file available locally, triggers @c localParseDataAvailable. @@ -67,32 +62,34 @@ public: * downloads the data file first and returns a local path. */ void getLocalDataFile(); + void setValgrindPid(qint64 pid); + void setValgrindRunnable(const ProjectExplorer::Runnable &runnable); signals: void finished(Valgrind::Callgrind::CallgrindController::Option option); - void localParseDataAvailable(const QString &file); - void statusMessage(const QString &msg); private: - void processError(QProcess::ProcessError); - void processFinished(int, QProcess::ExitStatus); + void handleControllerProcessError(QProcess::ProcessError); void foundRemoteFile(); void sftpInitialized(); void sftpJobFinished(QSsh::SftpJobId job, const QString &error); void cleanupTempFile(); - // callgrind_control process - Valgrind::ValgrindProcess *m_process; - // valgrind process - Valgrind::ValgrindProcess *m_valgrindProc; + void controllerProcessFinished(int, QProcess::ExitStatus); + void controllerProcessError(QProcess::ProcessError); + void controllerProcessClosed(bool success); - Option m_lastOption; + ProjectExplorer::ApplicationLauncher *m_controllerProcess; + ProjectExplorer::StandardRunnable m_valgrindRunnable; + qint64 m_pid = 0; + + Option m_lastOption = Unknown; // remote callgrind support - QSsh::SshConnection *m_ssh; + QSsh::SshConnection *m_ssh = nullptr; QString m_tempDataFile; QSsh::SshRemoteProcess::Ptr m_findRemoteFile; QSsh::SftpChannel::Ptr m_sftp; diff --git a/src/plugins/valgrind/callgrindengine.cpp b/src/plugins/valgrind/callgrindengine.cpp index 42b6f7e274e..9a0781e72d6 100644 --- a/src/plugins/valgrind/callgrindengine.cpp +++ b/src/plugins/valgrind/callgrindengine.cpp @@ -30,21 +30,22 @@ #include #include +#include #include #include -using namespace Debugger; -using namespace Valgrind; -using namespace Valgrind::Internal; +using namespace ProjectExplorer; using namespace Valgrind::Callgrind; -CallgrindToolRunner::CallgrindToolRunner(ProjectExplorer::RunControl *runControl) +namespace Valgrind { +namespace Internal { + +CallgrindToolRunner::CallgrindToolRunner(RunControl *runControl) : ValgrindToolRunner(runControl) { setDisplayName("CallgrindToolRunner"); - m_runner.setToolName("callgrind"); connect(&m_runner, &ValgrindRunner::finished, this, &CallgrindToolRunner::slotFinished); @@ -58,19 +59,19 @@ CallgrindToolRunner::CallgrindToolRunner(ProjectExplorer::RunControl *runControl connect(&m_controller, &CallgrindController::statusMessage, this, &CallgrindToolRunner::showStatusMessage); - connect(&m_runner, &ValgrindRunner::extraStart, this, [this] { - m_controller.setValgrindProcess(m_runner.valgrindProcess()); - }); + connect(&m_runner, &ValgrindRunner::valgrindStarted, + &m_controller, &CallgrindController::setValgrindPid); connect(&m_runner, &ValgrindRunner::extraProcessFinished, this, [this] { triggerParse(); - m_controller.setValgrindProcess(nullptr); }); + + m_controller.setValgrindRunnable(runnable()); } QStringList CallgrindToolRunner::toolArguments() const { - QStringList arguments; + QStringList arguments = {"--tool=callgrind"}; QTC_ASSERT(m_settings, return arguments); @@ -120,12 +121,10 @@ void CallgrindToolRunner::setPaused(bool paused) m_markAsPaused = paused; // call controller only if it is attached to a valgrind process - if (m_controller.valgrindProcess()) { - if (paused) - pause(); - else - unpause(); - } + if (paused) + pause(); + else + unpause(); } void CallgrindToolRunner::setToggleCollectFunction(const QString &toggleCollectFunction) @@ -202,3 +201,6 @@ void CallgrindToolRunner::controllerFinished(CallgrindController::Option option) break; // do nothing } } + +} // Internal +} // Valgrind diff --git a/src/plugins/valgrind/callgrindtextmark.cpp b/src/plugins/valgrind/callgrindtextmark.cpp index cfd19c7a0ce..e08d42f0400 100644 --- a/src/plugins/valgrind/callgrindtextmark.cpp +++ b/src/plugins/valgrind/callgrindtextmark.cpp @@ -48,7 +48,7 @@ CallgrindTextMark::CallgrindTextMark(const QPersistentModelIndex &index, setPriority(TextEditor::TextMark::HighPriority); } -void CallgrindTextMark::paint(QPainter *painter, const QRect &paintRect) const +void CallgrindTextMark::paintIcon(QPainter *painter, const QRect &paintRect) const { if (!m_modelIndex.isValid()) return; diff --git a/src/plugins/valgrind/callgrindtextmark.h b/src/plugins/valgrind/callgrindtextmark.h index f5f1699a257..828dc7f5bd6 100644 --- a/src/plugins/valgrind/callgrindtextmark.h +++ b/src/plugins/valgrind/callgrindtextmark.h @@ -49,7 +49,7 @@ public: const Valgrind::Callgrind::Function *function() const; - virtual void paint(QPainter *painter, const QRect &paintRect) const; + virtual void paintIcon(QPainter *painter, const QRect &paintRect) const; private: QPersistentModelIndex m_modelIndex; diff --git a/src/plugins/valgrind/callgrindtool.cpp b/src/plugins/valgrind/callgrindtool.cpp index 2419985b838..c93a406c900 100644 --- a/src/plugins/valgrind/callgrindtool.cpp +++ b/src/plugins/valgrind/callgrindtool.cpp @@ -289,7 +289,6 @@ CallgrindTool::CallgrindTool(QObject *parent) auto runControl = new RunControl(runConfig, CALLGRIND_RUN_MODE); const auto runnable = dlg.runnable(); runControl->setRunnable(runnable); - runControl->setConnection(UrlConnection(dlg.serverUrl())); runControl->setDisplayName(runnable.executable); createRunTool(runControl); ProjectExplorerPlugin::startRunControl(runControl); diff --git a/src/plugins/valgrind/memcheckengine.cpp b/src/plugins/valgrind/memcheckengine.cpp index d6f44798e29..5be26e86bd2 100644 --- a/src/plugins/valgrind/memcheckengine.cpp +++ b/src/plugins/valgrind/memcheckengine.cpp @@ -26,7 +26,6 @@ #include "memcheckengine.h" #include "memchecktool.h" -#include "valgrindprocess.h" #include "valgrindsettings.h" #include "xmlprotocol/error.h" #include "xmlprotocol/status.h" @@ -51,8 +50,33 @@ using namespace Valgrind::XmlProtocol; namespace Valgrind { namespace Internal { +class LocalAddressFinder : public RunWorker +{ +public: + LocalAddressFinder(RunControl *runControl, QHostAddress *localServerAddress) + : RunWorker(runControl), connection(device()->sshParameters()) + { + connect(&connection, &QSsh::SshConnection::connected, this, [this, localServerAddress] { + *localServerAddress = connection.connectionInfo().localAddress; + reportStarted(); + }); + connect(&connection, &QSsh::SshConnection::error, this, [this] { + reportFailure(); + }); + } + + void start() override + { + connection.connectToHost(); + } + + QSsh::SshConnection connection; +}; + MemcheckToolRunner::MemcheckToolRunner(RunControl *runControl, bool withGdb) - : ValgrindToolRunner(runControl), m_withGdb(withGdb) + : ValgrindToolRunner(runControl), + m_withGdb(withGdb), + m_localServerAddress(QHostAddress::LocalHost) { setDisplayName("MemcheckToolRunner"); connect(m_runner.parser(), &XmlProtocol::ThreadedParser::error, @@ -61,15 +85,19 @@ MemcheckToolRunner::MemcheckToolRunner(RunControl *runControl, bool withGdb) this, &MemcheckToolRunner::suppressionCount); if (withGdb) { - connect(&m_runner, &ValgrindRunner::started, + connect(&m_runner, &ValgrindRunner::valgrindStarted, this, &MemcheckToolRunner::startDebugger); connect(&m_runner, &ValgrindRunner::logMessageReceived, this, &MemcheckToolRunner::appendLog); - m_runner.disableXml(); +// m_runner.disableXml(); } else { connect(m_runner.parser(), &XmlProtocol::ThreadedParser::internalError, this, &MemcheckToolRunner::internalParserError); } + + // We need a real address to connect to from the outside. + if (device()->type() != ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE) + addDependency(new LocalAddressFinder(runControl, &m_localServerAddress)); } QString MemcheckToolRunner::progressTitle() const @@ -79,10 +107,7 @@ QString MemcheckToolRunner::progressTitle() const void MemcheckToolRunner::start() { -// MemcheckTool::engineStarting(this); - - appendMessage(tr("Analyzing memory of %1").arg(executable()) + QLatin1Char('\n'), - Utils::NormalMessageFormat); + m_runner.setLocalServerAddress(m_localServerAddress); ValgrindToolRunner::start(); } @@ -95,8 +120,7 @@ void MemcheckToolRunner::stop() QStringList MemcheckToolRunner::toolArguments() const { - QStringList arguments; - arguments << "--gen-suppressions=all"; + QStringList arguments = {"--tool=memcheck", "--gen-suppressions=all"}; QTC_ASSERT(m_settings, return arguments); @@ -137,10 +161,8 @@ QStringList MemcheckToolRunner::suppressionFiles() const return m_settings->suppressionFiles(); } -void MemcheckToolRunner::startDebugger() +void MemcheckToolRunner::startDebugger(qint64 valgrindPid) { - const qint64 valgrindPid = m_runner.valgrindProcess()->pid(); - Debugger::DebuggerStartParameters sp; sp.inferior = runnable().as(); sp.startMode = Debugger::AttachToRemoteServer; @@ -149,12 +171,10 @@ void MemcheckToolRunner::startDebugger() sp.useContinueInsteadOfRun = true; sp.expectedSignals.append("SIGTRAP"); - QString errorMessage; - auto gdbRunControl = new RunControl(nullptr, ProjectExplorer::Constants::DEBUG_RUN_MODE); - (void) new Debugger::DebuggerRunTool(gdbRunControl, sp, &errorMessage); - connect(gdbRunControl, &RunControl::finished, - gdbRunControl, &RunControl::deleteLater); - gdbRunControl->initiateStart(); + auto gdbWorker = new Debugger::DebuggerRunTool(runControl()); + gdbWorker->setStartParameters(sp); + gdbWorker->initiateStart(); + connect(runControl(), &RunControl::finished, gdbWorker, &RunControl::deleteLater); } void MemcheckToolRunner::appendLog(const QByteArray &data) diff --git a/src/plugins/valgrind/memcheckengine.h b/src/plugins/valgrind/memcheckengine.h index e77d4ec02d6..6113390e91c 100644 --- a/src/plugins/valgrind/memcheckengine.h +++ b/src/plugins/valgrind/memcheckengine.h @@ -31,6 +31,8 @@ #include "valgrindrunner.h" #include "xmlprotocol/threadedparser.h" +#include + namespace Valgrind { namespace Internal { @@ -56,10 +58,11 @@ private: QString progressTitle() const override; QStringList toolArguments() const override; - void startDebugger(); + void startDebugger(qint64 valgrindPid); void appendLog(const QByteArray &data); const bool m_withGdb; + QHostAddress m_localServerAddress; }; } // namespace Internal diff --git a/src/plugins/valgrind/memchecktool.cpp b/src/plugins/valgrind/memchecktool.cpp index 16977250a69..e6c70188340 100644 --- a/src/plugins/valgrind/memchecktool.cpp +++ b/src/plugins/valgrind/memchecktool.cpp @@ -454,7 +454,6 @@ MemcheckTool::MemcheckTool(QObject *parent) rc->createWorker(MEMCHECK_RUN_MODE); const auto runnable = dlg.runnable(); rc->setRunnable(runnable); - rc->setConnection(UrlConnection(dlg.serverUrl())); rc->setDisplayName(runnable.executable); ProjectExplorerPlugin::startRunControl(rc); }); diff --git a/src/plugins/valgrind/valgrind.pro b/src/plugins/valgrind/valgrind.pro index aa431013297..592fe8338b4 100644 --- a/src/plugins/valgrind/valgrind.pro +++ b/src/plugins/valgrind/valgrind.pro @@ -11,7 +11,6 @@ HEADERS += \ valgrindconfigwidget.h \ valgrindsettings.h \ valgrindrunner.h \ - valgrindprocess.h \ callgrindcostdelegate.h \ callgrindcostview.h \ callgrindhelper.h \ @@ -33,7 +32,6 @@ SOURCES += \ valgrindconfigwidget.cpp \ valgrindsettings.cpp \ valgrindrunner.cpp \ - valgrindprocess.cpp \ callgrindcostdelegate.cpp \ callgrindcostview.cpp \ callgrindhelper.cpp \ diff --git a/src/plugins/valgrind/valgrind.qbs b/src/plugins/valgrind/valgrind.qbs index d7e4874365c..963fa2265db 100644 --- a/src/plugins/valgrind/valgrind.qbs +++ b/src/plugins/valgrind/valgrind.qbs @@ -34,7 +34,6 @@ QtcPlugin { "valgrindconfigwidget.cpp", "valgrindconfigwidget.h", "valgrindconfigwidget.ui", "valgrindengine.cpp", "valgrindengine.h", "valgrindplugin.cpp", "valgrindplugin.h", - "valgrindprocess.cpp", "valgrindprocess.h", "valgrindruncontrolfactory.cpp", "valgrindruncontrolfactory.h", "valgrindrunner.cpp", "valgrindrunner.h", "valgrindsettings.cpp", "valgrindsettings.h", diff --git a/src/plugins/valgrind/valgrind_test.pri b/src/plugins/valgrind/valgrind_test.pri index 7ddd22d6a83..cb00a02fc97 100644 --- a/src/plugins/valgrind/valgrind_test.pri +++ b/src/plugins/valgrind/valgrind_test.pri @@ -27,8 +27,7 @@ HEADERS += \ $$PWD/callgrind/callgrindcycledetection.h \ $$PWD/callgrind/callgrindproxymodel.h \ $$PWD/callgrind/callgrindstackbrowser.h \ - $$PWD/valgrindrunner.h \ - $$PWD/valgrindprocess.h + $$PWD/valgrindrunner.h SOURCES += $$PWD/xmlprotocol/error.cpp \ $$PWD/xmlprotocol/frame.cpp \ @@ -53,7 +52,6 @@ SOURCES += $$PWD/xmlprotocol/error.cpp \ $$PWD/callgrind/callgrindcycledetection.cpp \ $$PWD/callgrind/callgrindproxymodel.cpp \ $$PWD/callgrind/callgrindstackbrowser.cpp \ - $$PWD/valgrindrunner.cpp \ - $$PWD/valgrindprocess.cpp + $$PWD/valgrindrunner.cpp LIBS += -L$$IDE_PLUGIN_PATH/QtProject diff --git a/src/plugins/valgrind/valgrindengine.cpp b/src/plugins/valgrind/valgrindengine.cpp index 649a1d75948..b87728ba482 100644 --- a/src/plugins/valgrind/valgrindengine.cpp +++ b/src/plugins/valgrind/valgrindengine.cpp @@ -106,6 +106,7 @@ void ValgrindToolRunner::stop() { m_isStopping = true; m_runner.stop(); + reportStopped(); // FIXME: Restrict to non-running scenarios? } QString ValgrindToolRunner::executable() const diff --git a/src/plugins/valgrind/valgrindprocess.cpp b/src/plugins/valgrind/valgrindprocess.cpp deleted file mode 100644 index 5f45c90bb15..00000000000 --- a/src/plugins/valgrind/valgrindprocess.cpp +++ /dev/null @@ -1,320 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Author: Milian Wolff, KDAB (milian.wolff@kdab.com) -** 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 "valgrindprocess.h" - -#include - -#include -#include -#include - -#include -#include - -using namespace ProjectExplorer; - -namespace Valgrind { - -ValgrindProcess::ValgrindProcess(const IDevice::ConstPtr &device, - QObject *parent) - : QObject(parent), m_device(device) -{ - m_remote.m_connection = 0; - m_remote.m_error = QProcess::UnknownError; - m_pid = 0; -} - -ValgrindProcess::~ValgrindProcess() -{ - if (m_remote.m_connection) - QSsh::releaseConnection(m_remote.m_connection); -} - -void ValgrindProcess::setProcessChannelMode(QProcess::ProcessChannelMode mode) -{ - if (isLocal()) - m_localProcess.setProcessChannelMode(mode); - ///TODO: remote support this by handling the mode internally -} - -QString ValgrindProcess::workingDirectory() const -{ - return m_debuggee.workingDirectory; -} - -bool ValgrindProcess::isRunning() const -{ - if (isLocal()) - return m_localProcess.isRunning(); - else - return m_remote.m_process && m_remote.m_process->isRunning(); -} - -void ValgrindProcess::setValgrindExecutable(const QString &valgrindExecutable) -{ - m_valgrindExecutable = valgrindExecutable; -} - -void ValgrindProcess::setDebuggee(const StandardRunnable &debuggee) -{ - m_debuggee = debuggee; -} - -void ValgrindProcess::setValgrindArguments(const QStringList &valgrindArguments) -{ - m_valgrindArguments = valgrindArguments; -} - -void ValgrindProcess::close() -{ - if (isLocal()) { - m_localProcess.stop(); - } else { - QTC_ASSERT(m_remote.m_connection->state() == QSsh::SshConnection::Connected, return); - if (m_remote.m_process) { - if (m_pid) { - const QString killTemplate = QString::fromLatin1("kill -%2 %1" // kill - ).arg(m_pid); - - const QString niceKill = killTemplate.arg(QLatin1String("SIGTERM")); - const QString brutalKill = killTemplate.arg(QLatin1String("SIGKILL")); - const QString remoteCall = niceKill + QLatin1String("; sleep 1; ") + brutalKill; - - QSsh::SshRemoteProcess::Ptr cleanup = m_remote.m_connection->createRemoteProcess(remoteCall.toUtf8()); - cleanup->start(); - } - } - } -} - -void ValgrindProcess::run(ApplicationLauncher::Mode runMode) -{ - if (isLocal()) { - connect(&m_localProcess, &ApplicationLauncher::processExited, - this, &ValgrindProcess::finished); - connect(&m_localProcess, &ApplicationLauncher::processStarted, - this, &ValgrindProcess::localProcessStarted); - connect(&m_localProcess, &ApplicationLauncher::error, - this, &ValgrindProcess::error); - connect(&m_localProcess, &ApplicationLauncher::appendMessage, - this, &ValgrindProcess::processOutput); - - StandardRunnable valgrind; - valgrind.executable = m_valgrindExecutable; - valgrind.runMode = runMode; - valgrind.commandLineArguments = argumentString(Utils::HostOsInfo::hostOs()); - valgrind.workingDirectory = m_debuggee.workingDirectory; - valgrind.environment = m_debuggee.environment; - m_localProcess.start(valgrind); - - } else { - // connect to host and wait for connection - if (!m_remote.m_connection) - m_remote.m_connection = QSsh::acquireConnection(m_device->sshParameters()); - - if (m_remote.m_connection->state() != QSsh::SshConnection::Connected) { - connect(m_remote.m_connection, &QSsh::SshConnection::connected, - this, &ValgrindProcess::connected); - connect(m_remote.m_connection, &QSsh::SshConnection::error, - this, &ValgrindProcess::handleError); - if (m_remote.m_connection->state() == QSsh::SshConnection::Unconnected) - m_remote.m_connection->connectToHost(); - } else { - connected(); - } - } -} - -QString ValgrindProcess::errorString() const -{ - if (isLocal()) - return m_localProcess.errorString(); - else - return m_remote.m_errorString; -} - -QProcess::ProcessError ValgrindProcess::processError() const -{ - if (isLocal()) - return m_localProcess.processError(); - else - return m_remote.m_error; -} - -void ValgrindProcess::handleError(QSsh::SshError error) -{ - if (!isLocal()) { - switch (error) { - case QSsh::SshTimeoutError: - m_remote.m_error = QProcess::Timedout; - break; - default: - m_remote.m_error = QProcess::FailedToStart; - break; - } - } - m_remote.m_errorString = m_remote.m_connection->errorString(); - emit this->error(m_remote.m_error); -} - -qint64 ValgrindProcess::pid() const -{ - return m_pid; -} - -void ValgrindProcess::handleRemoteStderr() -{ - const QString b = QString::fromUtf8(m_remote.m_process->readAllStandardError()); - if (!b.isEmpty()) - emit processOutput(b, Utils::StdErrFormat); -} - -void ValgrindProcess::handleRemoteStdout() -{ - const QString b = QString::fromUtf8(m_remote.m_process->readAllStandardOutput()); - if (!b.isEmpty()) - emit processOutput(b, Utils::StdOutFormat); -} - -/// Remote -void ValgrindProcess::connected() -{ - QTC_ASSERT(m_remote.m_connection->state() == QSsh::SshConnection::Connected, return); - - emit localHostAddressRetrieved(m_remote.m_connection->connectionInfo().localAddress); - - // connected, run command - QString cmd; - - if (!m_debuggee.workingDirectory.isEmpty()) - cmd += QString::fromLatin1("cd '%1' && ").arg(m_debuggee.workingDirectory); - - cmd += m_valgrindExecutable + QLatin1Char(' ') + argumentString(Utils::OsTypeLinux); - - m_remote.m_process = m_remote.m_connection->createRemoteProcess(cmd.toUtf8()); - for (auto it = m_debuggee.environment.constBegin(); it != m_debuggee.environment.constEnd(); ++it) - m_remote.m_process->addToEnvironment(it.key().toUtf8(), it.value().toUtf8()); - - connect(m_remote.m_process.data(), &QSsh::SshRemoteProcess::readyReadStandardError, - this, &ValgrindProcess::handleRemoteStderr); - connect(m_remote.m_process.data(), &QSsh::SshRemoteProcess::readyReadStandardOutput, - this, &ValgrindProcess::handleRemoteStdout); - connect(m_remote.m_process.data(), &QSsh::SshRemoteProcess::closed, - this, &ValgrindProcess::closed); - connect(m_remote.m_process.data(), &QSsh::SshRemoteProcess::started, - this, &ValgrindProcess::remoteProcessStarted); - m_remote.m_process->start(); -} - -QSsh::SshConnection *ValgrindProcess::connection() const -{ - return m_remote.m_connection; -} - -bool ValgrindProcess::isLocal() const -{ - return m_device->type() == ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE; -} - -void ValgrindProcess::localProcessStarted() -{ - m_pid = m_localProcess.applicationPID().pid(); - emit started(); -} - -void ValgrindProcess::remoteProcessStarted() -{ - QTC_ASSERT(m_remote.m_connection->state() == QSsh::SshConnection::Connected, return); - - // find out what PID our process has - - // NOTE: valgrind cloaks its name, - // e.g.: valgrind --tool=memcheck foobar - // => ps aux, pidof will see valgrind.bin - // => pkill/killall/top... will see memcheck-amd64-linux or similar - // hence we need to do something more complex... - - // plain path to exe, m_valgrindExe contains e.g. env vars etc. pp. - const QString proc = m_valgrindExecutable.split(QLatin1Char(' ')).last(); - // sleep required since otherwise we might only match "bash -c..." - // and not the actual valgrind run - const QString cmd = QString::fromLatin1("sleep 1; ps ax" // list all processes with aliased name - " | grep '\\b%1.*%2'" // find valgrind process - " | tail -n 1" // limit to single process - // we pick the last one, first would be "bash -c ..." - " | awk '{print $1;}'" // get pid - ).arg(proc, Utils::FileName::fromString(m_debuggee.executable).fileName()); - - m_remote.m_findPID = m_remote.m_connection->createRemoteProcess(cmd.toUtf8()); - connect(m_remote.m_findPID.data(), &QSsh::SshRemoteProcess::readyReadStandardError, - this, &ValgrindProcess::handleRemoteStderr); - connect(m_remote.m_findPID.data(), &QSsh::SshRemoteProcess::readyReadStandardOutput, - this, &ValgrindProcess::findPIDOutputReceived); - m_remote.m_findPID->start(); -} - -void ValgrindProcess::findPIDOutputReceived() -{ - bool ok; - m_pid = m_remote.m_findPID->readAllStandardOutput().trimmed().toLongLong(&ok); - if (!ok) { - m_pid = 0; - m_remote.m_errorString = tr("Could not determine remote PID."); - m_remote.m_error = QProcess::FailedToStart; - emit ValgrindProcess::error(QProcess::FailedToStart); - close(); - } else { - emit started(); - } -} - -QString ValgrindProcess::argumentString(Utils::OsType osType) const -{ - QString arguments = Utils::QtcProcess::joinArgs(m_valgrindArguments, osType); - if (!m_debuggee.executable.isEmpty()) - Utils::QtcProcess::addArg(&arguments, m_debuggee.executable, osType); - Utils::QtcProcess::addArgs(&arguments, m_debuggee.commandLineArguments); - return arguments; -} - -void ValgrindProcess::closed(int status) -{ - QTC_ASSERT(m_remote.m_process, return); - - m_remote.m_errorString = m_remote.m_process->errorString(); - if (status == QSsh::SshRemoteProcess::FailedToStart) { - m_remote.m_error = QProcess::FailedToStart; - emit ValgrindProcess::error(QProcess::FailedToStart); - } else if (status == QSsh::SshRemoteProcess::NormalExit) { - emit finished(m_remote.m_process->exitCode(), QProcess::NormalExit); - } else if (status == QSsh::SshRemoteProcess::CrashExit) { - m_remote.m_error = QProcess::Crashed; - emit finished(m_remote.m_process->exitCode(), QProcess::CrashExit); - } -} - -} // namespace Valgrind diff --git a/src/plugins/valgrind/valgrindprocess.h b/src/plugins/valgrind/valgrindprocess.h deleted file mode 100644 index b85214e0954..00000000000 --- a/src/plugins/valgrind/valgrindprocess.h +++ /dev/null @@ -1,110 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Author: Milian Wolff, KDAB (milian.wolff@kdab.com) -** 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 -#include -#include - -#include -#include -#include -#include - -namespace Valgrind { - -/** - * Process for supplying local and remote valgrind runs - */ -class ValgrindProcess : public QObject -{ - Q_OBJECT - -public: - ValgrindProcess(const ProjectExplorer::IDevice::ConstPtr &device, QObject *parent); - ~ValgrindProcess(); - - bool isRunning() const; - - void setValgrindExecutable(const QString &valgrindExecutable); - void setValgrindArguments(const QStringList &valgrindArguments); - void setDebuggee(const ProjectExplorer::StandardRunnable &debuggee); - - void run(ProjectExplorer::ApplicationLauncher::Mode runMode); - void close(); - - QString errorString() const; - QProcess::ProcessError processError() const; - - void setProcessChannelMode(QProcess::ProcessChannelMode mode); - QString workingDirectory() const; - - ProjectExplorer::IDevice::ConstPtr device() const { return m_device; } - - qint64 pid() const; - QSsh::SshConnection *connection() const; - bool isLocal() const; - -signals: - void started(); - void finished(int, QProcess::ExitStatus); - void error(QProcess::ProcessError); - void processOutput(const QString &, Utils::OutputFormat format); - void localHostAddressRetrieved(const QHostAddress &localHostAddress); - -private: - void handleRemoteStderr(); - void handleRemoteStdout(); - void handleError(QSsh::SshError); - - void closed(int); - void connected(); - void localProcessStarted(); - void remoteProcessStarted(); - void findPIDOutputReceived(); - - QString argumentString(Utils::OsType osType) const; - - ProjectExplorer::StandardRunnable m_debuggee; - ProjectExplorer::ApplicationLauncher m_localProcess; - qint64 m_pid; - ProjectExplorer::IDevice::ConstPtr m_device; - - struct Remote { - QSsh::SshConnection *m_connection; - QSsh::SshRemoteProcess::Ptr m_process; - QString m_errorString; - QProcess::ProcessError m_error; - QSsh::SshRemoteProcess::Ptr m_findPID; - } m_remote; - - QSsh::SshConnectionParameters m_params; - QString m_valgrindExecutable; - QStringList m_valgrindArguments; -}; - -} // namespace Valgrind diff --git a/src/plugins/valgrind/valgrindrunner.cpp b/src/plugins/valgrind/valgrindrunner.cpp index 5f348cb3536..dec6098c688 100644 --- a/src/plugins/valgrind/valgrindrunner.cpp +++ b/src/plugins/valgrind/valgrindrunner.cpp @@ -25,55 +25,196 @@ ****************************************************************************/ #include "valgrindrunner.h" -#include "valgrindprocess.h" #include "xmlprotocol/threadedparser.h" -#include - -#include #include #include - -#include -#include +#include #include #include #include using namespace ProjectExplorer; +using namespace Utils; namespace Valgrind { -class ValgrindRunner::Private +class ValgrindRunner::Private : public QObject { public: - ValgrindProcess *process = nullptr; + Private(ValgrindRunner *owner) : q(owner) {} + + void run(); + + void handleRemoteStderr(const QByteArray &b); + void handleRemoteStdout(const QByteArray &b); + + void closed(bool success); + void localProcessStarted(); + void remoteProcessStarted(); + void findPIDOutputReceived(const QByteArray &out); + + ValgrindRunner *q; + StandardRunnable m_debuggee; + ApplicationLauncher m_valgrindProcess; + IDevice::ConstPtr m_device; + + ApplicationLauncher m_findPID; + + QString m_valgrindExecutable; + QStringList m_valgrindArguments; + + QHostAddress localServerAddress; QProcess::ProcessChannelMode channelMode = QProcess::SeparateChannels; - bool finished = false; - QString valgrindExecutable; - QStringList valgrindArguments; - StandardRunnable debuggee; - IDevice::ConstPtr device; - QString tool; + bool m_finished = false; QTcpServer xmlServer; XmlProtocol::ThreadedParser parser; QTcpServer logServer; QTcpSocket *logSocket = nullptr; + + // Workaround for valgrind bug when running vgdb with xml output + // https://bugs.kde.org/show_bug.cgi?id=343902 bool disableXml = false; }; -ValgrindRunner::ValgrindRunner(QObject *parent) - : QObject(parent), d(new Private) +void ValgrindRunner::Private::run() +{ + connect(&m_valgrindProcess, &ApplicationLauncher::processExited, + this, &ValgrindRunner::Private::closed); + connect(&m_valgrindProcess, &ApplicationLauncher::processStarted, + this, &ValgrindRunner::Private::localProcessStarted); + connect(&m_valgrindProcess, &ApplicationLauncher::error, + q, &ValgrindRunner::processError); + connect(&m_valgrindProcess, &ApplicationLauncher::appendMessage, + q, &ValgrindRunner::processOutputReceived); + connect(&m_valgrindProcess, &ApplicationLauncher::finished, + q, &ValgrindRunner::finished); + + connect(&m_valgrindProcess, &ApplicationLauncher::remoteStderr, + this, &ValgrindRunner::Private::handleRemoteStderr); + connect(&m_valgrindProcess, &ApplicationLauncher::remoteStdout, + this, &ValgrindRunner::Private::handleRemoteStdout); + connect(&m_valgrindProcess, &ApplicationLauncher::remoteProcessStarted, + this, &ValgrindRunner::Private::remoteProcessStarted); + + QStringList fullArgs = m_valgrindArguments; + if (HostOsInfo::isMacHost()) + // May be slower to start but without it we get no filenames for symbols. + fullArgs << "--dsymutil=yes"; + fullArgs << m_debuggee.executable; + + StandardRunnable valgrind; + valgrind.executable = m_valgrindExecutable; + valgrind.workingDirectory = m_debuggee.workingDirectory; + valgrind.environment = m_debuggee.environment; + valgrind.runMode = m_debuggee.runMode; + valgrind.device = m_device; + valgrind.commandLineArguments = QtcProcess::joinArgs(fullArgs, m_device->osType()); + Utils::QtcProcess::addArgs(&valgrind.commandLineArguments, m_debuggee.commandLineArguments); + + if (m_device->type() == ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE) + m_valgrindProcess.start(valgrind); + else + m_valgrindProcess.start(valgrind, m_device); +} + +void ValgrindRunner::Private::handleRemoteStderr(const QByteArray &b) +{ + if (!b.isEmpty()) + q->processOutputReceived(QString::fromUtf8(b), Utils::StdErrFormat); +} + +void ValgrindRunner::Private::handleRemoteStdout(const QByteArray &b) +{ + if (!b.isEmpty()) + q->processOutputReceived(QString::fromUtf8(b), Utils::StdOutFormat); +} + +void ValgrindRunner::Private::localProcessStarted() +{ + qint64 pid = m_valgrindProcess.applicationPID().pid(); + emit q->valgrindStarted(pid); +} + +void ValgrindRunner::Private::remoteProcessStarted() +{ + // find out what PID our process has + + // NOTE: valgrind cloaks its name, + // e.g.: valgrind --tool=memcheck foobar + // => ps aux, pidof will see valgrind.bin + // => pkill/killall/top... will see memcheck-amd64-linux or similar + // hence we need to do something more complex... + + // plain path to exe, m_valgrindExe contains e.g. env vars etc. pp. + const QString proc = m_valgrindExecutable.split(' ').last(); + + StandardRunnable findPid; + findPid.executable = "/bin/sh"; + // sleep required since otherwise we might only match "bash -c..." + // and not the actual valgrind run + findPid.commandLineArguments = QString("-c \"" + "sleep 1; ps ax" // list all processes with aliased name + " | grep '\\b%1.*%2'" // find valgrind process + " | tail -n 1" // limit to single process + // we pick the last one, first would be "bash -c ..." + " | awk '{print $1;}'" // get pid + "\"" + ).arg(proc, Utils::FileName::fromString(m_debuggee.executable).fileName()); + +// m_remote.m_findPID = m_remote.m_connection->createRemoteProcess(cmd.toUtf8()); + connect(&m_findPID, &ApplicationLauncher::remoteStderr, + this, &ValgrindRunner::Private::handleRemoteStderr); + connect(&m_findPID, &ApplicationLauncher::remoteStdout, + this, &ValgrindRunner::Private::findPIDOutputReceived); + m_findPID.start(findPid, m_device); +} + +void ValgrindRunner::Private::findPIDOutputReceived(const QByteArray &out) +{ + if (out.isEmpty()) + return; + bool ok; + qint64 pid = out.trimmed().toLongLong(&ok); + if (!ok) { +// m_remote.m_errorString = tr("Could not determine remote PID."); +// emit ValgrindRunner::Private::error(QProcess::FailedToStart); +// close(); + } else { + emit q->valgrindStarted(pid); + } +} + +void ValgrindRunner::Private::closed(bool success) +{ + Q_UNUSED(success); +// QTC_ASSERT(m_remote.m_process, return); + +// m_remote.m_errorString = m_remote.m_process->errorString(); +// if (status == QSsh::SshRemoteProcess::FailedToStart) { +// m_remote.m_error = QProcess::FailedToStart; +// q->processError(QProcess::FailedToStart); +// } else if (status == QSsh::SshRemoteProcess::NormalExit) { +// q->processFinished(m_remote.m_process->exitCode(), QProcess::NormalExit); +// } else if (status == QSsh::SshRemoteProcess::CrashExit) { +// m_remote.m_error = QProcess::Crashed; +// q->processFinished(m_remote.m_process->exitCode(), QProcess::CrashExit); +// } + q->processFinished(0, QProcess::NormalExit); +} + + +ValgrindRunner::ValgrindRunner(QObject *parent) + : QObject(parent), d(new Private(this)) { - setToolName("memcheck"); } ValgrindRunner::~ValgrindRunner() { - if (d->process && d->process->isRunning()) { + if (d->m_valgrindProcess.isRunning()) { // make sure we don't delete the thread while it's still running waitForFinished(); } @@ -87,37 +228,17 @@ ValgrindRunner::~ValgrindRunner() void ValgrindRunner::setValgrindExecutable(const QString &executable) { - d->valgrindExecutable = executable; -} - -QString ValgrindRunner::valgrindExecutable() const -{ - return d->valgrindExecutable; + d->m_valgrindExecutable = executable; } void ValgrindRunner::setValgrindArguments(const QStringList &toolArguments) { - d->valgrindArguments = toolArguments; -} - -QStringList ValgrindRunner::valgrindArguments() const -{ - return d->valgrindArguments; -} - -QStringList ValgrindRunner::fullValgrindArguments() const -{ - QStringList fullArgs = valgrindArguments(); - fullArgs << QString("--tool=%1").arg(d->tool); - if (Utils::HostOsInfo::isMacHost()) - // May be slower to start but without it we get no filenames for symbols. - fullArgs << QLatin1String("--dsymutil=yes"); - return fullArgs; + d->m_valgrindArguments = toolArguments; } void ValgrindRunner::setDebuggee(const StandardRunnable &debuggee) { - d->debuggee = debuggee; + d->m_debuggee = debuggee; } void ValgrindRunner::setProcessChannelMode(QProcess::ProcessChannelMode mode) @@ -125,19 +246,19 @@ void ValgrindRunner::setProcessChannelMode(QProcess::ProcessChannelMode mode) d->channelMode = mode; } -void ValgrindRunner::setDevice(const IDevice::ConstPtr &device) +void ValgrindRunner::setLocalServerAddress(const QHostAddress &localServerAddress) { - d->device = device; + d->localServerAddress = localServerAddress; } -IDevice::ConstPtr ValgrindRunner::device() const +void ValgrindRunner::setDevice(const IDevice::ConstPtr &device) { - return d->device; + d->m_device = device; } void ValgrindRunner::waitForFinished() const { - if (d->finished || !d->process) + if (d->m_finished) return; QEventLoop loop; @@ -145,53 +266,55 @@ void ValgrindRunner::waitForFinished() const loop.exec(); } -void ValgrindRunner::setToolName(const QString &toolName) +static void handleSocketParameter(const QString &prefix, const QTcpServer &tcpServer, + bool *useXml, QStringList *arguments) { - d->tool = toolName; + QHostAddress serverAddress = tcpServer.serverAddress(); + if (serverAddress.protocol() != QAbstractSocket::IPv4Protocol) { + // Report will end up in the Application Output pane, i.e. not have + // clickable items, but that's better than nothing. + qWarning("Need IPv4 for valgrind"); + *useXml = false; + } else { + *arguments << QString("%1=%2:%3").arg(prefix).arg(serverAddress.toString()) + .arg(tcpServer.serverPort()); + } } bool ValgrindRunner::start() { - // FIXME: Remove hack. - if (d->tool == "memcheck" - && device()->type() == ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE) { - if (!startServers(QHostAddress::LocalHost)) + if (!d->localServerAddress.isNull()) { + if (!startServers()) return false; - setValgrindArguments(memcheckLogArguments() + valgrindArguments()); + + bool enableXml = !d->disableXml; + + QStringList arguments = {"--child-silent-after-fork=yes"}; + + handleSocketParameter("--xml-socket", d->xmlServer, &enableXml, &arguments); + handleSocketParameter("--log-socket", d->logServer, &enableXml, &arguments); + + if (enableXml) + arguments << "--xml=yes"; + + d->m_valgrindArguments = arguments + d->m_valgrindArguments; } - d->process = new ValgrindProcess(d->device, this); - d->process->setProcessChannelMode(d->channelMode); + d->m_valgrindProcess.setProcessChannelMode(d->channelMode); // consider appending our options last so they override any interfering user-supplied options // -q as suggested by valgrind manual - d->process->setValgrindExecutable(d->valgrindExecutable); - d->process->setValgrindArguments(fullValgrindArguments()); - d->process->setDebuggee(d->debuggee); - - QObject::connect(d->process, &ValgrindProcess::processOutput, - this, &ValgrindRunner::processOutputReceived); - QObject::connect(d->process, &ValgrindProcess::started, - this, &ValgrindRunner::started); - QObject::connect(d->process, &ValgrindProcess::finished, - this, &ValgrindRunner::processFinished); - QObject::connect(d->process, &ValgrindProcess::error, - this, &ValgrindRunner::processError); - QObject::connect(d->process, &ValgrindProcess::localHostAddressRetrieved, - this, &ValgrindRunner::localHostAddressRetrieved); - - d->process->run(d->debuggee.runMode); - - emit extraStart(); + d->m_valgrindExecutable = d->m_valgrindExecutable; + d->run(); return true; } void ValgrindRunner::processError(QProcess::ProcessError e) { - if (d->finished) + if (d->m_finished) return; - d->finished = true; + d->m_finished = true; // make sure we don't wait for the connection anymore emit processErrorReceived(errorString(), e); @@ -202,40 +325,26 @@ void ValgrindRunner::processFinished(int ret, QProcess::ExitStatus status) { emit extraProcessFinished(); - if (d->finished) + if (d->m_finished) return; - d->finished = true; + d->m_finished = true; // make sure we don't wait for the connection anymore emit finished(); if (ret != 0 || status == QProcess::CrashExit) - emit processErrorReceived(errorString(), d->process->processError()); -} - -void ValgrindRunner::localHostAddressRetrieved(const QHostAddress &localHostAddress) -{ - if (startServers(localHostAddress)) { - setValgrindArguments(memcheckLogArguments() + valgrindArguments()); - valgrindProcess()->setValgrindArguments(fullValgrindArguments()); - } + emit processErrorReceived(errorString(), d->m_valgrindProcess.processError()); } QString ValgrindRunner::errorString() const { - return d->process ? d->process->errorString() : QString(); + return d->m_valgrindProcess.errorString(); } void ValgrindRunner::stop() { - QTC_ASSERT(d->process, finished(); return); - d->process->close(); -} - -ValgrindProcess *ValgrindRunner::valgrindProcess() const -{ - return d->process; + d->m_valgrindProcess.stop(); } XmlProtocol::ThreadedParser *ValgrindRunner::parser() const @@ -243,14 +352,6 @@ XmlProtocol::ThreadedParser *ValgrindRunner::parser() const return &d->parser; } - -// Workaround for valgrind bug when running vgdb with xml output -// https://bugs.kde.org/show_bug.cgi?id=343902 -void ValgrindRunner::disableXml() -{ - d->disableXml = true; -} - void ValgrindRunner::xmlSocketConnected() { QTcpSocket *socket = d->xmlServer.nextPendingConnection(); @@ -274,10 +375,10 @@ void ValgrindRunner::readLogSocket() emit logMessageReceived(d->logSocket->readAll()); } -bool ValgrindRunner::startServers(const QHostAddress &localHostAddress) +bool ValgrindRunner::startServers() { - bool check = d->xmlServer.listen(localHostAddress); - const QString ip = localHostAddress.toString(); + bool check = d->xmlServer.listen(d->localServerAddress); + const QString ip = d->localServerAddress.toString(); if (!check) { emit processErrorReceived(tr("XmlServer on %1:").arg(ip) + ' ' + d->xmlServer.errorString(), QProcess::FailedToStart ); @@ -286,7 +387,7 @@ bool ValgrindRunner::startServers(const QHostAddress &localHostAddress) d->xmlServer.setMaxPendingConnections(1); connect(&d->xmlServer, &QTcpServer::newConnection, this, &ValgrindRunner::xmlSocketConnected); - check = d->logServer.listen(localHostAddress); + check = d->logServer.listen(d->localServerAddress); if (!check) { emit processErrorReceived(tr("LogServer on %1:").arg(ip) + ' ' + d->logServer.errorString(), QProcess::FailedToStart ); @@ -298,17 +399,4 @@ bool ValgrindRunner::startServers(const QHostAddress &localHostAddress) return true; } -QStringList ValgrindRunner::memcheckLogArguments() const -{ - QStringList arguments; - if (!d->disableXml) - arguments << QLatin1String("--xml=yes"); - arguments << QString::fromLatin1("--xml-socket=%1:%2") - .arg(d->xmlServer.serverAddress().toString()).arg(d->xmlServer.serverPort()) - << QLatin1String("--child-silent-after-fork=yes") - << QString::fromLatin1("--log-socket=%1:%2") - .arg(d->logServer.serverAddress().toString()).arg(d->logServer.serverPort()); - return arguments; -} - } // namespace Valgrind diff --git a/src/plugins/valgrind/valgrindrunner.h b/src/plugins/valgrind/valgrindrunner.h index 9732d093567..e567cd88399 100644 --- a/src/plugins/valgrind/valgrindrunner.h +++ b/src/plugins/valgrind/valgrindrunner.h @@ -26,12 +26,9 @@ #pragma once -#include - #include #include -#include #include @@ -39,8 +36,6 @@ namespace Valgrind { namespace XmlProtocol { class ThreadedParser; } -class ValgrindProcess; - class ValgrindRunner : public QObject { Q_OBJECT @@ -49,48 +44,35 @@ public: explicit ValgrindRunner(QObject *parent = 0); ~ValgrindRunner(); - QString valgrindExecutable() const; void setValgrindExecutable(const QString &executable); - QStringList valgrindArguments() const; - QStringList fullValgrindArguments() const; void setValgrindArguments(const QStringList &toolArguments); - void setDebuggee(const ProjectExplorer::StandardRunnable &debuggee) ; + void setDebuggee(const ProjectExplorer::StandardRunnable &debuggee); void setProcessChannelMode(QProcess::ProcessChannelMode mode); - + void setLocalServerAddress(const QHostAddress &localServerAddress); void setDevice(const ProjectExplorer::IDevice::ConstPtr &device); - ProjectExplorer::IDevice::ConstPtr device() const; void waitForFinished() const; - void setToolName(const QString &toolName); QString errorString() const; bool start(); void stop(); - ValgrindProcess *valgrindProcess() const; - XmlProtocol::ThreadedParser *parser() const; - void disableXml(); signals: void logMessageReceived(const QByteArray &); - void extraStart(); - void processOutputReceived(const QString &, Utils::OutputFormat); void processErrorReceived(const QString &, QProcess::ProcessError); - void started(); + void valgrindStarted(qint64 pid); void finished(); void extraProcessFinished(); private: - bool startServers(const QHostAddress &localHostAddress); - QStringList memcheckLogArguments() const; - + bool startServers(); void processError(QProcess::ProcessError); void processFinished(int, QProcess::ExitStatus); - void localHostAddressRetrieved(const QHostAddress &localHostAddress); void xmlSocketConnected(); void logSocketConnected(); void readLogSocket(); diff --git a/src/plugins/winrt/winrtdevice.cpp b/src/plugins/winrt/winrtdevice.cpp index 2f5ef04ae55..f6519bf94ab 100644 --- a/src/plugins/winrt/winrtdevice.cpp +++ b/src/plugins/winrt/winrtdevice.cpp @@ -119,6 +119,11 @@ QVariantMap WinRtDevice::toMap() const return map; } +Utils::OsType WinRtDevice::osType() const +{ + return Utils::OsTypeWindows; +} + IDevice::Ptr WinRtDevice::clone() const { return IDevice::Ptr(new WinRtDevice(*this)); diff --git a/src/plugins/winrt/winrtdevice.h b/src/plugins/winrt/winrtdevice.h index 5915ac73f70..694badf32a8 100644 --- a/src/plugins/winrt/winrtdevice.h +++ b/src/plugins/winrt/winrtdevice.h @@ -45,6 +45,7 @@ public: ProjectExplorer::DeviceProcessSignalOperation::Ptr signalOperation() const override; void fromMap(const QVariantMap &map) override; QVariantMap toMap() const override; + Utils::OsType osType() const override; ProjectExplorer::IDevice::Ptr clone() const override; static QString displayNameForType(Core::Id type); diff --git a/src/tools/clangbackend/ipcsource/clangdocument.cpp b/src/tools/clangbackend/ipcsource/clangdocument.cpp index 117a77a8481..3cfcfabe092 100644 --- a/src/tools/clangbackend/ipcsource/clangdocument.cpp +++ b/src/tools/clangbackend/ipcsource/clangdocument.cpp @@ -423,12 +423,15 @@ bool operator==(const Document &first, const Document &second) && first.projectPart().id() == second.projectPart().id(); } -void PrintTo(const Document &document, ::std::ostream *os) +std::ostream &operator<<(std::ostream &os, const Document &document) { - *os << "Document(" - << document.filePath().constData() << ", " - << document.projectPart().id().constData() << ", " - << document.documentRevision() << ")"; + os << "(" + << document.filePath() << ", " + << document.projectPart().id() << ", " + << document.documentRevision() + << ")"; + + return os; } } // namespace ClangBackEnd diff --git a/src/tools/clangbackend/ipcsource/clangdocument.h b/src/tools/clangbackend/ipcsource/clangdocument.h index 138e96a9460..15555ace101 100644 --- a/src/tools/clangbackend/ipcsource/clangdocument.h +++ b/src/tools/clangbackend/ipcsource/clangdocument.h @@ -133,5 +133,5 @@ private: }; bool operator==(const Document &first, const Document &second); -void PrintTo(const Document &document, ::std::ostream *os); +std::ostream &operator<<(std::ostream &os, const Document &document); } // namespace ClangBackEnd diff --git a/src/tools/clangbackend/ipcsource/clangstring.h b/src/tools/clangbackend/ipcsource/clangstring.h index 09049153abb..685055cff03 100644 --- a/src/tools/clangbackend/ipcsource/clangstring.h +++ b/src/tools/clangbackend/ipcsource/clangstring.h @@ -107,7 +107,6 @@ public: { return second == first; } - template::value>::type > @@ -124,11 +123,9 @@ public: return second == first; } - friend std::ostream &operator<<(std::ostream &out, const ClangString &string) + friend std::ostream &operator<<(std::ostream &os, const ClangString &string) { - out << string.cString(); - - return out; + return os << string.cString(); } private: diff --git a/src/tools/clangbackend/ipcsource/clangtype.cpp b/src/tools/clangbackend/ipcsource/clangtype.cpp index 6b14b38dd84..dd0e192f7a3 100644 --- a/src/tools/clangbackend/ipcsource/clangtype.cpp +++ b/src/tools/clangbackend/ipcsource/clangtype.cpp @@ -144,17 +144,20 @@ bool operator==(Type first, Type second) return clang_equalTypes(first.cxType, second.cxType); } -void PrintTo(CXTypeKind typeKind, ::std::ostream* os) +std::ostream &operator<<(std::ostream &os, CXTypeKind typeKind) { ClangString typeKindSpelling(clang_getTypeKindSpelling(typeKind)); - *os << typeKindSpelling.cString(); + + return os << typeKindSpelling.cString(); } -void PrintTo(const Type &type, ::std::ostream* os) +std::ostream &operator<<(std::ostream &os, const Type &type) { ClangString typeKindSpelling(clang_getTypeKindSpelling(type.kind())); - *os << typeKindSpelling.cString() - << ": \"" << type.spelling().cString() << "\""; + os << typeKindSpelling + << ": \"" << type.spelling() << "\""; + + return os; } diff --git a/src/tools/clangbackend/ipcsource/clangtype.h b/src/tools/clangbackend/ipcsource/clangtype.h index 71ea1506ee5..f26fe080f6b 100644 --- a/src/tools/clangbackend/ipcsource/clangtype.h +++ b/src/tools/clangbackend/ipcsource/clangtype.h @@ -77,6 +77,6 @@ private: bool operator==(Type first, Type second); -void PrintTo(CXTypeKind typeKind, ::std::ostream* os); -void PrintTo(const Type &type, ::std::ostream* os); +std::ostream &operator<<(std::ostream &os, CXTypeKind typeKind); +std::ostream &operator<<(std::ostream &os, const Type &type); } // namespace ClangBackEnd diff --git a/src/tools/clangbackend/ipcsource/codecompletionsextractor.cpp b/src/tools/clangbackend/ipcsource/codecompletionsextractor.cpp index cac1f50e290..1c810e50698 100644 --- a/src/tools/clangbackend/ipcsource/codecompletionsextractor.cpp +++ b/src/tools/clangbackend/ipcsource/codecompletionsextractor.cpp @@ -28,10 +28,6 @@ #include "clangstring.h" #include "codecompletionchunkconverter.h" -#ifdef CLANGBACKEND_TESTS -#include -#endif - #include namespace ClangBackEnd { @@ -344,15 +340,15 @@ const CodeCompletion &CodeCompletionsExtractor::currentCodeCompletion() const return currentCodeCompletion_; } -#ifdef CLANGBACKEND_TESTS -void PrintTo(const CodeCompletionsExtractor &extractor, std::ostream *os) +std::ostream &operator<<(std::ostream &os, const CodeCompletionsExtractor &extractor) { - *os << "name: " << ::testing::PrintToString(extractor.currentCodeCompletion().text()) - << ", kind: " << ::testing::PrintToString(extractor.currentCodeCompletion().completionKind()) - << ", priority: " << extractor.currentCodeCompletion().priority() - << ", kind: " << ::testing::PrintToString(extractor.currentCodeCompletion().availability()); + os << "name: " << extractor.currentCodeCompletion().text() + << ", kind: " << extractor.currentCodeCompletion().completionKind() + << ", priority: " << extractor.currentCodeCompletion().priority() + << ", kind: " << extractor.currentCodeCompletion().availability(); + + return os; } -#endif } // namespace ClangBackEnd diff --git a/src/tools/clangbackend/ipcsource/codecompletionsextractor.h b/src/tools/clangbackend/ipcsource/codecompletionsextractor.h index 8a4c7c03ab1..57e9bd5afcf 100644 --- a/src/tools/clangbackend/ipcsource/codecompletionsextractor.h +++ b/src/tools/clangbackend/ipcsource/codecompletionsextractor.h @@ -31,6 +31,8 @@ #include +#include + namespace ClangBackEnd { class CodeCompletionsExtractor @@ -78,7 +80,5 @@ private: uint cxCodeCompleteResultIndex = -1; }; -#ifdef CLANGBACKEND_TESTS -void PrintTo(const CodeCompletionsExtractor &extractor, ::std::ostream* os); -#endif +std::ostream &operator<<(std::ostream &os, const CodeCompletionsExtractor &extractor); } // namespace ClangBackEnd diff --git a/src/tools/clangbackend/ipcsource/cursor.cpp b/src/tools/clangbackend/ipcsource/cursor.cpp index c9f8dd5ab81..518fd013d24 100644 --- a/src/tools/clangbackend/ipcsource/cursor.cpp +++ b/src/tools/clangbackend/ipcsource/cursor.cpp @@ -403,29 +403,31 @@ bool operator!=(const Cursor &first, const Cursor &second) return !(first == second); } -void PrintTo(CXCursorKind cursorKind, ::std::ostream *os) +std::ostream &operator<<(std::ostream &os, CXCursorKind cursorKind) { ClangString cursorKindSpelling(clang_getCursorKindSpelling(cursorKind)); - *os << cursorKindSpelling.cString(); + return os << cursorKindSpelling.cString(); } -void PrintTo(const Cursor &cursor, ::std::ostream*os) +std::ostream &operator<<(std::ostream &os, const Cursor &cursor) { if (cursor.isValid()) { ClangString cursorKindSpelling(clang_getCursorKindSpelling(cursor.kind())); - *os << cursorKindSpelling.cString() << " "; + os << cursorKindSpelling << " "; auto identifier = cursor.displayName(); if (identifier.hasContent()) { - *os << "\"" - << identifier - << "\": "; + os << "\"" + << identifier + << "\": "; } - PrintTo(cursor.sourceLocation(), os); + os << cursor.sourceLocation(); } else { - *os << "Invalid cursor!"; + os << "Invalid cursor!"; } + + return os; } } // namespace ClangBackEnd diff --git a/src/tools/clangbackend/ipcsource/cursor.h b/src/tools/clangbackend/ipcsource/cursor.h index 234ad900f9e..0187d8448b1 100644 --- a/src/tools/clangbackend/ipcsource/cursor.h +++ b/src/tools/clangbackend/ipcsource/cursor.h @@ -130,6 +130,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); +std::ostream &operator<<(std::ostream &os, CXCursorKind cursorKind); +std::ostream &operator<<(std::ostream &os, const Cursor &cursor); + } // namespace ClangBackEnd diff --git a/src/tools/clangbackend/ipcsource/sourcelocation.cpp b/src/tools/clangbackend/ipcsource/sourcelocation.cpp index 5d54600c3c5..161ed5b0a50 100644 --- a/src/tools/clangbackend/ipcsource/sourcelocation.cpp +++ b/src/tools/clangbackend/ipcsource/sourcelocation.cpp @@ -114,15 +114,17 @@ SourceLocation::operator CXSourceLocation() const return cxSourceLocation; } -void PrintTo(const SourceLocation &sourceLocation, std::ostream *os) +std::ostream &operator<<(std::ostream &os, const SourceLocation &sourceLocation) { auto filePath = sourceLocation.filePath(); if (filePath.hasContent()) - *os << filePath.constData() << ", "; + os << filePath << ", "; - *os << "line: " << sourceLocation.line() - << ", column: "<< sourceLocation.column() - << ", offset: "<< sourceLocation.offset(); + os << "line: " << sourceLocation.line() + << ", column: "<< sourceLocation.column() + << ", offset: "<< sourceLocation.offset(); + + return os; } } // namespace ClangBackEnd diff --git a/src/tools/clangbackend/ipcsource/sourcelocation.h b/src/tools/clangbackend/ipcsource/sourcelocation.h index 7379773e500..65c3ec69ad6 100644 --- a/src/tools/clangbackend/ipcsource/sourcelocation.h +++ b/src/tools/clangbackend/ipcsource/sourcelocation.h @@ -72,6 +72,6 @@ private: bool operator==(const SourceLocation &first, const SourceLocation &second); -void PrintTo(const SourceLocation &sourceLocation, ::std::ostream* os); +std::ostream &operator<<(std::ostream &os, const SourceLocation &sourceLocation); } // namespace ClangBackEnd diff --git a/src/tools/clangbackend/ipcsource/sourcerange.cpp b/src/tools/clangbackend/ipcsource/sourcerange.cpp index 86029cfd3ee..20c6efb5e65 100644 --- a/src/tools/clangbackend/ipcsource/sourcerange.cpp +++ b/src/tools/clangbackend/ipcsource/sourcerange.cpp @@ -100,13 +100,14 @@ bool operator==(const SourceRange &first, const SourceRange &second) return clang_equalRanges(first.cxSourceRange, second.cxSourceRange); } -void PrintTo(const SourceRange &sourceRange, ::std::ostream* os) +std::ostream &operator<<(std::ostream &os, const SourceRange &sourceRange) { - *os << "["; - PrintTo(sourceRange.start(), os); - *os << ", "; - PrintTo(sourceRange.end(), os); - *os << "]"; + os << "[" + << sourceRange.start() << ", " + << sourceRange.end() + << "]"; + + return os; } } // namespace ClangBackEnd diff --git a/src/tools/clangbackend/ipcsource/sourcerange.h b/src/tools/clangbackend/ipcsource/sourcerange.h index 955896ccfb0..b8083e86955 100644 --- a/src/tools/clangbackend/ipcsource/sourcerange.h +++ b/src/tools/clangbackend/ipcsource/sourcerange.h @@ -61,5 +61,5 @@ private: }; bool operator==(const SourceRange &first, const SourceRange &second); -void PrintTo(const SourceRange &sourceRange, ::std::ostream* os); +std::ostream &operator<<(std::ostream &os, const SourceRange &sourceRange); } // namespace ClangBackEnd diff --git a/src/tools/clangbackend/ipcsource/unsavedfile.cpp b/src/tools/clangbackend/ipcsource/unsavedfile.cpp index 8822e2939ef..923d4456e8a 100644 --- a/src/tools/clangbackend/ipcsource/unsavedfile.cpp +++ b/src/tools/clangbackend/ipcsource/unsavedfile.cpp @@ -97,12 +97,14 @@ bool UnsavedFile::replaceAt(uint position, uint length, const Utf8String &replac return false; } -void PrintTo(const UnsavedFile &unsavedFile, std::ostream *os) +std::ostream &operator<<(std::ostream &os, const UnsavedFile &unsavedFile) { - *os << "UnsavedFile(" - << unsavedFile.m_filePath.constData() << ", " - << unsavedFile.m_fileContent.constData() << ", " - << unsavedFile.m_fileContent.byteSize() << ")"; + os << "UnsavedFile(" + << unsavedFile.m_filePath << ", " + << unsavedFile.m_fileContent << ", " + << unsavedFile.m_fileContent << ")"; + + return os; } } // namespace ClangBackEnd diff --git a/src/tools/clangbackend/ipcsource/unsavedfile.h b/src/tools/clangbackend/ipcsource/unsavedfile.h index ff1f354c878..3021da89b5c 100644 --- a/src/tools/clangbackend/ipcsource/unsavedfile.h +++ b/src/tools/clangbackend/ipcsource/unsavedfile.h @@ -34,7 +34,7 @@ using uint = unsigned int; class UnsavedFile { public: - friend void PrintTo(const UnsavedFile &unsavedFile, std::ostream *os); + friend std::ostream &operator<<(std::ostream &os, const UnsavedFile &unsavedFile); UnsavedFile(); UnsavedFile(const Utf8String &filePath, const Utf8String &fileContent); diff --git a/src/tools/clangrefactoringbackend/source/clangrefactoringbackend-source.pri b/src/tools/clangrefactoringbackend/source/clangrefactoringbackend-source.pri index 37d503f210c..7a695e5ca4d 100644 --- a/src/tools/clangrefactoringbackend/source/clangrefactoringbackend-source.pri +++ b/src/tools/clangrefactoringbackend/source/clangrefactoringbackend-source.pri @@ -1,8 +1,7 @@ INCLUDEPATH += $$PWD HEADERS += \ - $$PWD/clangrefactoringbackend_global.h \ - $$PWD/clangquerygatherer.h + $$PWD/clangrefactoringbackend_global.h !isEmpty(LIBTOOLING_LIBS) { SOURCES += \ @@ -15,7 +14,8 @@ SOURCES += \ $$PWD/clangquery.cpp \ $$PWD/clangtool.cpp \ $$PWD/sourcerangeextractor.cpp \ - $$PWD/locationsourcefilecallbacks.cpp + $$PWD/locationsourcefilecallbacks.cpp \ + $$PWD/clangquerygatherer.cpp HEADERS += \ $$PWD/refactoringcompilationdatabase.h \ @@ -30,8 +30,6 @@ HEADERS += \ $$PWD/clangquery.h \ $$PWD/clangtool.h \ $$PWD/sourcerangeextractor.h \ - $$PWD/locationsourcefilecallbacks.h + $$PWD/locationsourcefilecallbacks.h \ + $$PWD/clangquerygatherer.h } - -SOURCES += \ - $$PWD/clangquerygatherer.cpp diff --git a/tests/auto/valgrind/valgrindautotest.qbs b/tests/auto/valgrind/valgrindautotest.qbs index 7e7760bd396..78f546144f1 100644 --- a/tests/auto/valgrind/valgrindautotest.qbs +++ b/tests/auto/valgrind/valgrindautotest.qbs @@ -27,7 +27,6 @@ QtcAutotest { name: "Other files from plugin" prefix: product.pluginDir + "/" files: [ - "valgrindprocess.h", "valgrindprocess.cpp", "valgrindrunner.h", "valgrindrunner.cpp", ] } diff --git a/tests/unit/unittest/unittest.pro b/tests/unit/unittest/unittest.pro index 054ae386e59..73e0ed31a3f 100644 --- a/tests/unit/unittest/unittest.pro +++ b/tests/unit/unittest/unittest.pro @@ -63,7 +63,6 @@ SOURCES += \ projectupdater-test.cpp \ pchmanagerserver-test.cpp \ pchmanagerclientserverinprocess-test.cpp \ - clangquerygatherer-test.cpp !isEmpty(LIBCLANG_LIBS) { SOURCES += \ @@ -125,6 +124,7 @@ SOURCES += \ !isEmpty(LIBTOOLING_LIBS) { SOURCES += \ clangquery-test.cpp \ + clangquerygatherer-test.cpp \ clangqueryprojectfindfilter-test.cpp \ refactoringclientserverinprocess-test.cpp \ refactoringclient-test.cpp \