Debugger: Use an aspect for the source path mapping

More in line with the other settings.

Change-Id: I86494f1955120cddda7d2f2eec8ba0fdbfd99585
Reviewed-by: David Schulz <david.schulz@qt.io>
This commit is contained in:
hjk
2021-03-05 12:48:26 +01:00
parent cb55af8e55
commit 641604429a
11 changed files with 197 additions and 177 deletions

View File

@@ -254,7 +254,7 @@ void CdbEngine::init()
} }
} }
const SourcePathMap &sourcePathMap = Internal::globalDebuggerOptions()->sourcePathMap; const SourcePathMap &sourcePathMap = debuggerSettings()->sourcePathMap.value();
if (!sourcePathMap.isEmpty()) { if (!sourcePathMap.isEmpty()) {
for (auto it = sourcePathMap.constBegin(), cend = sourcePathMap.constEnd(); it != cend; ++it) { for (auto it = sourcePathMap.constBegin(), cend = sourcePathMap.constEnd(); it != cend; ++it) {
m_sourcePathMappings.push_back({QDir::toNativeSeparators(it.key()), m_sourcePathMappings.push_back({QDir::toNativeSeparators(it.key()),

View File

@@ -27,31 +27,15 @@
#include "debuggeractions.h" #include "debuggeractions.h"
#include "debuggerinternalconstants.h" #include "debuggerinternalconstants.h"
#include "debuggercore.h"
#include "debuggersourcepathmappingwidget.h"
#include <coreplugin/icore.h> #include <coreplugin/icore.h>
#include <app/app_version.h>
#include <utils/hostosinfo.h>
#include <utils/layoutbuilder.h> #include <utils/layoutbuilder.h>
#include <utils/pathchooser.h>
#include <utils/qtcassert.h>
#include <utils/variablechooser.h>
#include <QCoreApplication>
#include <QLabel>
#include <QTextStream>
using namespace Core; using namespace Core;
using namespace Debugger::Constants; using namespace Debugger::Constants;
using namespace ProjectExplorer;
using namespace Utils; using namespace Utils;
namespace Utils {
}
namespace Debugger { namespace Debugger {
namespace Internal { namespace Internal {
@@ -68,12 +52,6 @@ class CommonOptionsPageWidget : public Core::IOptionsPageWidget
public: public:
explicit CommonOptionsPageWidget() explicit CommonOptionsPageWidget()
{ {
m_sourceMappingWidget = new DebuggerSourcePathMappingWidget(this);
GlobalDebuggerOptions *options = Internal::globalDebuggerOptions();
SourcePathMap allPathMap = options->sourcePathMap;
m_sourceMappingWidget->setSourcePathMap(allPathMap);
DebuggerSettings &s = *debuggerSettings(); DebuggerSettings &s = *debuggerSettings();
using namespace Layouting; using namespace Layouting;
@@ -100,29 +78,18 @@ public:
Column { Column {
Group { Title("Behavior"), Row { col1, col2, Stretch() } }, Group { Title("Behavior"), Row { col1, col2, Stretch() } },
m_sourceMappingWidget, s.sourcePathMap,
Stretch() Stretch()
}.attachTo(this); }.attachTo(this);
} }
void apply() final; void apply() final { m_group.apply(); m_group.writeSettings(ICore::settings()); }
void finish() final { m_group.finish(); } void finish() final { m_group.finish(); }
private: private:
AspectContainer &m_group = debuggerSettings()->page1; AspectContainer &m_group = debuggerSettings()->page1;
DebuggerSourcePathMappingWidget *m_sourceMappingWidget = nullptr;
}; };
void CommonOptionsPageWidget::apply()
{
m_group.apply();
m_group.writeSettings(ICore::settings());
GlobalDebuggerOptions *options = Internal::globalDebuggerOptions();
options->sourcePathMap = m_sourceMappingWidget->sourcePathMap();
options->toSettings();
}
CommonOptionsPage::CommonOptionsPage() CommonOptionsPage::CommonOptionsPage()
{ {
setId(DEBUGGER_COMMON_SETTINGS_ID); setId(DEBUGGER_COMMON_SETTINGS_ID);

View File

@@ -41,55 +41,15 @@
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
#include <QDebug> #include <QDebug>
#include <QSettings>
using namespace Utils; using namespace Utils;
static const char debugModeSettingsGroupC[] = "DebugMode"; const char debugModeSettingsGroupC[] = "DebugMode";
static const char cdbSettingsGroupC[] = "CDB2"; const char cdbSettingsGroupC[] = "CDB2";
static const char sourcePathMappingArrayNameC[] = "SourcePathMappings";
static const char sourcePathMappingSourceKeyC[] = "Source";
static const char sourcePathMappingTargetKeyC[] = "Target";
namespace Debugger { namespace Debugger {
namespace Internal { namespace Internal {
void GlobalDebuggerOptions::toSettings() const
{
QSettings *s = Core::ICore::settings();
s->beginWriteArray(sourcePathMappingArrayNameC);
if (!sourcePathMap.isEmpty()) {
const QString sourcePathMappingSourceKey(sourcePathMappingSourceKeyC);
const QString sourcePathMappingTargetKey(sourcePathMappingTargetKeyC);
int i = 0;
for (auto it = sourcePathMap.constBegin(), cend = sourcePathMap.constEnd();
it != cend;
++it, ++i) {
s->setArrayIndex(i);
s->setValue(sourcePathMappingSourceKey, it.key());
s->setValue(sourcePathMappingTargetKey, it.value());
}
}
s->endArray();
}
void GlobalDebuggerOptions::fromSettings()
{
QSettings *s = Core::ICore::settings();
sourcePathMap.clear();
if (const int count = s->beginReadArray(sourcePathMappingArrayNameC)) {
const QString sourcePathMappingSourceKey(sourcePathMappingSourceKeyC);
const QString sourcePathMappingTargetKey(sourcePathMappingTargetKeyC);
for (int i = 0; i < count; ++i) {
s->setArrayIndex(i);
const QString key = s->value(sourcePathMappingSourceKey).toString();
const QString value = s->value(sourcePathMappingTargetKey).toString();
sourcePathMap.insert(key, value);
}
}
s->endArray();
}
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
// //
// DebuggerSettings // DebuggerSettings
@@ -604,6 +564,8 @@ DebuggerSettings::DebuggerSettings()
page1.registerAspect(&showQmlObjectTree); page1.registerAspect(&showQmlObjectTree);
page1.registerAspect(&stationaryEditorWhileStepping); page1.registerAspect(&stationaryEditorWhileStepping);
page1.registerAspect(&sourcePathMap);
// Page 2 // Page 2
page2.registerAspect(&gdbWatchdogTimeout); page2.registerAspect(&gdbWatchdogTimeout);
page2.registerAspect(&skipKnownFrames); page2.registerAspect(&skipKnownFrames);

View File

@@ -35,22 +35,36 @@
namespace Debugger { namespace Debugger {
namespace Internal { namespace Internal {
class SourcePathMapAspectPrivate;
// Entries starting with '(' are considered regular expressions in the ElfReader.
// This is useful when there are multiple build machines with different
// path, and the user would like to match anything up to some known
// directory to his local project.
// Syntax: (/home/.*)/KnownSubdir -> /home/my/project
using SourcePathMap = QMap<QString, QString>; using SourcePathMap = QMap<QString, QString>;
// Global debugger options that are not stored as saved action. class SourcePathMapAspect : public Utils::BaseAspect
class GlobalDebuggerOptions
{ {
public: public:
void toSettings() const; SourcePathMapAspect();
void fromSettings(); ~SourcePathMapAspect() override;
// Entries starting with '(' are considered regular expressions in the ElfReader. void fromMap(const QVariantMap &map) override;
// This is useful when there are multiple build machines with different void toMap(QVariantMap &map) const override;
// path, and the user would like to match anything up to some known
// directory to his local project.
// Syntax: (/home/.*)/KnownSubdir -> /home/my/project
SourcePathMap sourcePathMap; void addToLayout(Utils::LayoutBuilder &builder) override;
QVariant volatileValue() const override;
void setVolatileValue(const QVariant &val) override;
void readSettings(const QSettings *settings) override;
void writeSettings(QSettings *settings) const override;
SourcePathMap value() const;
private:
SourcePathMapAspectPrivate *d = nullptr;
}; };
class GeneralSettings class GeneralSettings
@@ -85,6 +99,8 @@ public:
Utils::BoolAspect showQmlObjectTree; Utils::BoolAspect showQmlObjectTree;
Utils::BoolAspect stationaryEditorWhileStepping; Utils::BoolAspect stationaryEditorWhileStepping;
SourcePathMapAspect sourcePathMap;
// Page 2: GDB // Page 2: GDB
Utils::IntegerAspect gdbWatchdogTimeout; Utils::IntegerAspect gdbWatchdogTimeout;
Utils::BoolAspect skipKnownFrames; Utils::BoolAspect skipKnownFrames;
@@ -189,3 +205,5 @@ DebuggerSettings *debuggerSettings();
} // namespace Internal } // namespace Internal
} // namespace Debugger } // namespace Debugger
Q_DECLARE_METATYPE(Debugger::Internal::SourcePathMap)

View File

@@ -42,8 +42,6 @@ namespace Utils { class BaseTreeView; }
namespace Debugger { namespace Debugger {
namespace Internal { namespace Internal {
class GlobalDebuggerOptions;
enum TestCases enum TestCases
{ {
// Gdb // Gdb
@@ -53,8 +51,6 @@ enum TestCases
// Some convenience. // Some convenience.
void openTextEditor(const QString &titlePattern, const QString &contents); void openTextEditor(const QString &titlePattern, const QString &contents);
GlobalDebuggerOptions *globalDebuggerOptions();
bool isTestRun(); bool isTestRun();
QAction *addAction(QMenu *menu, const QString &display, bool on, QAction *addAction(QMenu *menu, const QString &display, bool on,

View File

@@ -2812,10 +2812,10 @@ void CppDebuggerEngine::validateRunParameters(DebuggerRunParameters &rp)
bool hasEmbeddedInfo = elfData.indexOf(".debug_info") >= 0; bool hasEmbeddedInfo = elfData.indexOf(".debug_info") >= 0;
bool hasLink = elfData.indexOf(".gnu_debuglink") >= 0; bool hasLink = elfData.indexOf(".gnu_debuglink") >= 0;
if (hasEmbeddedInfo) { if (hasEmbeddedInfo) {
const GlobalDebuggerOptions *options = Internal::globalDebuggerOptions(); const SourcePathMap sourcePathMap = debuggerSettings()->sourcePathMap.value();
QList<QPair<QRegularExpression, QString>> globalRegExpSourceMap; QList<QPair<QRegularExpression, QString>> globalRegExpSourceMap;
globalRegExpSourceMap.reserve(options->sourcePathMap.size()); globalRegExpSourceMap.reserve(sourcePathMap.size());
for (auto it = options->sourcePathMap.begin(), end = options->sourcePathMap.end(); it != end; ++it) { for (auto it = sourcePathMap.begin(), end = sourcePathMap.end(); it != end; ++it) {
if (it.key().startsWith('(')) { if (it.key().startsWith('(')) {
const QString expanded = Utils::globalMacroExpander()->expand(it.value()); const QString expanded = Utils::globalMacroExpander()->expand(it.value());
if (!expanded.isEmpty()) if (!expanded.isEmpty())

View File

@@ -694,7 +694,6 @@ public:
Console m_console; // ensure Debugger Console is created before settings are taken into account Console m_console; // ensure Debugger Console is created before settings are taken into account
DebuggerSettings m_debuggerSettings; DebuggerSettings m_debuggerSettings;
QStringList m_arguments; QStringList m_arguments;
GlobalDebuggerOptions m_globalDebuggerOptions;
DebuggerItemManager m_debuggerItemManager; DebuggerItemManager m_debuggerItemManager;
@@ -1189,8 +1188,6 @@ DebuggerPluginPrivate::DebuggerPluginPrivate(const QStringList &arguments)
this, &DebuggerPluginPrivate::updatePresetState); this, &DebuggerPluginPrivate::updatePresetState);
connect(EngineManager::instance(), &EngineManager::currentEngineChanged, connect(EngineManager::instance(), &EngineManager::currentEngineChanged,
this, &DebuggerPluginPrivate::updatePresetState); this, &DebuggerPluginPrivate::updatePresetState);
m_globalDebuggerOptions.fromSettings();
} }
@@ -2054,11 +2051,6 @@ void openTextEditor(const QString &titlePattern0, const QString &contents)
QTC_ASSERT(editor, return); QTC_ASSERT(editor, return);
} }
Internal::GlobalDebuggerOptions *globalDebuggerOptions()
{
return &dd->m_globalDebuggerOptions;
}
/////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////
// //
// DebuggerPlugin // DebuggerPlugin

View File

@@ -24,33 +24,74 @@
****************************************************************************/ ****************************************************************************/
#include "debuggersourcepathmappingwidget.h" #include "debuggersourcepathmappingwidget.h"
#include "debuggeractions.h"
#include "debuggerengine.h" #include "debuggerengine.h"
#include <utils/buildablehelperlibrary.h> #include <utils/buildablehelperlibrary.h>
#include <utils/fancylineedit.h> #include <utils/fancylineedit.h>
#include <utils/hostosinfo.h> #include <utils/hostosinfo.h>
#include <utils/layoutbuilder.h>
#include <utils/pathchooser.h> #include <utils/pathchooser.h>
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
#include <utils/synchronousprocess.h> #include <utils/synchronousprocess.h>
#include <utils/variablechooser.h> #include <utils/variablechooser.h>
#include <QStandardItemModel> #include <QFileDialog>
#include <QTreeView> #include <QFormLayout>
#include <QGroupBox>
#include <QLabel>
#include <QLineEdit> #include <QLineEdit>
#include <QPushButton> #include <QPushButton>
#include <QFormLayout> #include <QSettings>
#include <QFileDialog> #include <QStandardItemModel>
#include <QLabel> #include <QTreeView>
using namespace Utils; using namespace Utils;
enum { SourceColumn, TargetColumn, ColumnCount };
namespace Debugger { namespace Debugger {
namespace Internal { namespace Internal {
class SourcePathMappingModel;
enum { SourceColumn, TargetColumn, ColumnCount };
using Mapping = QPair<QString, QString>; using Mapping = QPair<QString, QString>;
using SourcePathMap = DebuggerSourcePathMappingWidget::SourcePathMap;
class DebuggerSourcePathMappingWidget : public QGroupBox
{
Q_DECLARE_TR_FUNCTIONS(Debugger::Internal::DebuggerSourcePathMappingWidget)
public:
DebuggerSourcePathMappingWidget();
SourcePathMap sourcePathMap() const;
void setSourcePathMap(const SourcePathMap &);
private:
void slotAdd();
void slotAddQt();
void slotRemove();
void slotCurrentRowChanged(const QModelIndex &,const QModelIndex &);
void slotEditSourceFieldChanged();
void slotEditTargetFieldChanged();
void resizeColumns();
void updateEnabled();
QString editSourceField() const;
QString editTargetField() const;
void setEditFieldMapping(const QPair<QString, QString> &m);
int currentRow() const;
void setCurrentRow(int r);
SourcePathMappingModel *m_model;
QTreeView *m_treeView;
QPushButton *m_addButton;
QPushButton *m_addQtButton;
QPushButton *m_removeButton;
QLineEdit *m_sourceLineEdit;
Utils::PathChooser *m_targetChooser;
};
// Qt's various build paths for unpatched versions. // Qt's various build paths for unpatched versions.
QStringList qtBuildPaths() QStringList qtBuildPaths()
@@ -198,8 +239,7 @@ void SourcePathMappingModel::setTarget(int row, const QString &t)
Path mappings to be applied using source path substitution in GDB. Path mappings to be applied using source path substitution in GDB.
*/ */
DebuggerSourcePathMappingWidget::DebuggerSourcePathMappingWidget(QWidget *parent) : DebuggerSourcePathMappingWidget::DebuggerSourcePathMappingWidget() :
QGroupBox(parent),
m_model(new SourcePathMappingModel(this)), m_model(new SourcePathMappingModel(this)),
m_treeView(new QTreeView(this)), m_treeView(new QTreeView(this)),
m_addButton(new QPushButton(tr("Add"), this)), m_addButton(new QPushButton(tr("Add"), this)),
@@ -431,11 +471,8 @@ static QString findQtInstallPath(const FilePath &qmakePath)
return QString(); return QString();
} }
/* Merge settings for an installed Qt (unless another setting /* Merge settings for an installed Qt (unless another setting is already in the map. */
* is already in the map. */ SourcePathMap mergePlatformQtPath(const DebuggerRunParameters &sp, const SourcePathMap &in)
DebuggerSourcePathMappingWidget::SourcePathMap
DebuggerSourcePathMappingWidget::mergePlatformQtPath(const DebuggerRunParameters &sp,
const SourcePathMap &in)
{ {
const FilePath qmake = BuildableHelperLibrary::findSystemQt(sp.inferior.environment); const FilePath qmake = BuildableHelperLibrary::findSystemQt(sp.inferior.environment);
// FIXME: Get this from the profile? // FIXME: Get this from the profile?
@@ -456,5 +493,105 @@ DebuggerSourcePathMappingWidget::SourcePathMap
return rc; return rc;
} }
//
// SourcePathMapAspect
//
class SourcePathMapAspectPrivate
{
public:
QPointer<DebuggerSourcePathMappingWidget> m_widget;
};
SourcePathMapAspect::SourcePathMapAspect()
: d(new SourcePathMapAspectPrivate)
{
}
SourcePathMapAspect::~SourcePathMapAspect()
{
delete d;
}
void SourcePathMapAspect::fromMap(const QVariantMap &)
{
QTC_CHECK(false); // This is only used via read/writeSettings
}
void SourcePathMapAspect::toMap(QVariantMap &) const
{
QTC_CHECK(false);
}
void SourcePathMapAspect::addToLayout(LayoutBuilder &builder)
{
QTC_CHECK(!d->m_widget);
d->m_widget = createSubWidget<DebuggerSourcePathMappingWidget>();
d->m_widget->setSourcePathMap(value());
builder.addRow(d->m_widget.data());
}
QVariant SourcePathMapAspect::volatileValue() const
{
QTC_CHECK(!isAutoApply());
QTC_ASSERT(d->m_widget, return {});
return QVariant::fromValue(d->m_widget->sourcePathMap());
}
void SourcePathMapAspect::setVolatileValue(const QVariant &val)
{
QTC_CHECK(!isAutoApply());
if (d->m_widget)
d->m_widget->setSourcePathMap(val.value<SourcePathMap>());
}
const char sourcePathMappingArrayNameC[] = "SourcePathMappings";
const char sourcePathMappingSourceKeyC[] = "Source";
const char sourcePathMappingTargetKeyC[] = "Target";
SourcePathMap SourcePathMapAspect::value() const
{
return BaseAspect::value().value<SourcePathMap>();
}
void SourcePathMapAspect::writeSettings(QSettings *s) const
{
const SourcePathMap sourcePathMap = value();
s->beginWriteArray(sourcePathMappingArrayNameC);
if (!sourcePathMap.isEmpty()) {
const QString sourcePathMappingSourceKey(sourcePathMappingSourceKeyC);
const QString sourcePathMappingTargetKey(sourcePathMappingTargetKeyC);
int i = 0;
for (auto it = sourcePathMap.constBegin(), cend = sourcePathMap.constEnd();
it != cend;
++it, ++i) {
s->setArrayIndex(i);
s->setValue(sourcePathMappingSourceKey, it.key());
s->setValue(sourcePathMappingTargetKey, it.value());
}
}
s->endArray();
}
void SourcePathMapAspect::readSettings(const QSettings *settings)
{
// Eeks. But legitimate, this operates on ICore::settings();
QSettings *s = const_cast<QSettings *>(settings);
SourcePathMap sourcePathMap;
if (const int count = s->beginReadArray(sourcePathMappingArrayNameC)) {
const QString sourcePathMappingSourceKey(sourcePathMappingSourceKeyC);
const QString sourcePathMappingTargetKey(sourcePathMappingTargetKeyC);
for (int i = 0; i < count; ++i) {
s->setArrayIndex(i);
const QString key = s->value(sourcePathMappingSourceKey).toString();
const QString value = s->value(sourcePathMappingTargetKey).toString();
sourcePathMap.insert(key, value);
}
}
s->endArray();
setValue(QVariant::fromValue(sourcePathMap));
}
} // namespace Internal } // namespace Internal
} // namespace Debugger } // namespace Debugger

View File

@@ -25,67 +25,17 @@
#pragma once #pragma once
#include <QGroupBox>
#include <QMap> #include <QMap>
#include <QString>
QT_BEGIN_NAMESPACE
class QStandardItemModel;
class QTreeView;
class QLineEdit;
class QPushButton;
class QLineEdit;
class QModelIndex;
QT_END_NAMESPACE
namespace Utils { class PathChooser; }
namespace Debugger { namespace Debugger {
namespace Internal { namespace Internal {
class DebuggerRunParameters; class DebuggerRunParameters;
class SourcePathMappingModel; using SourcePathMap = QMap<QString, QString>;
/* Merge settings for an installed Qt (unless another setting
class DebuggerSourcePathMappingWidget : public QGroupBox * is already in the map. */
{ SourcePathMap mergePlatformQtPath(const DebuggerRunParameters &sp, const SourcePathMap &in);
Q_OBJECT
public:
using SourcePathMap = QMap<QString, QString>;
explicit DebuggerSourcePathMappingWidget(QWidget *parent = nullptr);
SourcePathMap sourcePathMap() const;
void setSourcePathMap(const SourcePathMap &);
/* Merge settings for an installed Qt (unless another setting
* is already in the map. */
static SourcePathMap mergePlatformQtPath(const DebuggerRunParameters &sp,
const SourcePathMap &in);
private:
void slotAdd();
void slotAddQt();
void slotRemove();
void slotCurrentRowChanged(const QModelIndex &,const QModelIndex &);
void slotEditSourceFieldChanged();
void slotEditTargetFieldChanged();
void resizeColumns();
void updateEnabled();
QString editSourceField() const;
QString editTargetField() const;
void setEditFieldMapping(const QPair<QString, QString> &m);
int currentRow() const;
void setCurrentRow(int r);
SourcePathMappingModel *m_model;
QTreeView *m_treeView;
QPushButton *m_addButton;
QPushButton *m_addQtButton;
QPushButton *m_removeButton;
QLineEdit *m_sourceLineEdit;
Utils::PathChooser *m_targetChooser;
};
} // namespace Internal } // namespace Internal
} // namespace Debugger } // namespace Debugger

View File

@@ -3949,8 +3949,7 @@ void GdbEngine::setupEngine()
// Apply source path mappings from global options. // Apply source path mappings from global options.
//showMessage(_("Assuming Qt is installed at %1").arg(qtInstallPath)); //showMessage(_("Assuming Qt is installed at %1").arg(qtInstallPath));
const SourcePathMap sourcePathMap = const SourcePathMap sourcePathMap =
DebuggerSourcePathMappingWidget::mergePlatformQtPath(rp, mergePlatformQtPath(rp, debuggerSettings()->sourcePathMap.value());
Internal::globalDebuggerOptions()->sourcePathMap);
const SourcePathMap completeSourcePathMap = const SourcePathMap completeSourcePathMap =
mergeStartParametersSourcePathMap(rp, sourcePathMap); mergeStartParametersSourcePathMap(rp, sourcePathMap);
for (auto it = completeSourcePathMap.constBegin(), cend = completeSourcePathMap.constEnd(); for (auto it = completeSourcePathMap.constBegin(), cend = completeSourcePathMap.constEnd();

View File

@@ -267,8 +267,7 @@ void LldbEngine::setupEngine()
const DebuggerRunParameters &rp = runParameters(); const DebuggerRunParameters &rp = runParameters();
const SourcePathMap sourcePathMap = const SourcePathMap sourcePathMap =
DebuggerSourcePathMappingWidget::mergePlatformQtPath(rp, mergePlatformQtPath(rp, debuggerSettings()->sourcePathMap.value());
Internal::globalDebuggerOptions()->sourcePathMap);
for (auto it = sourcePathMap.constBegin(), cend = sourcePathMap.constEnd(); for (auto it = sourcePathMap.constBegin(), cend = sourcePathMap.constEnd();
it != cend; it != cend;
++it) { ++it) {