CppEditor: Make it possible to specify default values in generate constructor quickfix

Change-Id: If73b4bdad1e3878091378d800bec2f1682a55c9f
Reviewed-by: Christian Kandeler <christian.kandeler@qt.io>
This commit is contained in:
Leander Schulten
2021-01-18 21:57:42 +01:00
parent 3e2cb9d3d2
commit 8192f7f4f4
2 changed files with 87 additions and 8 deletions

View File

@@ -7731,6 +7731,26 @@ public:
QTest::newRow("changed parameter order") QTest::newRow("changed parameter order")
<< header << expected << QByteArray() << QByteArray() << Inside; << header << expected << QByteArray() << QByteArray() << Inside;
header = R"--(
class@ Foo{
int test;
int di_test;
public:
};
)--";
expected = R"--(
class Foo{
int test;
int di_test;
public:
Foo(int test, int di_test = 42) : test(test),
di_test(di_test)
{}
};
)--";
QTest::newRow("default parameters")
<< header << expected << QByteArray() << QByteArray() << Inside;
const QByteArray common = R"--( const QByteArray common = R"--(
namespace N{ namespace N{
template<typename T> template<typename T>

View File

@@ -8433,6 +8433,7 @@ public:
QString memberVariableName; QString memberVariableName;
QString parameterName; QString parameterName;
QString defaultValue;
bool init = true; bool init = true;
bool customValueType; // for the generation later bool customValueType; // for the generation later
Symbol *symbol; // for the right type later Symbol *symbol; // for the right type later
@@ -8443,17 +8444,34 @@ using ConstructorMemberCandidates = std::vector<ConstructorMemberInfo>;
class ConstructorParams : public QAbstractTableModel class ConstructorParams : public QAbstractTableModel
{ {
Q_OBJECT
std::vector<ConstructorMemberInfo *> &infos; std::vector<ConstructorMemberInfo *> &infos;
void validateOrder()
{
// parameters with default values must be at the end
bool foundWithDefault = false;
for (auto info : infos) {
if (info->init) {
if (foundWithDefault && info->defaultValue.isEmpty()) {
emit validOrder(false);
return;
}
foundWithDefault |= !info->defaultValue.isEmpty();
}
}
emit validOrder(true);
}
public: public:
enum Column { ShouldInitColumn, MemberNameColumn, ParameterNameColumn }; enum Column { ShouldInitColumn, MemberNameColumn, ParameterNameColumn, DefaultValueColumn };
ConstructorParams(QObject *parent, std::vector<ConstructorMemberInfo *> &infos) ConstructorParams(QObject *parent, std::vector<ConstructorMemberInfo *> &infos)
: QAbstractTableModel(parent) : QAbstractTableModel(parent)
, infos(infos) , infos(infos)
{} {}
int rowCount(const QModelIndex & /*parent*/ = {}) const override { return infos.size(); } int rowCount(const QModelIndex & /*parent*/ = {}) const override { return infos.size(); }
int columnCount(const QModelIndex & /*parent*/ = {}) const override { return 3; } int columnCount(const QModelIndex & /*parent*/ = {}) const override { return 4; }
QVariant data(const QModelIndex &index, int role) const override QVariant data(const QModelIndex &index, int role) const override
{ {
if (index.row() < 0 || index.row() >= rowCount()) if (index.row() < 0 || index.row() >= rowCount())
@@ -8465,6 +8483,11 @@ public:
if ((role == Qt::DisplayRole || role == Qt::EditRole) if ((role == Qt::DisplayRole || role == Qt::EditRole)
&& index.column() == ParameterNameColumn) && index.column() == ParameterNameColumn)
return infos[index.row()]->parameterName; return infos[index.row()]->parameterName;
if ((role == Qt::DisplayRole || role == Qt::EditRole)
&& index.column() == DefaultValueColumn)
return infos[index.row()]->defaultValue;
if ((role == Qt::ToolTipRole) && index.column() == DefaultValueColumn)
return Overview{}.prettyType(infos[index.row()]->symbol->type());
return {}; return {};
} }
bool setData(const QModelIndex &index, const QVariant &value, int role) override bool setData(const QModelIndex &index, const QVariant &value, int role) override
@@ -8472,12 +8495,18 @@ public:
if (index.column() == ShouldInitColumn && role == Qt::CheckStateRole) { if (index.column() == ShouldInitColumn && role == Qt::CheckStateRole) {
infos[index.row()]->init = value.toInt() == Qt::Checked; infos[index.row()]->init = value.toInt() == Qt::Checked;
emit dataChanged(this->index(index.row(), 1), this->index(index.row(), 2)); emit dataChanged(this->index(index.row(), 1), this->index(index.row(), 2));
validateOrder();
return true; return true;
} }
if (index.column() == ParameterNameColumn && role == Qt::EditRole) { if (index.column() == ParameterNameColumn && role == Qt::EditRole) {
infos[index.row()]->parameterName = value.toString(); infos[index.row()]->parameterName = value.toString();
return true; return true;
} }
if (index.column() == DefaultValueColumn && role == Qt::EditRole) {
infos[index.row()]->defaultValue = value.toString();
validateOrder();
return true;
}
return false; return false;
} }
Qt::DropActions supportedDropActions() const override { return Qt::MoveAction; } Qt::DropActions supportedDropActions() const override { return Qt::MoveAction; }
@@ -8498,7 +8527,7 @@ public:
return f; return f;
if (index.column() == MemberNameColumn) if (index.column() == MemberNameColumn)
return f | Qt::ItemIsEnabled; return f | Qt::ItemIsEnabled;
if (index.column() == ParameterNameColumn) if (index.column() == ParameterNameColumn || index.column() == DefaultValueColumn)
return f | Qt::ItemIsEnabled | Qt::ItemIsEditable; return f | Qt::ItemIsEnabled | Qt::ItemIsEditable;
return {}; return {};
} }
@@ -8513,6 +8542,8 @@ public:
return tr("Member Name"); return tr("Member Name");
case ParameterNameColumn: case ParameterNameColumn:
return tr("Parameter Name"); return tr("Parameter Name");
case DefaultValueColumn:
return tr("Default Value");
} }
} }
return {}; return {};
@@ -8535,6 +8566,7 @@ public:
if (row < sourceRow) if (row < sourceRow)
++sourceRow; ++sourceRow;
infos.erase(infos.begin() + sourceRow); infos.erase(infos.begin() + sourceRow);
validateOrder();
return true; return true;
} }
return false; return false;
@@ -8576,6 +8608,8 @@ public:
QProxyStyle::drawPrimitive(element, option, painter, widget); QProxyStyle::drawPrimitive(element, option, painter, widget);
} }
}; };
signals:
void validOrder(bool valid);
}; };
class GenerateConstructorDialog : public QDialog class GenerateConstructorDialog : public QDialog
@@ -8609,6 +8643,20 @@ public:
connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
const auto errorLabel = new QLabel(
tr("Parameters without default value must come before parameters with default value."));
errorLabel->setStyleSheet("color: #ff0000");
errorLabel->setVisible(false);
QSizePolicy labelSizePolicy = errorLabel->sizePolicy();
labelSizePolicy.setRetainSizeWhenHidden(true);
errorLabel->setSizePolicy(labelSizePolicy);
connect(model,
&ConstructorParams::validOrder,
[=, button = buttonBox->button(QDialogButtonBox::Ok)](bool valid) {
button->setEnabled(valid);
errorLabel->setVisible(!valid);
});
// setup select all/none checkbox // setup select all/none checkbox
QCheckBox *const checkBox = new QCheckBox(tr("Initialize all members")); QCheckBox *const checkBox = new QCheckBox(tr("Initialize all members"));
checkBox->setChecked(true); checkBox->setChecked(true);
@@ -8659,6 +8707,7 @@ public:
mainLayout->addLayout(row); mainLayout->addLayout(row);
mainLayout->addWidget(checkBox); mainLayout->addWidget(checkBox);
mainLayout->addWidget(view); mainLayout->addWidget(view);
mainLayout->addWidget(errorLabel);
mainLayout->addWidget(buttonBox); mainLayout->addWidget(buttonBox);
int left, right; int left, right;
mainLayout->getContentsMargins(&left, nullptr, &right, nullptr); mainLayout->getContentsMargins(&left, nullptr, &right, nullptr);
@@ -8720,12 +8769,18 @@ private:
if (dlg.exec() == QDialog::Rejected) if (dlg.exec() == QDialog::Rejected)
return; return;
accessSpec = dlg.accessSpec(); accessSpec = dlg.accessSpec();
} else if (infos.size() >= 3) { } else {
if (infos.size() >= 3) {
// if we are testing and have 3 or more members => change the order // if we are testing and have 3 or more members => change the order
// move first element to the back // move first element to the back
infos.push_back(infos[0]); infos.push_back(infos[0]);
infos.erase(infos.begin()); infos.erase(infos.begin());
} }
for (auto info : infos) {
if (info->memberVariableName.startsWith("di_"))
info->defaultValue = "42";
}
}
if (infos.empty()) if (infos.empty())
return; return;
struct GenerateConstructorRefactoringHelper : public GetterSetterRefactoringHelper struct GenerateConstructorRefactoringHelper : public GetterSetterRefactoringHelper
@@ -8787,6 +8842,8 @@ private:
member->type = makeConstRef(member->type); member->type = makeConstRef(member->type);
inClassDeclaration += overview.prettyType(member->type, member->parameterName); inClassDeclaration += overview.prettyType(member->type, member->parameterName);
if (!member->defaultValue.isEmpty())
inClassDeclaration += " = " + member->defaultValue;
inClassDeclaration += ", "; inClassDeclaration += ", ";
QString param = member->parameterName; QString param = member->parameterName;
if (implFile) { if (implFile) {
@@ -8929,3 +8986,5 @@ void destroyCppQuickFixes()
} // namespace Internal } // namespace Internal
} // namespace CppEditor } // namespace CppEditor
#include "cppquickfixes.moc"