aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/qtdesignstudio/examples/loginui1/qtquickcontrols2.conf2
-rw-r--r--doc/qtdesignstudio/examples/loginui2/qtquickcontrols2.conf2
-rw-r--r--doc/qtdesignstudio/examples/loginui3/qtquickcontrols2.conf2
-rw-r--r--doc/qtdesignstudio/examples/loginui4/qtquickcontrols2.conf2
-rw-r--r--src/libs/cplusplus/NamePrettyPrinter.cpp2
-rw-r--r--src/libs/utils/infobar.cpp54
-rw-r--r--src/libs/utils/infobar.h7
-rw-r--r--src/libs/utils/theme/theme.h2
-rw-r--r--src/plugins/coreplugin/CMakeLists.txt9
-rw-r--r--src/plugins/coreplugin/coreplugin.cpp2
-rw-r--r--src/plugins/coreplugin/coreplugin.qbs17
-rw-r--r--src/plugins/coreplugin/fancytabwidget.cpp2
-rw-r--r--src/plugins/coreplugin/locator/locator.cpp2
-rw-r--r--src/plugins/coreplugin/locator/locator.pri20
-rw-r--r--src/plugins/cppeditor/CMakeLists.txt11
-rw-r--r--src/plugins/cppeditor/cppeditor.pro14
-rw-r--r--src/plugins/cppeditor/cppeditor.qbs12
-rw-r--r--src/plugins/cppeditor/cppeditorconstants.h25
-rw-r--r--src/plugins/cppeditor/cppeditorplugin.cpp20
-rw-r--r--src/plugins/cppeditor/cppeditorplugin.h27
-rw-r--r--src/plugins/cppeditor/cppquickfix_test.cpp2398
-rw-r--r--src/plugins/cppeditor/cppquickfixes.cpp1985
-rw-r--r--src/plugins/cppeditor/cppquickfixprojectsettings.cpp187
-rw-r--r--src/plugins/cppeditor/cppquickfixprojectsettings.h67
-rw-r--r--src/plugins/cppeditor/cppquickfixprojectsettingswidget.cpp104
-rw-r--r--src/plugins/cppeditor/cppquickfixprojectsettingswidget.h63
-rw-r--r--src/plugins/cppeditor/cppquickfixprojectsettingswidget.ui48
-rw-r--r--src/plugins/cppeditor/cppquickfixsettings.cpp446
-rw-r--r--src/plugins/cppeditor/cppquickfixsettings.h149
-rw-r--r--src/plugins/cppeditor/cppquickfixsettingspage.cpp62
-rw-r--r--src/plugins/cppeditor/cppquickfixsettingspage.h48
-rw-r--r--src/plugins/cppeditor/cppquickfixsettingswidget.cpp272
-rw-r--r--src/plugins/cppeditor/cppquickfixsettingswidget.h72
-rw-r--r--src/plugins/cppeditor/cppquickfixsettingswidget.ui961
-rw-r--r--src/plugins/cpptools/cppcodestylesettings.h2
-rw-r--r--src/plugins/cpptools/cppcodestylesettingspage.cpp4
-rw-r--r--src/plugins/cpptools/cppcodestylesettingspage.ui27
-rw-r--r--src/plugins/texteditor/semantichighlighter.cpp103
38 files changed, 5448 insertions, 1784 deletions
diff --git a/doc/qtdesignstudio/examples/loginui1/qtquickcontrols2.conf b/doc/qtdesignstudio/examples/loginui1/qtquickcontrols2.conf
index 75b2cb8fff..87a95d0114 100644
--- a/doc/qtdesignstudio/examples/loginui1/qtquickcontrols2.conf
+++ b/doc/qtdesignstudio/examples/loginui1/qtquickcontrols2.conf
@@ -3,4 +3,4 @@
; http://doc.qt.io/qt-5/qtquickcontrols2-configuration.html
[Controls]
-Style=Default
+Style=Basic
diff --git a/doc/qtdesignstudio/examples/loginui2/qtquickcontrols2.conf b/doc/qtdesignstudio/examples/loginui2/qtquickcontrols2.conf
index 75b2cb8fff..87a95d0114 100644
--- a/doc/qtdesignstudio/examples/loginui2/qtquickcontrols2.conf
+++ b/doc/qtdesignstudio/examples/loginui2/qtquickcontrols2.conf
@@ -3,4 +3,4 @@
; http://doc.qt.io/qt-5/qtquickcontrols2-configuration.html
[Controls]
-Style=Default
+Style=Basic
diff --git a/doc/qtdesignstudio/examples/loginui3/qtquickcontrols2.conf b/doc/qtdesignstudio/examples/loginui3/qtquickcontrols2.conf
index 75b2cb8fff..87a95d0114 100644
--- a/doc/qtdesignstudio/examples/loginui3/qtquickcontrols2.conf
+++ b/doc/qtdesignstudio/examples/loginui3/qtquickcontrols2.conf
@@ -3,4 +3,4 @@
; http://doc.qt.io/qt-5/qtquickcontrols2-configuration.html
[Controls]
-Style=Default
+Style=Basic
diff --git a/doc/qtdesignstudio/examples/loginui4/qtquickcontrols2.conf b/doc/qtdesignstudio/examples/loginui4/qtquickcontrols2.conf
index 75b2cb8fff..87a95d0114 100644
--- a/doc/qtdesignstudio/examples/loginui4/qtquickcontrols2.conf
+++ b/doc/qtdesignstudio/examples/loginui4/qtquickcontrols2.conf
@@ -3,4 +3,4 @@
; http://doc.qt.io/qt-5/qtquickcontrols2-configuration.html
[Controls]
-Style=Default
+Style=Basic
diff --git a/src/libs/cplusplus/NamePrettyPrinter.cpp b/src/libs/cplusplus/NamePrettyPrinter.cpp
index 6195302178..89d427fafa 100644
--- a/src/libs/cplusplus/NamePrettyPrinter.cpp
+++ b/src/libs/cplusplus/NamePrettyPrinter.cpp
@@ -75,6 +75,8 @@ void NamePrettyPrinter::visit(const TemplateNameId *name)
_name = QString::fromUtf8(id->chars(), id->size());
else
_name = QLatin1String("anonymous");
+ if (!_overview->showTemplateParameters)
+ return;
_name += QLatin1Char('<');
for (int index = 0; index < name->templateArgumentCount(); ++index) {
if (index != 0)
diff --git a/src/libs/utils/infobar.cpp b/src/libs/utils/infobar.cpp
index 554cab1ac1..d3be41e478 100644
--- a/src/libs/utils/infobar.cpp
+++ b/src/libs/utils/infobar.cpp
@@ -34,6 +34,7 @@
#include <QSettings>
#include <QVBoxLayout>
#include <QLabel>
+#include <QPaintEngine>
#include <QToolButton>
#include <QComboBox>
@@ -43,7 +44,38 @@ namespace Utils {
QSet<Id> InfoBar::globallySuppressed;
QSettings *InfoBar::m_settings = nullptr;
-Utils::Theme *InfoBar::m_theme = nullptr;
+
+class InfoBarWidget : public QWidget
+{
+public:
+ InfoBarWidget(Qt::Edge edge, QWidget *parent = nullptr);
+
+protected:
+ void paintEvent(QPaintEvent *event) override;
+
+private:
+ const Qt::Edge m_edge;
+};
+
+InfoBarWidget::InfoBarWidget(Qt::Edge edge, QWidget *parent)
+ : QWidget(parent)
+ , m_edge(edge)
+{
+ const bool topEdge = m_edge == Qt::TopEdge;
+ setContentsMargins(2, topEdge ? 0 : 1, 0, topEdge ? 1 : 0);
+}
+
+void InfoBarWidget::paintEvent(QPaintEvent *event)
+{
+ QWidget::paintEvent(event);
+ QPainter p(this);
+ p.fillRect(rect(), creatorTheme()->color(Theme::InfoBarBackground));
+ const QRectF adjustedRect = QRectF(rect()).adjusted(0.5, 0.5, -0.5, -0.5);
+ const bool topEdge = m_edge == Qt::TopEdge;
+ p.setPen(creatorTheme()->color(Theme::FancyToolBarSeparatorColor));
+ p.drawLine(QLineF(topEdge ? adjustedRect.bottomLeft() : adjustedRect.topLeft(),
+ topEdge ? adjustedRect.bottomRight() : adjustedRect.topRight()));
+}
InfoBarEntry::InfoBarEntry(Id _id, const QString &_infoText, GlobalSuppression _globalSuppression)
: m_id(_id)
@@ -146,10 +178,9 @@ void InfoBar::globallyUnsuppressInfo(Id id)
writeGloballySuppressedToSettings();
}
-void InfoBar::initialize(QSettings *settings, Theme *theme)
+void InfoBar::initialize(QSettings *settings)
{
m_settings = settings;
- m_theme = theme;
if (QTC_GUARD(m_settings)) {
const QStringList list = m_settings->value(QLatin1String(C_SUPPRESSED_WARNINGS)).toStringList();
@@ -204,9 +235,9 @@ void InfoBarDisplay::setInfoBar(InfoBar *infoBar)
update();
}
-void InfoBarDisplay::setStyle(QFrame::Shadow style)
+void InfoBarDisplay::setEdge(Qt::Edge edge)
{
- m_style = style;
+ m_edge = edge;
update();
}
@@ -235,18 +266,7 @@ void InfoBarDisplay::update()
return;
for (const InfoBarEntry &info : m_infoBar->m_infoBarEntries) {
- QFrame *infoWidget = new QFrame;
-
- QPalette pal;
- if (QTC_GUARD(InfoBar::m_theme)) {
- pal.setColor(QPalette::Window, InfoBar::m_theme->color(Theme::InfoBarBackground));
- pal.setColor(QPalette::WindowText, InfoBar::m_theme->color(Theme::InfoBarText));
- }
-
- infoWidget->setPalette(pal);
- infoWidget->setFrameStyle(QFrame::Panel | m_style);
- infoWidget->setLineWidth(1);
- infoWidget->setAutoFillBackground(true);
+ auto infoWidget = new InfoBarWidget(m_edge);
auto hbox = new QHBoxLayout;
hbox->setContentsMargins(2, 2, 2, 2);
diff --git a/src/libs/utils/infobar.h b/src/libs/utils/infobar.h
index 8b7090fb53..2d168ed712 100644
--- a/src/libs/utils/infobar.h
+++ b/src/libs/utils/infobar.h
@@ -100,7 +100,7 @@ public:
static void clearGloballySuppressed();
static bool anyGloballySuppressed();
- static void initialize(QSettings *settings, Theme *theme);
+ static void initialize(QSettings *settings);
signals:
void changed();
@@ -114,7 +114,6 @@ private:
static QSet<Id> globallySuppressed;
static QSettings *m_settings;
- static Theme *m_theme;
friend class InfoBarDisplay;
};
@@ -127,7 +126,7 @@ public:
InfoBarDisplay(QObject *parent = nullptr);
void setTarget(QBoxLayout *layout, int index);
void setInfoBar(InfoBar *infoBar);
- void setStyle(QFrame::Shadow style);
+ void setEdge(Qt::Edge edge);
InfoBar *infoBar() const;
@@ -139,7 +138,7 @@ private:
QList<QWidget *> m_infoWidgets;
InfoBar *m_infoBar = nullptr;
QBoxLayout *m_boxLayout = nullptr;
- QFrame::Shadow m_style = QFrame::Raised;
+ Qt::Edge m_edge = Qt::TopEdge;
int m_boxIndex = 0;
bool m_isShowingDetailsWidget = false;
};
diff --git a/src/libs/utils/theme/theme.h b/src/libs/utils/theme/theme.h
index 21ecc007c5..d0c1f869db 100644
--- a/src/libs/utils/theme/theme.h
+++ b/src/libs/utils/theme/theme.h
@@ -89,7 +89,7 @@ public:
FancyToolButtonSelectedColor,
FutureProgressBackgroundColor,
InfoBarBackground,
- InfoBarText,
+ InfoBarText, // TODO: Deprecate. Unused.
MenuBarEmptyAreaBackgroundColor,
MenuBarItemBackgroundColor,
MenuBarItemTextColorDisabled,
diff --git a/src/plugins/coreplugin/CMakeLists.txt b/src/plugins/coreplugin/CMakeLists.txt
index 6705478bfb..d5e02881f4 100644
--- a/src/plugins/coreplugin/CMakeLists.txt
+++ b/src/plugins/coreplugin/CMakeLists.txt
@@ -102,6 +102,7 @@ add_qtc_plugin(Core
locator/externaltoolsfilter.cpp locator/externaltoolsfilter.h
locator/filesystemfilter.cpp locator/filesystemfilter.h locator/filesystemfilter.ui
locator/ilocatorfilter.cpp locator/ilocatorfilter.h
+ locator/javascriptfilter.cpp locator/javascriptfilter.h
locator/locator.cpp locator/locator.h
locator/locatorconstants.h
locator/locatorfiltersfilter.cpp locator/locatorfiltersfilter.h
@@ -184,14 +185,6 @@ extend_qtc_plugin(Core
SOURCES progressmanager/progressmanager_x11.cpp
)
-extend_qtc_plugin(Core
- CONDITION Qt5_VERSION VERSION_GREATER_EQUAL 5.14.0
- FEATURE_INFO "Script Locator filter"
- DEFINES WITH_JAVASCRIPTFILTER
- SOURCES
- locator/javascriptfilter.cpp locator/javascriptfilter.h
-)
-
if ((NOT WIN32) AND (NOT APPLE))
# install logo
foreach(size 16 24 32 48 64 128 256 512)
diff --git a/src/plugins/coreplugin/coreplugin.cpp b/src/plugins/coreplugin/coreplugin.cpp
index b2a6155077..1b621a9979 100644
--- a/src/plugins/coreplugin/coreplugin.cpp
+++ b/src/plugins/coreplugin/coreplugin.cpp
@@ -150,7 +150,7 @@ bool CorePlugin::initialize(const QStringList &arguments, QString *errorMessage)
Theme *themeFromArg = ThemeEntry::createTheme(args.themeId);
setCreatorTheme(themeFromArg ? themeFromArg
: ThemeEntry::createTheme(ThemeEntry::themeSetting()));
- InfoBar::initialize(ICore::settings(), creatorTheme());
+ InfoBar::initialize(ICore::settings());
new ActionManager(this);
ActionManager::setPresentationModeEnabled(args.presentationMode);
m_mainWindow = new MainWindow;
diff --git a/src/plugins/coreplugin/coreplugin.qbs b/src/plugins/coreplugin/coreplugin.qbs
index aaa05fd5b9..87878791c0 100644
--- a/src/plugins/coreplugin/coreplugin.qbs
+++ b/src/plugins/coreplugin/coreplugin.qbs
@@ -23,11 +23,6 @@ Project {
Depends { name: "app_version_header" }
- Properties {
- condition: Utilities.versionCompare(Qt.qml.version, "5.14.0") >= 0
- cpp.defines: base.concat("WITH_JAVASCRIPTFILTER")
- }
-
cpp.dynamicLibraries: {
if (qbs.targetOS.contains("windows"))
return ["ole32", "user32"]
@@ -351,6 +346,8 @@ Project {
"filesystemfilter.ui",
"ilocatorfilter.cpp",
"ilocatorfilter.h",
+ "javascriptfilter.cpp",
+ "javascriptfilter.h",
"locatorconstants.h",
"locatorfiltersfilter.cpp",
"locatorfiltersfilter.h",
@@ -374,16 +371,6 @@ Project {
}
Group {
- name: "Locator Javascript Filter"
- condition: Utilities.versionCompare(Qt.qml.version, "5.14.0") >= 0
- prefix: "locator/"
- files: [
- "javascriptfilter.cpp",
- "javascriptfilter.h",
- ]
- }
-
- Group {
name: "Locator_mac"
condition: qbs.targetOS.contains("macos")
files: [
diff --git a/src/plugins/coreplugin/fancytabwidget.cpp b/src/plugins/coreplugin/fancytabwidget.cpp
index ea2cc88e4a..cd62339d80 100644
--- a/src/plugins/coreplugin/fancytabwidget.cpp
+++ b/src/plugins/coreplugin/fancytabwidget.cpp
@@ -519,7 +519,7 @@ FancyTabWidget::FancyTabWidget(QWidget *parent)
vlayout->addWidget(m_statusBar);
m_infoBarDisplay.setTarget(vlayout, 1);
- m_infoBarDisplay.setStyle(QFrame::Sunken);
+ m_infoBarDisplay.setEdge(Qt::BottomEdge);
auto mainLayout = new QHBoxLayout;
mainLayout->setContentsMargins(0, 0, 0, 0);
diff --git a/src/plugins/coreplugin/locator/locator.cpp b/src/plugins/coreplugin/locator/locator.cpp
index e7b3f05859..ea79a27dc2 100644
--- a/src/plugins/coreplugin/locator/locator.cpp
+++ b/src/plugins/coreplugin/locator/locator.cpp
@@ -81,9 +81,7 @@ public:
LocatorManager m_locatorManager;
LocatorSettingsPage m_locatorSettingsPage;
-#ifdef WITH_JAVASCRIPTFILTER
JavaScriptFilter m_javaScriptFilter;
-#endif
OpenDocumentsFilter m_openDocumentsFilter;
FileSystemFilter m_fileSystemFilter;
ExecuteFilter m_executeFilter;
diff --git a/src/plugins/coreplugin/locator/locator.pri b/src/plugins/coreplugin/locator/locator.pri
index ae5cf6e440..fea0082722 100644
--- a/src/plugins/coreplugin/locator/locator.pri
+++ b/src/plugins/coreplugin/locator/locator.pri
@@ -16,7 +16,8 @@ HEADERS += \
$$PWD/locatorsearchutils.h \
$$PWD/locatorsettingspage.h \
$$PWD/urllocatorfilter.h \
- $$PWD/externaltoolsfilter.h
+ $$PWD/externaltoolsfilter.h \
+ $$PWD/javascriptfilter.h
SOURCES += \
$$PWD/locator.cpp \
@@ -33,22 +34,11 @@ SOURCES += \
$$PWD/locatorsearchutils.cpp \
$$PWD/locatorsettingspage.cpp \
$$PWD/urllocatorfilter.cpp \
- $$PWD/externaltoolsfilter.cpp
-
-FORMS += \
- $$PWD/urllocatorfilter.ui
-
-minQtVersion(5, 14, 0) {
- DEFINES += WITH_JAVASCRIPTFILTER
-
- HEADERS += \
- $$PWD/javascriptfilter.h
-
- SOURCES += \
- $$PWD/javascriptfilter.cpp
-}
+ $$PWD/externaltoolsfilter.cpp \
+ $$PWD/javascriptfilter.cpp
FORMS += \
+ $$PWD/urllocatorfilter.ui \
$$PWD/filesystemfilter.ui \
$$PWD/directoryfilter.ui \
$$PWD/locatorsettingspage.ui
diff --git a/src/plugins/cppeditor/CMakeLists.txt b/src/plugins/cppeditor/CMakeLists.txt
index d2a55ca8cf..c038c8314d 100644
--- a/src/plugins/cppeditor/CMakeLists.txt
+++ b/src/plugins/cppeditor/CMakeLists.txt
@@ -25,10 +25,19 @@ add_qtc_plugin(CppEditor
cppquickfix.cpp cppquickfix.h
cppquickfixassistant.cpp cppquickfixassistant.h
cppquickfixes.cpp cppquickfixes.h
+ cppquickfixprojectsettings.cpp cppquickfixprojectsettings.h
+ cppquickfixprojectsettingswidget.cpp cppquickfixprojectsettingswidget.h
+ cppquickfixprojectsettingswidget.ui
+ cppquickfixsettings.cpp cppquickfixsettings.h
+ cppquickfixsettingspage.cpp cppquickfixsettingspage.h
+ cppquickfixsettingswidget.cpp cppquickfixsettingswidget.h cppquickfixsettingswidget.ui
cpptypehierarchy.cpp cpptypehierarchy.h
cppuseselectionsupdater.cpp cppuseselectionsupdater.h
resourcepreviewhoverhandler.cpp resourcepreviewhoverhandler.h
- EXPLICIT_MOC cppeditor.h
+ EXPLICIT_MOC
+ cppeditor.h
+ cppquickfixsettingswidget.h
+ cppquickfixprojectsettingswidget.h
)
extend_qtc_plugin(CppEditor
diff --git a/src/plugins/cppeditor/cppeditor.pro b/src/plugins/cppeditor/cppeditor.pro
index 74b1daf63b..e0659bc9be 100644
--- a/src/plugins/cppeditor/cppeditor.pro
+++ b/src/plugins/cppeditor/cppeditor.pro
@@ -24,6 +24,11 @@ HEADERS += \
cppquickfix.h \
cppquickfixassistant.h \
cppquickfixes.h \
+ cppquickfixprojectsettings.h \
+ cppquickfixprojectsettingswidget.h \
+ cppquickfixsettings.h \
+ cppquickfixsettingspage.h \
+ cppquickfixsettingswidget.h \
cpptypehierarchy.h \
cppuseselectionsupdater.h \
resourcepreviewhoverhandler.h
@@ -48,13 +53,20 @@ SOURCES += \
cppquickfix.cpp \
cppquickfixassistant.cpp \
cppquickfixes.cpp \
+ cppquickfixprojectsettings.cpp \
+ cppquickfixprojectsettingswidget.cpp \
+ cppquickfixsettings.cpp \
+ cppquickfixsettingspage.cpp \
+ cppquickfixsettingswidget.cpp \
cpptypehierarchy.cpp \
cppuseselectionsupdater.cpp \
resourcepreviewhoverhandler.cpp
FORMS += \
cpppreprocessordialog.ui \
- cppcodemodelinspectordialog.ui
+ cppcodemodelinspectordialog.ui \
+ cppquickfixprojectsettingswidget.ui \
+ cppquickfixsettingswidget.ui
RESOURCES += \
cppeditor.qrc
diff --git a/src/plugins/cppeditor/cppeditor.qbs b/src/plugins/cppeditor/cppeditor.qbs
index 5a44f175eb..de9b4d3101 100644
--- a/src/plugins/cppeditor/cppeditor.qbs
+++ b/src/plugins/cppeditor/cppeditor.qbs
@@ -64,6 +64,18 @@ QtcPlugin {
"cppquickfixassistant.h",
"cppquickfixes.cpp",
"cppquickfixes.h",
+ "cppquickfixprojectsettings.cpp",
+ "cppquickfixprojectsettings.h",
+ "cppquickfixprojectsettingswidget.cpp",
+ "cppquickfixprojectsettingswidget.h",
+ "cppquickfixprojectsettingswidget.ui",
+ "cppquickfixsettings.cpp",
+ "cppquickfixsettings.h",
+ "cppquickfixsettingspage.cpp",
+ "cppquickfixsettingspage.h",
+ "cppquickfixsettingswidget.cpp",
+ "cppquickfixsettingswidget.h",
+ "cppquickfixsettingswidget.ui",
"cpptypehierarchy.cpp",
"cpptypehierarchy.h",
"cppuseselectionsupdater.cpp",
diff --git a/src/plugins/cppeditor/cppeditorconstants.h b/src/plugins/cppeditor/cppeditorconstants.h
index d1fb5f1706..a22442d897 100644
--- a/src/plugins/cppeditor/cppeditorconstants.h
+++ b/src/plugins/cppeditor/cppeditorconstants.h
@@ -53,5 +53,30 @@ const char CPP_SNIPPETS_GROUP_ID[] = "C++";
const char EXTRA_PREPROCESSOR_DIRECTIVES[] = "CppEditor.ExtraPreprocessorDirectives-";
const char PREFERRED_PARSE_CONTEXT[] = "CppEditor.PreferredParseContext-";
+const char QUICK_FIX_PROJECT_PANEL_ID[] = "CppEditor.QuickFix";
+const char QUICK_FIX_SETTINGS_ID[] = "CppEditor.QuickFix";
+const char QUICK_FIX_SETTINGS_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("CppTools", "Quick Fixes");
+const char QUICK_FIX_SETTING_GETTER_OUTSIDE_CLASS_FROM[] = "GettersOutsideClassFrom";
+const char QUICK_FIX_SETTING_GETTER_IN_CPP_FILE_FROM[] = "GettersInCppFileFrom";
+const char QUICK_FIX_SETTING_SETTER_OUTSIDE_CLASS_FROM[] = "SettersOutsideClassFrom";
+const char QUICK_FIX_SETTING_SETTER_IN_CPP_FILE_FROM[] = "SettersInCppFileFrom";
+const char QUICK_FIX_SETTING_GETTER_ATTRIBUTES[] = "GetterAttributes";
+const char QUICK_FIX_SETTING_GETTER_NAME_TEMPLATE[] = "GetterNameTemplate";
+const char QUICK_FIX_SETTING_SETTER_NAME_TEMPLATE[] = "SetterNameTemplate";
+const char QUICK_FIX_SETTING_SIGNAL_NAME_TEMPLATE[] = "SignalNameTemplate";
+const char QUICK_FIX_SETTING_RESET_NAME_TEMPLATE[] = "ResetNameTemplate";
+const char QUICK_FIX_SETTING_SIGNAL_WITH_NEW_VALUE[] = "SignalWithNewValue";
+const char QUICK_FIX_SETTING_SETTER_AS_SLOT[] = "SetterAsSlot";
+const char QUICK_FIX_SETTING_SETTER_PARAMETER_NAME[] = "SetterParameterName";
+const char QUICK_FIX_SETTING_CPP_FILE_NAMESPACE_HANDLING[] = "CppFileNamespaceHandling";
+const char QUICK_FIX_SETTING_MEMBER_VARIABEL_NAME_TEMPLATE[] = "MemberVariableNameTemplate";
+const char QUICK_FIX_SETTING_VALUE_TYPES[] = "ValueTypes";
+const char QUICK_FIX_SETTING_CUSTOM_TEMPLATES[] = "CustomTemplate";
+const char QUICK_FIX_SETTING_CUSTOM_TEMPLATE_TYPES[] = "Types";
+const char QUICK_FIX_SETTING_CUSTOM_TEMPLATE_COMPARISON[] = "Comparison";
+const char QUICK_FIX_SETTING_CUSTOM_TEMPLATE_RETURN_TYPE[] = "ReturnType";
+const char QUICK_FIX_SETTING_CUSTOM_TEMPLATE_RETURN_EXPRESSION[] = "ReturnExpression";
+const char QUICK_FIX_SETTING_CUSTOM_TEMPLATE_ASSIGNMENT[] = "Assignment";
+
} // namespace Constants
} // namespace CppEditor
diff --git a/src/plugins/cppeditor/cppeditorplugin.cpp b/src/plugins/cppeditor/cppeditorplugin.cpp
index 3cbdd9d6be..7d8ac56154 100644
--- a/src/plugins/cppeditor/cppeditorplugin.cpp
+++ b/src/plugins/cppeditor/cppeditorplugin.cpp
@@ -29,13 +29,15 @@
#include "cppcodemodelinspectordialog.h"
#include "cppeditor.h"
#include "cppeditorconstants.h"
-#include "cppeditorwidget.h"
#include "cppeditordocument.h"
+#include "cppeditorwidget.h"
#include "cpphighlighter.h"
#include "cppincludehierarchy.h"
#include "cppoutline.h"
#include "cppquickfixassistant.h"
#include "cppquickfixes.h"
+#include "cppquickfixprojectsettingswidget.h"
+#include "cppquickfixsettingspage.h"
#include "cpptypehierarchy.h"
#include "resourcepreviewhoverhandler.h"
@@ -56,10 +58,11 @@
#include <coreplugin/progressmanager/progressmanager.h>
#include <cpptools/cpphoverhandler.h>
#include <cpptools/cpptoolsconstants.h>
-#include <texteditor/texteditoractionhandler.h>
-#include <texteditor/texteditorconstants.h>
+#include <projectexplorer/projectpanelfactory.h>
#include <texteditor/colorpreviewhoverhandler.h>
#include <texteditor/snippets/snippetprovider.h>
+#include <texteditor/texteditoractionhandler.h>
+#include <texteditor/texteditorconstants.h>
#include <utils/hostosinfo.h>
#include <utils/mimetypes/mimedatabase.h>
@@ -124,6 +127,7 @@ public:
QAction *m_openIncludeHierarchyAction = nullptr;
CppQuickFixAssistProvider m_quickFixProvider;
+ CppQuickFixSettingsPage m_quickFixSettingsPage;
QPointer<CppCodeModelInspectorDialog> m_cppCodeModelInspectorDialog;
@@ -164,6 +168,16 @@ bool CppEditorPlugin::initialize(const QStringList & /*arguments*/, QString *err
{
Q_UNUSED(errorMessage)
+ auto panelFactory = new ProjectExplorer::ProjectPanelFactory;
+ panelFactory->setPriority(100);
+ panelFactory->setId(Constants::QUICK_FIX_PROJECT_PANEL_ID);
+ panelFactory->setDisplayName(
+ QCoreApplication::translate("CppTools", Constants::QUICK_FIX_SETTINGS_DISPLAY_NAME));
+ panelFactory->setCreateWidgetFunction([](ProjectExplorer::Project *project) {
+ return new CppQuickFixProjectSettingsWidget(project);
+ });
+ ProjectExplorer::ProjectPanelFactory::registerFactory(panelFactory);
+
d = new CppEditorPluginPrivate;
SnippetProvider::registerGroup(Constants::CPP_SNIPPETS_GROUP_ID, tr("C++", "SnippetProvider"),
diff --git a/src/plugins/cppeditor/cppeditorplugin.h b/src/plugins/cppeditor/cppeditorplugin.h
index 869bc68bb5..a68c2edf72 100644
--- a/src/plugins/cppeditor/cppeditorplugin.h
+++ b/src/plugins/cppeditor/cppeditorplugin.h
@@ -103,19 +103,32 @@ private slots:
void test_quickfix_data();
void test_quickfix();
- void test_quickfix_GenerateGetterSetter_basicGetterWithPrefixAndNamespaceToCpp();
- void test_quickfix_GenerateGetterSetter_createNamespaceInCpp_data();
- void test_quickfix_GenerateGetterSetter_createNamespaceInCpp();
+ void test_quickfix_GenerateGetterSetter_namespaceHandlingCreate_data();
+ void test_quickfix_GenerateGetterSetter_namespaceHandlingCreate();
+ void test_quickfix_GenerateGetterSetter_namespaceHandlingAddUsing_data();
+ void test_quickfix_GenerateGetterSetter_namespaceHandlingAddUsing();
+ void test_quickfix_GenerateGetterSetter_namespaceHandlingFullyQualify_data();
+ void test_quickfix_GenerateGetterSetter_namespaceHandlingFullyQualify();
+ void test_quickfix_GenerateGetterSetter_customNames_data();
+ void test_quickfix_GenerateGetterSetter_customNames();
+ void test_quickfix_GenerateGetterSetter_valueTypes_data();
+ void test_quickfix_GenerateGetterSetter_valueTypes();
+ void test_quickfix_GenerateGetterSetter_customTemplate();
+ void test_quickfix_GenerateGetterSetter_needThis();
+ void test_quickfix_GenerateGetterSetter_offeredFixes_data();
+ void test_quickfix_GenerateGetterSetter_offeredFixes();
+ void test_quickfix_GenerateGetterSetter_generalTests_data();
+ void test_quickfix_GenerateGetterSetter_generalTests();
void test_quickfix_GenerateGetterSetter_onlyGetter();
- void test_quickfix_GenerateGetterSetter_onlyGetter_DontPreferGetterWithGet();
void test_quickfix_GenerateGetterSetter_onlySetter();
- void test_quickfix_GenerateGetterSetter_onlySetterHeaderFile();
+ void test_quickfix_GenerateGetterSetter_inlineInHeaderFile();
void test_quickfix_GenerateGetterSetter_onlySetterHeaderFileWithIncludeGuard();
- void test_quickfix_GenerateGetterSetter_offerGetterWhenSetterPresent();
- void test_quickfix_GenerateGetterSetter_offerSetterWhenGetterPresent();
void test_quickfix_GenerateGettersSetters_data();
void test_quickfix_GenerateGettersSetters();
+ void test_quickfix_InsertQtPropertyMembers_data();
+ void test_quickfix_InsertQtPropertyMembers();
+
void test_quickfix_InsertMemberFromInitialization_data();
void test_quickfix_InsertMemberFromInitialization();
diff --git a/src/plugins/cppeditor/cppquickfix_test.cpp b/src/plugins/cppeditor/cppquickfix_test.cpp
index 1dbfeafedf..c362ff1ee0 100644
--- a/src/plugins/cppeditor/cppquickfix_test.cpp
+++ b/src/plugins/cppeditor/cppquickfix_test.cpp
@@ -23,13 +23,14 @@
**
****************************************************************************/
+#include "cppquickfix_test.h"
#include "cppeditor.h"
-#include "cppeditorwidget.h"
#include "cppeditorplugin.h"
#include "cppeditortestcase.h"
+#include "cppeditorwidget.h"
#include "cppquickfixassistant.h"
#include "cppquickfixes.h"
-#include "cppquickfix_test.h"
+#include "cppquickfixsettings.h"
#include <cpptools/cppcodestylepreferences.h>
#include <cpptools/cppmodelmanager.h>
@@ -341,6 +342,15 @@ typedef QSharedPointer<CppQuickFixFactory> CppQuickFixFactoryPtr;
namespace CppEditor {
namespace Internal {
+class QuickFixSettings
+{
+ const CppQuickFixSettings original = *CppQuickFixSettings::instance();
+
+public:
+ CppQuickFixSettings *operator->() { return CppQuickFixSettings::instance(); }
+ ~QuickFixSettings() { *CppQuickFixSettings::instance() = original; }
+};
+
void CppEditorPlugin::test_quickfix_data()
{
QTest::addColumn<CppQuickFixFactoryPtr>("factory");
@@ -622,405 +632,7 @@ void CppEditorPlugin::test_quickfix_data()
"}\n"
);
- // Checks:
- // 1. If the name does not start with ("m_" or "_") and does not
- // end with "_", we are forced to prefix the getter with "get".
- // 2. Setter: Use pass by value on integer/float and pointer types.
- QTest::newRow("GenerateGetterSetter_basicGetterWithPrefix")
- << CppQuickFixFactoryPtr(new GenerateGetterSetter) << _(
- "\n"
- "class Something\n"
- "{\n"
- " int @it;\n"
- "};\n"
- ) << _(
- "\n"
- "class Something\n"
- "{\n"
- " int it;\n"
- "\n"
- "public:\n"
- " int getIt() const;\n"
- " void setIt(int value);\n"
- "};\n"
- "\n"
- "int Something::getIt() const\n"
- "{\n"
- " return it;\n"
- "}\n"
- "\n"
- "void Something::setIt(int value)\n"
- "{\n"
- " it = value;\n"
- "}\n"
- );
-
- // Checks: In addition to test_quickfix_GenerateGetterSetter_basicGetterWithPrefix
- // generated definitions should fit in the namespace.
- QTest::newRow("GenerateGetterSetter_basicGetterWithPrefixAndNamespace")
- << CppQuickFixFactoryPtr(new GenerateGetterSetter) << _(
- "namespace SomeNamespace {\n"
- "class Something\n"
- "{\n"
- " int @it;\n"
- "};\n"
- "}\n"
- ) << _(
- "namespace SomeNamespace {\n"
- "class Something\n"
- "{\n"
- " int it;\n"
- "\n"
- "public:\n"
- " int getIt() const;\n"
- " void setIt(int value);\n"
- "};\n"
- "\n"
- "int Something::getIt() const\n"
- "{\n"
- " return it;\n"
- "}\n"
- "\n"
- "void Something::setIt(int value)\n"
- "{\n"
- " it = value;\n"
- "}\n"
- "\n"
- "}\n"
- );
-
- // Checks:
- // 1. Getter: "get" prefix is not necessary.
- // 2. Setter: Parameter name is base name.
- QTest::newRow("GenerateGetterSetter_basicGetterWithoutPrefix")
- << CppQuickFixFactoryPtr(new GenerateGetterSetter) << _(
- "\n"
- "class Something\n"
- "{\n"
- " int @m_it;\n"
- "};\n"
- ) << _(
- "\n"
- "class Something\n"
- "{\n"
- " int m_it;\n"
- "\n"
- "public:\n"
- " int it() const;\n"
- " void setIt(int it);\n"
- "};\n"
- "\n"
- "int Something::it() const\n"
- "{\n"
- " return m_it;\n"
- "}\n"
- "\n"
- "void Something::setIt(int it)\n"
- "{\n"
- " m_it = it;\n"
- "}\n"
- );
-
- // Checks if getter uses 'get' prefix if member function with such a prefix is found
- QTest::newRow("GenerateGetterSetter_getterWithGetPrefix")
- << CppQuickFixFactoryPtr(new GenerateGetterSetter) << _(
- "\n"
- "class Something\n"
- "{\n"
- " int getFoo();\n"
- " int @m_it;\n"
- "};\n"
- ) << _(
- "\n"
- "class Something\n"
- "{\n"
- " int getFoo();\n"
- " int m_it;\n"
- "\n"
- "public:\n"
- " int getIt() const;\n"
- " void setIt(int it);\n"
- "};\n"
- "\n"
- "int Something::getIt() const\n"
- "{\n"
- " return m_it;\n"
- "}\n"
- "\n"
- "void Something::setIt(int it)\n"
- "{\n"
- " m_it = it;\n"
- "}\n"
- );
-
- // Check: Setter: Use pass by reference for parameters which
- // are not integer, float or pointers.
- QTest::newRow("GenerateGetterSetter_customType")
- << CppQuickFixFactoryPtr(new GenerateGetterSetter) << _(
- "\n"
- "class Something\n"
- "{\n"
- " MyType @it;\n"
- "};\n"
- ) << _(
- "\n"
- "class Something\n"
- "{\n"
- " MyType it;\n"
- "\n"
- "public:\n"
- " MyType getIt() const;\n"
- " void setIt(const MyType &value);\n"
- "};\n"
- "\n"
- "MyType Something::getIt() const\n"
- "{\n"
- " return it;\n"
- "}\n"
- "\n"
- "void Something::setIt(const MyType &value)\n"
- "{\n"
- " it = value;\n"
- "}\n"
- );
-
- // Checks:
- // 1. Setter: No setter is generated for const members.
- // 2. Getter: Return a non-const type since it pass by value anyway.
- QTest::newRow("GenerateGetterSetter_constMember")
- << CppQuickFixFactoryPtr(new GenerateGetterSetter) << _(
- "\n"
- "class Something\n"
- "{\n"
- " const int @it;\n"
- "};\n"
- ) << _(
- "\n"
- "class Something\n"
- "{\n"
- " const int it;\n"
- "\n"
- "public:\n"
- " int getIt() const;\n"
- "};\n"
- "\n"
- "int Something::getIt() const\n"
- "{\n"
- " return it;\n"
- "}\n"
- );
-
- // Checks: No special treatment for pointer to non const.
- QTest::newRow("GenerateGetterSetter_pointerToNonConst")
- << CppQuickFixFactoryPtr(new GenerateGetterSetter) << _(
- "\n"
- "class Something\n"
- "{\n"
- " int *it@;\n"
- "};\n"
- ) << _(
- "\n"
- "class Something\n"
- "{\n"
- " int *it;\n"
- "\n"
- "public:\n"
- " int *getIt() const;\n"
- " void setIt(int *value);\n"
- "};\n"
- "\n"
- "int *Something::getIt() const\n"
- "{\n"
- " return it;\n"
- "}\n"
- "\n"
- "void Something::setIt(int *value)\n"
- "{\n"
- " it = value;\n"
- "}\n"
- );
-
- // Checks: No special treatment for pointer to const.
- QTest::newRow("GenerateGetterSetter_pointerToConst")
- << CppQuickFixFactoryPtr(new GenerateGetterSetter) << _(
- "\n"
- "class Something\n"
- "{\n"
- " const int *it@;\n"
- "};\n"
- ) << _(
- "\n"
- "class Something\n"
- "{\n"
- " const int *it;\n"
- "\n"
- "public:\n"
- " const int *getIt() const;\n"
- " void setIt(const int *value);\n"
- "};\n"
- "\n"
- "const int *Something::getIt() const\n"
- "{\n"
- " return it;\n"
- "}\n"
- "\n"
- "void Something::setIt(const int *value)\n"
- "{\n"
- " it = value;\n"
- "}\n"
- );
-
// Checks: No special treatment for reference to non const.
- QTest::newRow("GenerateGetterSetter_referenceToNonConst")
- << CppQuickFixFactoryPtr(new GenerateGetterSetter) << _(
- "\n"
- "class Something\n"
- "{\n"
- " int &it@;\n"
- "};\n"
- ) << _(
- "\n"
- "class Something\n"
- "{\n"
- " int &it;\n"
- "\n"
- "public:\n"
- " int &getIt() const;\n"
- " void setIt(const int &value);\n"
- "};\n"
- "\n"
- "int &Something::getIt() const\n"
- "{\n"
- " return it;\n"
- "}\n"
- "\n"
- "void Something::setIt(const int &value)\n"
- "{\n"
- " it = value;\n"
- "}\n"
- );
-
- // Checks: No special treatment for reference to const.
- QTest::newRow("GenerateGetterSetter_referenceToConst")
- << CppQuickFixFactoryPtr(new GenerateGetterSetter) << _(
- "\n"
- "class Something\n"
- "{\n"
- " const int &it@;\n"
- "};\n"
- ) << _(
- "\n"
- "class Something\n"
- "{\n"
- " const int &it;\n"
- "\n"
- "public:\n"
- " const int &getIt() const;\n"
- " void setIt(const int &value);\n"
- "};\n"
- "\n"
- "const int &Something::getIt() const\n"
- "{\n"
- " return it;\n"
- "}\n"
- "\n"
- "void Something::setIt(const int &value)\n"
- "{\n"
- " it = value;\n"
- "}\n"
- );
-
- // Checks:
- // 1. Setter: Setter is a static function.
- // 2. Getter: Getter is a static, non const function.
- QTest::newRow("GenerateGetterSetter_staticMember")
- << CppQuickFixFactoryPtr(new GenerateGetterSetter) << _(
- "\n"
- "class Something\n"
- "{\n"
- " static int @m_member;\n"
- "};\n"
- ) << _(
- "\n"
- "class Something\n"
- "{\n"
- " static int m_member;\n"
- "\n"
- "public:\n"
- " static int member();\n"
- " static void setMember(int member);\n"
- "};\n"
- "\n"
- "int Something::member()\n"
- "{\n"
- " return m_member;\n"
- "}\n"
- "\n"
- "void Something::setMember(int member)\n"
- "{\n"
- " m_member = member;\n"
- "}\n"
- );
-
- // Check: Check if it works on the second declarator
- QTest::newRow("GenerateGetterSetter_secondDeclarator")
- << CppQuickFixFactoryPtr(new GenerateGetterSetter) << _(
- "\n"
- "class Something\n"
- "{\n"
- " int *foo, @it;\n"
- "};\n"
- ) << _(
- "\n"
- "class Something\n"
- "{\n"
- " int *foo, it;\n"
- "\n"
- "public:\n"
- " int getIt() const;\n"
- " void setIt(int value);\n"
- "};\n"
- "\n"
- "int Something::getIt() const\n"
- "{\n"
- " return it;\n"
- "}\n"
- "\n"
- "void Something::setIt(int value)\n"
- "{\n"
- " it = value;\n"
- "}\n"
- );
-
- // Check: Quick fix is offered for "int *@it;" ('@' denotes the text cursor position)
- QTest::newRow("GenerateGetterSetter_triggeringRightAfterPointerSign")
- << CppQuickFixFactoryPtr(new GenerateGetterSetter) << _(
- "\n"
- "class Something\n"
- "{\n"
- " int *@it;\n"
- "};\n"
- ) << _(
- "\n"
- "class Something\n"
- "{\n"
- " int *it;\n"
- "\n"
- "public:\n"
- " int *getIt() const;\n"
- " void setIt(int *value);\n"
- "};\n"
- "\n"
- "int *Something::getIt() const\n"
- "{\n"
- " return it;\n"
- "}\n"
- "\n"
- "void Something::setIt(int *value)\n"
- "{\n"
- " it = value;\n"
- "}\n"
- );
// Check: Quick fix is not triggered on a member function.
QTest::newRow("GenerateGetterSetter_notTriggeringOnMemberFunction")
@@ -1032,119 +644,6 @@ void CppEditorPlugin::test_quickfix_data()
<< CppQuickFixFactoryPtr(new GenerateGetterSetter)
<< _("class Something { void @a[10]; };\n") << _();
- // Check: Do not offer the quick fix if there is a getter and the variable is const
- QTest::newRow("GenerateGetterSetter_notTriggeringWhenGetterAndConstVariable")
- << CppQuickFixFactoryPtr(new GenerateGetterSetter) << _(
- "class Foo\n"
- "{\n"
- "public:\n"
- " const int bar@;\n"
- " int getBar() const;\n"
- "};\n"
- ) << _();
-
- // Check: Do not offer the quick fix if there is a getter and a setter
- QTest::newRow("GenerateGetterSetter_notTriggeringWhenGetterAndConstVariable")
- << CppQuickFixFactoryPtr(new GenerateGetterSetter) << _(
- "class Foo\n"
- "{\n"
- "public:\n"
- " const int bar@;\n"
- " int getBar() const;\n"
- " void setBar(int value);\n"
- "};\n"
- ) << _();
-
- // Checks if "m_" is recognized as "m" with the postfix "_" and not simply as "m_" prefix.
- QTest::newRow("GenerateGetterSetter_recognizeMasVariableName")
- << CppQuickFixFactoryPtr(new GenerateGetterSetter) << _(
- "\n"
- "class Something\n"
- "{\n"
- " int @m_;\n"
- "};\n"
- ) << _(
- "\n"
- "class Something\n"
- "{\n"
- " int m_;\n"
- "\n"
- "public:\n"
- " int m() const;\n"
- " void setM(int m);\n"
- "};\n"
- "\n"
- "int Something::m() const\n"
- "{\n"
- " return m_;\n"
- "}\n"
- "\n"
- "void Something::setM(int m)\n"
- "{\n"
- " m_ = m;\n"
- "}\n"
- );
-
- // Checks if "m" followed by an upper character is recognized as a prefix
- QTest::newRow("GenerateGetterSetter_recognizeMFollowedByCapital")
- << CppQuickFixFactoryPtr(new GenerateGetterSetter) << _(
- "\n"
- "class Something\n"
- "{\n"
- " int @mFoo;\n"
- "};\n"
- ) << _(
- "\n"
- "class Something\n"
- "{\n"
- " int mFoo;\n"
- "\n"
- "public:\n"
- " int foo() const;\n"
- " void setFoo(int foo);\n"
- "};\n"
- "\n"
- "int Something::foo() const\n"
- "{\n"
- " return mFoo;\n"
- "}\n"
- "\n"
- "void Something::setFoo(int foo)\n"
- "{\n"
- " mFoo = foo;\n"
- "}\n"
- );
-
- // Checks if the declaration inside Q_PROPERTY macro is ignored and a getter created
- QTest::newRow("GenerateGetterSetter_ignoreQPropertiesMacro")
- << CppQuickFixFactoryPtr(new GenerateGetterSetter) << _(
- "class Something\n"
- "{\n"
- " Q_PROPERTY(int foo)\n"
- " int @m_foo;\n"
- "};\n"
- ) << _(
- "class Something\n"
- "{\n"
- " Q_PROPERTY(int foo)\n"
- " int m_foo;\n"
- "\n"
- "public:\n"
- " int foo() const;\n"
- " void setFoo(int foo);\n"
- "};\n"
- "\n"
- "int Something::foo() const\n"
- "{\n"
- " return m_foo;\n"
- "}\n"
- "\n"
- "void Something::setFoo(int foo)\n"
- "{\n"
- " m_foo = foo;\n"
- "}\n"
- );
-
QTest::newRow("MoveDeclarationOutOfIf_ifOnly")
<< CppQuickFixFactoryPtr(new MoveDeclarationOutOfIf) << _(
"void f()\n"
@@ -1579,138 +1078,6 @@ void CppEditorPlugin::test_quickfix_data()
<< _("void foo() {fo@r (int i = 0; i < -3; ++i) {}}\n")
<< _();
- QTest::newRow("InsertQtPropertyMembers")
- << CppQuickFixFactoryPtr(new InsertQtPropertyMembers)
- << _("struct XmarksTheSpot {\n"
- " @Q_PROPERTY(int it READ getIt WRITE setIt RESET resetIt NOTIFY itChanged)\n"
- "};\n"
- )
- << _("struct XmarksTheSpot {\n"
- " Q_PROPERTY(int it READ getIt WRITE setIt RESET resetIt NOTIFY itChanged)\n"
- "\n"
- "public:\n"
- " int getIt() const\n"
- " {\n"
- " return m_it;\n"
- " }\n"
- "\n"
- "public slots:\n"
- " void setIt(int it)\n"
- " {\n"
- " if (m_it == it)\n"
- " return;\n"
- "\n"
- " m_it = it;\n"
- " emit itChanged(m_it);\n"
- " }\n"
- " void resetIt()\n"
- " {\n"
- " setIt({}); // TODO: Adapt to use your actual default value\n"
- " }\n"
- "\n"
- "signals:\n"
- " void itChanged(int it);\n"
- "\n"
- "private:\n"
- " int m_it;\n"
- "};\n"
- );
-
- QTest::newRow("InsertQtPropertyMembersResetWithoutSet")
- << CppQuickFixFactoryPtr(new InsertQtPropertyMembers)
- << _("struct XmarksTheSpot {\n"
- " @Q_PROPERTY(int it READ getIt RESET resetIt NOTIFY itChanged)\n"
- "};\n"
- )
- << _("struct XmarksTheSpot {\n"
- " Q_PROPERTY(int it READ getIt RESET resetIt NOTIFY itChanged)\n"
- "\n"
- "public:\n"
- " int getIt() const\n"
- " {\n"
- " return m_it;\n"
- " }\n"
- "\n"
- "public slots:\n"
- " void resetIt()\n"
- " {\n"
- " static const int defaultValue{}; // TODO: Adapt to use your actual default value\n"
- " if (m_it == defaultValue)\n"
- " return;\n"
- "\n"
- " m_it = defaultValue;\n"
- " emit itChanged(m_it);\n"
- " }\n"
- "\n"
- "signals:\n"
- " void itChanged(int it);\n"
- "\n"
- "private:\n"
- " int m_it;\n"
- "};\n"
- );
-
- QTest::newRow("InsertQtPropertyMembersResetWithoutSetAndNotify")
- << CppQuickFixFactoryPtr(new InsertQtPropertyMembers)
- << _("struct XmarksTheSpot {\n"
- " @Q_PROPERTY(int it READ getIt RESET resetIt)\n"
- "};\n"
- )
- << _("struct XmarksTheSpot {\n"
- " Q_PROPERTY(int it READ getIt RESET resetIt)\n"
- "\n"
- "public:\n"
- " int getIt() const\n"
- " {\n"
- " return m_it;\n"
- " }\n"
- "\n"
- "public slots:\n"
- " void resetIt()\n"
- " {\n"
- " static const int defaultValue{}; // TODO: Adapt to use your actual default value\n"
- " m_it = defaultValue;\n"
- " }\n"
- "\n"
- "private:\n"
- " int m_it;\n"
- "};\n"
- );
-
- QTest::newRow("InsertQtPropertyMembersPrivateBeforePublic")
- << CppQuickFixFactoryPtr(new InsertQtPropertyMembers)
- << _("class XmarksTheSpot {\n"
- "private:\n"
- " @Q_PROPERTY(int it READ getIt WRITE setIt NOTIFY itChanged)\n"
- "public:\n"
- " void find();\n"
- "};\n"
- )
- << _("class XmarksTheSpot {\n"
- "private:\n"
- " Q_PROPERTY(int it READ getIt WRITE setIt NOTIFY itChanged)\n"
- " int m_it;\n"
- "\n"
- "public:\n"
- " void find();\n"
- " int getIt() const\n"
- " {\n"
- " return m_it;\n"
- " }\n"
- "public slots:\n"
- " void setIt(int it)\n"
- " {\n"
- " if (m_it == it)\n"
- " return;\n"
- "\n"
- " m_it = it;\n"
- " emit itChanged(m_it);\n"
- " }\n"
- "signals:\n"
- " void itChanged(int it);\n"
- "};\n"
- );
-
// Escape String Literal as UTF-8 (no-trigger)
QTest::newRow("EscapeStringLiteral_notrigger")
<< CppQuickFixFactoryPtr(new EscapeStringLiteral)
@@ -2091,62 +1458,7 @@ void CppEditorPlugin::test_quickfix()
QuickFixOperationTest(singleDocument(original, expected), factory.data());
}
-/// Checks: In addition to test_quickfix_GenerateGetterSetter_basicGetterWithPrefix
-/// generated definitions should fit in the namespace.
-void CppEditorPlugin::test_quickfix_GenerateGetterSetter_basicGetterWithPrefixAndNamespaceToCpp()
-{
- QList<QuickFixTestDocument::Ptr> testDocuments;
- QByteArray original;
- QByteArray expected;
-
- // Header File
- original =
- "namespace SomeNamespace {\n"
- "class Something\n"
- "{\n"
- " int @it;\n"
- "};\n"
- "}\n";
- expected =
- "namespace SomeNamespace {\n"
- "class Something\n"
- "{\n"
- " int it;\n"
- "\n"
- "public:\n"
- " int getIt() const;\n"
- " void setIt(int value);\n"
- "};\n"
- "}\n";
- testDocuments << QuickFixTestDocument::create("file.h", original, expected);
-
- // Source File
- original =
- "#include \"file.h\"\n"
- "namespace SomeNamespace {\n"
- "}\n";
- expected =
- "#include \"file.h\"\n"
- "namespace SomeNamespace {\n"
- "\n"
- "int Something::getIt() const\n"
- "{\n"
- " return it;\n"
- "}\n"
- "\n"
- "void Something::setIt(int value)\n"
- "{\n"
- " it = value;\n"
- "}\n"
- "\n"
- "}\n";
- testDocuments << QuickFixTestDocument::create("file.cpp", original, expected);
-
- GenerateGetterSetter factory;
- QuickFixOperationTest(testDocuments, &factory);
-}
-
-void CppEditorPlugin::test_quickfix_GenerateGetterSetter_createNamespaceInCpp_data()
+void CppEditorPlugin::test_quickfix_GenerateGetterSetter_namespaceHandlingCreate_data()
{
QTest::addColumn<QByteArrayList>("headers");
QTest::addColumn<QByteArrayList>("sources");
@@ -2220,38 +1532,78 @@ void CppEditorPlugin::test_quickfix_GenerateGetterSetter_createNamespaceInCpp_da
<< QByteArrayList{originalHeader, expectedHeader}
<< QByteArrayList{originalSource, expectedSource};
- originalSource =
- "#include \"file.h\"\n"
- "namespace N2 {} // decoy\n"
- "namespace {\n"
- "namespace N1 {\n"
- "namespace {\n"
- "}\n"
- "}\n"
- "}\n";
- expectedSource =
- "#include \"file.h\"\n"
- "namespace N2 {} // decoy\n"
- "namespace {\n"
- "namespace N1 {\n\n"
- "namespace N2 {\n"
- "int Something::getIt() const\n"
- "{\n"
- " return it;\n"
- "}\n"
- "\n"
- "void Something::setIt(int value)\n"
- "{\n"
- " it = value;\n"
- "}\n\n"
- "}\n\n"
- "namespace {\n"
- "}\n"
- "}\n"
- "}\n";
- QTest::addRow("insert inner namespace (with decoy)")
- << QByteArrayList{originalHeader, expectedHeader}
- << QByteArrayList{originalSource, expectedSource};
+ originalSource = "#include \"file.h\"\n"
+ "namespace N2 {} // decoy\n"
+ "namespace {\n"
+ "namespace N1 {\n"
+ "namespace {\n"
+ "}\n"
+ "}\n"
+ "}\n";
+ expectedSource = "#include \"file.h\"\n"
+ "namespace N2 {} // decoy\n"
+ "namespace {\n"
+ "namespace N1 {\n"
+ "namespace {\n"
+ "}\n"
+ "}\n"
+ "}\n"
+ "\n"
+ "\n"
+ "namespace N1 {\n"
+ "namespace N2 {\n"
+ "int Something::getIt() const\n"
+ "{\n"
+ " return it;\n"
+ "}\n"
+ "\n"
+ "void Something::setIt(int value)\n"
+ "{\n"
+ " it = value;\n"
+ "}\n"
+ "\n"
+ "}\n"
+ "}\n";
+ QTest::addRow("insert inner namespace (with decoy and unnamed)")
+ << QByteArrayList{originalHeader, expectedHeader}
+ << QByteArrayList{originalSource, expectedSource};
+
+ const QByteArray unnamedOriginalHeader = "namespace {\n" + originalHeader + "}\n";
+ const QByteArray unnamedExpectedHeader = "namespace {\n" + expectedHeader + "}\n";
+
+ originalSource = "#include \"file.h\"\n"
+ "namespace N2 {} // decoy\n"
+ "namespace {\n"
+ "namespace N1 {\n"
+ "namespace {\n"
+ "}\n"
+ "}\n"
+ "}\n";
+ expectedSource = "#include \"file.h\"\n"
+ "namespace N2 {} // decoy\n"
+ "namespace {\n"
+ "namespace N1 {\n"
+ "\n"
+ "namespace N2 {\n"
+ "int Something::getIt() const\n"
+ "{\n"
+ " return it;\n"
+ "}\n"
+ "\n"
+ "void Something::setIt(int value)\n"
+ "{\n"
+ " it = value;\n"
+ "}\n"
+ "\n"
+ "}\n"
+ "\n"
+ "namespace {\n"
+ "}\n"
+ "}\n"
+ "}\n";
+ QTest::addRow("insert inner namespace in unnamed (with decoy)")
+ << QByteArrayList{unnamedOriginalHeader, unnamedExpectedHeader}
+ << QByteArrayList{originalSource, expectedSource};
originalSource =
"#include \"file.h\"\n"
@@ -2362,19 +1714,1185 @@ void CppEditorPlugin::test_quickfix_GenerateGetterSetter_createNamespaceInCpp_da
<< QByteArrayList{originalSource, expectedSource};
}
-void CppEditorPlugin::test_quickfix_GenerateGetterSetter_createNamespaceInCpp()
+void CppEditorPlugin::test_quickfix_GenerateGetterSetter_namespaceHandlingCreate()
{
QFETCH(QByteArrayList, headers);
QFETCH(QByteArrayList, sources);
- QList<QuickFixTestDocument::Ptr> testDocuments({
- QuickFixTestDocument::create("file.h", headers.at(0), headers.at(1)),
- QuickFixTestDocument::create("file.cpp", sources.at(0), sources.at(1))});
+ QList<QuickFixTestDocument::Ptr> testDocuments(
+ {QuickFixTestDocument::create("file.h", headers.at(0), headers.at(1)),
+ QuickFixTestDocument::create("file.cpp", sources.at(0), sources.at(1))});
+
+ QuickFixSettings s;
+ s->cppFileNamespaceHandling = CppQuickFixSettings::MissingNamespaceHandling::CreateMissing;
+ s->setterParameterNameTemplate = "value";
+ s->getterNameTemplate = "get<Name>";
+ s->setterInCppFileFrom = 1;
+ s->getterInCppFileFrom = 1;
+ GenerateGetterSetter factory;
+ QuickFixOperationTest(testDocuments, &factory, ProjectExplorer::HeaderPaths(), 2);
+}
+
+void CppEditorPlugin::test_quickfix_GenerateGetterSetter_namespaceHandlingAddUsing_data()
+{
+ QTest::addColumn<QByteArrayList>("headers");
+ QTest::addColumn<QByteArrayList>("sources");
+
+ QByteArray originalSource;
+ QByteArray expectedSource;
+
+ const QByteArray originalHeader = "namespace N1 {\n"
+ "namespace N2 {\n"
+ "class Something\n"
+ "{\n"
+ " int @it;\n"
+ "};\n"
+ "}\n"
+ "}\n";
+ const QByteArray expectedHeader = "namespace N1 {\n"
+ "namespace N2 {\n"
+ "class Something\n"
+ "{\n"
+ " int it;\n"
+ "\n"
+ "public:\n"
+ " void setIt(int value);\n"
+ "};\n"
+ "}\n"
+ "}\n";
+
+ originalSource = "#include \"file.h\"\n";
+ expectedSource = "#include \"file.h\"\n\n"
+ "using namespace N1::N2;\n"
+ "void Something::setIt(int value)\n"
+ "{\n"
+ " it = value;\n"
+ "}\n";
+ QTest::addRow("add using namespaces") << QByteArrayList{originalHeader, expectedHeader}
+ << QByteArrayList{originalSource, expectedSource};
+
+ const QByteArray unnamedOriginalHeader = "namespace {\n" + originalHeader + "}\n";
+ const QByteArray unnamedExpectedHeader = "namespace {\n" + expectedHeader + "}\n";
+
+ originalSource = "#include \"file.h\"\n"
+ "namespace N2 {} // decoy\n"
+ "namespace {\n"
+ "namespace N1 {\n"
+ "namespace {\n"
+ "}\n"
+ "}\n"
+ "}\n";
+ expectedSource = "#include \"file.h\"\n"
+ "namespace N2 {} // decoy\n"
+ "namespace {\n"
+ "namespace N1 {\n"
+ "using namespace N2;\n"
+ "void Something::setIt(int value)\n"
+ "{\n"
+ " it = value;\n"
+ "}\n"
+ "namespace {\n"
+ "}\n"
+ "}\n"
+ "}\n";
+ QTest::addRow("insert using namespace into unnamed nested (with decoy)")
+ << QByteArrayList{unnamedOriginalHeader, unnamedExpectedHeader}
+ << QByteArrayList{originalSource, expectedSource};
+
+ originalSource = "#include \"file.h\"\n";
+ expectedSource = "#include \"file.h\"\n\n"
+ "using namespace N1::N2;\n"
+ "void Something::setIt(int value)\n"
+ "{\n"
+ " it = value;\n"
+ "}\n";
+ QTest::addRow("insert using namespace into unnamed")
+ << QByteArrayList{unnamedOriginalHeader, unnamedExpectedHeader}
+ << QByteArrayList{originalSource, expectedSource};
+
+ originalSource = "#include \"file.h\"\n"
+ "namespace N2 {} // decoy\n"
+ "namespace {\n"
+ "namespace N1 {\n"
+ "namespace {\n"
+ "}\n"
+ "}\n"
+ "}\n";
+ expectedSource = "#include \"file.h\"\n"
+ "namespace N2 {} // decoy\n"
+ "namespace {\n"
+ "namespace N1 {\n"
+ "namespace {\n"
+ "}\n"
+ "}\n"
+ "}\n"
+ "\n"
+ "using namespace N1::N2;\n"
+ "void Something::setIt(int value)\n"
+ "{\n"
+ " it = value;\n"
+ "}\n";
+ QTest::addRow("insert using namespace (with decoy)")
+ << QByteArrayList{originalHeader, expectedHeader}
+ << QByteArrayList{originalSource, expectedSource};
+}
+
+void CppEditorPlugin::test_quickfix_GenerateGetterSetter_namespaceHandlingAddUsing()
+{
+ QFETCH(QByteArrayList, headers);
+ QFETCH(QByteArrayList, sources);
+
+ QList<QuickFixTestDocument::Ptr> testDocuments(
+ {QuickFixTestDocument::create("file.h", headers.at(0), headers.at(1)),
+ QuickFixTestDocument::create("file.cpp", sources.at(0), sources.at(1))});
+
+ QuickFixSettings s;
+ s->cppFileNamespaceHandling = CppQuickFixSettings::MissingNamespaceHandling::AddUsingDirective;
+ s->setterParameterNameTemplate = "value";
+ s->setterInCppFileFrom = 1;
+
+ if (std::strstr(QTest::currentDataTag(), "unnamed nested") != nullptr)
+ QSKIP("TODO"); // FIXME
+ GenerateGetterSetter factory;
+ QuickFixOperationTest(testDocuments, &factory);
+}
+
+void CppEditorPlugin::test_quickfix_GenerateGetterSetter_namespaceHandlingFullyQualify_data()
+{
+ QTest::addColumn<QByteArrayList>("headers");
+ QTest::addColumn<QByteArrayList>("sources");
+
+ QByteArray originalSource;
+ QByteArray expectedSource;
+
+ const QByteArray originalHeader = "namespace N1 {\n"
+ "namespace N2 {\n"
+ "class Something\n"
+ "{\n"
+ " int @it;\n"
+ "};\n"
+ "}\n"
+ "}\n";
+ const QByteArray expectedHeader = "namespace N1 {\n"
+ "namespace N2 {\n"
+ "class Something\n"
+ "{\n"
+ " int it;\n"
+ "\n"
+ "public:\n"
+ " void setIt(int value);\n"
+ "};\n"
+ "}\n"
+ "}\n";
+
+ originalSource = "#include \"file.h\"\n";
+ expectedSource = "#include \"file.h\"\n\n"
+ "void N1::N2::Something::setIt(int value)\n"
+ "{\n"
+ " it = value;\n"
+ "}\n";
+ QTest::addRow("fully qualify") << QByteArrayList{originalHeader, expectedHeader}
+ << QByteArrayList{originalSource, expectedSource};
+
+ originalSource = "#include \"file.h\"\n"
+ "namespace N2 {} // decoy\n";
+ expectedSource = "#include \"file.h\"\n"
+ "namespace N2 {} // decoy\n"
+ "\n"
+ "void N1::N2::Something::setIt(int value)\n"
+ "{\n"
+ " it = value;\n"
+ "}\n";
+ QTest::addRow("fully qualify (with decoy)") << QByteArrayList{originalHeader, expectedHeader}
+ << QByteArrayList{originalSource, expectedSource};
+
+ originalSource = "#include \"file.h\"\n"
+ "namespace N2 {} // decoy\n"
+ "namespace {\n"
+ "namespace N1 {\n"
+ "namespace {\n"
+ "}\n"
+ "}\n"
+ "}\n";
+ expectedSource = "#include \"file.h\"\n"
+ "namespace N2 {} // decoy\n"
+ "namespace {\n"
+ "namespace N1 {\n"
+ "namespace {\n"
+ "}\n"
+ "}\n"
+ "}\n"
+ "\n"
+ "void N1::N2::Something::setIt(int value)\n"
+ "{\n"
+ " it = value;\n"
+ "}\n";
+ QTest::addRow("qualify in inner namespace (with decoy)")
+ << QByteArrayList{originalHeader, expectedHeader}
+ << QByteArrayList{originalSource, expectedSource};
+
+ const QByteArray unnamedOriginalHeader = "namespace {\n" + originalHeader + "}\n";
+ const QByteArray unnamedExpectedHeader = "namespace {\n" + expectedHeader + "}\n";
+ originalSource = "#include \"file.h\"\n"
+ "namespace N2 {} // decoy\n"
+ "namespace {\n"
+ "namespace N1 {\n"
+ "namespace {\n"
+ "}\n"
+ "}\n"
+ "}\n";
+ expectedSource = "#include \"file.h\"\n"
+ "namespace N2 {} // decoy\n"
+ "namespace {\n"
+ "namespace N1 {\n"
+ "void N2::Something::setIt(int value)\n"
+ "{\n"
+ " it = value;\n"
+ "}\n"
+ "namespace {\n"
+ "}\n"
+ "}\n"
+ "}\n";
+ QTest::addRow("qualify in inner namespace unnamed nested (with decoy)")
+ << QByteArrayList{unnamedOriginalHeader, unnamedExpectedHeader}
+ << QByteArrayList{originalSource, expectedSource};
+
+ originalSource = "#include \"file.h\"\n";
+ expectedSource = "#include \"file.h\"\n\n"
+ "void N1::N2::Something::setIt(int value)\n"
+ "{\n"
+ " it = value;\n"
+ "}\n";
+ QTest::addRow("qualify in unnamed namespace")
+ << QByteArrayList{unnamedOriginalHeader, unnamedExpectedHeader}
+ << QByteArrayList{originalSource, expectedSource};
+}
+
+void CppEditorPlugin::test_quickfix_GenerateGetterSetter_namespaceHandlingFullyQualify()
+{
+ QFETCH(QByteArrayList, headers);
+ QFETCH(QByteArrayList, sources);
+
+ QList<QuickFixTestDocument::Ptr> testDocuments(
+ {QuickFixTestDocument::create("file.h", headers.at(0), headers.at(1)),
+ QuickFixTestDocument::create("file.cpp", sources.at(0), sources.at(1))});
+
+ QuickFixSettings s;
+ s->cppFileNamespaceHandling = CppQuickFixSettings::MissingNamespaceHandling::RewriteType;
+ s->setterParameterNameTemplate = "value";
+ s->setterInCppFileFrom = 1;
+
+ if (std::strstr(QTest::currentDataTag(), "unnamed nested") != nullptr)
+ QSKIP("TODO"); // FIXME
GenerateGetterSetter factory;
QuickFixOperationTest(testDocuments, &factory);
}
+void CppEditorPlugin::test_quickfix_GenerateGetterSetter_customNames_data()
+{
+ QTest::addColumn<QByteArrayList>("headers");
+ QTest::addColumn<int>("operation");
+
+ QByteArray originalSource;
+ QByteArray expectedSource;
+
+ // Check if right names are created
+ originalSource = R"-(
+class Test {
+ int m_fooBar_test@;
+};
+)-";
+ expectedSource = R"-(
+class Test {
+ int m_fooBar_test;
+
+public:
+ int give_me_foo_bar_test() const
+ {
+ return m_fooBar_test;
+ }
+ void Seet_FooBar_test(int New_Foo_Bar_Test)
+ {
+ if (m_fooBar_test == New_Foo_Bar_Test)
+ return;
+ m_fooBar_test = New_Foo_Bar_Test;
+ emit newFooBarTestValue();
+ }
+ void set_fooBarTest_toDefault()
+ {
+ Seet_FooBar_test({}); // TODO: Adapt to use your actual default value
+ }
+
+signals:
+ void newFooBarTestValue();
+
+private:
+ Q_PROPERTY(int fooBar_test READ give_me_foo_bar_test WRITE Seet_FooBar_test RESET set_fooBarTest_toDefault NOTIFY newFooBarTestValue)
+};
+)-";
+ QTest::addRow("create right names") << QByteArrayList{originalSource, expectedSource} << 4;
+
+ // Check if not triggered with custom names
+ originalSource = R"-(
+class Test {
+ int m_fooBar_test@;
+
+public:
+ int give_me_foo_bar_test() const
+ {
+ return m_fooBar_test;
+ }
+ void Seet_FooBar_test(int New_Foo_Bar_Test)
+ {
+ if (m_fooBar_test == New_Foo_Bar_Test)
+ return;
+ m_fooBar_test = New_Foo_Bar_Test;
+ emit newFooBarTestValue();
+ }
+ void set_fooBarTest_toDefault()
+ {
+ Seet_FooBar_test({}); // TODO: Adapt to use your actual default value
+ }
+
+signals:
+ void newFooBarTestValue();
+
+private:
+ Q_PROPERTY(int fooBar_test READ give_me_foo_bar_test WRITE Seet_FooBar_test RESET set_fooBarTest_toDefault NOTIFY newFooBarTestValue)
+};
+)-";
+ expectedSource = "";
+ QTest::addRow("everything already exists") << QByteArrayList{originalSource, expectedSource} << 4;
+
+ // create from Q_PROPERTY with custom names
+ originalSource = R"-(
+class Test {
+ Q_PROPER@TY(int fooBar_test READ give_me_foo_bar_test WRITE Seet_FooBar_test RESET set_fooBarTest_toDefault NOTIFY newFooBarTestValue)
+
+public:
+ int give_me_foo_bar_test() const
+ {
+ return mem_fooBar_test;
+ }
+ void Seet_FooBar_test(int New_Foo_Bar_Test)
+ {
+ if (mem_fooBar_test == New_Foo_Bar_Test)
+ return;
+ mem_fooBar_test = New_Foo_Bar_Test;
+ emit newFooBarTestValue();
+ }
+ void set_fooBarTest_toDefault()
+ {
+ Seet_FooBar_test({}); // TODO: Adapt to use your actual default value
+ }
+
+signals:
+ void newFooBarTestValue();
+};
+)-";
+ expectedSource = R"-(
+class Test {
+ Q_PROPERTY(int fooBar_test READ give_me_foo_bar_test WRITE Seet_FooBar_test RESET set_fooBarTest_toDefault NOTIFY newFooBarTestValue)
+
+public:
+ int give_me_foo_bar_test() const
+ {
+ return mem_fooBar_test;
+ }
+ void Seet_FooBar_test(int New_Foo_Bar_Test)
+ {
+ if (mem_fooBar_test == New_Foo_Bar_Test)
+ return;
+ mem_fooBar_test = New_Foo_Bar_Test;
+ emit newFooBarTestValue();
+ }
+ void set_fooBarTest_toDefault()
+ {
+ Seet_FooBar_test({}); // TODO: Adapt to use your actual default value
+ }
+
+signals:
+ void newFooBarTestValue();
+private:
+ int mem_fooBar_test;
+};
+)-";
+ QTest::addRow("create only member variable")
+ << QByteArrayList{originalSource, expectedSource} << 0;
+
+ // create from Q_PROPERTY with custom names
+ originalSource = R"-(
+class Test {
+ Q_PROPE@RTY(int fooBar_test READ give_me_foo_bar_test WRITE Seet_FooBar_test RESET set_fooBarTest_toDefault NOTIFY newFooBarTestValue)
+ int mem_fooBar_test;
+public:
+};
+)-";
+ expectedSource = R"-(
+class Test {
+ Q_PROPERTY(int fooBar_test READ give_me_foo_bar_test WRITE Seet_FooBar_test RESET set_fooBarTest_toDefault NOTIFY newFooBarTestValue)
+ int mem_fooBar_test;
+public:
+ int give_me_foo_bar_test() const
+ {
+ return mem_fooBar_test;
+ }
+ void Seet_FooBar_test(int New_Foo_Bar_Test)
+ {
+ if (mem_fooBar_test == New_Foo_Bar_Test)
+ return;
+ mem_fooBar_test = New_Foo_Bar_Test;
+ emit newFooBarTestValue();
+ }
+ void set_fooBarTest_toDefault()
+ {
+ Seet_FooBar_test({}); // TODO: Adapt to use your actual default value
+ }
+signals:
+ void newFooBarTestValue();
+};
+)-";
+ QTest::addRow("create methods with given member variable")
+ << QByteArrayList{originalSource, expectedSource} << 0;
+}
+
+void CppEditorPlugin::test_quickfix_GenerateGetterSetter_customNames()
+{
+ QFETCH(QByteArrayList, headers);
+ QFETCH(int, operation);
+
+ QList<QuickFixTestDocument::Ptr> testDocuments(
+ {QuickFixTestDocument::create("file.h", headers.at(0), headers.at(1))});
+
+ QuickFixSettings s;
+ s->setterInCppFileFrom = 0;
+ s->getterInCppFileFrom = 0;
+ s->setterNameTemplate = "Seet_<Name>";
+ s->getterNameTemplate = "give_me_<snake>";
+ s->signalNameTemplate = "new<Camel>Value";
+ s->setterParameterNameTemplate = "New_<Snake>";
+ s->resetNameTemplate = "set_<camel>_toDefault";
+ s->memberVariableNameTemplate = "mem_<name>";
+ if (operation == 0) {
+ InsertQtPropertyMembers factory;
+ QuickFixOperationTest(testDocuments, &factory, ProjectExplorer::HeaderPaths(), operation);
+ } else {
+ GenerateGetterSetter factory;
+ QuickFixOperationTest(testDocuments, &factory, ProjectExplorer::HeaderPaths(), operation);
+ }
+}
+
+void CppEditorPlugin::test_quickfix_GenerateGetterSetter_valueTypes_data()
+{
+ QTest::addColumn<QByteArrayList>("headers");
+ QTest::addColumn<int>("operation");
+
+ QByteArray originalSource;
+ QByteArray expectedSource;
+
+ // int should be a value type
+ originalSource = R"-(
+class Test {
+ int i@;
+};
+)-";
+ expectedSource = R"-(
+class Test {
+ int i;
+
+public:
+ int getI() const
+ {
+ return i;
+ }
+};
+)-";
+ QTest::addRow("int") << QByteArrayList{originalSource, expectedSource} << 1;
+
+ // return type should be only int without const
+ originalSource = R"-(
+class Test {
+ const int i@;
+};
+)-";
+ expectedSource = R"-(
+class Test {
+ const int i;
+
+public:
+ int getI() const
+ {
+ return i;
+ }
+};
+)-";
+ QTest::addRow("const int") << QByteArrayList{originalSource, expectedSource} << 0;
+
+ // float should be a value type
+ originalSource = R"-(
+class Test {
+ float f@;
+};
+)-";
+ expectedSource = R"-(
+class Test {
+ float f;
+
+public:
+ float getF() const
+ {
+ return f;
+ }
+};
+)-";
+ QTest::addRow("float") << QByteArrayList{originalSource, expectedSource} << 1;
+
+ // pointer should be a value type
+ originalSource = R"-(
+class Test {
+ void* v@;
+};
+)-";
+ expectedSource = R"-(
+class Test {
+ void* v;
+
+public:
+ void *getV() const
+ {
+ return v;
+ }
+};
+)-";
+ QTest::addRow("pointer") << QByteArrayList{originalSource, expectedSource} << 1;
+
+ // reference should be a value type (setter is const ref)
+ originalSource = R"-(
+class Test {
+ int& r@;
+};
+)-";
+ expectedSource = R"-(
+class Test {
+ int& r;
+
+public:
+ int &getR() const
+ {
+ return r;
+ }
+ void setR(const int &newR)
+ {
+ r = newR;
+ }
+};
+)-";
+ QTest::addRow("reference to value type") << QByteArrayList{originalSource, expectedSource} << 2;
+
+ // reference should be a value type
+ originalSource = R"-(
+using bar = int;
+class Test {
+ bar i@;
+};
+)-";
+ expectedSource = R"-(
+using bar = int;
+class Test {
+ bar i;
+
+public:
+ bar getI() const
+ {
+ return i;
+ }
+};
+)-";
+ QTest::addRow("value type through using") << QByteArrayList{originalSource, expectedSource} << 1;
+
+ // enum should be a value type
+ originalSource = R"-(
+enum Foo{V1, V2};
+class Test {
+ Foo e@;
+};
+)-";
+ expectedSource = R"-(
+enum Foo{V1, V2};
+class Test {
+ Foo e;
+
+public:
+ Foo getE() const
+ {
+ return e;
+ }
+};
+)-";
+ QTest::addRow("enum") << QByteArrayList{originalSource, expectedSource} << 1;
+
+ // class should not be a value type
+ originalSource = R"-(
+class NoVal{};
+class Test {
+ NoVal n@;
+};
+)-";
+ expectedSource = R"-(
+class NoVal{};
+class Test {
+ NoVal n;
+
+public:
+ const NoVal &getN() const
+ {
+ return n;
+ }
+};
+)-";
+ QTest::addRow("class") << QByteArrayList{originalSource, expectedSource} << 1;
+
+ // custom classes can be a value type
+ originalSource = R"-(
+class Value{};
+class Test {
+ Value v@;
+};
+)-";
+ expectedSource = R"-(
+class Value{};
+class Test {
+ Value v;
+
+public:
+ Value getV() const
+ {
+ return v;
+ }
+};
+)-";
+ QTest::addRow("value class") << QByteArrayList{originalSource, expectedSource} << 1;
+
+ // custom classes (in namespace) can be a value type
+ originalSource = R"-(
+namespace N1{
+class Value{};
+}
+class Test {
+ N1::Value v@;
+};
+)-";
+ expectedSource = R"-(
+namespace N1{
+class Value{};
+}
+class Test {
+ N1::Value v;
+
+public:
+ N1::Value getV() const
+ {
+ return v;
+ }
+};
+)-";
+ QTest::addRow("value class in namespace") << QByteArrayList{originalSource, expectedSource} << 1;
+
+ // custom template class can be a value type
+ originalSource = R"-(
+template<typename T>
+class Value{};
+class Test {
+ Value<int> v@;
+};
+)-";
+ expectedSource = R"-(
+template<typename T>
+class Value{};
+class Test {
+ Value<int> v;
+
+public:
+ Value<int> getV() const
+ {
+ return v;
+ }
+};
+)-";
+ QTest::addRow("value template class") << QByteArrayList{originalSource, expectedSource} << 1;
+}
+
+void CppEditorPlugin::test_quickfix_GenerateGetterSetter_valueTypes()
+{
+ QFETCH(QByteArrayList, headers);
+ QFETCH(int, operation);
+
+ QList<QuickFixTestDocument::Ptr> testDocuments(
+ {QuickFixTestDocument::create("file.h", headers.at(0), headers.at(1))});
+
+ QuickFixSettings s;
+ s->setterInCppFileFrom = 0;
+ s->getterInCppFileFrom = 0;
+ s->getterNameTemplate = "get<Name>";
+ s->valueTypes << "Value";
+
+ GenerateGetterSetter factory;
+ QuickFixOperationTest(testDocuments, &factory, ProjectExplorer::HeaderPaths(), operation);
+}
+
+/// Checks: Use template for a custom type
+void CppEditorPlugin::test_quickfix_GenerateGetterSetter_customTemplate()
+{
+ QList<QuickFixTestDocument::Ptr> testDocuments;
+ QByteArray original;
+ QByteArray expected;
+
+ const _ customTypeDecl = R"--(
+namespace N1 {
+ namespace N2 {
+ struct test{};
+ }
+ template<typename T>
+ struct custom {
+ void assign(const custom<T>&);
+ bool equals(const custom<T>&);
+ T* get();
+ };
+)--";
+ // Header File
+ original = customTypeDecl + R"--(
+class Foo
+{
+public:
+ custom<N2::test> bar@;
+};
+})--";
+ expected = customTypeDecl + R"--(
+class Foo
+{
+public:
+ custom<N2::test> bar@;
+ N2::test*getBar() const;
+ void setBar(const custom<N2::test> &newBar);
+signals:
+ void barChanged(N2::test*);
+private:
+ Q_PROPERTY(N2::test* bar READ getBar NOTIFY barChanged)
+};
+})--";
+ testDocuments << QuickFixTestDocument::create("file.h", original, expected);
+
+ // Source File
+ original = "";
+ expected = R"-(
+using namespace N1;
+N2::test*Foo::getBar() const
+{
+ return bar.get();
+}
+
+void Foo::setBar(const custom<N2::test> &newBar)
+{
+ if (bar.equals(newBar))
+ return;
+ bar.assign(newBar);
+ emit barChanged(bar.get());
+}
+)-";
+
+ testDocuments << QuickFixTestDocument::create("file.cpp", original, expected);
+
+ QuickFixSettings s;
+ s->cppFileNamespaceHandling = CppQuickFixSettings::MissingNamespaceHandling::AddUsingDirective;
+ s->getterNameTemplate = "get<Name>";
+ s->getterInCppFileFrom = 1;
+ s->signalWithNewValue = true;
+ CppQuickFixSettings::CustomTemplate t;
+ t.types.append("custom");
+ t.equalComparison = "<cur>.equals(<new>)";
+ t.returnExpression = "<cur>.get()";
+ t.returnType = "<T>*";
+ t.assignment = "<cur>.assign(<new>)";
+ s->customTemplates.push_back(t);
+
+ GenerateGetterSetter factory;
+ QuickFixOperationTest(testDocuments, &factory, ProjectExplorer::HeaderPaths(), 5);
+}
+
+/// Checks: if the setter parameter name is the same as the member variable name, this-> is needed
+void CppEditorPlugin::test_quickfix_GenerateGetterSetter_needThis()
+{
+ QList<QuickFixTestDocument::Ptr> testDocuments;
+
+ // Header File
+ const QByteArray original = R"-(
+class Foo {
+ int bar@;
+public:
+};
+)-";
+ const QByteArray expected = R"-(
+class Foo {
+ int bar@;
+public:
+ void setBar(int bar)
+ {
+ this->bar = bar;
+ }
+};
+)-";
+ testDocuments << QuickFixTestDocument::create("file.h", original, expected);
+
+ QuickFixSettings s;
+ s->setterParameterNameTemplate = "<name>";
+ s->setterInCppFileFrom = 0;
+
+ GenerateGetterSetter factory;
+ QuickFixOperationTest(testDocuments, &factory, ProjectExplorer::HeaderPaths(), 0);
+}
+
+void CppEditorPlugin::test_quickfix_GenerateGetterSetter_offeredFixes_data()
+{
+ QTest::addColumn<QByteArray>("header");
+ QTest::addColumn<QStringList>("offered");
+
+ QByteArray header;
+ QStringList offered;
+ const QString setter = QStringLiteral("Generate Setter");
+ const QString getter = QStringLiteral("Generate Getter");
+ const QString getset = QStringLiteral("Generate Getter and Setter");
+ const QString constQandMissing = QStringLiteral(
+ "Generate Constant Q_PROPERTY and Missing Members");
+ const QString qAndResetAndMissing = QStringLiteral(
+ "Generate Q_PROPERTY and Missing Members with Reset Function");
+ const QString qAndMissing = QStringLiteral("Generate Q_PROPERTY and Missing Members");
+ const QStringList all{setter, getter, getset, constQandMissing, qAndResetAndMissing, qAndMissing};
+
+ header = R"-(
+class Foo {
+ static int bar@;
+};
+)-";
+ offered = QStringList{setter, getter, getset, constQandMissing};
+ QTest::addRow("static") << header << offered;
+
+ header = R"-(
+class Foo {
+ static const int bar@;
+};
+)-";
+ offered = QStringList{getter, constQandMissing};
+ QTest::addRow("const static") << header << offered;
+
+ header = R"-(
+class Foo {
+ const int bar@;
+};
+)-";
+ offered = QStringList{getter, constQandMissing};
+ QTest::addRow("const") << header << offered;
+
+ header = R"-(
+class Foo {
+ const int bar@;
+ int getBar() const;
+};
+)-";
+ offered = QStringList{constQandMissing};
+ QTest::addRow("const + getter") << header << offered;
+
+ header = R"-(
+class Foo {
+ const int bar@;
+ int getBar() const;
+ void setBar(int value);
+};
+)-";
+ offered = QStringList{};
+ QTest::addRow("const + getter + setter") << header << offered;
+
+ header = R"-(
+class Foo {
+ const int* bar@;
+};
+)-";
+ offered = all;
+ QTest::addRow("pointer to const") << header << offered;
+
+ header = R"-(
+class Foo {
+ int bar@;
+public:
+ int bar();
+};
+)-";
+ offered = QStringList{setter, constQandMissing, qAndResetAndMissing, qAndMissing};
+ QTest::addRow("existing getter") << header << offered;
+
+ header = R"-(
+class Foo {
+ int bar@;
+public:
+ set setBar(int);
+};
+)-";
+ offered = QStringList{getter};
+ QTest::addRow("existing setter") << header << offered;
+
+ header = R"-(
+class Foo {
+ int bar@;
+signals:
+ void barChanged(int);
+};
+)-";
+ offered = QStringList{setter, getter, getset, qAndResetAndMissing, qAndMissing};
+ QTest::addRow("existing signal (no const Q_PROPERTY)") << header << offered;
+
+ header = R"-(
+class Foo {
+ int m_bar@;
+ Q_PROPERTY(int bar)
+};
+)-";
+ offered = QStringList{}; // user should use "InsertQPropertyMembers", no duplicated code
+ QTest::addRow("existing Q_PROPERTY") << header << offered;
+}
+
+void CppEditorPlugin::test_quickfix_GenerateGetterSetter_offeredFixes()
+{
+ QFETCH(QByteArray, header);
+ QFETCH(QStringList, offered);
+
+ QList<QuickFixTestDocument::Ptr> testDocuments(
+ {QuickFixTestDocument::create("file.h", header, header)});
+
+ GenerateGetterSetter factory;
+ QuickFixOfferedOperationsTest(testDocuments, &factory, ProjectExplorer::HeaderPaths(), offered);
+}
+
+void CppEditorPlugin::test_quickfix_GenerateGetterSetter_generalTests_data()
+{
+ QTest::addColumn<int>("operation");
+ QTest::addColumn<QByteArray>("original");
+ QTest::addColumn<QByteArray>("expected");
+
+ QTest::newRow("GenerateGetterSetter_referenceToNonConst")
+ << 2
+ << _("\n"
+ "class Something\n"
+ "{\n"
+ " int &it@;\n"
+ "};\n")
+ << _("\n"
+ "class Something\n"
+ "{\n"
+ " int &it;\n"
+ "\n"
+ "public:\n"
+ " int &getIt() const;\n"
+ " void setIt(const int &it);\n"
+ "};\n"
+ "\n"
+ "int &Something::getIt() const\n"
+ "{\n"
+ " return it;\n"
+ "}\n"
+ "\n"
+ "void Something::setIt(const int &it)\n"
+ "{\n"
+ " this->it = it;\n"
+ "}\n");
+
+ // Checks: No special treatment for reference to const.
+ QTest::newRow("GenerateGetterSetter_referenceToConst")
+ << 2
+ << _("\n"
+ "class Something\n"
+ "{\n"
+ " const int &it@;\n"
+ "};\n")
+ << _("\n"
+ "class Something\n"
+ "{\n"
+ " const int &it;\n"
+ "\n"
+ "public:\n"
+ " const int &getIt() const;\n"
+ " void setIt(const int &it);\n"
+ "};\n"
+ "\n"
+ "const int &Something::getIt() const\n"
+ "{\n"
+ " return it;\n"
+ "}\n"
+ "\n"
+ "void Something::setIt(const int &it)\n"
+ "{\n"
+ " this->it = it;\n"
+ "}\n");
+
+ // Checks:
+ // 1. Setter: Setter is a static function.
+ // 2. Getter: Getter is a static, non const function.
+ QTest::newRow("GenerateGetterSetter_staticMember")
+ << 2
+ << _("\n"
+ "class Something\n"
+ "{\n"
+ " static int @m_member;\n"
+ "};\n")
+ << _("\n"
+ "class Something\n"
+ "{\n"
+ " static int m_member;\n"
+ "\n"
+ "public:\n"
+ " static int member();\n"
+ " static void setMember(int member);\n"
+ "};\n"
+ "\n"
+ "int Something::member()\n"
+ "{\n"
+ " return m_member;\n"
+ "}\n"
+ "\n"
+ "void Something::setMember(int member)\n"
+ "{\n"
+ " m_member = member;\n"
+ "}\n");
+
+ // Check: Check if it works on the second declarator
+ // clang-format off
+ QTest::newRow("GenerateGetterSetter_secondDeclarator") << 2
+ << _("\n"
+ "class Something\n"
+ "{\n"
+ " int *foo, @it;\n"
+ "};\n")
+ << _("\n"
+ "class Something\n"
+ "{\n"
+ " int *foo, it;\n"
+ "\n"
+ "public:\n"
+ " int getIt() const;\n"
+ " void setIt(int it);\n"
+ "};\n"
+ "\n"
+ "int Something::getIt() const\n"
+ "{\n"
+ " return it;\n"
+ "}\n"
+ "\n"
+ "void Something::setIt(int it)\n"
+ "{\n"
+ " this->it = it;\n"
+ "}\n");
+ // clang-format on
+
+ // Check: Quick fix is offered for "int *@it;" ('@' denotes the text cursor position)
+ QTest::newRow("GenerateGetterSetter_triggeringRightAfterPointerSign")
+ << 2
+ << _("\n"
+ "class Something\n"
+ "{\n"
+ " int *@it;\n"
+ "};\n")
+ << _("\n"
+ "class Something\n"
+ "{\n"
+ " int *it;\n"
+ "\n"
+ "public:\n"
+ " int *getIt() const;\n"
+ " void setIt(int *it);\n"
+ "};\n"
+ "\n"
+ "int *Something::getIt() const\n"
+ "{\n"
+ " return it;\n"
+ "}\n"
+ "\n"
+ "void Something::setIt(int *it)\n"
+ "{\n"
+ " this->it = it;\n"
+ "}\n");
+
+ // Checks if "m_" is recognized as "m" with the postfix "_" and not simply as "m_" prefix.
+ QTest::newRow("GenerateGetterSetter_recognizeMasVariableName")
+ << 2
+ << _("\n"
+ "class Something\n"
+ "{\n"
+ " int @m_;\n"
+ "};\n")
+ << _("\n"
+ "class Something\n"
+ "{\n"
+ " int m_;\n"
+ "\n"
+ "public:\n"
+ " int m() const;\n"
+ " void setM(int m);\n"
+ "};\n"
+ "\n"
+ "int Something::m() const\n"
+ "{\n"
+ " return m_;\n"
+ "}\n"
+ "\n"
+ "void Something::setM(int m)\n"
+ "{\n"
+ " m_ = m;\n"
+ "}\n");
+
+ // Checks if "m" followed by an upper character is recognized as a prefix
+ QTest::newRow("GenerateGetterSetter_recognizeMFollowedByCapital")
+ << 2
+ << _("\n"
+ "class Something\n"
+ "{\n"
+ " int @mFoo;\n"
+ "};\n")
+ << _("\n"
+ "class Something\n"
+ "{\n"
+ " int mFoo;\n"
+ "\n"
+ "public:\n"
+ " int foo() const;\n"
+ " void setFoo(int foo);\n"
+ "};\n"
+ "\n"
+ "int Something::foo() const\n"
+ "{\n"
+ " return mFoo;\n"
+ "}\n"
+ "\n"
+ "void Something::setFoo(int foo)\n"
+ "{\n"
+ " mFoo = foo;\n"
+ "}\n");
+}
+void CppEditorPlugin::test_quickfix_GenerateGetterSetter_generalTests()
+{
+ QFETCH(int, operation);
+ QFETCH(QByteArray, original);
+ QFETCH(QByteArray, expected);
+
+ QuickFixSettings s;
+ s->setterParameterNameTemplate = "<name>";
+ s->getterInCppFileFrom = 1;
+ s->setterInCppFileFrom = 1;
+
+ GenerateGetterSetter factory;
+ QuickFixOperationTest(singleDocument(original, expected),
+ &factory,
+ ProjectExplorer::HeaderPaths(),
+ operation);
+}
/// Checks: Only generate getter
void CppEditorPlugin::test_quickfix_GenerateGetterSetter_onlyGetter()
{
@@ -2408,6 +2926,9 @@ void CppEditorPlugin::test_quickfix_GenerateGetterSetter_onlyGetter()
"}\n";
testDocuments << QuickFixTestDocument::create("file.cpp", original, expected);
+ QuickFixSettings s;
+ s->getterInCppFileFrom = 1;
+ s->getterNameTemplate = "get<Name>";
GenerateGetterSetter factory;
QuickFixOperationTest(testDocuments, &factory, ProjectExplorer::HeaderPaths(), 1);
}
@@ -2445,33 +2966,64 @@ void CppEditorPlugin::test_quickfix_GenerateGetterSetter_onlySetter()
"}\n";
testDocuments << QuickFixTestDocument::create("file.cpp", original, expected);
+ QuickFixSettings s;
+ s->setterInCppFileFrom = 1;
+ s->setterParameterNameTemplate = "value";
+
GenerateGetterSetter factory;
- QuickFixOperationTest(testDocuments, &factory, ProjectExplorer::HeaderPaths(), 2);
+ QuickFixOperationTest(testDocuments, &factory, ProjectExplorer::HeaderPaths(), 0);
}
-void CppEditorPlugin::test_quickfix_GenerateGetterSetter_onlySetterHeaderFile()
+void CppEditorPlugin::test_quickfix_GenerateGetterSetter_inlineInHeaderFile()
{
QList<QuickFixTestDocument::Ptr> testDocuments;
- const QByteArray original =
- "class Foo\n"
- "{\n"
- "public:\n"
- " int bar@;\n"
- "};\n";
- const QByteArray expected =
- "class Foo\n"
- "{\n"
- "public:\n"
- " int bar@;\n"
- " void setBar(int value);\n"
- "};\n\n"
- "inline void Foo::setBar(int value)\n"
- "{\n"
- " bar = value;\n"
- "}\n";
+ const QByteArray original = R"-(
+class Foo {
+public:
+ int bar@;
+};
+)-";
+ const QByteArray expected = R"-(
+class Foo {
+public:
+ int bar;
+ int getBar() const;
+ void setBar(int value);
+ void resetBar();
+signals:
+ void barChanged();
+private:
+ Q_PROPERTY(int bar READ getBar WRITE setBar RESET resetBar NOTIFY barChanged)
+};
+
+inline int Foo::getBar() const
+{
+ return bar;
+}
+
+inline void Foo::setBar(int value)
+{
+ if (bar == value)
+ return;
+ bar = value;
+ emit barChanged();
+}
+
+inline void Foo::resetBar()
+{
+ setBar({}); // TODO: Adapt to use your actual default defaultValue
+}
+)-";
testDocuments << QuickFixTestDocument::create("file.h", original, expected);
+
+ QuickFixSettings s;
+ s->setterOutsideClassFrom = 1;
+ s->getterOutsideClassFrom = 1;
+ s->setterParameterNameTemplate = "value";
+ s->getterNameTemplate = "get<Name>";
+
GenerateGetterSetter factory;
- QuickFixOperationTest(testDocuments, &factory, ProjectExplorer::HeaderPaths(), 2);
+ QuickFixOperationTest(testDocuments, &factory, ProjectExplorer::HeaderPaths(), 4);
}
void CppEditorPlugin::test_quickfix_GenerateGetterSetter_onlySetterHeaderFileWithIncludeGuard()
@@ -2502,8 +3054,13 @@ void CppEditorPlugin::test_quickfix_GenerateGetterSetter_onlySetterHeaderFileWit
"#endif\n";
testDocuments << QuickFixTestDocument::create("file.h", original, expected);
+
+ QuickFixSettings s;
+ s->setterOutsideClassFrom = 1;
+ s->setterParameterNameTemplate = "value";
+
GenerateGetterSetter factory;
- QuickFixOperationTest(testDocuments, &factory, ProjectExplorer::HeaderPaths(), 2);
+ QuickFixOperationTest(testDocuments, &factory, ProjectExplorer::HeaderPaths(), 0);
}
class CppCodeStyleSettingsChanger {
@@ -2545,130 +3102,12 @@ CppCodeStyleSettings CppCodeStyleSettingsChanger::currentSettings()
return preferences->currentDelegate()->value().value<CppCodeStyleSettings>();
}
-void CppEditorPlugin::test_quickfix_GenerateGetterSetter_onlyGetter_DontPreferGetterWithGet()
-{
- CppCodeStyleSettings modifiedSettings = CppCodeStyleSettingsChanger::currentSettings();
- modifiedSettings.preferGetterNameWithoutGetPrefix = false;
- CppCodeStyleSettingsChanger changer(modifiedSettings);
-
- QList<QuickFixTestDocument::Ptr> testDocuments;
- QByteArray original;
- QByteArray expected;
-
- // Header File
- original =
- "class Foo\n"
- "{\n"
- "public:\n"
- " int m_bar@;\n"
- "};\n";
- expected =
- "class Foo\n"
- "{\n"
- "public:\n"
- " int m_bar@;\n"
- " int getBar() const;\n"
- "};\n";
- testDocuments << QuickFixTestDocument::create("file.h", original, expected);
-
- // Source File
- original.resize(0);
- expected =
- "\n"
- "int Foo::getBar() const\n"
- "{\n"
- " return m_bar;\n"
- "}\n";
- testDocuments << QuickFixTestDocument::create("file.cpp", original, expected);
-
- GenerateGetterSetter factory;
- QuickFixOperationTest(testDocuments, &factory, ProjectExplorer::HeaderPaths(), 1);
-}
-
-/// Checks: Offer a "generate getter" quick fix if there is a setter
-void CppEditorPlugin::test_quickfix_GenerateGetterSetter_offerGetterWhenSetterPresent()
-{
- QList<QuickFixTestDocument::Ptr> testDocuments;
- QByteArray original;
- QByteArray expected;
-
- // Header File
- original =
- "class Foo\n"
- "{\n"
- "public:\n"
- " int bar@;\n"
- " void setBar(int value);\n"
- "};\n";
- expected =
- "class Foo\n"
- "{\n"
- "public:\n"
- " int bar;\n"
- " void setBar(int value);\n"
- " int getBar() const;\n"
- "};\n";
- testDocuments << QuickFixTestDocument::create("file.h", original, expected);
-
- // Source File
- original.resize(0);
- expected =
- "\n"
- "int Foo::getBar() const\n"
- "{\n"
- " return bar;\n"
- "}\n";
- testDocuments << QuickFixTestDocument::create("file.cpp", original, expected);
-
- GenerateGetterSetter factory;
- QuickFixOperationTest(testDocuments, &factory);
-}
-
-/// Checks: Offer a "generate setter" quick fix if there is a getter
-void CppEditorPlugin::test_quickfix_GenerateGetterSetter_offerSetterWhenGetterPresent()
-{
- QList<QuickFixTestDocument::Ptr> testDocuments;
- QByteArray original;
- QByteArray expected;
-
- // Header File
- original =
- "class Foo\n"
- "{\n"
- "public:\n"
- " int bar@;\n"
- " int getBar() const;\n"
- "};\n";
- expected =
- "class Foo\n"
- "{\n"
- "public:\n"
- " int bar;\n"
- " int getBar() const;\n"
- " void setBar(int value);\n"
- "};\n";
- testDocuments << QuickFixTestDocument::create("file.h", original, expected);
-
- // Source File
- original.resize(0);
- expected =
- "\n"
- "void Foo::setBar(int value)\n"
- "{\n"
- " bar = value;\n"
- "}\n";
- testDocuments << QuickFixTestDocument::create("file.cpp", original, expected);
-
- GenerateGetterSetter factory;
- QuickFixOperationTest(testDocuments, &factory);
-}
-
void CppEditorPlugin::test_quickfix_GenerateGettersSetters_data()
{
QTest::addColumn<QByteArray>("original");
QTest::addColumn<QByteArray>("expected");
- const QByteArray noCandidates = R"(
+ const QByteArray onlyReset = R"(
class @Foo {
public:
int bar() const;
@@ -2676,7 +3115,23 @@ public:
private:
int m_bar;
};)";
- QTest::addRow("without candidates") << noCandidates << QByteArray();
+
+ const QByteArray onlyResetAfter = R"(
+class @Foo {
+public:
+ int bar() const;
+ void setBar(int bar);
+ void resetBar();
+
+private:
+ int m_bar;
+};
+inline void Foo::resetBar()
+{
+ setBar({}); // TODO: Adapt to use your actual default defaultValue
+}
+)";
+ QTest::addRow("only reset") << onlyReset << onlyResetAfter;
const QByteArray withCandidates = R"(
class @Foo {
@@ -2707,10 +3162,16 @@ public:
int m_alreadyPublic;
- void setBar2(int bar2);
-
- QString getBar3() const;
+ void resetBar();
+ void setBar2(int value);
+ void resetBar2();
+ const QString &getBar3() const;
void setBar3(const QString &value);
+ void resetBar3();
+
+signals:
+ void bar2Changed();
+ void bar3Changed();
private:
friend void distraction();
@@ -2720,20 +3181,43 @@ private:
int m_bar;
int bar2_;
QString bar3;
+ Q_PROPERTY(int bar2 READ getBar2 WRITE setBar2 RESET resetBar2 NOTIFY bar2Changed)
+ Q_PROPERTY(QString bar3 READ getBar3 WRITE setBar3 RESET resetBar3 NOTIFY bar3Changed)
};
-inline void Foo::setBar2(int bar2)
+inline void Foo::resetBar()
+{
+ setBar({}); // TODO: Adapt to use your actual default defaultValue
+}
+
+inline void Foo::setBar2(int value)
+{
+ if (bar2_ == value)
+ return;
+ bar2_ = value;
+ emit bar2Changed();
+}
+
+inline void Foo::resetBar2()
{
- bar2_ = bar2;
+ setBar2({}); // TODO: Adapt to use your actual default defaultValue
}
-inline QString Foo::getBar3() const
+inline const QString &Foo::getBar3() const
{
return bar3;
}
inline void Foo::setBar3(const QString &value)
{
+ if (bar3 == value)
+ return;
bar3 = value;
+ emit bar3Changed();
+}
+
+inline void Foo::resetBar3()
+{
+ setBar3({}); // TODO: Adapt to use your actual default defaultValue
}
)";
QTest::addRow("with candidates") << withCandidates << after;
@@ -2750,10 +3234,156 @@ void CppEditorPlugin::test_quickfix_GenerateGettersSetters()
QFETCH(QByteArray, original);
QFETCH(QByteArray, expected);
+ QuickFixSettings s;
+ s->getterNameTemplate = "get<Name>";
+ s->setterParameterNameTemplate = "value";
+ s->setterOutsideClassFrom = 1;
+ s->getterOutsideClassFrom = 1;
+
TestFactory factory;
QuickFixOperationTest({QuickFixTestDocument::create("file.h", original, expected)}, &factory);
}
+void CppEditorPlugin::test_quickfix_InsertQtPropertyMembers_data()
+{
+ QTest::addColumn<QByteArray>("original");
+ QTest::addColumn<QByteArray>("expected");
+
+ QTest::newRow("InsertQtPropertyMembers")
+ << _("struct XmarksTheSpot {\n"
+ " @Q_PROPERTY(int it READ getIt WRITE setIt RESET resetIt NOTIFY itChanged)\n"
+ "};\n")
+ << _("struct XmarksTheSpot {\n"
+ " Q_PROPERTY(int it READ getIt WRITE setIt RESET resetIt NOTIFY itChanged)\n"
+ "\n"
+ "public:\n"
+ " int getIt() const\n"
+ " {\n"
+ " return m_it;\n"
+ " }\n"
+ "\n"
+ "public slots:\n"
+ " void setIt(int it)\n"
+ " {\n"
+ " if (m_it == it)\n"
+ " return;\n"
+ " m_it = it;\n"
+ " emit itChanged(m_it);\n"
+ " }\n"
+ " void resetIt()\n"
+ " {\n"
+ " setIt({}); // TODO: Adapt to use your actual default value\n"
+ " }\n"
+ "\n"
+ "signals:\n"
+ " void itChanged(int);\n"
+ "\n"
+ "private:\n"
+ " int m_it;\n"
+ "};\n");
+
+ QTest::newRow("InsertQtPropertyMembersResetWithoutSet")
+ << _("struct XmarksTheSpot {\n"
+ " @Q_PROPERTY(int it READ getIt RESET resetIt NOTIFY itChanged)\n"
+ "};\n")
+ << _("struct XmarksTheSpot {\n"
+ " Q_PROPERTY(int it READ getIt RESET resetIt NOTIFY itChanged)\n"
+ "\n"
+ "public:\n"
+ " int getIt() const\n"
+ " {\n"
+ " return m_it;\n"
+ " }\n"
+ "\n"
+ "public slots:\n"
+ " void resetIt()\n"
+ " {\n"
+ " static int defaultValue{}; // TODO: Adapt to use your actual default "
+ "value\n"
+ " if (m_it == defaultValue)\n"
+ " return;\n"
+ " m_it = defaultValue;\n"
+ " emit itChanged(m_it);\n"
+ " }\n"
+ "\n"
+ "signals:\n"
+ " void itChanged(int);\n"
+ "\n"
+ "private:\n"
+ " int m_it;\n"
+ "};\n");
+
+ QTest::newRow("InsertQtPropertyMembersResetWithoutSetAndNotify")
+ << _("struct XmarksTheSpot {\n"
+ " @Q_PROPERTY(int it READ getIt RESET resetIt)\n"
+ "};\n")
+ << _("struct XmarksTheSpot {\n"
+ " Q_PROPERTY(int it READ getIt RESET resetIt)\n"
+ "\n"
+ "public:\n"
+ " int getIt() const\n"
+ " {\n"
+ " return m_it;\n"
+ " }\n"
+ "\n"
+ "public slots:\n"
+ " void resetIt()\n"
+ " {\n"
+ " static int defaultValue{}; // TODO: Adapt to use your actual default "
+ "value\n"
+ " m_it = defaultValue;\n"
+ " }\n"
+ "\n"
+ "private:\n"
+ " int m_it;\n"
+ "};\n");
+
+ QTest::newRow("InsertQtPropertyMembersPrivateBeforePublic")
+ << _("class XmarksTheSpot {\n"
+ "private:\n"
+ " @Q_PROPERTY(int it READ getIt WRITE setIt NOTIFY itChanged)\n"
+ "public:\n"
+ " void find();\n"
+ "};\n")
+ << _("class XmarksTheSpot {\n"
+ "private:\n"
+ " Q_PROPERTY(int it READ getIt WRITE setIt NOTIFY itChanged)\n"
+ " int m_it;\n"
+ "\n"
+ "public:\n"
+ " void find();\n"
+ " int getIt() const\n"
+ " {\n"
+ " return m_it;\n"
+ " }\n"
+ "public slots:\n"
+ " void setIt(int it)\n"
+ " {\n"
+ " if (m_it == it)\n"
+ " return;\n"
+ " m_it = it;\n"
+ " emit itChanged(m_it);\n"
+ " }\n"
+ "signals:\n"
+ " void itChanged(int);\n"
+ "};\n");
+}
+
+void CppEditorPlugin::test_quickfix_InsertQtPropertyMembers()
+{
+ QFETCH(QByteArray, original);
+ QFETCH(QByteArray, expected);
+
+ QuickFixSettings s;
+ s->setterAsSlot = true;
+ s->setterInCppFileFrom = 0;
+ s->setterParameterNameTemplate = "<name>";
+ s->signalWithNewValue = true;
+
+ InsertQtPropertyMembers factory;
+ QuickFixOperationTest({QuickFixTestDocument::create("file.cpp", original, expected)}, &factory);
+}
+
void CppEditorPlugin::test_quickfix_InsertMemberFromInitialization_data()
{
QTest::addColumn<QByteArray>("original");
diff --git a/src/plugins/cppeditor/cppquickfixes.cpp b/src/plugins/cppeditor/cppquickfixes.cpp
index 50d0da5aff..10e99470ac 100644
--- a/src/plugins/cppeditor/cppquickfixes.cpp
+++ b/src/plugins/cppeditor/cppquickfixes.cpp
@@ -25,16 +25,16 @@
#include "cppquickfixes.h"
-#include "cppeditorwidget.h"
#include "cppeditordocument.h"
+#include "cppeditorwidget.h"
#include "cppfunctiondecldeflink.h"
-#include "cppquickfixassistant.h"
#include "cppinsertvirtualmethods.h"
+#include "cppquickfixassistant.h"
+#include "cppquickfixprojectsettings.h"
#include <coreplugin/icore.h>
#include <coreplugin/messagebox.h>
-#include <cpptools/cppvirtualfunctionassistprovider.h>
#include <cpptools/baseeditordocumentprocessor.h>
#include <cpptools/cppclassesfilter.h>
#include <cpptools/cppcodestylesettings.h>
@@ -43,6 +43,7 @@
#include <cpptools/cpptoolsbridge.h>
#include <cpptools/cpptoolsconstants.h>
#include <cpptools/cpptoolsreuse.h>
+#include <cpptools/cppvirtualfunctionassistprovider.h>
#include <cpptools/includeutils.h>
#include <cpptools/insertionpointlocator.h>
#include <cpptools/symbolfinder.h>
@@ -81,8 +82,8 @@
#include <QRegularExpression>
#include <QSharedPointer>
#include <QStack>
-#include <QTextCursor>
#include <QTextCodec>
+#include <QTextCursor>
#include <QVBoxLayout>
#include <bitset>
@@ -169,7 +170,7 @@ private:
if (id)
name = QString::fromUtf8(id->chars(), id->size());
if (name != m_remainingNamespaces.first())
- return name.isEmpty();
+ return false;
if (!ns->linkage_body) {
m_done = true;
@@ -390,8 +391,11 @@ QStringList getNamespaceNames(const Namespace *firstNamespace)
if (scope->name() && scope->name()->identifier()) {
namespaces.prepend(QString::fromUtf8(scope->name()->identifier()->chars(),
scope->name()->identifier()->size()));
+ } else {
+ namespaces.prepend(""); // an unnamed namespace
}
}
+ namespaces.pop_front(); // the "global namespace" is one namespace, but not an unnamed
return namespaces;
}
@@ -496,13 +500,6 @@ inline bool isQtStringTranslation(const QByteArray &id)
return id == "tr" || id == "trUtf8" || id == "translate" || id == "QT_TRANSLATE_NOOP";
}
-inline bool isQtFuzzyComparable(const QString &typeName)
-{
- return typeName == QLatin1String("double")
- || typeName == QLatin1String("float")
- || typeName == QLatin1String("qreal");
-}
-
Class *isMemberFunction(const LookupContext &context, Function *function)
{
QTC_ASSERT(function, return nullptr);
@@ -613,6 +610,17 @@ QString memberBaseName(const QString &name)
{
QString baseName = name;
+ CppQuickFixSettings *settings = CppQuickFixProjectsSettings::getQuickFixSettings(
+ ProjectExplorer::ProjectTree::currentProject());
+ const QString &nameTemplate = settings->memberVariableNameTemplate;
+ const QString prefix = nameTemplate.left(nameTemplate.indexOf('<'));
+ const QString postfix = nameTemplate.mid(nameTemplate.lastIndexOf('>') + 1);
+ if (name.startsWith(prefix) && name.endsWith(postfix)) {
+ const QString base = name.mid(prefix.length(), name.length() - postfix.length());
+ if (!base.isEmpty())
+ return base;
+ }
+
// Remove leading and trailing "_"
while (baseName.startsWith(QLatin1Char('_')))
baseName.remove(0, 1);
@@ -3625,519 +3633,1069 @@ void InsertDefsFromDecls::match(const CppQuickFixInterface &interface, QuickFixO
namespace {
-bool hasClassMemberWithGetPrefix(const Class *klass)
+Utils::optional<FullySpecifiedType> getFirstTemplateParameter(const Name *name)
{
- if (!klass)
- return false;
+ if (const QualifiedNameId *qualifiedName = name->asQualifiedNameId())
+ return getFirstTemplateParameter(qualifiedName->name());
- for (int i = 0; i < klass->memberCount(); ++i) {
- const Symbol *symbol = klass->memberAt(i);
- if (symbol->isFunction() || symbol->isDeclaration()) {
- if (const Name *symbolName = symbol->name()) {
- if (const Identifier *id = symbolName->identifier()) {
- if (!strncmp(id->chars(), "get", 3))
- return true;
+ if (const TemplateNameId *templateName = name->asTemplateNameId()) {
+ if (templateName->templateArgumentCount() > 0)
+ return templateName->templateArgumentAt(0).type();
+ }
+ return {};
+}
+
+Utils::optional<FullySpecifiedType> getFirstTemplateParameter(Type *type)
+{
+ if (NamedType *namedType = type->asNamedType())
+ return getFirstTemplateParameter(namedType->name());
+
+ return {};
+}
+
+Utils::optional<FullySpecifiedType> getFirstTemplateParameter(FullySpecifiedType type)
+{
+ return getFirstTemplateParameter(type.type());
+}
+
+QString symbolAtDifferentLocation(const CppQuickFixInterface &interface,
+ Symbol *symbol,
+ CppRefactoringFilePtr &targetFile,
+ InsertionLocation targetLocation)
+{
+ QTC_ASSERT(symbol, return QString());
+ Scope *scopeAtInsertPos = targetFile->cppDocument()->scopeAt(targetLocation.line(),
+ targetLocation.column());
+
+ LookupContext cppContext(targetFile->cppDocument(), interface.snapshot());
+ ClassOrNamespace *cppCoN = cppContext.lookupType(scopeAtInsertPos);
+ if (!cppCoN)
+ cppCoN = cppContext.globalNamespace();
+ SubstitutionEnvironment env;
+ env.setContext(interface.context());
+ env.switchScope(symbol->enclosingScope());
+ UseMinimalNames q(cppCoN);
+ env.enter(&q);
+ Control *control = interface.context().bindings()->control().data();
+ Overview oo = CppCodeStyleSettings::currentProjectCodeStyleOverview();
+ return oo.prettyName(LookupContext::minimalName(symbol, cppCoN, control));
+}
+
+FullySpecifiedType typeAtDifferentLocation(const CppQuickFixInterface &interface,
+ FullySpecifiedType type,
+ Scope *originalScope,
+ CppRefactoringFilePtr &targetFile,
+ InsertionLocation targetLocation)
+{
+ Scope *scopeAtInsertPos = targetFile->cppDocument()->scopeAt(targetLocation.line(),
+ targetLocation.column());
+
+ LookupContext cppContext(targetFile->cppDocument(), interface.snapshot());
+ ClassOrNamespace *cppCoN = cppContext.lookupType(scopeAtInsertPos);
+ if (!cppCoN)
+ cppCoN = cppContext.globalNamespace();
+ SubstitutionEnvironment env;
+ env.setContext(interface.context());
+ env.switchScope(originalScope);
+ UseMinimalNames q(cppCoN);
+ env.enter(&q);
+ Control *control = interface.context().bindings()->control().data();
+ return rewriteType(type, &env, control);
+}
+
+struct ExistingGetterSetterData
+{
+ Class *clazz = nullptr;
+ Declaration *declarationSymbol = nullptr;
+ QString getterName;
+ QString setterName;
+ QString resetName;
+ QString signalName;
+ QString qPropertyName;
+ QString memberVariableName;
+ Document::Ptr doc;
+
+ int computePossibleFlags() const;
+};
+
+class GetterSetterRefactoringHelper
+{
+public:
+ GetterSetterRefactoringHelper(CppQuickFixOperation *operation, const QString &fileName, Class *clazz)
+ : m_operation(operation)
+ , m_changes(m_operation->snapshot())
+ , m_locator(m_changes)
+ , m_class(clazz)
+ {
+ m_headerFile = m_changes.file(fileName);
+ QString cppFileName = correspondingHeaderOrSource(fileName, &m_isHeaderHeaderFile);
+ if (!m_isHeaderHeaderFile || !QFile::exists(cppFileName)) {
+ // there is no "source" file
+ m_sourceFile = m_headerFile;
+ } else {
+ m_sourceFile = m_changes.file(cppFileName);
+ }
+ }
+
+ void performGeneration(ExistingGetterSetterData data, int generationFlags);
+
+ void applyChanges()
+ {
+ const auto classLayout = {
+ InsertionPointLocator::Public,
+ InsertionPointLocator::PublicSlot,
+ InsertionPointLocator::Signals,
+ InsertionPointLocator::Protected,
+ InsertionPointLocator::ProtectedSlot,
+ InsertionPointLocator::PrivateSlot,
+ InsertionPointLocator::Private,
+ };
+ for (auto spec : classLayout) {
+ const auto iter = m_headerFileCode.find(spec);
+ if (iter != m_headerFileCode.end())
+ insertAndIndent(m_headerFile, headerLocationFor(spec), *iter);
+ }
+ if (!m_sourceFileCode.isEmpty() && m_sourceFileInsertionPoint.isValid())
+ insertAndIndent(m_sourceFile, m_sourceFileInsertionPoint, m_sourceFileCode);
+
+ if (!m_headerFileChangeSet.isEmpty()) {
+ m_headerFile->setChangeSet(m_headerFileChangeSet);
+ m_headerFile->apply();
+ }
+ if (!m_sourceFileChangeSet.isEmpty()) {
+ m_sourceFile->setOpenEditor();
+ m_sourceFile->setChangeSet(m_sourceFileChangeSet);
+ m_sourceFile->apply();
+ }
+ }
+
+ bool hasSourceFile() { return m_headerFile != m_sourceFile; }
+
+protected:
+ void insertAndIndent(const RefactoringFilePtr &file,
+ const InsertionLocation &loc,
+ const QString &text)
+ {
+ int targetPosition1 = file->position(loc.line(), loc.column());
+ int targetPosition2 = qMax(0, file->position(loc.line(), 1) - 1);
+ ChangeSet &changeSet = file == m_headerFile ? m_headerFileChangeSet : m_sourceFileChangeSet;
+ changeSet.insert(targetPosition1, loc.prefix() + text + loc.suffix());
+ file->appendIndentRange(ChangeSet::Range(targetPosition2, targetPosition1));
+ }
+
+ FullySpecifiedType makeConstRef(FullySpecifiedType type)
+ {
+ type.setConst(true);
+ return m_operation->currentFile()->cppDocument()->control()->referenceType(type, false);
+ }
+
+ FullySpecifiedType addConstToReference(FullySpecifiedType type)
+ {
+ if (ReferenceType *ref = type.type()->asReferenceType()) {
+ FullySpecifiedType elemType = ref->elementType();
+ if (elemType.isConst())
+ return type;
+ elemType.setConst(true);
+ return m_operation->currentFile()->cppDocument()->control()->referenceType(elemType,
+ false);
+ }
+ return type;
+ }
+
+ QString symbolAt(Symbol *symbol, CppRefactoringFilePtr &targetFile, InsertionLocation targetLocation)
+ {
+ return symbolAtDifferentLocation(*m_operation, symbol, targetFile, targetLocation);
+ }
+
+ FullySpecifiedType typeAt(FullySpecifiedType type,
+ Scope *originalScope,
+ CppRefactoringFilePtr &targetFile,
+ InsertionLocation targetLocation)
+ {
+ return typeAtDifferentLocation(*m_operation, type, originalScope, targetFile, targetLocation);
+ }
+
+ void addHeaderCode(InsertionPointLocator::AccessSpec spec, QString code)
+ {
+ QString &existing = m_headerFileCode[spec];
+ existing += code;
+ if (!existing.endsWith('\n'))
+ existing += '\n';
+ }
+
+ InsertionLocation headerLocationFor(InsertionPointLocator::AccessSpec spec)
+ {
+ const auto insertionPoint = m_headerInsertionPoints.find(spec);
+ if (insertionPoint != m_headerInsertionPoints.end())
+ return *insertionPoint;
+ const InsertionLocation loc = m_locator.methodDeclarationInClass(m_headerFile->fileName(),
+ m_class,
+ spec);
+ m_headerInsertionPoints.insert(spec, loc);
+ return loc;
+ }
+
+ InsertionLocation sourceLocationFor(Declaration *declarationSymbol)
+ {
+ if (m_sourceFileInsertionPoint.isValid())
+ return m_sourceFileInsertionPoint;
+ m_sourceFileInsertionPoint = insertLocationForMethodDefinition(
+ declarationSymbol,
+ false,
+ m_settings->createMissingNamespacesinCppFile() ? NamespaceHandling::CreateMissing
+ : NamespaceHandling::Ignore,
+ m_changes,
+ m_sourceFile->fileName());
+ if (m_settings->addUsingNamespaceinCppFile()) {
+ // check if we have to insert a using namespace ...
+ auto requiredNamespaces = getNamespaceNames(declarationSymbol->enclosingClass());
+ NSCheckerVisitor visitor(m_sourceFile.get(),
+ requiredNamespaces,
+ m_sourceFile->position(m_sourceFileInsertionPoint.line(),
+ m_sourceFileInsertionPoint.column()));
+ visitor.accept(m_sourceFile->cppDocument()->translationUnit()->ast());
+ if (auto rns = visitor.remainingNamespaces(); !rns.empty()) {
+ QString ns = "using namespace ";
+ for (auto &n : rns) {
+ if (!n.isEmpty()) { // we have to ignore unnamed namespaces
+ ns += n;
+ ns += "::";
+ }
}
+ ns.resize(ns.size() - 2); // remove last '::'
+ ns += ";\n";
+ const auto &loc = m_sourceFileInsertionPoint;
+ m_sourceFileInsertionPoint = InsertionLocation(loc.fileName(),
+ loc.prefix() + ns,
+ loc.suffix(),
+ loc.line(),
+ loc.column());
}
}
+ return m_sourceFileInsertionPoint;
}
- return false;
-}
-class GenerateGetterSetterOperation : public CppQuickFixOperation
+ void addSourceFileCode(QString code)
+ {
+ while (!m_sourceFileCode.isEmpty() && !m_sourceFileCode.endsWith("\n\n"))
+ m_sourceFileCode += '\n';
+ m_sourceFileCode += code;
+ }
+
+private:
+ CppQuickFixOperation *m_operation;
+ CppRefactoringChanges m_changes;
+ CppRefactoringFilePtr m_headerFile;
+ CppRefactoringFilePtr m_sourceFile;
+ ChangeSet m_headerFileChangeSet;
+ ChangeSet m_sourceFileChangeSet;
+ InsertionPointLocator m_locator;
+ QMap<InsertionPointLocator::AccessSpec, InsertionLocation> m_headerInsertionPoints;
+ InsertionLocation m_sourceFileInsertionPoint;
+ CppQuickFixSettings *m_settings = CppQuickFixProjectsSettings::getQuickFixSettings(
+ ProjectExplorer::ProjectTree::currentProject());
+ QString m_sourceFileCode;
+ Class *m_class;
+ QMap<InsertionPointLocator::AccessSpec, QString> m_headerFileCode;
+ bool m_isHeaderHeaderFile; // the "header" (where the class is defined) can be a source file
+};
+
+class GenerateGetterSetterOp : public CppQuickFixOperation
{
public:
- enum OperationType {
- InvalidType,
- GetterSetterType,
- GetterType,
- SetterType
+ enum GenerateFlag {
+ GenerateGetter = 1 << 0,
+ GenerateSetter = 1 << 1,
+ GenerateSignal = 1 << 2,
+ GenerateMemberVariable = 1 << 3,
+ GenerateReset = 1 << 4,
+ GenerateProperty = 1 << 5,
+ GenerateConstantProperty = 1 << 6,
+ HaveExistingQProperty = 1 << 7,
};
- GenerateGetterSetterOperation(const CppQuickFixInterface &interface)
+ GenerateGetterSetterOp(const CppQuickFixInterface &interface,
+ ExistingGetterSetterData data,
+ int generateFlags,
+ int priority,
+ const QString &description)
: CppQuickFixOperation(interface)
+ , m_generateFlags(generateFlags)
+ , m_data(data)
{
- const QList<AST *> &path = interface.path();
- // We expect something like
- // [0] TranslationUnitAST
- // [1] NamespaceAST
- // [2] LinkageBodyAST
- // [3] SimpleDeclarationAST
- // [4] ClassSpecifierAST
- // [5] SimpleDeclarationAST
- // [6] DeclaratorAST
- // [7] DeclaratorIdAST
- // [8] SimpleNameAST
-
- const int n = path.size();
- if (n < 6)
- return;
+ setDescription(description);
+ setPriority(priority);
+ }
- int i = 1;
- m_variableName = path.at(n - i++)->asSimpleName();
- m_declaratorId = path.at(n - i++)->asDeclaratorId();
- // DeclaratorAST might be preceded by PointerAST, e.g. for the case
- // "class C { char *@s; };", where '@' denotes the text cursor position.
- if (!(m_declarator = path.at(n - i++)->asDeclarator())) {
- --i;
- if (path.at(n - i++)->asPointer()) {
- if (n < 7)
- return;
- m_declarator = path.at(n - i++)->asDeclarator();
+ static void generateQuickFixes(QuickFixOperations &results,
+ const CppQuickFixInterface &interface,
+ const ExistingGetterSetterData &data,
+ const int possibleFlags)
+ {
+ // flags can have the value HaveExistingQProperty or a combination of all other values
+ // of the enum 'GenerateFlag'
+ int p = 0;
+ if (possibleFlags & HaveExistingQProperty) {
+ const auto desc = CppQuickFixFactory::tr("Generate Missing Q_PROPERTY Members");
+ results << new GenerateGetterSetterOp(interface, data, possibleFlags, ++p, desc);
+ } else {
+ if (possibleFlags & GenerateSetter) {
+ const auto desc = CppQuickFixFactory::tr("Generate Setter");
+ results << new GenerateGetterSetterOp(interface, data, GenerateSetter, ++p, desc);
+ }
+ if (possibleFlags & GenerateGetter) {
+ const auto desc = CppQuickFixFactory::tr("Generate Getter");
+ results << new GenerateGetterSetterOp(interface, data, GenerateGetter, ++p, desc);
+ }
+ if (possibleFlags & GenerateGetter && possibleFlags & GenerateSetter) {
+ const auto desc = CppQuickFixFactory::tr("Generate Getter and Setter");
+ const auto flags = GenerateGetter | GenerateSetter;
+ results << new GenerateGetterSetterOp(interface, data, flags, ++p, desc);
+ }
+
+ if (possibleFlags & GenerateConstantProperty) {
+ const auto desc = CppQuickFixFactory::tr(
+ "Generate Constant Q_PROPERTY and Missing Members");
+ const auto flags = possibleFlags & ~(GenerateSetter | GenerateSignal | GenerateReset);
+ results << new GenerateGetterSetterOp(interface, data, flags, ++p, desc);
+ }
+ if (possibleFlags & GenerateProperty) {
+ if (possibleFlags & GenerateReset) {
+ const auto desc = CppQuickFixFactory::tr(
+ "Generate Q_PROPERTY and Missing Members with Reset Function");
+ const auto flags = possibleFlags & ~GenerateConstantProperty;
+ results << new GenerateGetterSetterOp(interface, data, flags, ++p, desc);
+ }
+ const auto desc = CppQuickFixFactory::tr("Generate Q_PROPERTY and Missing Members");
+ const auto flags = possibleFlags & ~GenerateConstantProperty & ~GenerateReset;
+ results << new GenerateGetterSetterOp(interface, data, flags, ++p, desc);
}
}
- m_variableDecl = path.at(n - i++)->asSimpleDeclaration();
- m_classSpecifier = path.at(n - i++)->asClassSpecifier();
- m_classDecl = path.at(n - i++)->asSimpleDeclaration();
+ }
- if (!isValid())
- return;
+ void perform() override
+ {
+ GetterSetterRefactoringHelper helper(this, currentFile()->fileName(), m_data.clazz);
+ helper.performGeneration(m_data, m_generateFlags);
+ helper.applyChanges();
+ }
- // Do not get triggered on member functions and arrays
- if (m_declarator->postfix_declarator_list) {
- m_offerQuickFix = false;
- return;
- }
+private:
+ int m_generateFlags;
+ ExistingGetterSetterData m_data;
+};
- // Construct getter and setter names
- const Name *variableName = m_variableName->name;
- if (!variableName) {
- m_offerQuickFix = false;
- return;
- }
- const Identifier *variableId = variableName->identifier();
- if (!variableId) {
- m_offerQuickFix = false;
- return;
- }
- m_variableString = QString::fromUtf8(variableId->chars(), variableId->size());
-
- determineGetterSetterNames();
-
- // Check if the class has already a getter and/or a setter.
- // This is only a simple check which should suffice not triggering the
- // same quick fix again. Limitations:
- // 1) It only checks in the current class, but not in base classes.
- // 2) It compares only names instead of types/signatures.
- // 3) Symbols in Qt property declarations are ignored.
- bool hasGetter = false;
- bool hasSetter = false;
- if (Class *klass = m_classSpecifier->symbol) {
- for (int i = 0; i < klass->memberCount(); ++i) {
- Symbol *symbol = klass->memberAt(i);
- if (symbol->isQtPropertyDeclaration())
- continue;
- if (const Name *symbolName = symbol->name()) {
- if (const Identifier *id = symbolName->identifier()) {
- const QString memberName = QString::fromUtf8(id->chars(), id->size());
- if (memberName == m_getterName)
- hasGetter = true;
- if (memberName == m_setterName)
- hasSetter = true;
- if (hasGetter && hasSetter)
- break;
- }
- }
- } // for
- }
- if (hasGetter && hasSetter) {
- m_offerQuickFix = false;
- return;
+int ExistingGetterSetterData::computePossibleFlags() const
+{
+ const bool isConst = declarationSymbol->type().isConst();
+ const bool isStatic = declarationSymbol->type().isStatic();
+ using Flag = GenerateGetterSetterOp::GenerateFlag;
+ int generateFlags = 0;
+ if (getterName.isEmpty())
+ generateFlags |= Flag::GenerateGetter;
+ if (!isConst) {
+ if (resetName.isEmpty())
+ generateFlags |= Flag::GenerateReset;
+ if (!isStatic && signalName.isEmpty() && setterName.isEmpty())
+ generateFlags |= Flag::GenerateSignal;
+ if (setterName.isEmpty())
+ generateFlags |= Flag::GenerateSetter;
+ }
+ if (!isStatic) {
+ const bool hasSignal = !signalName.isEmpty() || generateFlags & Flag::GenerateSignal;
+ if (!isConst && hasSignal)
+ generateFlags |= Flag::GenerateProperty;
+ }
+ if (setterName.isEmpty() && signalName.isEmpty())
+ generateFlags |= Flag::GenerateConstantProperty;
+ return generateFlags;
+}
+
+void GetterSetterRefactoringHelper::performGeneration(ExistingGetterSetterData data, int generateFlags)
+{
+ using Flag = GenerateGetterSetterOp::GenerateFlag;
+
+ if (generateFlags & Flag::GenerateGetter && data.getterName.isEmpty()) {
+ data.getterName = m_settings->getGetterName(data.qPropertyName);
+ if (data.getterName == data.memberVariableName) {
+ data.getterName = "get" + data.memberVariableName.left(1).toUpper()
+ + data.memberVariableName.mid(1);
}
+ }
+ if (generateFlags & Flag::GenerateSetter && data.setterName.isEmpty())
+ data.setterName = m_settings->getSetterName(data.qPropertyName);
+ if (generateFlags & Flag::GenerateSignal && data.signalName.isEmpty())
+ data.signalName = m_settings->getSignalName(data.qPropertyName);
+ if (generateFlags & Flag::GenerateReset && data.resetName.isEmpty())
+ data.resetName = m_settings->getResetName(data.qPropertyName);
- // Find the right symbol in the simple declaration
- const List<Symbol *> *symbols = m_variableDecl->symbols;
- QTC_ASSERT(symbols, return);
- for (; symbols; symbols = symbols->next) {
- Symbol *s = symbols->value;
- if (const Name *name = s->name()) {
+ FullySpecifiedType memberVariableType = data.declarationSymbol->type();
+ memberVariableType.setConst(false);
+ const bool isMemberVariableStatic = memberVariableType.isStatic();
+ memberVariableType.setStatic(false);
+ Overview overview = CppCodeStyleSettings::currentProjectCodeStyleOverview();
+ overview.showTemplateParameters = false;
+ // TODO does not work with using. e.g. 'using foo = std::unique_ptr<int>'
+ // TODO must be fully qualified
+ auto getSetTemplate = m_settings->findGetterSetterTemplate(overview.prettyType(memberVariableType));
+ overview.showTemplateParameters = true;
+
+ // Ok... - If a type is a Named type we have to search recusive for the real type
+ const bool isValueType = [settings = m_settings,
+ scope = data.declarationSymbol->enclosingScope(),
+ document = m_headerFile->cppDocument(),
+ &snapshot = m_changes.snapshot()](FullySpecifiedType type) {
+ // a type is a value type if it is one of the following
+ const auto isTypeValueType = [](const FullySpecifiedType &t) {
+ return t->isPointerType() || t->isEnumType() || t->isIntegerType() || t->isFloatType()
+ || t->isReferenceType();
+ };
+ if (type->isNamedType()) {
+ // we need a recursive search and a lookup context
+ LookupContext context(document, snapshot);
+ auto isValueType = [settings, &context, &isTypeValueType](const Name *name,
+ Scope *scope,
+ auto &isValueType) mutable -> bool {
+ // maybe the type is a custom value type by name
if (const Identifier *id = name->identifier()) {
- const QString symbolName = QString::fromUtf8(id->chars(), id->size());
- if (symbolName == m_variableString) {
- m_symbol = s;
- break;
+ if (settings->isValueType(QString::fromUtf8(id->chars(), id->size())))
+ return true;
+ }
+ // search for the type declaration
+ QList<LookupItem> localLookup = context.lookup(name, scope);
+ for (auto &&i : localLookup) {
+ if (isTypeValueType(i.type()))
+ return true;
+ if (i.type()->isNamedType()) { // check if we have to search recursively
+ const Name *newName = i.type()->asNamedType()->name();
+ Scope *newScope = i.declaration()->enclosingScope();
+ if (newName == name && newScope == scope)
+ continue; // we have found the start location of the search
+ return isValueType(newName, newScope, isValueType);
+ }
+ return false;
+ }
+ return false;
+ };
+ // start recursion
+ return isValueType(type->asNamedType()->name(), scope, isValueType);
+ }
+ return isTypeValueType(type);
+ }(memberVariableType);
+ const FullySpecifiedType parameterType = isValueType ? memberVariableType
+ : makeConstRef(memberVariableType);
+
+ QString baseName = memberBaseName(data.memberVariableName);
+ if (baseName.isEmpty())
+ baseName = data.memberVariableName;
+
+ const QString parameterName = m_settings->getSetterParameterName(baseName);
+ if (parameterName == data.memberVariableName)
+ data.memberVariableName = "this->" + data.memberVariableName;
+
+ getSetTemplate.replacePlaceholders(data.memberVariableName, parameterName);
+
+ using Pattern = CppQuickFixSettings::GetterSetterTemplate;
+ Utils::optional<FullySpecifiedType> returnTypeTemplateParameter;
+ if (getSetTemplate.returnTypeTemplate.has_value()) {
+ QString returnTypeTemplate = getSetTemplate.returnTypeTemplate.value();
+ if (returnTypeTemplate.contains(Pattern::TEMPLATE_PARAMETER_PATTERN)) {
+ returnTypeTemplateParameter = getFirstTemplateParameter(data.declarationSymbol->type());
+ if (!returnTypeTemplateParameter.has_value())
+ return; // Maybe report error to the user
+ }
+ }
+ const FullySpecifiedType returnTypeHeader = [&] {
+ if (!getSetTemplate.returnTypeTemplate.has_value())
+ return parameterType;
+ QString typeTemplate = getSetTemplate.returnTypeTemplate.value();
+ if (returnTypeTemplateParameter.has_value())
+ typeTemplate.replace(Pattern::TEMPLATE_PARAMETER_PATTERN,
+ overview.prettyType(returnTypeTemplateParameter.value()));
+ if (typeTemplate.contains(Pattern::TYPE_PATTERN))
+ typeTemplate.replace(Pattern::TYPE_PATTERN,
+ overview.prettyType(data.declarationSymbol->type()));
+ Control *control = m_operation->currentFile()->cppDocument()->control();
+ std::string utf8TypeName = typeTemplate.toUtf8().toStdString();
+ return FullySpecifiedType(control->namedType(control->identifier(utf8TypeName.c_str())));
+ }();
+
+ // getter declaration
+ if (generateFlags & Flag::GenerateGetter) {
+ // maybe we added 'this->' to memberVariableName because of a collision with parameterName
+ // but here the 'this->' is not needed
+ const QString returnExpression = QString{getSetTemplate.returnExpression}.replace("this->",
+ "");
+ QString getterInClassDeclaration = overview.prettyType(returnTypeHeader, data.getterName)
+ + QLatin1String("()");
+ if (isMemberVariableStatic)
+ getterInClassDeclaration.prepend(QLatin1String("static "));
+ else
+ getterInClassDeclaration += QLatin1String(" const");
+ getterInClassDeclaration.prepend(m_settings->getterAttributes + QLatin1Char(' '));
+ auto getterLocation = m_settings->determineGetterLocation(1);
+ if (getterLocation == CppQuickFixSettings::FunctionLocation::InsideClass) {
+ getterInClassDeclaration += QLatin1String("\n{\nreturn ") + returnExpression
+ + QLatin1String(";\n}\n");
+ } else {
+ getterInClassDeclaration += QLatin1String(";\n");
+ }
+ addHeaderCode(InsertionPointLocator::Public, getterInClassDeclaration);
+ if (getterLocation == CppQuickFixSettings::FunctionLocation::CppFile && !hasSourceFile())
+ getterLocation = CppQuickFixSettings::FunctionLocation::OutsideClass;
+
+ if (getterLocation != CppQuickFixSettings::FunctionLocation::InsideClass) {
+ const auto getReturnTypeAt = [&](CppRefactoringFilePtr targetFile,
+ InsertionLocation targetLoc) {
+ if (getSetTemplate.returnTypeTemplate.has_value()) {
+ QString returnType = getSetTemplate.returnTypeTemplate.value();
+ if (returnTypeTemplateParameter.has_value()) {
+ const QString templateTypeName = overview.prettyType(typeAt(
+ returnTypeTemplateParameter.value(), data.clazz, targetFile, targetLoc));
+ returnType.replace(Pattern::TEMPLATE_PARAMETER_PATTERN, templateTypeName);
+ }
+ if (returnType.contains(Pattern::TYPE_PATTERN)) {
+ const QString declarationType = overview.prettyType(
+ typeAt(memberVariableType, data.clazz, targetFile, targetLoc));
+ returnType.replace(Pattern::TYPE_PATTERN, declarationType);
}
+ Control *control = m_operation->currentFile()->cppDocument()->control();
+ std::string utf8String = returnType.toUtf8().toStdString();
+ return FullySpecifiedType(
+ control->namedType(control->identifier(utf8String.c_str())));
+ } else {
+ FullySpecifiedType returnType = typeAt(memberVariableType,
+ data.clazz,
+ targetFile,
+ targetLoc);
+ if (!isValueType)
+ return makeConstRef(returnType);
+ return returnType;
}
+ };
+ const QString constSpec = isMemberVariableStatic ? QLatin1String("")
+ : QLatin1String(" const");
+ if (getterLocation == CppQuickFixSettings::FunctionLocation::CppFile) {
+ InsertionLocation loc = sourceLocationFor(data.declarationSymbol);
+ FullySpecifiedType returnType;
+ QString clazz;
+ if (m_settings->rewriteTypesinCppFile()) {
+ returnType = getReturnTypeAt(m_sourceFile, loc);
+ clazz = symbolAt(data.clazz, m_sourceFile, loc);
+ } else {
+ returnType = returnTypeHeader;
+ const Identifier *identifier = data.clazz->name()->identifier();
+ clazz = QString::fromUtf8(identifier->chars(), identifier->size());
+ }
+ const QString code = overview.prettyType(returnType, clazz + "::" + data.getterName)
+ + "()" + constSpec + "\n{\nreturn " + returnExpression + ";\n}";
+ addSourceFileCode(code);
+ } else if (getterLocation == CppQuickFixSettings::FunctionLocation::OutsideClass) {
+ InsertionLocation loc = insertLocationForMethodDefinition(data.declarationSymbol,
+ false,
+ NamespaceHandling::Ignore,
+ m_changes,
+ m_headerFile->fileName());
+ const FullySpecifiedType returnType = getReturnTypeAt(m_headerFile, loc);
+ const QString clazz = symbolAt(data.clazz, m_headerFile, loc);
+ QString code = overview.prettyType(returnType, clazz + "::" + data.getterName)
+ + "()" + constSpec + "\n{\nreturn " + returnExpression + ";\n}";
+ if (m_isHeaderHeaderFile)
+ code.prepend("inline ");
+ insertAndIndent(m_headerFile, loc, code);
}
}
+ }
- QTC_ASSERT(m_symbol, return);
- if (hasSetter) { // hasGetter is false in this case
- m_type = GetterType;
- } else { // no setter
- if (hasGetter) {
- if (m_symbol->type().isConst()) {
- m_offerQuickFix = false;
- return;
+ // setter declaration
+ const InsertionPointLocator::AccessSpec setterAccessSpec = m_settings->setterAsSlot
+ ? InsertionPointLocator::PublicSlot
+ : InsertionPointLocator::Public;
+ const auto createSetterBodyWithSignal = [this, &getSetTemplate, &data] {
+ QString body;
+ QTextStream setter(&body);
+ setter << "if (" << getSetTemplate.equalComparison << ")\nreturn;\n";
+
+ setter << getSetTemplate.assignment << ";\n";
+ if (m_settings->signalWithNewValue)
+ setter << "emit " << data.signalName << "(" << getSetTemplate.returnExpression << ");\n";
+ else
+ setter << "emit " << data.signalName << "();\n";
+
+ return body;
+ };
+ if (generateFlags & Flag::GenerateSetter) {
+ QString headerDeclaration = "void " + data.setterName + '('
+ + overview.prettyType(addConstToReference(parameterType),
+ parameterName)
+ + ")";
+ if (isMemberVariableStatic)
+ headerDeclaration.prepend("static ");
+ QString body = "\n{\n";
+ if (data.signalName.isEmpty())
+ body += getSetTemplate.assignment + ";\n";
+ else
+ body += createSetterBodyWithSignal();
+
+ body += "}";
+
+ auto setterLocation = m_settings->determineSetterLocation(body.count('\n') - 2);
+ if (setterLocation == CppQuickFixSettings::FunctionLocation::CppFile && !hasSourceFile())
+ setterLocation = CppQuickFixSettings::FunctionLocation::OutsideClass;
+
+ if (setterLocation == CppQuickFixSettings::FunctionLocation::InsideClass) {
+ headerDeclaration += body;
+ } else {
+ headerDeclaration += ";\n";
+ if (setterLocation == CppQuickFixSettings::FunctionLocation::CppFile) {
+ InsertionLocation loc = sourceLocationFor(data.declarationSymbol);
+ QString clazz;
+ FullySpecifiedType newParameterType = parameterType;
+ if (m_settings->rewriteTypesinCppFile()) {
+ newParameterType = typeAt(memberVariableType, data.clazz, m_sourceFile, loc);
+ if (!isValueType)
+ newParameterType = makeConstRef(newParameterType);
+ clazz = symbolAt(data.clazz, m_sourceFile, loc);
} else {
- m_type = SetterType;
+ const Identifier *identifier = data.clazz->name()->identifier();
+ clazz = QString::fromUtf8(identifier->chars(), identifier->size());
}
- } else {
- m_type = (m_symbol->type().isConst()) ? GetterType : GetterSetterType;
+ newParameterType = addConstToReference(newParameterType);
+ const QString code = "void " + clazz + "::" + data.setterName + '('
+ + overview.prettyType(newParameterType, parameterName) + ')'
+ + body;
+ addSourceFileCode(code);
+ } else if (setterLocation == CppQuickFixSettings::FunctionLocation::OutsideClass) {
+ InsertionLocation loc = insertLocationForMethodDefinition(data.declarationSymbol,
+ false,
+ NamespaceHandling::Ignore,
+ m_changes,
+ m_headerFile->fileName());
+
+ FullySpecifiedType newParameterType = typeAt(data.declarationSymbol->type(),
+ data.clazz,
+ m_headerFile,
+ loc);
+ if (!isValueType)
+ newParameterType = makeConstRef(newParameterType);
+ newParameterType = addConstToReference(newParameterType);
+ QString clazz = symbolAt(data.clazz, m_headerFile, loc);
+
+ QString code = "void " + clazz + "::" + data.setterName + '('
+ + overview.prettyType(newParameterType, parameterName) + ')' + body;
+ if (m_isHeaderHeaderFile)
+ code.prepend("inline ");
+ insertAndIndent(m_headerFile, loc, code);
}
}
- updateDescriptionAndPriority();
+ addHeaderCode(setterAccessSpec, headerDeclaration);
}
- // Clones "other" in order to prevent all the initial detection made in the ctor.
- GenerateGetterSetterOperation(const CppQuickFixInterface &interface,
- GenerateGetterSetterOperation *other, OperationType type)
- : CppQuickFixOperation(interface)
- , m_type(type)
- , m_variableName(other->m_variableName)
- , m_declaratorId(other->m_declaratorId)
- , m_declarator(other->m_declarator)
- , m_variableDecl(other->m_variableDecl)
- , m_classSpecifier(other->m_classSpecifier)
- , m_classDecl(other->m_classDecl)
- , m_symbol(other->m_symbol)
- , m_baseName(other->m_baseName)
- , m_getterName(other->m_getterName)
- , m_setterName(other->m_setterName)
- , m_variableString(other->m_variableString)
- , m_offerQuickFix(other->m_offerQuickFix)
- {
- QTC_ASSERT(isValid(), return);
- updateDescriptionAndPriority();
- }
-
- void determineGetterSetterNames()
- {
- m_baseName = memberBaseName(m_variableString);
- if (m_baseName.isEmpty())
- m_baseName = QLatin1String("value");
-
- // Getter Name
- const Utils::optional<CppCodeStyleSettings> codeStyleSettings
- = CppCodeStyleSettings::currentProjectCodeStyle();
- const CppCodeStyleSettings settings
- = codeStyleSettings.value_or(CppCodeStyleSettings::currentGlobalCodeStyle());
- const bool hasValidBaseName = m_baseName != m_variableString;
- const bool getPrefixIsAlreadyUsed = hasClassMemberWithGetPrefix(m_classSpecifier->symbol);
- if (settings.preferGetterNameWithoutGetPrefix && hasValidBaseName && !getPrefixIsAlreadyUsed) {
- m_getterName = m_baseName;
+ // reset declaration
+ if (generateFlags & Flag::GenerateReset) {
+ QString headerDeclaration = "void " + data.resetName + "()";
+ if (isMemberVariableStatic)
+ headerDeclaration.prepend("static ");
+ QString body = "\n{\n";
+ if (!data.setterName.isEmpty()) {
+ body += data.setterName + "({}); // TODO: Adapt to use your actual default value\n";
} else {
- const QString baseNameWithCapital = m_baseName.left(1).toUpper() + m_baseName.mid(1);
- m_getterName = QLatin1String("get") + baseNameWithCapital;
+ body += "static $TYPE defaultValue{}; "
+ "// TODO: Adapt to use your actual default value\n";
+ if (data.signalName.isEmpty())
+ body += getSetTemplate.assignment + ";\n";
+ else
+ body += createSetterBodyWithSignal();
}
+ body += "}";
- // Setter Name
- const QString baseNameWithCapital = m_baseName.left(1).toUpper() + m_baseName.mid(1);
- m_setterName = QLatin1String("set") + baseNameWithCapital;
- }
+ // the template use <parameterName> as new value name, but we want to use 'defaultValue'
+ body.replace(QRegularExpression("\\b" + parameterName + "\\b"), "defaultValue");
+ // body.count('\n') - 2 : do not count the 2 at start
+ auto resetLocation = m_settings->determineSetterLocation(body.count('\n') - 2);
+ if (resetLocation == CppQuickFixSettings::FunctionLocation::CppFile && !hasSourceFile())
+ resetLocation = CppQuickFixSettings::FunctionLocation::OutsideClass;
- void updateDescriptionAndPriority()
- {
- switch (m_type) {
- case GetterSetterType:
- setPriority(5);
- setDescription(CppQuickFixFactory::tr("Create Getter and Setter Member Functions"));
- break;
- case GetterType:
- setPriority(4);
- setDescription(CppQuickFixFactory::tr("Create Getter Member Function"));
- break;
- case SetterType:
- setPriority(3);
- setDescription(CppQuickFixFactory::tr("Create Setter Member Function"));
- break;
- default:
- break;
+ if (resetLocation == CppQuickFixSettings::FunctionLocation::InsideClass) {
+ headerDeclaration += body.replace("$TYPE", overview.prettyType(memberVariableType));
+ } else {
+ headerDeclaration += ";\n";
+ if (resetLocation == CppQuickFixSettings::FunctionLocation::CppFile) {
+ const InsertionLocation loc = sourceLocationFor(data.declarationSymbol);
+ QString clazz;
+ FullySpecifiedType type = memberVariableType;
+ if (m_settings->rewriteTypesinCppFile()) {
+ type = typeAt(memberVariableType, data.clazz, m_sourceFile, loc);
+ clazz = symbolAt(data.clazz, m_sourceFile, loc);
+ } else {
+ const Identifier *identifier = data.clazz->name()->identifier();
+ clazz = QString::fromUtf8(identifier->chars(), identifier->size());
+ }
+ const QString code = "void " + clazz + "::" + data.resetName + "()"
+ + body.replace("$TYPE", overview.prettyType(type));
+ addSourceFileCode(code);
+ } else if (resetLocation == CppQuickFixSettings::FunctionLocation::OutsideClass) {
+ const InsertionLocation loc = insertLocationForMethodDefinition(
+ data.declarationSymbol,
+ false,
+ NamespaceHandling::Ignore,
+ m_changes,
+ m_headerFile->fileName());
+ const FullySpecifiedType type = typeAt(data.declarationSymbol->type(),
+ data.clazz,
+ m_headerFile,
+ loc);
+ const QString clazz = symbolAt(data.clazz, m_headerFile, loc);
+ QString code = "void " + clazz + "::" + data.resetName + "()"
+ + body.replace("$TYPE", overview.prettyType(type));
+ if (m_isHeaderHeaderFile)
+ code.prepend("inline ");
+ insertAndIndent(m_headerFile, loc, code);
+ }
}
+ addHeaderCode(setterAccessSpec, headerDeclaration);
}
- bool isValid() const
- {
- return m_variableName
- && m_declaratorId
- && m_declarator
- && m_variableDecl
- && m_classSpecifier
- && m_classDecl
- && m_offerQuickFix;
+ // signal declaration
+ if (generateFlags & Flag::GenerateSignal) {
+ const auto &paramType = overview.prettyType(returnTypeHeader);
+ const QString newValue = m_settings->signalWithNewValue ? paramType : QString();
+ const QString declaration = QString("void %1(%2);\n").arg(data.signalName, newValue);
+ addHeaderCode(InsertionPointLocator::Signals, declaration);
}
- static void addGetterAndOrSetter(
- const CppQuickFixInterface *quickFix,
- Symbol *symbol,
- const ClassSpecifierAST *classSpecifier,
- const QString &rawName,
- const QString &baseName,
- const QString &getterName,
- const QString &setterName,
- OperationType op)
- {
- CppRefactoringChanges refactoring(quickFix->snapshot());
- CppRefactoringFilePtr currentFile = refactoring.file(quickFix->filePath().toString());
+ // member variable
+ if (generateFlags & Flag::GenerateMemberVariable) {
+ const QString storageDeclaration = overview.prettyType(memberVariableType,
+ data.memberVariableName)
+ + QLatin1String(";\n");
+ addHeaderCode(InsertionPointLocator::Private, storageDeclaration);
+ }
- QTC_ASSERT(symbol, return);
- FullySpecifiedType fullySpecifiedType = symbol->type();
- Type *type = fullySpecifiedType.type();
- QTC_ASSERT(type, return);
- Overview oo = CppCodeStyleSettings::currentProjectCodeStyleOverview();
- oo.showFunctionSignatures = true;
- oo.showReturnTypes = true;
- oo.showArgumentNames = true;
- const QString typeString = oo.prettyType(fullySpecifiedType);
-
- const NameAST *classNameAST = classSpecifier->name;
- QTC_ASSERT(classNameAST, return);
- const Name *className = classNameAST->name;
- QTC_ASSERT(className, return);
- const Identifier *classId = className->identifier();
- QTC_ASSERT(classId, return);
- QString classString = QString::fromUtf8(classId->chars(), classId->size());
-
- bool wasHeader = true;
- QString declFileName = currentFile->fileName();
- QString implFileName = correspondingHeaderOrSource(declFileName, &wasHeader);
- const bool sameFile = !wasHeader || !QFile::exists(implFileName);
- if (sameFile)
- implFileName = declFileName;
+ // Q_PROPERTY
+ if (generateFlags & Flag::GenerateProperty || generateFlags & Flag::GenerateConstantProperty) {
+ // Use the returnTypeHeader as base because of custom types in getSetTemplates.
+ // Remove const reference from type.
+ FullySpecifiedType type = returnTypeHeader;
+ if (ReferenceType *ref = type.type()->asReferenceType())
+ type = ref->elementType();
+ type.setConst(false);
- InsertionPointLocator locator(refactoring);
- InsertionLocation declLocation = locator.methodDeclarationInClass
- (declFileName, classSpecifier->symbol->asClass(), InsertionPointLocator::Public);
-
- const bool passByValue = type->isIntegerType() || type->isFloatType()
- || type->isPointerType() || type->isEnumType();
- const QString paramName = baseName != rawName ? baseName : QLatin1String("value");
- QString paramString;
- if (passByValue) {
- paramString = oo.prettyType(fullySpecifiedType, paramName);
- } else {
- const ReferenceType *refType = type->asReferenceType();
- FullySpecifiedType constParamType(refType ? refType->elementType()
- : fullySpecifiedType);
- constParamType.setConst(true);
- QScopedPointer<ReferenceType> referenceType(new ReferenceType(constParamType, false));
- const FullySpecifiedType referenceToConstParamType(referenceType.data());
- paramString = oo.prettyType(referenceToConstParamType, paramName);
- }
-
- const bool isStatic = symbol->storage() == Symbol::Static;
-
- // Construct declaration strings
- QString declaration = declLocation.prefix();
- QString getterTypeString = typeString;
- FullySpecifiedType getterType(fullySpecifiedType);
- if (fullySpecifiedType.isConst()) {
- getterType.setConst(false);
- getterTypeString = oo.prettyType(getterType);
- }
-
- const QString declarationGetterTypeAndNameString = oo.prettyType(getterType, getterName);
- const QString declarationGetter = QString::fromLatin1("%1%2()%3;\n")
- .arg(isStatic ? QLatin1String("static ") : QString(),
- declarationGetterTypeAndNameString,
- isStatic ? QString() : QLatin1String(" const"));
- const QString declarationSetter = QString::fromLatin1("%1void %2(%3);\n")
- .arg(isStatic ? QLatin1String("static ") : QString(),
- setterName,
- paramString);
-
- const auto generateGetter = [op] { return op == GetterSetterType || op == GetterType; };
- const auto generateSetter = [op] { return op == GetterSetterType || op == SetterType; };
-
- if (generateGetter())
- declaration += declarationGetter;
- if (generateSetter())
- declaration += declarationSetter;
- declaration += declLocation.suffix();
-
- // Construct implementation strings
- const QString implementationGetterTypeAndNameString = oo.prettyType(
- getterType, QString::fromLatin1("%1::%2").arg(classString, getterName));
- const QString inlineSpecifier = sameFile && wasHeader ? QString("inline") : QString();
- const QString implementationGetter = QString::fromLatin1("%4 %1()%2\n"
- "{\n"
- "return %3;\n"
- "}")
- .arg(implementationGetterTypeAndNameString,
- isStatic ? QString() : QLatin1String(" const"),
- rawName, inlineSpecifier);
- const QString implementationSetter = QString::fromLatin1("%6 void %1::%2(%3)\n"
- "{\n"
- "%4 = %5;\n"
- "}")
- .arg(classString,
- setterName,
- paramString,
- rawName,
- paramName,
- inlineSpecifier);
-
- QString implementation;
- if (generateGetter())
- implementation += implementationGetter;
- if (generateSetter() && !fullySpecifiedType.isConst()) {
- if (!implementation.isEmpty())
- implementation += QLatin1String("\n\n");
- implementation += implementationSetter;
- }
-
- // Create and apply changes
- ChangeSet currChanges;
- int declInsertPos = currentFile->position(qMax(1, declLocation.line()),
- declLocation.column());
- currChanges.insert(declInsertPos, declaration);
-
- if (sameFile) {
- InsertionLocation loc = insertLocationForMethodDefinition(
- symbol, false, NamespaceHandling::CreateMissing, refactoring,
- currentFile->fileName());
- implementation = loc.prefix() + implementation + loc.suffix();
- const int implInsertPos = currentFile->position(loc.line(), loc.column());
- currChanges.insert(implInsertPos, implementation);
- currentFile->appendIndentRange(
- ChangeSet::Range(implInsertPos, implInsertPos + implementation.size()));
+ QString propertyDeclaration = QLatin1String("Q_PROPERTY(") + overview.prettyType(type)
+ + QLatin1Char(' ') + memberBaseName(data.memberVariableName);
+ bool needMember = false;
+ if (data.getterName.isEmpty())
+ needMember = true;
+ else
+ propertyDeclaration += QLatin1String(" READ ") + data.getterName;
+ if (generateFlags & Flag::GenerateConstantProperty) {
+ if (needMember)
+ propertyDeclaration += QLatin1String(" MEMBER ") + data.memberVariableName;
+ propertyDeclaration.append(QLatin1String(" CONSTANT"));
} else {
- CppRefactoringChanges implRef(quickFix->snapshot());
- CppRefactoringFilePtr implFile = implRef.file(implFileName);
- ChangeSet implChanges;
- InsertionLocation loc = insertLocationForMethodDefinition(
- symbol, false, NamespaceHandling::CreateMissing,
- implRef, implFileName);
- implementation = loc.prefix() + implementation + loc.suffix();
- const int implInsertPos = implFile->position(loc.line(), loc.column());
- implChanges.insert(implInsertPos, implementation);
- implFile->setChangeSet(implChanges);
- implFile->appendIndentRange(
- ChangeSet::Range(implInsertPos, implInsertPos + implementation.size()));
- implFile->apply();
- }
- currentFile->setChangeSet(currChanges);
- currentFile->appendIndentRange(
- ChangeSet::Range(declInsertPos, declInsertPos + declaration.size()));
- currentFile->apply();
+ if (data.setterName.isEmpty()) {
+ needMember = true;
+ } else if (!getSetTemplate.returnTypeTemplate.has_value()) {
+ // if the return type of the getter and then Q_PROPERTY is different than
+ // the setter type, we should not add WRITE to the Q_PROPERTY
+ propertyDeclaration.append(QLatin1String(" WRITE ")).append(data.setterName);
+ }
+ if (needMember)
+ propertyDeclaration += QLatin1String(" MEMBER ") + data.memberVariableName;
+ if (!data.resetName.isEmpty())
+ propertyDeclaration += QLatin1String(" RESET ") + data.resetName;
+ propertyDeclaration.append(QLatin1String(" NOTIFY ")).append(data.signalName);
+ }
+
+ propertyDeclaration.append(QLatin1String(")\n"));
+ addHeaderCode(InsertionPointLocator::Private, propertyDeclaration);
}
+}
- void perform() override
- {
- addGetterAndOrSetter(this, m_symbol, m_classSpecifier, m_variableString, m_baseName,
- m_getterName, m_setterName, m_type);
+QStringList toStringList(const QList<Symbol *> names)
+{
+ QStringList list;
+ list.reserve(names.size());
+ for (const auto symbol : names) {
+ const Identifier *const id = symbol->identifier();
+ list << QString::fromUtf8(id->chars(), id->size());
}
+ return list;
+}
- OperationType m_type = InvalidType;
- SimpleNameAST *m_variableName = nullptr;
- DeclaratorIdAST *m_declaratorId = nullptr;
- DeclaratorAST *m_declarator = nullptr;
- SimpleDeclarationAST *m_variableDecl = nullptr;
- ClassSpecifierAST *m_classSpecifier = nullptr;
- SimpleDeclarationAST *m_classDecl = nullptr;
- Symbol *m_symbol = nullptr;
+void findExistingFunctions(ExistingGetterSetterData &existing, QStringList memberFunctionNames)
+{
+ const CppQuickFixSettings *settings = CppQuickFixProjectsSettings::getQuickFixSettings(
+ ProjectExplorer::ProjectTree::currentProject());
+ const QString lowerBaseName = memberBaseName(existing.memberVariableName).toLower();
+ const QStringList getterNames{lowerBaseName,
+ "get_" + lowerBaseName,
+ "get" + lowerBaseName,
+ "is_" + lowerBaseName,
+ "is" + lowerBaseName,
+ settings->getGetterName(lowerBaseName)};
+ const QStringList setterNames{"set_" + lowerBaseName,
+ "set" + lowerBaseName,
+ settings->getSetterName(lowerBaseName)};
+ const QStringList resetNames{"reset_" + lowerBaseName,
+ "reset" + lowerBaseName,
+ settings->getResetName(lowerBaseName)};
+ const QStringList signalNames{lowerBaseName + "_changed",
+ lowerBaseName + "changed",
+ settings->getSignalName(lowerBaseName)};
+ for (const auto &memberFunctionName : memberFunctionNames) {
+ const QString lowerName = memberFunctionName.toLower();
+ if (getterNames.contains(lowerName))
+ existing.getterName = memberFunctionName;
+ else if (setterNames.contains(lowerName))
+ existing.setterName = memberFunctionName;
+ else if (resetNames.contains(lowerName))
+ existing.resetName = memberFunctionName;
+ else if (signalNames.contains(lowerName))
+ existing.signalName = memberFunctionName;
+ }
+}
- QString m_baseName;
- QString m_getterName;
- QString m_setterName;
- QString m_variableString;
- bool m_offerQuickFix = true;
-};
+QList<Symbol *> getMemberFunctions(const Class *clazz)
+{
+ QList<Symbol *> memberFunctions;
+ for (auto it = clazz->memberBegin(); it != clazz->memberEnd(); ++it) {
+ Symbol *const s = *it;
+ if (!s->identifier() || !s->type())
+ continue;
+ if ((s->isDeclaration() && s->type()->asFunctionType()) || s->asFunction())
+ memberFunctions << s;
+ }
+ return memberFunctions;
+}
} // anonymous namespace
-void GenerateGetterSetter::match(const CppQuickFixInterface &interface,
- QuickFixOperations &result)
+void GenerateGetterSetter::match(const CppQuickFixInterface &interface, QuickFixOperations &result)
{
- auto op = new GenerateGetterSetterOperation(interface);
- if (op->m_type != GenerateGetterSetterOperation::InvalidType) {
- result << op;
- if (op->m_type == GenerateGetterSetterOperation::GetterSetterType) {
- result << new GenerateGetterSetterOperation(
- interface, op, GenerateGetterSetterOperation::GetterType);
- result << new GenerateGetterSetterOperation(
- interface, op, GenerateGetterSetterOperation::SetterType);
+ ExistingGetterSetterData existing;
+
+ const QList<AST *> &path = interface.path();
+ // We expect something like
+ // [0] TranslationUnitAST
+ // [1] NamespaceAST
+ // [2] LinkageBodyAST
+ // [3] SimpleDeclarationAST
+ // [4] ClassSpecifierAST
+ // [5] SimpleDeclarationAST
+ // [6] DeclaratorAST
+ // [7] DeclaratorIdAST
+ // [8] SimpleNameAST
+
+ const int n = path.size();
+ if (n < 6)
+ return;
+
+ int i = 1;
+ const auto variableNameAST = path.at(n - i++)->asSimpleName();
+ const auto declaratorId = path.at(n - i++)->asDeclaratorId();
+ // DeclaratorAST might be preceded by PointerAST, e.g. for the case
+ // "class C { char *@s; };", where '@' denotes the text cursor position.
+ auto declarator = path.at(n - i++)->asDeclarator();
+ if (!declarator) {
+ --i;
+ if (path.at(n - i++)->asPointer()) {
+ if (n < 7)
+ return;
+ declarator = path.at(n - i++)->asDeclarator();
}
- } else {
- delete op;
}
+ const auto variableDecl = path.at(n - i++)->asSimpleDeclaration();
+ const auto classSpecifier = path.at(n - i++)->asClassSpecifier();
+ const auto classDecl = path.at(n - i++)->asSimpleDeclaration();
+
+ if (!(variableNameAST && declaratorId && variableDecl && classSpecifier && classDecl))
+ return;
+
+ // Do not get triggered on member functconstions and arrays
+ if (declarator->postfix_declarator_list) {
+ return;
+ }
+
+ // Construct getter and setter names
+ const Name *variableName = variableNameAST->name;
+ if (!variableName) {
+ return;
+ }
+ const Identifier *variableId = variableName->identifier();
+ if (!variableId) {
+ return;
+ }
+ existing.memberVariableName = QString::fromUtf8(variableId->chars(), variableId->size());
+
+ // Find the right symbol (for typeName) in the simple declaration
+ Symbol *symbol = nullptr;
+ const List<Symbol *> *symbols = variableDecl->symbols;
+ QTC_ASSERT(symbols, return );
+ for (; symbols; symbols = symbols->next) {
+ Symbol *s = symbols->value;
+ if (const Name *name = s->name()) {
+ if (const Identifier *id = name->identifier()) {
+ const QString symbolName = QString::fromUtf8(id->chars(), id->size());
+ if (symbolName == existing.memberVariableName) {
+ symbol = s;
+ break;
+ }
+ }
+ }
+ }
+ if (!symbol) {
+ // no type can be determined
+ return;
+ }
+ if (!symbol->isDeclaration()) {
+ return;
+ }
+ existing.declarationSymbol = symbol->asDeclaration();
+
+ existing.clazz = classSpecifier->symbol;
+ if (!existing.clazz)
+ return;
+
+ auto file = interface.currentFile();
+ // check if a Q_PROPERTY exist
+ const QString baseName = memberBaseName(existing.memberVariableName);
+ // eg: we have 'int m_test' and now 'Q_PROPERTY(int foo WRITE setTest MEMBER m_test NOTIFY tChanged)'
+ for (auto it = classSpecifier->member_specifier_list; it; it = it->next) {
+ if (it->value->asQtPropertyDeclaration()) {
+ auto propDecl = it->value->asQtPropertyDeclaration();
+ // iterator over 'READ ...', ...
+ auto p = propDecl->property_declaration_item_list;
+ // first check, if we have a MEMBER and the member is equal to the baseName
+ for (; p; p = p->next) {
+ const char *tokenString = file->tokenAt(p->value->item_name_token).spell();
+ if (!qstrcmp(tokenString, "MEMBER")) {
+ if (baseName == file->textOf(p->value->expression))
+ return;
+ }
+ }
+ // no MEMBER, but maybe the property name is the same
+ const QString propertyName = file->textOf(propDecl->property_name);
+ // we compare the baseName. e.g. 'test' instead of 'm_test'
+ if (propertyName == baseName)
+ return; // TODO Maybe offer quick fix "Add missing Q_PROPERTY Members"
+ }
+ }
+
+ findExistingFunctions(existing, toStringList(getMemberFunctions(existing.clazz)));
+ existing.qPropertyName = memberBaseName(existing.memberVariableName);
+
+ const int possibleFlags = existing.computePossibleFlags();
+ GenerateGetterSetterOp::generateQuickFixes(result, interface, existing, possibleFlags);
}
-class MemberInfo {
+class MemberInfo
+{
public:
- MemberInfo(Symbol *m, const QString &r, const QString &b, bool g, bool s)
- : member(m), rawName(r), baseName(b), hasGetter(g), hasSetter(s) {}
-
- Symbol *member = nullptr;
- QString rawName;
- QString baseName;
- bool hasGetter = false;
- bool hasSetter = false;
- bool getterRequested = false;
- bool setterRequested = false;
+ MemberInfo(ExistingGetterSetterData data, int possibleFlags)
+ : data(data)
+ , possibleFlags(possibleFlags)
+ {}
+
+ ExistingGetterSetterData data;
+ int possibleFlags;
+ int requestedFlags = 0;
};
using GetterSetterCandidates = std::vector<MemberInfo>;
class CandidateTreeItem : public Utils::TreeItem
{
public:
- static const int NameColumn = 0;
- static const int GetterColumn = 1;
- static const int SetterColumn = 2;
+ enum Column {
+ NameColumn,
+ GetterColumn,
+ SetterColumn,
+ SignalColumn,
+ ResetColumn,
+ QPropertyColumn,
+ ConstantQPropertyColumn
+ };
+ using Flag = GenerateGetterSetterOp::GenerateFlag;
+ constexpr static Flag ColumnFlag[] = {
+ static_cast<Flag>(-1),
+ Flag::GenerateGetter,
+ Flag::GenerateSetter,
+ Flag::GenerateSignal,
+ Flag::GenerateReset,
+ Flag::GenerateProperty,
+ Flag::GenerateConstantProperty,
+ };
- CandidateTreeItem(MemberInfo *candidate) : m_candidate(candidate) { }
+ CandidateTreeItem(MemberInfo *memberInfo)
+ : m_memberInfo(memberInfo)
+ {}
private:
QVariant data(int column, int role) const override
{
- switch (column) {
- case NameColumn:
- if (role == Qt::DisplayRole)
- return m_candidate->rawName;
- break;
- case GetterColumn:
- if (role == Qt::CheckStateRole)
- return m_candidate->hasGetter || m_candidate->getterRequested
- ? Qt::Checked : Qt::Unchecked;
- break;
- case SetterColumn:
- if (role == Qt::CheckStateRole)
- return m_candidate->hasSetter || m_candidate->setterRequested ?
- Qt::Checked : Qt::Unchecked;
- break;
+ if (role == Qt::DisplayRole && column == NameColumn)
+ return m_memberInfo->data.memberVariableName;
+ if (role == Qt::CheckStateRole && column > 0
+ && column <= static_cast<int>(std::size(ColumnFlag))) {
+ return m_memberInfo->requestedFlags & ColumnFlag[column] ? Qt::Checked : Qt::Unchecked;
}
return {};
}
bool setData(int column, const QVariant &data, int role) override
{
- switch (column) {
- case GetterColumn:
- if (role == Qt::CheckStateRole && !m_candidate->hasGetter) {
- m_candidate->getterRequested = data.toInt() == Qt::Checked;
- return true;
- }
- break;
- case SetterColumn:
- if (role == Qt::CheckStateRole && !m_candidate->hasSetter) {
- m_candidate->setterRequested = data.toInt() == Qt::Checked;
- return true;
+ if (column < 1 || column > static_cast<int>(std::size(ColumnFlag)))
+ return false;
+ if (role != Qt::CheckStateRole)
+ return false;
+ if (!(m_memberInfo->possibleFlags & ColumnFlag[column]))
+ return false;
+ const bool nowChecked = data.toInt() == Qt::Checked;
+ if (nowChecked)
+ m_memberInfo->requestedFlags |= ColumnFlag[column];
+ else
+ m_memberInfo->requestedFlags &= ~ColumnFlag[column];
+
+ if (nowChecked) {
+ if (column == QPropertyColumn) {
+ m_memberInfo->requestedFlags |= Flag::GenerateGetter;
+ m_memberInfo->requestedFlags |= Flag::GenerateSetter;
+ m_memberInfo->requestedFlags |= Flag::GenerateSignal;
+ m_memberInfo->requestedFlags &= ~Flag::GenerateConstantProperty;
+ } else if (column == ConstantQPropertyColumn) {
+ m_memberInfo->requestedFlags |= Flag::GenerateGetter;
+ m_memberInfo->requestedFlags &= ~Flag::GenerateSetter;
+ m_memberInfo->requestedFlags &= ~Flag::GenerateSignal;
+ m_memberInfo->requestedFlags &= ~Flag::GenerateReset;
+ m_memberInfo->requestedFlags &= ~Flag::GenerateProperty;
+ } else if (column == SetterColumn || column == SignalColumn || column == ResetColumn) {
+ m_memberInfo->requestedFlags &= ~Flag::GenerateConstantProperty;
}
- break;
- default:
- break;
+ } else {
+ if (column == SignalColumn)
+ m_memberInfo->requestedFlags &= ~Flag::GenerateProperty;
}
- return false;
+ for (int i = 0; i < 16; ++i) {
+ const bool allowed = m_memberInfo->possibleFlags & (1 << i);
+ if (!allowed)
+ m_memberInfo->requestedFlags &= ~(1 << i); // clear bit
+ }
+ update();
+ return true;
}
Qt::ItemFlags flags(int column) const override
{
- switch (column) {
- case NameColumn:
+ if (column == NameColumn)
return Qt::ItemIsEnabled;
- case GetterColumn:
- if (m_candidate->hasGetter)
- return {};
- return Qt::ItemIsEnabled | Qt::ItemIsUserCheckable;
- case SetterColumn:
- if (m_candidate->hasSetter)
- return {};
+ if (column < 1 || column > static_cast<int>(std::size(ColumnFlag)))
+ return {};
+ if (m_memberInfo->possibleFlags & ColumnFlag[column])
return Qt::ItemIsEnabled | Qt::ItemIsUserCheckable;
- }
return {};
}
- MemberInfo * const m_candidate;
+ MemberInfo *const m_memberInfo;
};
class GenerateGettersSettersDialog : public QDialog
@@ -4145,66 +4703,88 @@ class GenerateGettersSettersDialog : public QDialog
Q_DECLARE_TR_FUNCTIONS(GenerateGettersSettersDialog)
public:
GenerateGettersSettersDialog(const GetterSetterCandidates &candidates)
- : QDialog(), m_candidates(candidates)
+ : QDialog()
+ , m_candidates(candidates)
{
+ using Flags = GenerateGetterSetterOp::GenerateFlag;
setWindowTitle(tr("Getters and Setters"));
const auto model = new Utils::TreeModel<Utils::TreeItem, CandidateTreeItem>(this);
- model->setHeader(QStringList({tr("Member"), tr("Getter"), tr("Setter")}));
+ model->setHeader(QStringList({
+ tr("Member"),
+ tr("Getter"),
+ tr("Setter"),
+ tr("Signal"),
+ tr("Reset"),
+ tr("QProperty"),
+ tr("Constant QProperty"),
+ }));
for (MemberInfo &candidate : m_candidates)
model->rootItem()->appendChild(new CandidateTreeItem(&candidate));
const auto view = new Utils::BaseTreeView(this);
view->setModel(model);
+ int optimalWidth = 0;
+ for (int i = 0; i < model->columnCount(QModelIndex{}); ++i) {
+ view->resizeColumnToContents(i);
+ optimalWidth += view->columnWidth(i);
+ }
- const auto buttonBox
- = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
+ const auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
const auto setCheckStateForAll = [model](int column, int checkState) {
- for (int i = 0; i < model->rowCount(); ++i) {
- model->setData(model->index(i, column), checkState,
- Qt::CheckStateRole);
- }
+ for (int i = 0; i < model->rowCount(); ++i)
+ model->setData(model->index(i, column), checkState, Qt::CheckStateRole);
};
const auto preventPartiallyChecked = [](QCheckBox *checkbox) {
if (checkbox->checkState() == Qt::PartiallyChecked)
checkbox->setCheckState(Qt::Checked);
};
-
- QCheckBox *allGettersCheckbox = nullptr;
- if (Utils::anyOf(candidates, [](const MemberInfo &mi) { return !mi.hasGetter; })) {
- allGettersCheckbox = new QCheckBox(tr("Create getters for all members"));
- connect(allGettersCheckbox, &QCheckBox::stateChanged, [setCheckStateForAll](int state) {
- if (state != Qt::PartiallyChecked)
- setCheckStateForAll(CandidateTreeItem::GetterColumn, state);
- });
- connect(allGettersCheckbox, &QCheckBox::clicked, this,
- [allGettersCheckbox, preventPartiallyChecked] {
- preventPartiallyChecked(allGettersCheckbox);
- });
- }
- QCheckBox *allSettersCheckbox = nullptr;
- if (Utils::anyOf(candidates, [](const MemberInfo &mi) { return !mi.hasSetter; })) {
- allSettersCheckbox = new QCheckBox(tr("Create setters for all members"));
- connect(allSettersCheckbox, &QCheckBox::stateChanged, [setCheckStateForAll](int state) {
+ using Column = CandidateTreeItem::Column;
+ const auto createConnections = [=](QCheckBox *checkbox, Column column) {
+ connect(checkbox, &QCheckBox::stateChanged, [setCheckStateForAll, column](int state) {
if (state != Qt::PartiallyChecked)
- setCheckStateForAll(CandidateTreeItem::SetterColumn, state);
+ setCheckStateForAll(column, state);
});
- connect(allSettersCheckbox, &QCheckBox::clicked, this,
- [allSettersCheckbox, preventPartiallyChecked] {
- preventPartiallyChecked(allSettersCheckbox);
+ connect(checkbox, &QCheckBox::clicked, this, [checkbox, preventPartiallyChecked] {
+ preventPartiallyChecked(checkbox);
});
+ };
+ std::array<QCheckBox *, 4> checkBoxes = {};
+ constexpr Column CheckBoxColumn[4] = {Column::GetterColumn,
+ Column::SetterColumn,
+ Column::SignalColumn,
+ Column::QPropertyColumn};
+ static_assert(std::size(CheckBoxColumn) == checkBoxes.size(),
+ "Must contain the same number of elements");
+ for (std::size_t i = 0; i < checkBoxes.size(); ++i) {
+ if (Utils::anyOf(candidates, [i, CheckBoxColumn](const MemberInfo &mi) {
+ return mi.possibleFlags & CandidateTreeItem::ColumnFlag[CheckBoxColumn[i]];
+ })) {
+ const Column column = CheckBoxColumn[i];
+ if (column == Column::GetterColumn)
+ checkBoxes[i] = new QCheckBox(tr("Create getters for all members"));
+ else if (column == Column::SetterColumn)
+ checkBoxes[i] = new QCheckBox(tr("Create setters for all members"));
+ else if (column == Column::SignalColumn)
+ checkBoxes[i] = new QCheckBox(tr("Create signals for all members"));
+ else if (column == Column::QPropertyColumn)
+ checkBoxes[i] = new QCheckBox(tr("Create Q_PROPERTY for all members"));
+
+ createConnections(checkBoxes[i], column);
+ }
}
- const auto hasGetterCount = Utils::count(m_candidates, [](const MemberInfo &mi) {
- return mi.hasGetter; });
- const auto hasSetterCount = Utils::count(m_candidates, [](const MemberInfo &mi) {
- return mi.hasSetter; });
- connect(model, &QAbstractItemModel::dataChanged, this,
- [this, allGettersCheckbox, allSettersCheckbox, hasGetterCount, hasSetterCount] {
- const int getterRequestedCount = Utils::count(m_candidates, [](const MemberInfo &mi) {
- return mi.getterRequested; });
- const int setterRequestedCount = Utils::count(m_candidates, [](const MemberInfo &mi) {
- return mi.setterRequested; });
+ connect(model, &QAbstractItemModel::dataChanged, this, [this, checkBoxes, CheckBoxColumn] {
+ const auto countExisting = [this](Flags flag) {
+ return Utils::count(m_candidates, [flag](const MemberInfo &mi) {
+ return !(mi.possibleFlags & flag);
+ });
+ };
+ const auto countRequested = [this](Flags flag) {
+ return Utils::count(m_candidates, [flag](const MemberInfo &mi) {
+ return mi.requestedFlags & flag;
+ });
+ };
const auto countToState = [this](int requestedCount, int alreadyExistsCount) {
if (requestedCount == 0)
return Qt::Unchecked;
@@ -4212,25 +4792,28 @@ public:
return Qt::Checked;
return Qt::PartiallyChecked;
};
- if (allGettersCheckbox) {
- allGettersCheckbox->setCheckState(countToState(getterRequestedCount,
- hasGetterCount));
- }
- if (allSettersCheckbox) {
- allSettersCheckbox->setCheckState(countToState(setterRequestedCount,
- hasSetterCount));
+ for (std::size_t i = 0; i < checkBoxes.size(); ++i) {
+ if (checkBoxes[i]) {
+ const Flags flag = CandidateTreeItem::ColumnFlag[CheckBoxColumn[i]];
+ checkBoxes[i]->setCheckState(
+ countToState(countRequested(flag), countExisting(flag)));
+ }
}
});
const auto mainLayout = new QVBoxLayout(this);
mainLayout->addWidget(new QLabel(tr("Please select the getters and/or setters "
"to be created.")));
- if (allGettersCheckbox)
- mainLayout->addWidget(allGettersCheckbox);
- if (allSettersCheckbox)
- mainLayout->addWidget(allSettersCheckbox);
+ for (auto checkBox : checkBoxes) {
+ if (checkBox)
+ mainLayout->addWidget(checkBox);
+ }
mainLayout->addWidget(view);
mainLayout->addWidget(buttonBox);
+ int left, right;
+ mainLayout->getContentsMargins(&left, nullptr, &right, nullptr);
+ optimalWidth += left + right;
+ resize(optimalWidth, mainLayout->sizeHint().height());
}
GetterSetterCandidates candidates() const { return m_candidates; }
@@ -4252,14 +4835,14 @@ public:
return;
// Determine if cursor is on a class
- const SimpleNameAST * const nameAST = path.at(path.size() - 1)->asSimpleName();
+ const SimpleNameAST *const nameAST = path.at(path.size() - 1)->asSimpleName();
if (!nameAST || !interface.isCursorOn(nameAST))
- return;
+ return;
m_classAST = path.at(path.size() - 2)->asClassSpecifier();
if (!m_classAST)
return;
- const Class * const theClass = m_classAST->symbol;
+ Class *const theClass = m_classAST->symbol;
if (!theClass)
return;
@@ -4267,8 +4850,8 @@ public:
QList<Symbol *> dataMembers;
QList<Symbol *> memberFunctions;
for (auto it = theClass->memberBegin(); it != theClass->memberEnd(); ++it) {
- Symbol * const s = *it;
- if (!s->identifier() || !s->type())
+ Symbol *const s = *it;
+ if (!s->identifier() || !s->type() || s->type().isTypedef())
continue;
if ((s->isDeclaration() && s->type()->asFunctionType()) || s->asFunction())
memberFunctions << s;
@@ -4276,29 +4859,43 @@ public:
dataMembers << s;
}
- for (Symbol * const member : dataMembers) {
- const QString rawName = QString::fromUtf8(member->identifier()->chars(),
- member->identifier()->size());
- const QString semanticName = memberBaseName(rawName);
- const QString capitalizedSemanticName = semanticName.at(0).toUpper()
- + semanticName.mid(1);
- const QStringList getterNames{semanticName, "get_" + semanticName,
- "get" + capitalizedSemanticName, "is_" + semanticName,
- "is" + capitalizedSemanticName};
- const QStringList setterNames{"set_" + semanticName,
- "set" + capitalizedSemanticName};
- const bool hasGetter = Utils::anyOf(memberFunctions, [&getterNames](const Symbol *s) {
- const Identifier * const id = s->identifier();
- const auto funcName = QString::fromUtf8(id->chars(), id->size());
- return getterNames.contains(funcName);
- });
- const bool hasSetter = Utils::anyOf(memberFunctions, [&setterNames](const Symbol *s) {
- const Identifier * const id = s->identifier();
- const auto funcName = QString::fromUtf8(id->chars(), id->size());
- return setterNames.contains(funcName);
- });
- if (!hasGetter || !hasSetter)
- m_candidates.emplace_back(member, rawName, semanticName, hasGetter, hasSetter);
+ auto file = interface.currentFile();
+ QStringList qPropertyNames; // name after MEMBER or name of the property
+ for (auto it = m_classAST->member_specifier_list; it; it = it->next) {
+ if (it->value->asQtPropertyDeclaration()) {
+ auto propDecl = it->value->asQtPropertyDeclaration();
+ // iterator over 'READ ...', ... and check if we have a MEMBER
+ for (auto p = propDecl->property_declaration_item_list; p; p = p->next) {
+ const char *tokenString = file->tokenAt(p->value->item_name_token).spell();
+ if (!qstrcmp(tokenString, "MEMBER"))
+ qPropertyNames << file->textOf(p->value->expression);
+ }
+ // no MEMBER, but maybe the property name is the same
+ qPropertyNames << file->textOf(propDecl->property_name);
+ }
+ }
+ const QStringList memberFunctionsAsStrings = toStringList(memberFunctions);
+
+ for (Symbol *const member : dataMembers) {
+ ExistingGetterSetterData existing;
+ existing.memberVariableName = QString::fromUtf8(member->identifier()->chars(),
+ member->identifier()->size());
+ existing.declarationSymbol = member->asDeclaration();
+ existing.clazz = theClass;
+
+ // check if a Q_PROPERTY exist
+ const QString baseName = memberBaseName(existing.memberVariableName);
+ if (qPropertyNames.contains(baseName)
+ || qPropertyNames.contains(existing.memberVariableName))
+ continue;
+
+ findExistingFunctions(existing, memberFunctionsAsStrings);
+ existing.qPropertyName = baseName;
+
+ int possibleFlags = existing.computePossibleFlags();
+ if (possibleFlags == 0)
+ continue;
+ m_candidates.emplace_back(existing, possibleFlags);
}
}
@@ -4320,42 +4917,19 @@ private:
return;
m_candidates = dlg.candidates();
}
-
- for (const MemberInfo &mi : m_candidates) {
- GenerateGetterSetterOperation::OperationType op
- = GenerateGetterSetterOperation::InvalidType;
- if (mi.getterRequested) {
- if (mi.setterRequested)
- op = GenerateGetterSetterOperation::GetterSetterType;
- else
- op = GenerateGetterSetterOperation::GetterType;
- } else if (mi.setterRequested) {
- op = GenerateGetterSetterOperation::SetterType;
+ if (m_candidates.empty())
+ return;
+ GetterSetterRefactoringHelper helper(this,
+ currentFile()->fileName(),
+ m_candidates.front().data.clazz);
+ for (MemberInfo &mi : m_candidates) {
+ if (mi.requestedFlags != 0) {
+ helper.performGeneration(mi.data, mi.requestedFlags);
}
- if (op == GenerateGetterSetterOperation::InvalidType)
- continue;
-
- const Utils::optional<CppCodeStyleSettings> codeStyleSettings
- = CppCodeStyleSettings::currentProjectCodeStyle();
- const CppCodeStyleSettings settings
- = codeStyleSettings.value_or(CppCodeStyleSettings::currentGlobalCodeStyle());
- const QString capitalizedBaseName = mi.baseName.at(0).toUpper() + mi.baseName.mid(1);
- const QString getterName = settings.preferGetterNameWithoutGetPrefix
- && mi.baseName != mi.rawName ? mi.baseName : "get" + capitalizedBaseName;
- const QString setterName = "set" + capitalizedBaseName;
- GenerateGetterSetterOperation::addGetterAndOrSetter(
- this,
- mi.member,
- m_classAST,
- mi.rawName,
- mi.baseName,
- getterName,
- setterName,
- op);
}
+ helper.applyChanges();
}
-
GetterSetterCandidates m_candidates;
const ClassSpecifierAST *m_classAST = nullptr;
bool m_hasData = false;
@@ -4370,10 +4944,9 @@ void GenerateGettersSettersForClass::match(const CppQuickFixInterface &interface
if (m_test) {
GetterSetterCandidates candidates = op->candidates();
for (MemberInfo &mi : candidates) {
- if (!mi.hasGetter)
- mi.getterRequested = true;
- if (!mi.hasSetter)
- mi.setterRequested = true;
+ mi.requestedFlags = mi.possibleFlags;
+ using Flag = GenerateGetterSetterOp::GenerateFlag;
+ mi.requestedFlags &= ~Flag::GenerateConstantProperty;
}
op->setGetterSetterData(candidates);
}
@@ -5651,159 +6224,40 @@ void ConvertFromAndToPointer::match(const CppQuickFixInterface &interface,
namespace {
-class InsertQtPropertyMembersOp: public CppQuickFixOperation
+void extractNames(const CppRefactoringFilePtr &file,
+ QtPropertyDeclarationAST *qtPropertyDeclaration,
+ ExistingGetterSetterData &data)
{
-public:
- enum GenerateFlag {
- GenerateGetter = 1 << 0,
- GenerateSetter = 1 << 1,
- GenerateSignal = 1 << 2,
- GenerateStorage = 1 << 3,
- GenerateReset = 1 << 4
- };
-
- InsertQtPropertyMembersOp(const CppQuickFixInterface &interface,
- int priority, QtPropertyDeclarationAST *declaration, Class *klass, int generateFlags,
- const QString &getterName, const QString &setterName, const QString &resetName,
- const QString &signalName, const QString &storageName)
- : CppQuickFixOperation(interface, priority)
- , m_declaration(declaration)
- , m_class(klass)
- , m_generateFlags(generateFlags)
- , m_getterName(getterName)
- , m_setterName(setterName)
- , m_resetName(resetName)
- , m_signalName(signalName)
- , m_storageName(storageName)
- {
- setDescription(CppQuickFixFactory::tr("Generate Missing Q_PROPERTY Members"));
- }
-
- void perform() override
- {
- CppRefactoringChanges refactoring(snapshot());
- CppRefactoringFilePtr file = refactoring.file(filePath().toString());
-
- InsertionPointLocator locator(refactoring);
- ChangeSet declarations;
-
- const QString typeName = file->textOf(m_declaration->type_id);
- const QString propertyName = file->textOf(m_declaration->property_name);
- QString baseName = memberBaseName(m_storageName);
- if (baseName.isEmpty() || baseName == m_storageName)
- baseName = QStringLiteral("arg");
-
- // getter declaration
- if (m_generateFlags & GenerateGetter) {
- const QString getterDeclaration = typeName + QLatin1Char(' ') + m_getterName +
- QLatin1String("() const\n{\nreturn ") + m_storageName + QLatin1String(";\n}\n");
- InsertionLocation getterLoc = locator.methodDeclarationInClass(file->fileName(), m_class, InsertionPointLocator::Public);
- QTC_ASSERT(getterLoc.isValid(), return);
- insertAndIndent(file, &declarations, getterLoc, getterDeclaration);
- }
-
- // setter declaration
- InsertionLocation setterLoc;
- if (m_generateFlags & GenerateSetter) {
- QString setterDeclaration;
- QTextStream setter(&setterDeclaration);
- setter << "void " << m_setterName << '(' << typeName << ' ' << baseName << ")\n{\n";
- if (m_signalName.isEmpty()) {
- setter << m_storageName << " = " << baseName << ";\n}\n";
- } else {
- if (isQtFuzzyComparable(typeName)) {
- setter << "qWarning(\"Floating point comparison needs context sanity check\");\n";
- setter << "if (qFuzzyCompare(" << m_storageName << ", " << baseName << "))\nreturn;\n\n";
- }
- else
- setter << "if (" << m_storageName << " == " << baseName << ")\nreturn;\n\n";
- setter << m_storageName << " = " << baseName << ";\nemit " << m_signalName
- << '(' << m_storageName << ");\n}\n";
- }
- setterLoc = locator.methodDeclarationInClass(file->fileName(), m_class, InsertionPointLocator::PublicSlot);
- QTC_ASSERT(setterLoc.isValid(), return);
- insertAndIndent(file, &declarations, setterLoc, setterDeclaration);
- }
-
- // reset declaration
- if (m_generateFlags & GenerateReset) {
- QString declaration;
- QTextStream stream(&declaration);
- stream << "void " << m_resetName << "()\n{\n";
- if (m_generateFlags & GenerateSetter) {
- stream << m_setterName << "({}); // TODO: Adapt to use your actual default value\n";
- } else {
- stream << "static const " << typeName << " defaultValue{}; "
- "// TODO: Adapt to use your actual default value\n";
- if (!m_signalName.isEmpty())
- stream << "if (" << m_storageName << " == defaultValue)\nreturn;\n\n";
- stream << m_storageName << " = defaultValue;\n";
- if (!m_signalName.isEmpty())
- stream << "emit " << m_signalName << '(' << m_storageName << ");\n";
- }
- stream << "}\n";
- const InsertionLocation loc = setterLoc.isValid()
- ? InsertionLocation(setterLoc.fileName(), {}, {}, setterLoc.line(), 1)
- : locator.methodDeclarationInClass(file->fileName(), m_class,
- InsertionPointLocator::PublicSlot);
- QTC_ASSERT(loc.isValid(), return);
- insertAndIndent(file, &declarations, loc, declaration);
- }
-
- // signal declaration
- if (m_generateFlags & GenerateSignal) {
- const QString declaration = QLatin1String("void ") + m_signalName + QLatin1Char('(')
- + typeName + QLatin1Char(' ') + baseName
- + QLatin1String(");\n");
- InsertionLocation loc = locator.methodDeclarationInClass(file->fileName(), m_class, InsertionPointLocator::Signals);
- QTC_ASSERT(loc.isValid(), return);
- insertAndIndent(file, &declarations, loc, declaration);
- }
-
- // storage
- if (m_generateFlags & GenerateStorage) {
- const QString storageDeclaration = typeName + QLatin1String(" m_")
- + propertyName + QLatin1String(";\n");
- InsertionLocation storageLoc = locator.methodDeclarationInClass(file->fileName(), m_class, InsertionPointLocator::Private);
- QTC_ASSERT(storageLoc.isValid(), return);
- insertAndIndent(file, &declarations, storageLoc, storageDeclaration);
- }
-
- file->setChangeSet(declarations);
- file->apply();
- }
-
-private:
- void insertAndIndent(const RefactoringFilePtr &file, ChangeSet *changeSet,
- const InsertionLocation &loc, const QString &text)
- {
- int targetPosition1 = file->position(loc.line(), loc.column());
- int targetPosition2 = qMax(0, file->position(loc.line(), 1) - 1);
- changeSet->insert(targetPosition1, loc.prefix() + text + loc.suffix());
- file->appendIndentRange(ChangeSet::Range(targetPosition2, targetPosition1));
+ QtPropertyDeclarationItemListAST *it = qtPropertyDeclaration->property_declaration_item_list;
+ for (; it; it = it->next) {
+ const char *tokenString = file->tokenAt(it->value->item_name_token).spell();
+ if (!qstrcmp(tokenString, "READ")) {
+ data.getterName = file->textOf(it->value->expression);
+ } else if (!qstrcmp(tokenString, "WRITE")) {
+ data.setterName = file->textOf(it->value->expression);
+ } else if (!qstrcmp(tokenString, "RESET")) {
+ data.resetName = file->textOf(it->value->expression);
+ } else if (!qstrcmp(tokenString, "NOTIFY")) {
+ data.signalName = file->textOf(it->value->expression);
+ } else if (!qstrcmp(tokenString, "MEMBER")) {
+ data.memberVariableName = file->textOf(it->value->expression);
+ }
}
-
- QtPropertyDeclarationAST *m_declaration;
- Class *m_class;
- int m_generateFlags;
- QString m_getterName;
- QString m_setterName;
- QString m_resetName;
- QString m_signalName;
- QString m_storageName;
-};
+}
} // anonymous namespace
-void InsertQtPropertyMembers::match(const CppQuickFixInterface &interface,
- QuickFixOperations &result)
+void InsertQtPropertyMembers::match(const CppQuickFixInterface &interface, QuickFixOperations &result)
{
- const QList<AST *> &path = interface.path();
+ using Flag = GenerateGetterSetterOp::GenerateFlag;
+ ExistingGetterSetterData existing;
+ // check for Q_PROPERTY
+ const QList<AST *> &path = interface.path();
if (path.isEmpty())
return;
- AST * const ast = path.last();
+ AST *const ast = path.last();
QtPropertyDeclarationAST *qtPropertyDeclaration = ast->asQtPropertyDeclaration();
if (!qtPropertyDeclaration || !qtPropertyDeclaration->type_id)
return;
@@ -5816,63 +6270,114 @@ void InsertQtPropertyMembers::match(const CppQuickFixInterface &interface,
}
if (!klass)
return;
+ existing.clazz = klass->symbol;
CppRefactoringFilePtr file = interface.currentFile();
const QString propertyName = file->textOf(qtPropertyDeclaration->property_name);
- QString getterName;
- QString setterName;
- QString resetName;
- QString signalName;
- int generateFlags = 0;
- QtPropertyDeclarationItemListAST *it = qtPropertyDeclaration->property_declaration_item_list;
- for (; it; it = it->next) {
- const char *tokenString = file->tokenAt(it->value->item_name_token).spell();
- if (!qstrcmp(tokenString, "READ")) {
- getterName = file->textOf(it->value->expression);
- generateFlags |= InsertQtPropertyMembersOp::GenerateGetter;
- } else if (!qstrcmp(tokenString, "WRITE")) {
- setterName = file->textOf(it->value->expression);
- generateFlags |= InsertQtPropertyMembersOp::GenerateSetter;
- } else if (!qstrcmp(tokenString, "RESET")) {
- resetName = file->textOf(it->value->expression);
- generateFlags |= InsertQtPropertyMembersOp::GenerateReset;
- } else if (!qstrcmp(tokenString, "NOTIFY")) {
- signalName = file->textOf(it->value->expression);
- generateFlags |= InsertQtPropertyMembersOp::GenerateSignal;
- }
- }
- const QString storageName = QLatin1String("m_") + propertyName;
- generateFlags |= InsertQtPropertyMembersOp::GenerateStorage;
-
- Class *c = klass->symbol;
-
+ existing.qPropertyName = propertyName;
+ extractNames(file, qtPropertyDeclaration, existing);
+
+ Control *control = interface.currentFile()->cppDocument()->control();
+
+ existing.declarationSymbol = control->newDeclaration(ast->firstToken(),
+ qtPropertyDeclaration->property_name->name);
+ existing.declarationSymbol->setVisibility(Symbol::Private);
+ existing.declarationSymbol->setEnclosingScope(existing.clazz);
+
+ {
+ // create a 'right' Type Object
+ // if we have Q_PROPERTY(int test ...) then we only get a NamedType for 'int', but we want
+ // a IntegerType. So create a new dummy file with a dummy declaration to get the right
+ // object
+ QByteArray type = file->textOf(qtPropertyDeclaration->type_id).toUtf8();
+ QByteArray newSource = file->document()
+ ->toPlainText()
+ .insert(file->startOf(qtPropertyDeclaration),
+ QString::fromUtf8(type + " __dummy;\n"))
+ .toUtf8();
+
+ Document::Ptr doc = interface.snapshot().preprocessedDocument(newSource, "___quickfix.h");
+ if (!doc->parse(Document::ParseTranlationUnit))
+ return;
+ doc->check();
+ class TypeFinder : public ASTVisitor
+ {
+ public:
+ FullySpecifiedType type;
+ TypeFinder(TranslationUnit *u)
+ : ASTVisitor(u)
+ {}
+ bool visit(SimpleDeclarationAST *ast) override
+ {
+ if (ast->symbols && !ast->symbols->next) {
+ const Name *name = ast->symbols->value->name();
+ if (name && name->asNameId() && name->asNameId()->identifier()) {
+ const Identifier *id = name->asNameId()->identifier();
+ if (QString::fromUtf8(id->chars(), id->size()) == "__dummy")
+ type = ast->symbols->value->type();
+ }
+ }
+ return true;
+ }
+ };
+ TypeFinder finder(doc->translationUnit());
+ finder.accept(doc->translationUnit()->ast());
+ if (finder.type.type()->isUndefinedType())
+ return;
+ existing.declarationSymbol->setType(finder.type);
+ existing.doc = doc; // to hold type
+ }
+ // check which methods are already there
+ const bool haveFixMemberVariableName = !existing.memberVariableName.isEmpty();
+ int generateFlags = Flag::GenerateMemberVariable;
+ if (!existing.resetName.isEmpty())
+ generateFlags |= Flag::GenerateReset;
+ if (!existing.setterName.isEmpty())
+ generateFlags |= Flag::GenerateSetter;
+ if (!existing.getterName.isEmpty())
+ generateFlags |= Flag::GenerateGetter;
+ if (!existing.signalName.isEmpty())
+ generateFlags |= Flag::GenerateSignal;
Overview overview;
- for (int i = 0; i < c->memberCount(); ++i) {
- Symbol *member = c->memberAt(i);
+ for (int i = 0; i < existing.clazz->memberCount(); ++i) {
+ Symbol *member = existing.clazz->memberAt(i);
FullySpecifiedType type = member->type();
if (member->asFunction() || (type.isValid() && type->asFunctionType())) {
const QString name = overview.prettyName(member->name());
- if (name == getterName)
- generateFlags &= ~InsertQtPropertyMembersOp::GenerateGetter;
- else if (name == setterName)
- generateFlags &= ~InsertQtPropertyMembersOp::GenerateSetter;
- else if (name == resetName)
- generateFlags &= ~InsertQtPropertyMembersOp::GenerateReset;
- else if (name == signalName)
- generateFlags &= ~InsertQtPropertyMembersOp::GenerateSignal;
+ if (name == existing.getterName)
+ generateFlags &= ~Flag::GenerateGetter;
+ else if (name == existing.setterName)
+ generateFlags &= ~Flag::GenerateSetter;
+ else if (name == existing.resetName)
+ generateFlags &= ~Flag::GenerateReset;
+ else if (name == existing.signalName)
+ generateFlags &= ~Flag::GenerateSignal;
} else if (member->asDeclaration()) {
const QString name = overview.prettyName(member->name());
- if (name == storageName)
- generateFlags &= ~InsertQtPropertyMembersOp::GenerateStorage;
+ if (haveFixMemberVariableName) {
+ if (name == existing.memberVariableName) {
+ generateFlags &= ~Flag::GenerateMemberVariable;
+ }
+ } else {
+ const QString baseName = memberBaseName(name);
+ if (existing.qPropertyName == baseName) {
+ existing.memberVariableName = name;
+ generateFlags &= ~Flag::GenerateMemberVariable;
+ }
+ }
}
}
-
- if (getterName.isEmpty() && setterName.isEmpty() && signalName.isEmpty())
+ if (generateFlags & Flag::GenerateMemberVariable) {
+ CppQuickFixSettings *settings = CppQuickFixProjectsSettings::getQuickFixSettings(
+ ProjectExplorer::ProjectTree::currentProject());
+ existing.memberVariableName = settings->getMemberVariableName(existing.qPropertyName);
+ }
+ if (generateFlags == 0) {
+ // everything is already there
return;
-
- result << new InsertQtPropertyMembersOp(interface, path.size() - 1, qtPropertyDeclaration, c,
- generateFlags, getterName, setterName, resetName,
- signalName, storageName);
+ }
+ generateFlags |= Flag::HaveExistingQProperty;
+ GenerateGetterSetterOp::generateQuickFixes(result, interface, existing, generateFlags);
}
namespace {
diff --git a/src/plugins/cppeditor/cppquickfixprojectsettings.cpp b/src/plugins/cppeditor/cppquickfixprojectsettings.cpp
new file mode 100644
index 0000000000..8299c255e4
--- /dev/null
+++ b/src/plugins/cppeditor/cppquickfixprojectsettings.cpp
@@ -0,0 +1,187 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Leander Schulten <Leander.Schulten@rwth-aachen.de>
+** 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 "cppquickfixprojectsettings.h"
+#include "cppeditorconstants.h"
+#include <coreplugin/icore.h>
+#include <QMessageBox>
+#include <QPushButton>
+#include <QSettings>
+#include <QtDebug>
+
+namespace CppEditor {
+namespace Internal {
+using namespace Constants;
+
+static const char SETTINGS_FILE_NAME[] = ".cppQuickFix";
+static const char USE_GLOBAL_SETTINGS[] = "UseGlobalSettings";
+
+CppQuickFixProjectsSettings::CppQuickFixProjectsSettings(ProjectExplorer::Project *project)
+{
+ m_project = project;
+ const auto settings = m_project->namedSettings(QUICK_FIX_SETTINGS_ID).toMap();
+ // if no option is saved try to load settings from a file
+ m_useGlobalSettings = settings.value(USE_GLOBAL_SETTINGS, false).toBool();
+ if (!m_useGlobalSettings) {
+ m_settingsFile = searchForCppQuickFixSettingsFile();
+ if (!m_settingsFile.isEmpty()) {
+ loadOwnSettingsFromFile();
+ m_useGlobalSettings = false;
+ } else {
+ m_useGlobalSettings = true;
+ }
+ }
+ connect(project, &ProjectExplorer::Project::aboutToSaveSettings, [this] {
+ auto settings = m_project->namedSettings(QUICK_FIX_SETTINGS_ID).toMap();
+ settings.insert(USE_GLOBAL_SETTINGS, m_useGlobalSettings);
+ m_project->setNamedSettings(QUICK_FIX_SETTINGS_ID, settings);
+ });
+}
+
+CppQuickFixSettings *CppQuickFixProjectsSettings::getSettings()
+{
+ if (m_useGlobalSettings)
+ return CppQuickFixSettings::instance();
+
+ return &m_ownSettings;
+}
+
+bool CppQuickFixProjectsSettings::isUsingGlobalSettings() const
+{
+ return m_useGlobalSettings;
+}
+
+const Utils::FilePath &CppQuickFixProjectsSettings::filePathOfSettingsFile() const
+{
+ return m_settingsFile;
+}
+
+CppQuickFixProjectsSettings::CppQuickFixProjectsSettingsPtr CppQuickFixProjectsSettings::getSettings(
+ ProjectExplorer::Project *project)
+{
+ const QString key = "CppQuickFixProjectsSettings";
+ QVariant v = project->extraData(key);
+ if (v.isNull()) {
+ v = QVariant::fromValue(
+ CppQuickFixProjectsSettingsPtr{new CppQuickFixProjectsSettings(project)});
+ project->setExtraData(key, v);
+ }
+ return v.value<QSharedPointer<CppQuickFixProjectsSettings>>();
+}
+
+CppQuickFixSettings *CppQuickFixProjectsSettings::getQuickFixSettings(ProjectExplorer::Project *project)
+{
+ if (project)
+ return getSettings(project)->getSettings();
+ return CppQuickFixSettings::instance();
+}
+
+Utils::FilePath CppQuickFixProjectsSettings::searchForCppQuickFixSettingsFile()
+{
+ auto cur = m_project->projectDirectory();
+ while (!cur.isEmpty()) {
+ const auto path = cur / SETTINGS_FILE_NAME;
+ if (path.exists())
+ return path;
+
+ cur = cur.parentDir();
+ }
+ return cur;
+}
+
+void CppQuickFixProjectsSettings::useGlobalSettings()
+{
+ m_useGlobalSettings = true;
+}
+
+bool CppQuickFixProjectsSettings::useCustomSettings()
+{
+ if (m_settingsFile.isEmpty()) {
+ m_settingsFile = searchForCppQuickFixSettingsFile();
+ const Utils::FilePath defaultLocation = m_project->projectDirectory() / SETTINGS_FILE_NAME;
+ if (m_settingsFile.isEmpty()) {
+ m_settingsFile = defaultLocation;
+ } else if (m_settingsFile != defaultLocation) {
+ QMessageBox msgBox(Core::ICore::dialogParent());
+ msgBox.setText(tr("Quick Fix settings are saved in a file. Existing settings file "
+ "'%1' found. Should this file be used or a "
+ "new one be created?")
+ .arg(m_settingsFile.toString()));
+ QPushButton *cancel = msgBox.addButton(QMessageBox::Cancel);
+ cancel->setToolTip(tr("Switch Back to Global Settings"));
+ QPushButton *useExisting = msgBox.addButton(tr("Use Existing"), QMessageBox::AcceptRole);
+ useExisting->setToolTip(m_settingsFile.toString());
+ QPushButton *createNew = msgBox.addButton(tr("Create New"), QMessageBox::ActionRole);
+ createNew->setToolTip(defaultLocation.toString());
+ msgBox.exec();
+ if (msgBox.clickedButton() == createNew) {
+ m_settingsFile = defaultLocation;
+ } else if (msgBox.clickedButton() != useExisting) {
+ m_settingsFile.clear();
+ return false;
+ }
+ }
+
+ resetOwnSettingsToGlobal();
+ }
+ if (m_settingsFile.exists())
+ loadOwnSettingsFromFile();
+
+ m_useGlobalSettings = false;
+ return true;
+}
+
+void CppQuickFixProjectsSettings::resetOwnSettingsToGlobal()
+{
+ m_ownSettings = *CppQuickFixSettings::instance();
+}
+
+bool CppQuickFixProjectsSettings::saveOwnSettings()
+{
+ if (m_settingsFile.isEmpty())
+ return false;
+
+ QSettings settings(m_settingsFile.toString(), QSettings::IniFormat);
+ if (settings.status() == QSettings::NoError) {
+ m_ownSettings.saveSettingsTo(&settings);
+ settings.sync();
+ return settings.status() == QSettings::NoError;
+ }
+ m_settingsFile.clear();
+ return false;
+}
+
+void CppQuickFixProjectsSettings::loadOwnSettingsFromFile()
+{
+ QSettings settings(m_settingsFile.toString(), QSettings::IniFormat);
+ if (settings.status() == QSettings::NoError) {
+ m_ownSettings.loadSettingsFrom(&settings);
+ return;
+ }
+ m_settingsFile.clear();
+}
+
+} // namespace Internal
+} // namespace CppEditor
diff --git a/src/plugins/cppeditor/cppquickfixprojectsettings.h b/src/plugins/cppeditor/cppquickfixprojectsettings.h
new file mode 100644
index 0000000000..b982a24088
--- /dev/null
+++ b/src/plugins/cppeditor/cppquickfixprojectsettings.h
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Leander Schulten <Leander.Schulten@rwth-aachen.de>
+** 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 "cppquickfixsettings.h"
+#include <projectexplorer/project.h>
+#include <utils/fileutils.h>
+
+namespace CppEditor {
+namespace Internal {
+
+class CppQuickFixProjectsSettings : public QObject
+{
+ Q_OBJECT
+public:
+ CppQuickFixProjectsSettings(ProjectExplorer::Project *project);
+ CppQuickFixSettings *getSettings();
+ bool isUsingGlobalSettings() const;
+ const Utils::FilePath &filePathOfSettingsFile() const;
+
+ using CppQuickFixProjectsSettingsPtr = QSharedPointer<CppQuickFixProjectsSettings>;
+ static CppQuickFixProjectsSettingsPtr getSettings(ProjectExplorer::Project *project);
+ static CppQuickFixSettings *getQuickFixSettings(ProjectExplorer::Project *project);
+
+ Utils::FilePath searchForCppQuickFixSettingsFile();
+
+ void useGlobalSettings();
+ [[nodiscard]] bool useCustomSettings();
+ void resetOwnSettingsToGlobal();
+ bool saveOwnSettings();
+
+private:
+ void loadOwnSettingsFromFile();
+
+ ProjectExplorer::Project *m_project;
+ Utils::FilePath m_settingsFile;
+ CppQuickFixSettings m_ownSettings;
+ bool m_useGlobalSettings;
+};
+
+} // namespace Internal
+} // namespace CppEditor
+
+Q_DECLARE_METATYPE(QSharedPointer<CppEditor::Internal::CppQuickFixProjectsSettings>)
diff --git a/src/plugins/cppeditor/cppquickfixprojectsettingswidget.cpp b/src/plugins/cppeditor/cppquickfixprojectsettingswidget.cpp
new file mode 100644
index 0000000000..91f2285668
--- /dev/null
+++ b/src/plugins/cppeditor/cppquickfixprojectsettingswidget.cpp
@@ -0,0 +1,104 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Leander Schulten <Leander.Schulten@rwth-aachen.de>
+** 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 "cppquickfixprojectsettingswidget.h"
+#include "cppquickfixsettingswidget.h"
+#include "ui_cppquickfixprojectsettingswidget.h"
+
+#include <QFile>
+
+using namespace CppEditor::Internal;
+
+CppQuickFixProjectSettingsWidget::CppQuickFixProjectSettingsWidget(ProjectExplorer::Project *project,
+ QWidget *parent)
+ : QWidget(parent)
+ , ui(new Ui::CppQuickFixProjectSettingsWidget)
+{
+ m_projectSettings = CppQuickFixProjectsSettings::getSettings(project);
+ ui->setupUi(this);
+ m_settingsWidget = new CppEditor::Internal::CppQuickFixSettingsWidget(this);
+ m_settingsWidget->loadSettings(m_projectSettings->getSettings());
+ ui->layout->addWidget(m_settingsWidget);
+ connect(ui->comboBox,
+ QOverload<int>::of(&QComboBox::currentIndexChanged),
+ this,
+ &CppQuickFixProjectSettingsWidget::currentItemChanged);
+ connect(ui->pushButton_custom,
+ &QAbstractButton::clicked,
+ this,
+ &CppQuickFixProjectSettingsWidget::buttonCustomClicked);
+ connect(m_settingsWidget, &CppEditor::Internal::CppQuickFixSettingsWidget::settingsChanged, [this] {
+ m_settingsWidget->saveSettings(m_projectSettings->getSettings());
+ if (!useGlobalSettings())
+ m_projectSettings->saveOwnSettings();
+ });
+ ui->comboBox->setCurrentIndex(m_projectSettings->isUsingGlobalSettings() ? 0 : 1);
+}
+
+CppQuickFixProjectSettingsWidget::~CppQuickFixProjectSettingsWidget()
+{
+ delete ui;
+}
+
+void CppQuickFixProjectSettingsWidget::currentItemChanged()
+{
+ if (useGlobalSettings()) {
+ const auto &path = m_projectSettings->filePathOfSettingsFile();
+ ui->pushButton_custom->setToolTip(tr("Custom settings are saved in a file. If you use the "
+ "global settings, you can delete that file."));
+ ui->pushButton_custom->setText(tr("Delete Custom Settings File"));
+ ui->pushButton_custom->setVisible(!path.isEmpty() && path.exists());
+ m_projectSettings->useGlobalSettings();
+ } else /*Custom*/ {
+ if (!m_projectSettings->useCustomSettings()) {
+ ui->comboBox->setCurrentIndex(0);
+ return;
+ }
+ ui->pushButton_custom->setToolTip(tr("Resets all settings to the global settings."));
+ ui->pushButton_custom->setText(tr("Reset to Global"));
+ ui->pushButton_custom->setVisible(true);
+ // otherwise you change the comboBox and exit and have no custom settings:
+ m_projectSettings->saveOwnSettings();
+ }
+ m_settingsWidget->loadSettings(m_projectSettings->getSettings());
+}
+
+void CppQuickFixProjectSettingsWidget::buttonCustomClicked()
+{
+ if (useGlobalSettings()) {
+ // delete file
+ QFile::remove(m_projectSettings->filePathOfSettingsFile().toString());
+ ui->pushButton_custom->setVisible(false);
+ } else /*Custom*/ {
+ m_projectSettings->resetOwnSettingsToGlobal();
+ m_projectSettings->saveOwnSettings();
+ m_settingsWidget->loadSettings(m_projectSettings->getSettings());
+ }
+}
+
+bool CppQuickFixProjectSettingsWidget::useGlobalSettings()
+{
+ return ui->comboBox->currentIndex() == 0;
+}
diff --git a/src/plugins/cppeditor/cppquickfixprojectsettingswidget.h b/src/plugins/cppeditor/cppquickfixprojectsettingswidget.h
new file mode 100644
index 0000000000..92617e346c
--- /dev/null
+++ b/src/plugins/cppeditor/cppquickfixprojectsettingswidget.h
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Leander Schulten <Leander.Schulten@rwth-aachen.de>
+** 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 "cppquickfixprojectsettings.h"
+
+#include <QWidget>
+
+QT_BEGIN_NAMESPACE
+namespace Ui { class CppQuickFixProjectSettingsWidget; }
+QT_END_NAMESPACE
+
+namespace ProjectExplorer { class Project; }
+
+namespace CppEditor {
+namespace Internal {
+class CppQuickFixSettingsWidget;
+class CppQuickFixProjectSettingsWidget : public QWidget
+{
+ Q_OBJECT
+
+public:
+ explicit CppQuickFixProjectSettingsWidget(ProjectExplorer::Project *project,
+ QWidget *parent = nullptr);
+ ~CppQuickFixProjectSettingsWidget();
+
+private slots:
+ void currentItemChanged();
+ void buttonCustomClicked();
+
+private:
+ bool useGlobalSettings();
+
+ Ui::CppQuickFixProjectSettingsWidget *ui;
+ CppQuickFixSettingsWidget *m_settingsWidget;
+ CppQuickFixProjectsSettings::CppQuickFixProjectsSettingsPtr m_projectSettings;
+};
+
+} // namespace Internal
+} // namespace CppEditor
diff --git a/src/plugins/cppeditor/cppquickfixprojectsettingswidget.ui b/src/plugins/cppeditor/cppquickfixprojectsettingswidget.ui
new file mode 100644
index 0000000000..ec419845a1
--- /dev/null
+++ b/src/plugins/cppeditor/cppquickfixprojectsettingswidget.ui
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>CppQuickFixProjectSettingsWidget</class>
+ <widget class="QWidget" name="CppQuickFixProjectSettingsWidget">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>532</width>
+ <height>345</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="0" column="1">
+ <widget class="QPushButton" name="pushButton_custom">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0" colspan="2">
+ <layout class="QVBoxLayout" name="layout"/>
+ </item>
+ <item row="0" column="0">
+ <widget class="QComboBox" name="comboBox">
+ <property name="currentIndex">
+ <number>-1</number>
+ </property>
+ <item>
+ <property name="text">
+ <string>Global Settings</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Custom Settings</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/plugins/cppeditor/cppquickfixsettings.cpp b/src/plugins/cppeditor/cppquickfixsettings.cpp
new file mode 100644
index 0000000000..a2ec232097
--- /dev/null
+++ b/src/plugins/cppeditor/cppquickfixsettings.cpp
@@ -0,0 +1,446 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Leander Schulten <Leander.Schulten@rwth-aachen.de>
+** 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 "cppquickfixsettings.h"
+#include "cppeditorconstants.h"
+#include <coreplugin/icore.h>
+#include <cpptools/cppcodestylesettings.h>
+#include <QRegularExpression>
+
+namespace CppEditor {
+CppQuickFixSettings::CppQuickFixSettings(bool loadGlobalSettings)
+{
+ setDefaultSettings();
+ if (loadGlobalSettings)
+ this->loadGlobalSettings();
+}
+
+void CppQuickFixSettings::loadGlobalSettings()
+{
+ // TODO remove the conversion of the old setting preferGetterNameWithoutGetPrefix of the
+ // CppCodeStyleSettings in 4.16 (also remove the member preferGetterNameWithoutGetPrefix)
+ getterNameTemplate = "__dummy";
+ loadSettingsFrom(Core::ICore::settings());
+ if (getterNameTemplate == "__dummy") {
+ // there was no saved property for getterNameTemplate
+ if (CppTools::CppCodeStyleSettings::currentGlobalCodeStyle().preferGetterNameWithoutGetPrefix)
+ getterNameTemplate = "<name>";
+ else
+ getterNameTemplate = "get<Name>";
+ }
+}
+
+void CppQuickFixSettings::loadSettingsFrom(QSettings *s)
+{
+ s->beginGroup(QLatin1String(Constants::QUICK_FIX_SETTINGS_ID));
+ getterOutsideClassFrom = s->value(QLatin1String(
+ Constants::QUICK_FIX_SETTING_GETTER_OUTSIDE_CLASS_FROM),
+ getterOutsideClassFrom)
+ .toInt();
+ getterInCppFileFrom = s->value(QLatin1String(
+ Constants::QUICK_FIX_SETTING_GETTER_IN_CPP_FILE_FROM),
+ getterInCppFileFrom)
+ .toInt();
+ setterOutsideClassFrom = s->value(QLatin1String(
+ Constants::QUICK_FIX_SETTING_SETTER_OUTSIDE_CLASS_FROM),
+ setterOutsideClassFrom)
+ .toInt();
+ setterInCppFileFrom = s->value(QLatin1String(
+ Constants::QUICK_FIX_SETTING_SETTER_IN_CPP_FILE_FROM),
+ setterInCppFileFrom)
+ .toInt();
+ getterAttributes = s->value(QLatin1String(Constants::QUICK_FIX_SETTING_GETTER_ATTRIBUTES),
+ getterAttributes)
+ .toString();
+ getterNameTemplate = s->value(QLatin1String(Constants::QUICK_FIX_SETTING_GETTER_NAME_TEMPLATE),
+ getterNameTemplate)
+ .toString();
+ setterNameTemplate = s->value(QLatin1String(Constants::QUICK_FIX_SETTING_SETTER_NAME_TEMPLATE),
+ setterNameTemplate)
+ .toString();
+ setterParameterNameTemplate = s->value(QLatin1String(
+ Constants::QUICK_FIX_SETTING_SETTER_PARAMETER_NAME),
+ setterParameterNameTemplate)
+ .toString();
+ resetNameTemplate = s->value(QLatin1String(Constants::QUICK_FIX_SETTING_RESET_NAME_TEMPLATE),
+ resetNameTemplate)
+ .toString();
+ signalNameTemplate = s->value(QLatin1String(Constants::QUICK_FIX_SETTING_SIGNAL_NAME_TEMPLATE),
+ signalNameTemplate)
+ .toString();
+ signalWithNewValue = s->value(QLatin1String(Constants::QUICK_FIX_SETTING_SIGNAL_WITH_NEW_VALUE),
+ signalWithNewValue)
+ .toBool();
+ setterAsSlot = s->value(QLatin1String(Constants::QUICK_FIX_SETTING_SETTER_AS_SLOT), setterAsSlot)
+ .toBool();
+ cppFileNamespaceHandling = static_cast<MissingNamespaceHandling>(
+ s->value(QLatin1String(Constants::QUICK_FIX_SETTING_CPP_FILE_NAMESPACE_HANDLING),
+ static_cast<int>(cppFileNamespaceHandling))
+ .toInt());
+ memberVariableNameTemplate
+ = s->value(QLatin1String(Constants::QUICK_FIX_SETTING_MEMBER_VARIABEL_NAME_TEMPLATE),
+ memberVariableNameTemplate)
+ .toString();
+ valueTypes = s->value(QLatin1String(Constants::QUICK_FIX_SETTING_VALUE_TYPES), valueTypes)
+ .toStringList();
+ int size = s->beginReadArray(QLatin1String(Constants::QUICK_FIX_SETTING_CUSTOM_TEMPLATES));
+ if (size > 0)
+ customTemplates.clear();
+
+ for (int i = 0; i < size; ++i) {
+ s->setArrayIndex(i);
+ CustomTemplate c;
+ c.types = s->value(QLatin1String(Constants::QUICK_FIX_SETTING_CUSTOM_TEMPLATE_TYPES))
+ .toStringList();
+ if (c.types.isEmpty())
+ continue;
+ c.equalComparison = s->value(QLatin1String(
+ Constants::QUICK_FIX_SETTING_CUSTOM_TEMPLATE_COMPARISON))
+ .toString();
+ c.returnType = s->value(QLatin1String(
+ Constants::QUICK_FIX_SETTING_CUSTOM_TEMPLATE_RETURN_TYPE))
+ .toString();
+ c.returnExpression
+ = s->value(
+ QLatin1String(Constants::QUICK_FIX_SETTING_CUSTOM_TEMPLATE_RETURN_EXPRESSION))
+ .toString();
+ c.assignment = s->value(
+ QLatin1String(Constants::QUICK_FIX_SETTING_CUSTOM_TEMPLATE_ASSIGNMENT))
+ .toString();
+ if (c.assignment.isEmpty() && c.returnType.isEmpty() && c.equalComparison.isEmpty())
+ continue; // nothing custom here
+
+ customTemplates.push_back(c);
+ }
+ s->endArray();
+ s->endGroup();
+}
+
+void CppQuickFixSettings::saveSettingsTo(QSettings *s)
+{
+ s->beginGroup(QLatin1String(Constants::QUICK_FIX_SETTINGS_ID));
+ s->setValue(QLatin1String(Constants::QUICK_FIX_SETTING_GETTER_OUTSIDE_CLASS_FROM),
+ getterOutsideClassFrom);
+ s->setValue(QLatin1String(Constants::QUICK_FIX_SETTING_GETTER_IN_CPP_FILE_FROM),
+ getterInCppFileFrom);
+ s->setValue(QLatin1String(Constants::QUICK_FIX_SETTING_SETTER_OUTSIDE_CLASS_FROM),
+ setterOutsideClassFrom);
+ s->setValue(QLatin1String(Constants::QUICK_FIX_SETTING_SETTER_IN_CPP_FILE_FROM),
+ setterInCppFileFrom);
+
+ s->setValue(QLatin1String(Constants::QUICK_FIX_SETTING_GETTER_ATTRIBUTES), getterAttributes);
+ s->setValue(QLatin1String(Constants::QUICK_FIX_SETTING_GETTER_NAME_TEMPLATE), getterNameTemplate);
+ s->setValue(QLatin1String(Constants::QUICK_FIX_SETTING_SETTER_NAME_TEMPLATE), setterNameTemplate);
+ s->setValue(QLatin1String(Constants::QUICK_FIX_SETTING_RESET_NAME_TEMPLATE), resetNameTemplate);
+ s->setValue(QLatin1String(Constants::QUICK_FIX_SETTING_SIGNAL_NAME_TEMPLATE), signalNameTemplate);
+ s->setValue(QLatin1String(Constants::QUICK_FIX_SETTING_SIGNAL_WITH_NEW_VALUE), signalWithNewValue);
+ s->setValue(QLatin1String(Constants::QUICK_FIX_SETTING_CPP_FILE_NAMESPACE_HANDLING),
+ static_cast<int>(cppFileNamespaceHandling));
+ s->setValue(QLatin1String(Constants::QUICK_FIX_SETTING_MEMBER_VARIABEL_NAME_TEMPLATE),
+ memberVariableNameTemplate);
+ s->setValue(QLatin1String(Constants::QUICK_FIX_SETTING_SETTER_PARAMETER_NAME),
+ setterParameterNameTemplate);
+ s->setValue(QLatin1String(Constants::QUICK_FIX_SETTING_SETTER_AS_SLOT), setterAsSlot);
+ s->setValue(QLatin1String(Constants::QUICK_FIX_SETTING_VALUE_TYPES), valueTypes);
+ s->beginWriteArray(QLatin1String(Constants::QUICK_FIX_SETTING_CUSTOM_TEMPLATES));
+ for (int i = 0; i < static_cast<int>(customTemplates.size()); ++i) {
+ const auto &c = customTemplates[i];
+ s->setArrayIndex(i);
+ s->setValue(QLatin1String(Constants::QUICK_FIX_SETTING_CUSTOM_TEMPLATE_TYPES), c.types);
+ s->setValue(QLatin1String(Constants::QUICK_FIX_SETTING_CUSTOM_TEMPLATE_COMPARISON),
+ c.equalComparison);
+ s->setValue(QLatin1String(Constants::QUICK_FIX_SETTING_CUSTOM_TEMPLATE_RETURN_TYPE),
+ c.returnType);
+ s->setValue(QLatin1String(Constants::QUICK_FIX_SETTING_CUSTOM_TEMPLATE_RETURN_EXPRESSION),
+ c.returnExpression);
+ s->setValue(QLatin1String(Constants::QUICK_FIX_SETTING_CUSTOM_TEMPLATE_ASSIGNMENT),
+ c.assignment);
+ }
+ s->endArray();
+ s->endGroup();
+}
+
+void CppQuickFixSettings::saveAsGlobalSettings()
+{
+ saveSettingsTo(Core::ICore::settings());
+}
+
+void CppQuickFixSettings::setDefaultSettings()
+{
+ valueTypes << "Pointer" // for Q...Pointer
+ << "optional" // for ...::optional
+ << "unique_ptr"; // for std::unique_ptr and boost::movelib::unique_ptr
+ valueTypes << "int"
+ << "long"
+ << "char"
+ << "real"
+ << "short"
+ << "unsigned"
+ << "size"
+ << "float"
+ << "double"
+ << "bool";
+ CustomTemplate floatingPoint;
+ floatingPoint.types << "float"
+ << "double"
+ << "qreal"
+ << "long double";
+ floatingPoint.equalComparison = "qFuzzyCompare(<cur>, <new>)";
+ customTemplates.push_back(floatingPoint);
+
+ CustomTemplate unique_ptr;
+ unique_ptr.types << "unique_ptr";
+ unique_ptr.assignment = "<cur> = std::move(<new>)";
+ unique_ptr.returnType = "<T>*";
+ unique_ptr.returnExpression = "<cur>.get()";
+ customTemplates.push_back(unique_ptr);
+}
+
+QString toUpperCamelCase(const QString &s)
+{
+ auto parts = s.split('_');
+ if (parts.size() == 1)
+ return s;
+
+ QString camel;
+ camel.reserve(s.length() - parts.size() + 1);
+ for (const auto &part : parts) {
+ camel += part[0].toUpper();
+ camel += part.mid(1);
+ }
+ return camel;
+}
+
+QString toSnakeCase(const QString &s, bool upperSnakeCase)
+{
+ QString snake;
+ snake.reserve(s.length() + 5);
+ if (upperSnakeCase)
+ snake += s[0].toUpper();
+ else
+ snake += s[0].toLower();
+
+ for (int i = 1; i < s.length(); ++i) {
+ if (s[i].isUpper() && s[i - 1].isLower()) {
+ snake += '_';
+ if (upperSnakeCase)
+ snake += s[i].toUpper();
+ else
+ snake += s[i].toLower();
+
+ } else {
+ if (s[i - 1] == '_') {
+ if (upperSnakeCase)
+ snake += s[i].toUpper();
+ else
+ snake += s[i].toLower();
+ } else {
+ snake += s[i];
+ }
+ }
+ }
+ return snake;
+}
+
+QString CppQuickFixSettings::replaceNamePlaceholders(const QString &nameTemplate,
+ const QString &name)
+{
+ const int start = nameTemplate.indexOf("<");
+ const int end = nameTemplate.indexOf(">");
+ if (start < 0 || end < 0)
+ return nameTemplate;
+
+ const auto before = nameTemplate.left(start);
+ const auto after = nameTemplate.right(nameTemplate.length() - end - 1);
+ if (name.isEmpty())
+ return before + after;
+
+ // const auto charBefore = start >= 1 ? nameTemplate.at(start - 1) : QChar{};
+ const auto nameType = nameTemplate.mid(start + 1, end - start - 1);
+ if (nameType == "name") {
+ return before + name + after;
+ } else if (nameType == "Name") {
+ return before + name.at(0).toUpper() + name.mid(1) + after;
+ } else if (nameType == "camel") {
+ auto camel = toUpperCamelCase(name);
+ camel.data()[0] = camel.data()[0].toLower();
+ return before + camel + after;
+ } else if (nameType == "Camel") {
+ return before + toUpperCamelCase(name) + after;
+ } else if (nameType == "snake") {
+ return before + toSnakeCase(name, false) + after;
+ } else if (nameType == "Snake") {
+ return before + toSnakeCase(name, true) + after;
+ } else {
+ return "templateHasErrors";
+ }
+}
+
+auto removeAndExtractTemplate(QString type)
+{
+ // maybe we have somethink like: myName::test<std::byte>::fancy<std::optional<int>>, then we want fancy
+ QString realType;
+ QString templateParameter;
+ int counter = 0;
+ int start = 0;
+ int templateStart;
+ for (int i = 0; i < type.length(); ++i) {
+ auto c = type[i];
+ if (c == '<') {
+ if (counter == 0) {
+ // template start
+ realType += type.mid(start, i - start);
+ templateStart = i + 1;
+ }
+ ++counter;
+ } else if (c == '>') {
+ --counter;
+ if (counter == 0) {
+ // template ends
+ start = i + 1;
+ templateParameter = type.mid(templateStart, i - templateStart);
+ }
+ }
+ }
+ if (start < type.length()) // add last block if there is one
+ realType += type.mid(start);
+
+ struct _
+ {
+ QString type;
+ QString templateParameter;
+ };
+ return _{realType, templateParameter};
+}
+
+auto withoutNamespace(QString type)
+{
+ const auto namespaceIndex = type.lastIndexOf("::");
+ if (namespaceIndex >= 0)
+ return type.mid(namespaceIndex + 2);
+ return type;
+}
+
+bool CppQuickFixSettings::isValueType(QString type) const
+{
+ // first remove template stuff
+ auto realType = removeAndExtractTemplate(type).type;
+ // remove namespaces: namespace_int::complex should not be matched by int
+ realType = withoutNamespace(realType);
+ for (const auto &valueType : valueTypes) {
+ if (realType.contains(valueType))
+ return true;
+ }
+ return false;
+}
+
+void CppQuickFixSettings::GetterSetterTemplate::replacePlaceholders(QString currentValueVariableName,
+ QString newValueVariableName)
+{
+ equalComparison = equalComparison.replace("<new>", newValueVariableName)
+ .replace("<cur>", currentValueVariableName);
+ assignment = assignment.replace("<new>", newValueVariableName)
+ .replace("<cur>", currentValueVariableName);
+ returnExpression = returnExpression.replace("<new>", newValueVariableName)
+ .replace("<cur>", currentValueVariableName);
+}
+
+CppQuickFixSettings::GetterSetterTemplate CppQuickFixSettings::findGetterSetterTemplate(
+ QString fullyQualifiedType) const
+{
+ const int index = fullyQualifiedType.lastIndexOf("::");
+ const QString namespaces = index >= 0 ? fullyQualifiedType.left(index) : "";
+ const QString typeOnly = index >= 0 ? fullyQualifiedType.mid(index + 2) : fullyQualifiedType;
+ CustomTemplate bestMatch;
+ enum MatchType { FullyExact, FullyContains, Exact, Contains, None } currentMatch = None;
+ QRegularExpression regex;
+ for (const auto &cTemplate : customTemplates) {
+ for (const auto &t : cTemplate.types) {
+ QString type = t;
+ bool fully = false;
+ if (t.contains("::")) {
+ const int index = t.lastIndexOf("::");
+ if (t.left(index) != namespaces)
+ continue;
+
+ type = t.mid(index + 2);
+ fully = true;
+ } else if (currentMatch <= FullyContains) {
+ continue;
+ }
+
+ MatchType match = None;
+ if (t.contains("*")) {
+ regex.setPattern('^' + QString(t).replace('*', ".*") + '$');
+ if (regex.match(typeOnly).isValid() != QRegularExpression::NormalMatch)
+ match = fully ? FullyContains : Contains;
+ } else if (t == typeOnly) {
+ match = fully ? FullyExact : Exact;
+ }
+ if (match < currentMatch) {
+ currentMatch = match;
+ bestMatch = cTemplate;
+ }
+ }
+ }
+
+ if (currentMatch != None) {
+ GetterSetterTemplate t;
+ if (!bestMatch.equalComparison.isEmpty())
+ t.equalComparison = bestMatch.equalComparison;
+ if (!bestMatch.returnExpression.isEmpty())
+ t.returnExpression = bestMatch.returnExpression;
+ if (!bestMatch.assignment.isEmpty())
+ t.assignment = bestMatch.assignment;
+ if (!bestMatch.returnType.isEmpty())
+ t.returnTypeTemplate = bestMatch.returnType;
+ return t;
+ }
+ return GetterSetterTemplate{};
+}
+
+CppQuickFixSettings::FunctionLocation CppQuickFixSettings::determineGetterLocation(int lineCount) const
+{
+ int outsideDiff = getterOutsideClassFrom > 0 ? lineCount - getterOutsideClassFrom : -1;
+ int cppDiff = getterInCppFileFrom > 0 ? lineCount - getterInCppFileFrom : -1;
+ if (outsideDiff > cppDiff) {
+ if (outsideDiff >= 0)
+ return FunctionLocation::OutsideClass;
+ }
+ return cppDiff >= 0 ? FunctionLocation::CppFile : FunctionLocation::InsideClass;
+}
+
+CppQuickFixSettings::FunctionLocation CppQuickFixSettings::determineSetterLocation(int lineCount) const
+{
+ int outsideDiff = setterOutsideClassFrom > 0 ? lineCount - setterOutsideClassFrom : -1;
+ int cppDiff = setterInCppFileFrom > 0 ? lineCount - setterInCppFileFrom : -1;
+ if (outsideDiff > cppDiff) {
+ if (outsideDiff >= 0)
+ return FunctionLocation::OutsideClass;
+ }
+ return cppDiff >= 0 ? FunctionLocation::CppFile : FunctionLocation::InsideClass;
+}
+
+} // namespace CppEditor
diff --git a/src/plugins/cppeditor/cppquickfixsettings.h b/src/plugins/cppeditor/cppquickfixsettings.h
new file mode 100644
index 0000000000..2b13f76de0
--- /dev/null
+++ b/src/plugins/cppeditor/cppquickfixsettings.h
@@ -0,0 +1,149 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Leander Schulten <Leander.Schulten@rwth-aachen.de>
+** 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 <utils/optional.h>
+
+#include <QString>
+#include <QStringList>
+
+#include <vector>
+
+QT_BEGIN_NAMESPACE
+class QSettings;
+QT_END_NAMESPACE
+
+namespace CppEditor {
+
+class CppQuickFixSettings
+{
+public:
+ static CppQuickFixSettings *instance()
+ {
+ static CppQuickFixSettings settings(true);
+ return &settings;
+ }
+ struct CustomTemplate
+ {
+ QStringList types;
+ QString equalComparison;
+ QString returnExpression;
+ QString returnType;
+ QString assignment;
+ };
+
+ struct GetterSetterTemplate
+ {
+ QString equalComparison = "<cur> == <new>";
+ QString returnExpression = "<cur>";
+ QString assignment = "<cur> = <new>";
+ const static inline QString TYPE_PATTERN = "<type>";
+ const static inline QString TEMPLATE_PARAMETER_PATTERN = "<T>";
+ Utils::optional<QString> returnTypeTemplate;
+ void replacePlaceholders(QString currentValueVariableName, QString newValueVariableName);
+ };
+
+ enum class FunctionLocation {
+ InsideClass,
+ OutsideClass,
+ CppFile,
+ };
+ enum class MissingNamespaceHandling {
+ CreateMissing,
+ AddUsingDirective,
+ RewriteType, // e.g. change classname to namespacename::classname in cpp file
+ };
+
+ explicit CppQuickFixSettings(bool loadGlobalSettings = false);
+
+ void loadGlobalSettings();
+ void loadSettingsFrom(QSettings *);
+ void saveSettingsTo(QSettings *);
+ void saveAsGlobalSettings();
+ void setDefaultSettings();
+
+ static QString replaceNamePlaceholders(const QString &nameTemplate, const QString &name);
+ bool isValueType(QString type) const;
+ GetterSetterTemplate findGetterSetterTemplate(QString fullyQualifiedType) const;
+
+ QString getGetterName(const QString &variableName) const
+ {
+ return replaceNamePlaceholders(getterNameTemplate, variableName);
+ }
+ QString getSetterName(const QString &variableName) const
+ {
+ return replaceNamePlaceholders(setterNameTemplate, variableName);
+ }
+ QString getSignalName(const QString &variableName) const
+ {
+ return replaceNamePlaceholders(signalNameTemplate, variableName);
+ }
+ QString getResetName(const QString &variableName) const
+ {
+ return replaceNamePlaceholders(resetNameTemplate, variableName);
+ }
+ QString getSetterParameterName(const QString &variableName) const
+ {
+ return replaceNamePlaceholders(setterParameterNameTemplate, variableName);
+ }
+ QString getMemberVariableName(const QString &variableName) const
+ {
+ return replaceNamePlaceholders(memberVariableNameTemplate, variableName);
+ }
+ FunctionLocation determineGetterLocation(int lineCount) const;
+ FunctionLocation determineSetterLocation(int lineCount) const;
+ bool createMissingNamespacesinCppFile() const
+ {
+ return cppFileNamespaceHandling == MissingNamespaceHandling::CreateMissing;
+ }
+ bool addUsingNamespaceinCppFile() const
+ {
+ return cppFileNamespaceHandling == MissingNamespaceHandling::AddUsingDirective;
+ }
+ bool rewriteTypesinCppFile() const
+ {
+ return cppFileNamespaceHandling == MissingNamespaceHandling::RewriteType;
+ }
+
+public:
+ int getterOutsideClassFrom = 0;
+ int getterInCppFileFrom = 2;
+ int setterOutsideClassFrom = 0;
+ int setterInCppFileFrom = 2;
+ QString getterAttributes; // e.g. [[nodiscard]]
+ QString getterNameTemplate = "<name>"; // or get<Name>
+ QString setterNameTemplate = "set<Name>"; // or set_<name> or Set<Name>
+ QString setterParameterNameTemplate = "new<Name>";
+ QString signalNameTemplate = "<name>Changed";
+ QString resetNameTemplate = "reset<Name>";
+ bool signalWithNewValue = false;
+ bool setterAsSlot = false;
+ MissingNamespaceHandling cppFileNamespaceHandling = MissingNamespaceHandling::CreateMissing;
+ QString memberVariableNameTemplate = "m_<name>";
+ QStringList valueTypes; // if contains use value. Ignores namespaces and template parameters
+ std::vector<CustomTemplate> customTemplates;
+};
+} // namespace CppEditor
diff --git a/src/plugins/cppeditor/cppquickfixsettingspage.cpp b/src/plugins/cppeditor/cppquickfixsettingspage.cpp
new file mode 100644
index 0000000000..63738f098f
--- /dev/null
+++ b/src/plugins/cppeditor/cppquickfixsettingspage.cpp
@@ -0,0 +1,62 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Leander Schulten <Leander.Schulten@rwth-aachen.de>
+** 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 "cppquickfixsettingspage.h"
+#include "cppeditorconstants.h"
+#include "cppquickfixsettings.h"
+#include "cppquickfixsettingswidget.h"
+#include "cpptools/cpptoolsconstants.h"
+#include <QCoreApplication>
+#include <QtDebug>
+
+using namespace CppEditor::Internal;
+
+CppQuickFixSettingsPage::CppQuickFixSettingsPage()
+{
+ setId(Constants::QUICK_FIX_SETTINGS_ID);
+ setDisplayName(QCoreApplication::translate("CppTools", Constants::QUICK_FIX_SETTINGS_DISPLAY_NAME));
+ setCategory(CppTools::Constants::CPP_SETTINGS_CATEGORY);
+}
+
+QWidget *CppQuickFixSettingsPage::widget()
+{
+ if (!m_widget) {
+ m_widget = new CppQuickFixSettingsWidget;
+ m_widget->loadSettings(CppQuickFixSettings::instance());
+ }
+ return m_widget;
+}
+
+void CppQuickFixSettingsPage::apply()
+{
+ const auto s = CppQuickFixSettings::instance();
+ m_widget->saveSettings(s);
+ s->saveAsGlobalSettings();
+}
+
+void CppEditor::Internal::CppQuickFixSettingsPage::finish()
+{
+ delete m_widget;
+}
diff --git a/src/plugins/cppeditor/cppquickfixsettingspage.h b/src/plugins/cppeditor/cppquickfixsettingspage.h
new file mode 100644
index 0000000000..d2f3f3e428
--- /dev/null
+++ b/src/plugins/cppeditor/cppquickfixsettingspage.h
@@ -0,0 +1,48 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Leander Schulten <Leander.Schulten@rwth-aachen.de>
+** 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 "coreplugin/dialogs/ioptionspage.h"
+#include <QPointer>
+
+namespace CppEditor {
+namespace Internal {
+class CppQuickFixSettingsWidget;
+
+class CppQuickFixSettingsPage : public Core::IOptionsPage
+{
+public:
+ CppQuickFixSettingsPage();
+
+ QWidget *widget() override;
+ void apply() override;
+ void finish() override;
+
+private:
+ QPointer<CppQuickFixSettingsWidget> m_widget;
+};
+
+} // namespace Internal
+} // namespace CppEditor
diff --git a/src/plugins/cppeditor/cppquickfixsettingswidget.cpp b/src/plugins/cppeditor/cppquickfixsettingswidget.cpp
new file mode 100644
index 0000000000..b996bd255f
--- /dev/null
+++ b/src/plugins/cppeditor/cppquickfixsettingswidget.cpp
@@ -0,0 +1,272 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Leander Schulten <Leander.Schulten@rwth-aachen.de>
+** 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 "cppquickfixsettingswidget.h"
+#include "cppquickfixsettings.h"
+#include "ui_cppquickfixsettingswidget.h"
+#include <QtDebug>
+
+using namespace CppEditor;
+using namespace CppEditor::Internal;
+
+CppQuickFixSettingsWidget::CppQuickFixSettingsWidget(QWidget *parent)
+ : QWidget(parent)
+ , ui(new ::Ui::CppQuickFixSettingsWidget)
+ , typeSplitter("\\s*,\\s*")
+{
+ ui->setupUi(this);
+ QObject::connect(ui->listWidget_customTemplates,
+ &QListWidget::currentItemChanged,
+ this,
+ &CppQuickFixSettingsWidget::currentCustomItemChanged);
+ QObject::connect(ui->pushButton_addValueType, &QPushButton::clicked, [this] {
+ auto item = new QListWidgetItem("<type>", ui->valueTypes);
+ item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsEnabled
+ | Qt::ItemNeverHasChildren);
+ ui->valueTypes->scrollToItem(item);
+ item->setSelected(true);
+ });
+ QObject::connect(ui->pushButton_addCustomTemplate, &QPushButton::clicked, [this] {
+ auto item = new QListWidgetItem("<type>", ui->listWidget_customTemplates);
+ item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemNeverHasChildren);
+ ui->listWidget_customTemplates->scrollToItem(item);
+ ui->listWidget_customTemplates->setCurrentItem(item);
+ ui->lineEdit_customTemplateTypes->setText("<type>");
+ });
+ QObject::connect(ui->pushButton_removeCustomTemplate, &QPushButton::clicked, [this] {
+ delete ui->listWidget_customTemplates->currentItem();
+ });
+ QObject::connect(ui->pushButton_removeValueType, &QPushButton::clicked, [this] {
+ delete ui->valueTypes->currentItem();
+ });
+ this->setEnabled(false);
+ this->ui->pushButton_removeCustomTemplate->setEnabled(false);
+ this->ui->groupBox_customTemplate->setEnabled(false);
+ this->ui->widget_getterCpp->setEnabled(false);
+ this->ui->widget_setterCpp->setEnabled(false);
+ this->ui->widget_getterOutside->setEnabled(false);
+ this->ui->widget_setterOutside->setEnabled(false);
+
+ const QString toolTip = QCoreApplication::translate("CppQuickFixSettingsWidget",
+ R"==(Use <name> for the variable
+Use <camel> for camel case
+Use <snake> for snake case
+Use <Name>, <Camel> and <Snake> for upper case
+e.g. name = "m_test_foo_":
+"set_<name> => "set_test_foo"
+"set<Name> => "setTest_foo"
+"set<Camel> => "setTestFoo")==");
+ this->ui->lineEdit_resetName->setToolTip(toolTip);
+ this->ui->lineEdit_setterName->setToolTip(toolTip);
+ this->ui->lineEdit_setterParameter->setToolTip(toolTip);
+ this->ui->lineEdit_signalName->setToolTip(toolTip);
+ this->ui->lineEdit_getterName->setToolTip(toolTip);
+ this->ui->lineEdit_memberVariableName->setToolTip(toolTip);
+
+ // connect controls to settingsChanged signal
+ auto then = [this] {
+ if (!isLoadingSettings)
+ emit settingsChanged();
+ };
+ QObject::connect(this->ui->checkBox_getterCpp, &QCheckBox::clicked, then);
+ QObject::connect(this->ui->checkBox_getterOutside, &QCheckBox::clicked, then);
+ QObject::connect(this->ui->checkBox_setterCpp, &QCheckBox::clicked, then);
+ QObject::connect(this->ui->checkBox_setterOutside, &QCheckBox::clicked, then);
+ QObject::connect(this->ui->checkBox_setterSlots, &QCheckBox::clicked, then);
+ QObject::connect(this->ui->checkBox_signalWithNewValue, &QCheckBox::clicked, then);
+ QObject::connect(this->ui->pushButton_addCustomTemplate, &QPushButton::clicked, then);
+ QObject::connect(this->ui->pushButton_removeCustomTemplate, &QPushButton::clicked, then);
+ QObject::connect(this->ui->pushButton_addValueType, &QPushButton::clicked, then);
+ QObject::connect(this->ui->pushButton_removeValueType, &QPushButton::clicked, then);
+ QObject::connect(this->ui->valueTypes, &QListWidget::itemChanged, then);
+ QObject::connect(this->ui->lineEdit_customTemplateAssignment, &QLineEdit::textEdited, then);
+ QObject::connect(this->ui->lineEdit_customTemplateComparison, &QLineEdit::textEdited, then);
+ QObject::connect(this->ui->lineEdit_customTemplateReturnExpression, &QLineEdit::textEdited, then);
+ QObject::connect(this->ui->lineEdit_customTemplateReturnType, &QLineEdit::textEdited, then);
+ QObject::connect(this->ui->lineEdit_customTemplateTypes, &QLineEdit::textEdited, then);
+ QObject::connect(this->ui->lineEdit_getterAttribute, &QLineEdit::textEdited, then);
+ QObject::connect(this->ui->lineEdit_getterName, &QLineEdit::textEdited, then);
+ QObject::connect(this->ui->lineEdit_memberVariableName, &QLineEdit::textEdited, then);
+ QObject::connect(this->ui->lineEdit_resetName, &QLineEdit::textEdited, then);
+ QObject::connect(this->ui->lineEdit_setterName, &QLineEdit::textEdited, then);
+ QObject::connect(this->ui->lineEdit_setterParameter, &QLineEdit::textEdited, then);
+ QObject::connect(this->ui->lineEdit_signalName, &QLineEdit::textEdited, then);
+ QObject::connect(this->ui->spinBox_getterCpp, &QSpinBox::editingFinished, then);
+ QObject::connect(this->ui->spinBox_getterOutside, &QSpinBox::editingFinished, then);
+ QObject::connect(this->ui->spinBox_setterCpp, &QSpinBox::editingFinished, then);
+ QObject::connect(this->ui->spinBox_setterOutside, &QSpinBox::editingFinished, then);
+ QObject::connect(this->ui->radioButton_addUsingnamespace, &QRadioButton::clicked, then);
+ QObject::connect(this->ui->radioButton_generateMissingNamespace, &QRadioButton::clicked, then);
+ QObject::connect(this->ui->radioButton_rewriteTypes, &QRadioButton::clicked, then);
+}
+
+CppQuickFixSettingsWidget::~CppQuickFixSettingsWidget()
+{
+ delete ui;
+}
+
+void CppQuickFixSettingsWidget::loadSettings(CppQuickFixSettings *settings)
+{
+ isLoadingSettings = true;
+ ui->checkBox_getterCpp->setChecked(settings->getterInCppFileFrom > 0);
+ ui->spinBox_getterCpp->setValue(std::abs(settings->getterInCppFileFrom));
+ ui->checkBox_setterCpp->setChecked(settings->setterInCppFileFrom > 0);
+ ui->spinBox_setterCpp->setValue(std::abs(settings->setterInCppFileFrom));
+ ui->checkBox_getterOutside->setChecked(settings->getterOutsideClassFrom > 0);
+ ui->spinBox_getterOutside->setValue(std::abs(settings->getterOutsideClassFrom));
+ ui->checkBox_setterOutside->setChecked(settings->setterOutsideClassFrom > 0);
+ ui->spinBox_setterOutside->setValue(std::abs(settings->setterOutsideClassFrom));
+ ui->lineEdit_getterAttribute->setText(settings->getterAttributes);
+ ui->lineEdit_getterName->setText(settings->getterNameTemplate);
+ ui->lineEdit_setterName->setText(settings->setterNameTemplate);
+ ui->lineEdit_setterParameter->setText(settings->setterParameterNameTemplate);
+ switch (settings->cppFileNamespaceHandling) {
+ case CppQuickFixSettings::MissingNamespaceHandling::RewriteType:
+ ui->radioButton_rewriteTypes->setChecked(true);
+ break;
+ case CppQuickFixSettings::MissingNamespaceHandling::CreateMissing:
+ ui->radioButton_generateMissingNamespace->setChecked(true);
+ break;
+ case CppQuickFixSettings::MissingNamespaceHandling::AddUsingDirective:
+ ui->radioButton_addUsingnamespace->setChecked(true);
+ break;
+ }
+ ui->lineEdit_resetName->setText(settings->resetNameTemplate);
+ ui->lineEdit_signalName->setText(settings->signalNameTemplate);
+ ui->lineEdit_memberVariableName->setText(settings->memberVariableNameTemplate);
+ ui->checkBox_setterSlots->setChecked(settings->setterAsSlot);
+ ui->checkBox_signalWithNewValue->setChecked(settings->signalWithNewValue);
+ ui->valueTypes->clear();
+ for (const auto &valueType : settings->valueTypes) {
+ auto item = new QListWidgetItem(valueType, ui->valueTypes);
+ item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsEnabled
+ | Qt::ItemNeverHasChildren);
+ }
+ ui->listWidget_customTemplates->clear();
+ for (const auto &customTemplate : settings->customTemplates) {
+ auto item = new QListWidgetItem(customTemplate.types.join(", "),
+ ui->listWidget_customTemplates);
+ item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemNeverHasChildren);
+ item->setData(CustomDataRoles::Types, customTemplate.types.join(", "));
+ item->setData(CustomDataRoles::Comparison, customTemplate.equalComparison);
+ item->setData(CustomDataRoles::Assignment, customTemplate.assignment);
+ item->setData(CustomDataRoles::ReturnType, customTemplate.returnType);
+ item->setData(CustomDataRoles::ReturnExpression, customTemplate.returnExpression);
+ }
+ if (ui->listWidget_customTemplates->count() > 0) {
+ ui->listWidget_customTemplates->setCurrentItem(ui->listWidget_customTemplates->item(0));
+ }
+ this->setEnabled(true);
+ isLoadingSettings = false;
+}
+
+void CppQuickFixSettingsWidget::saveSettings(CppQuickFixSettings *settings)
+{
+ // first write the current selected custom template back to the model
+ if (ui->listWidget_customTemplates->currentItem() != nullptr) {
+ auto item = ui->listWidget_customTemplates->currentItem();
+ auto list = ui->lineEdit_customTemplateTypes->text().split(typeSplitter, Qt::SkipEmptyParts);
+ item->setData(CustomDataRoles::Types, list);
+ item->setData(CustomDataRoles::Comparison, ui->lineEdit_customTemplateComparison->text());
+ item->setData(CustomDataRoles::Assignment, ui->lineEdit_customTemplateAssignment->text());
+ item->setData(CustomDataRoles::ReturnType, ui->lineEdit_customTemplateReturnType->text());
+ item->setData(CustomDataRoles::ReturnExpression,
+ ui->lineEdit_customTemplateReturnExpression->text());
+ }
+ const auto preGetOut = ui->checkBox_getterOutside->isChecked() ? 1 : -1;
+ settings->getterOutsideClassFrom = preGetOut * ui->spinBox_getterOutside->value();
+ const auto preSetOut = ui->checkBox_setterOutside->isChecked() ? 1 : -1;
+ settings->setterOutsideClassFrom = preSetOut * ui->spinBox_setterOutside->value();
+ const auto preGetCpp = ui->checkBox_getterCpp->isChecked() ? 1 : -1;
+ settings->getterInCppFileFrom = preGetCpp * ui->spinBox_getterCpp->value();
+ const auto preSetCpp = ui->checkBox_setterCpp->isChecked() ? 1 : -1;
+ settings->setterInCppFileFrom = preSetCpp * ui->spinBox_setterCpp->value();
+ settings->setterParameterNameTemplate = ui->lineEdit_setterParameter->text();
+ settings->setterAsSlot = ui->checkBox_setterSlots->isChecked();
+ settings->signalWithNewValue = ui->checkBox_signalWithNewValue->isChecked();
+ settings->getterAttributes = ui->lineEdit_getterAttribute->text();
+ settings->getterNameTemplate = ui->lineEdit_getterName->text();
+ settings->setterNameTemplate = ui->lineEdit_setterName->text();
+ settings->resetNameTemplate = ui->lineEdit_resetName->text();
+ settings->signalNameTemplate = ui->lineEdit_signalName->text();
+ settings->memberVariableNameTemplate = ui->lineEdit_memberVariableName->text();
+ if (ui->radioButton_rewriteTypes->isChecked()) {
+ settings->cppFileNamespaceHandling = CppQuickFixSettings::MissingNamespaceHandling::RewriteType;
+ } else if (ui->radioButton_addUsingnamespace->isChecked()) {
+ settings->cppFileNamespaceHandling = CppQuickFixSettings::MissingNamespaceHandling::AddUsingDirective;
+ } else if (ui->radioButton_generateMissingNamespace->isChecked()) {
+ settings->cppFileNamespaceHandling = CppQuickFixSettings::MissingNamespaceHandling::CreateMissing;
+ }
+ settings->valueTypes.clear();
+ for (int i = 0; i < ui->valueTypes->count(); ++i) {
+ settings->valueTypes << ui->valueTypes->item(i)->text();
+ }
+ settings->customTemplates.clear();
+ for (int i = 0; i < ui->listWidget_customTemplates->count(); ++i) {
+ auto item = ui->listWidget_customTemplates->item(i);
+ CppQuickFixSettings::CustomTemplate t;
+ t.types = item->data(CustomDataRoles::Types).toStringList();
+ t.equalComparison = item->data(CustomDataRoles::Comparison).toString();
+ t.assignment = item->data(CustomDataRoles::Assignment).toString();
+ t.returnExpression = item->data(CustomDataRoles::ReturnExpression).toString();
+ t.returnType = item->data(CustomDataRoles::ReturnType).toString();
+ settings->customTemplates.push_back(t);
+ }
+}
+
+void CppQuickFixSettingsWidget::currentCustomItemChanged(QListWidgetItem *newItem,
+ QListWidgetItem *oldItem)
+{
+ if (oldItem) {
+ auto list = ui->lineEdit_customTemplateTypes->text().split(typeSplitter, Qt::SkipEmptyParts);
+ oldItem->setData(CustomDataRoles::Types, list);
+ oldItem->setData(Qt::DisplayRole, list.join(", "));
+ oldItem->setData(CustomDataRoles::Comparison, ui->lineEdit_customTemplateComparison->text());
+ oldItem->setData(CustomDataRoles::Assignment, ui->lineEdit_customTemplateAssignment->text());
+ oldItem->setData(CustomDataRoles::ReturnType, ui->lineEdit_customTemplateReturnType->text());
+ oldItem->setData(CustomDataRoles::ReturnExpression,
+ ui->lineEdit_customTemplateReturnExpression->text());
+ }
+ this->ui->pushButton_removeCustomTemplate->setEnabled(newItem != nullptr);
+ this->ui->groupBox_customTemplate->setEnabled(newItem != nullptr);
+ if (newItem) {
+ this->ui->lineEdit_customTemplateTypes->setText(
+ newItem->data(CustomDataRoles::Types).toStringList().join(", "));
+ this->ui->lineEdit_customTemplateComparison->setText(
+ newItem->data(CustomDataRoles::Comparison).toString());
+ this->ui->lineEdit_customTemplateAssignment->setText(
+ newItem->data(CustomDataRoles::Assignment).toString());
+ this->ui->lineEdit_customTemplateReturnType->setText(
+ newItem->data(CustomDataRoles::ReturnType).toString());
+ this->ui->lineEdit_customTemplateReturnExpression->setText(
+ newItem->data(CustomDataRoles::ReturnExpression).toString());
+ } else {
+ this->ui->lineEdit_customTemplateTypes->setText("");
+ this->ui->lineEdit_customTemplateComparison->setText("");
+ this->ui->lineEdit_customTemplateAssignment->setText("");
+ this->ui->lineEdit_customTemplateReturnType->setText("");
+ this->ui->lineEdit_customTemplateReturnExpression->setText("");
+ }
+}
diff --git a/src/plugins/cppeditor/cppquickfixsettingswidget.h b/src/plugins/cppeditor/cppquickfixsettingswidget.h
new file mode 100644
index 0000000000..68450499d8
--- /dev/null
+++ b/src/plugins/cppeditor/cppquickfixsettingswidget.h
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Leander Schulten <Leander.Schulten@rwth-aachen.de>
+** 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.
+**
+****************************************************************************/
+
+#ifndef CppQuickFixSettingsWidget_H
+#define CppQuickFixSettingsWidget_H
+
+#include <QRegularExpression>
+#include <QWidget>
+
+QT_BEGIN_NAMESPACE
+class QListWidgetItem;
+namespace Ui { class CppQuickFixSettingsWidget; }
+QT_END_NAMESPACE
+
+namespace CppEditor {
+class CppQuickFixSettings;
+
+namespace Internal {
+
+class CppQuickFixSettingsWidget : public QWidget
+{
+ Q_OBJECT
+ enum CustomDataRoles {
+ Types = Qt::UserRole,
+ Comparison,
+ Assignment,
+ ReturnExpression,
+ ReturnType,
+ };
+
+public:
+ explicit CppQuickFixSettingsWidget(QWidget *parent = nullptr);
+ ~CppQuickFixSettingsWidget();
+ void loadSettings(CppQuickFixSettings *settings);
+ void saveSettings(CppQuickFixSettings *settings);
+private slots:
+ void currentCustomItemChanged(QListWidgetItem *newItem, QListWidgetItem *oldItem);
+signals:
+ void settingsChanged();
+
+private:
+ bool isLoadingSettings = false;
+ Ui::CppQuickFixSettingsWidget *ui;
+ const QRegularExpression typeSplitter;
+};
+
+} // namespace Internal
+} // namespace CppEditor
+
+#endif // CppQuickFixSettingsWidget_H
diff --git a/src/plugins/cppeditor/cppquickfixsettingswidget.ui b/src/plugins/cppeditor/cppquickfixsettingswidget.ui
new file mode 100644
index 0000000000..41b68d8ba9
--- /dev/null
+++ b/src/plugins/cppeditor/cppquickfixsettingswidget.ui
@@ -0,0 +1,961 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>CppQuickFixSettingsWidget</class>
+ <widget class="QWidget" name="CppQuickFixSettingsWidget">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>641</width>
+ <height>1074</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_3">
+ <item>
+ <widget class="QGroupBox" name="groupBox_2">
+ <property name="title">
+ <string>Generated Function Locations</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout_2">
+ <property name="horizontalSpacing">
+ <number>48</number>
+ </property>
+ <item row="3" column="2">
+ <widget class="QLabel" name="label_5">
+ <property name="text">
+ <string>Default</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="1" alignment="Qt::AlignHCenter">
+ <widget class="QWidget" name="widget2" native="true">
+ <layout class="QHBoxLayout" name="horizontalLayout_7">
+ <property name="leftMargin">
+ <number>1</number>
+ </property>
+ <property name="topMargin">
+ <number>1</number>
+ </property>
+ <property name="rightMargin">
+ <number>1</number>
+ </property>
+ <property name="bottomMargin">
+ <number>1</number>
+ </property>
+ <item alignment="Qt::AlignRight">
+ <widget class="QCheckBox" name="checkBox_setterOutside">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QWidget" name="widget_setterOutside" native="true">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout_9">
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="label_8">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>≥</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QSpinBox" name="spinBox_setterOutside">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimum">
+ <number>1</number>
+ </property>
+ </widget>
+ </item>
+ <item alignment="Qt::AlignLeft">
+ <widget class="QLabel" name="label_7">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>lines</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item row="5" column="1" alignment="Qt::AlignHCenter">
+ <widget class="QWidget" name="widget3" native="true">
+ <layout class="QHBoxLayout" name="horizontalLayout_6">
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <property name="leftMargin">
+ <number>1</number>
+ </property>
+ <property name="topMargin">
+ <number>1</number>
+ </property>
+ <property name="rightMargin">
+ <number>1</number>
+ </property>
+ <property name="bottomMargin">
+ <number>1</number>
+ </property>
+ <item alignment="Qt::AlignRight">
+ <widget class="QCheckBox" name="checkBox_setterCpp">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QWidget" name="widget_setterCpp" native="true">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <layout class="QHBoxLayout" name="group1">
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="label_6">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>≥</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QSpinBox" name="spinBox_setterCpp">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimum">
+ <number>1</number>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="label_14">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>lines</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item row="4" column="2" alignment="Qt::AlignHCenter">
+ <widget class="QWidget" name="widget" native="true">
+ <property name="maximumSize">
+ <size>
+ <width>16777215</width>
+ <height>40</height>
+ </size>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <property name="leftMargin">
+ <number>1</number>
+ </property>
+ <property name="topMargin">
+ <number>1</number>
+ </property>
+ <property name="rightMargin">
+ <number>1</number>
+ </property>
+ <property name="bottomMargin">
+ <number>1</number>
+ </property>
+ <item alignment="Qt::AlignRight">
+ <widget class="QCheckBox" name="checkBox_getterOutside">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ <property name="checkable">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QWidget" name="widget_getterOutside" native="true">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout_10">
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="label_13">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>≥</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QSpinBox" name="spinBox_getterOutside">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimum">
+ <number>1</number>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="label_9">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>lines</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item row="3" column="1">
+ <widget class="QLabel" name="label_4">
+ <property name="text">
+ <string>Default</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="2">
+ <widget class="QLabel" name="label_3">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <underline>true</underline>
+ </font>
+ </property>
+ <property name="text">
+ <string>Generate Getters</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLabel" name="label">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <underline>true</underline>
+ </font>
+ </property>
+ <property name="text">
+ <string>Generate Setters</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="0">
+ <widget class="QLabel" name="label_12">
+ <property name="text">
+ <string>In .cpp file:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="2" alignment="Qt::AlignHCenter">
+ <widget class="QWidget" name="widget4" native="true">
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <property name="leftMargin">
+ <number>1</number>
+ </property>
+ <property name="topMargin">
+ <number>1</number>
+ </property>
+ <property name="rightMargin">
+ <number>1</number>
+ </property>
+ <property name="bottomMargin">
+ <number>1</number>
+ </property>
+ <item alignment="Qt::AlignRight">
+ <widget class="QCheckBox" name="checkBox_getterCpp">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QWidget" name="widget_getterCpp" native="true">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout_11">
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="label_15">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>≥</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QSpinBox" name="spinBox_getterCpp">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimum">
+ <number>1</number>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="label_16">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>lines</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item row="0" column="3">
+ <spacer name="horizontalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>1</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="4" column="0">
+ <widget class="QLabel" name="label_11">
+ <property name="text">
+ <string>Outside class:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0">
+ <widget class="QLabel" name="label_10">
+ <property name="text">
+ <string>Inside class:</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="groupBox_4">
+ <property name="title">
+ <string>Getter Setter Generation Properties</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout_4">
+ <item row="1" column="0">
+ <widget class="QLabel" name="label_18">
+ <property name="text">
+ <string>Getter name:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1">
+ <widget class="QLineEdit" name="lineEdit_setterParameter">
+ <property name="placeholderText">
+ <string>For example, new&lt;Name&gt;</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="label_19">
+ <property name="text">
+ <string>Setter name:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="0" colspan="2">
+ <widget class="QCheckBox" name="checkBox_setterSlots">
+ <property name="text">
+ <string>Setters should be slots</string>
+ </property>
+ </widget>
+ </item>
+ <item row="7" column="0" colspan="2">
+ <widget class="QCheckBox" name="checkBox_signalWithNewValue">
+ <property name="text">
+ <string>Generate signals with the new value as parameter</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="0">
+ <widget class="QLabel" name="label_17">
+ <property name="text">
+ <string>Getter attributes:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0">
+ <widget class="QLabel" name="label_28">
+ <property name="text">
+ <string>Setter parameter name:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="0">
+ <widget class="QLabel" name="label_30">
+ <property name="text">
+ <string>Reset name:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="6" column="0">
+ <widget class="QLabel" name="label_29">
+ <property name="text">
+ <string>Signal name:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLineEdit" name="lineEdit_getterName">
+ <property name="placeholderText">
+ <string>See tool tip for more information</string>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="1">
+ <widget class="QLineEdit" name="lineEdit_resetName">
+ <property name="placeholderText">
+ <string>Normally reset&lt;Name&gt;</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="lineEdit_getterAttribute">
+ <property name="placeholderText">
+ <string>For example, [[nodiscard]]</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QLineEdit" name="lineEdit_setterName">
+ <property name="placeholderText">
+ <string>See tool tip for more information</string>
+ </property>
+ </widget>
+ </item>
+ <item row="6" column="1">
+ <widget class="QLineEdit" name="lineEdit_signalName">
+ <property name="placeholderText">
+ <string>Normally &lt;name&gt;Changed</string>
+ </property>
+ </widget>
+ </item>
+ <item row="8" column="0">
+ <widget class="QLabel" name="label_31">
+ <property name="text">
+ <string>Member variable name:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="8" column="1">
+ <widget class="QLineEdit" name="lineEdit_memberVariableName">
+ <property name="placeholderText">
+ <string>For example, m_&lt;name&gt;</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="groupBox">
+ <property name="title">
+ <string>Missing Namespace Handling</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <item>
+ <widget class="QRadioButton" name="radioButton_generateMissingNamespace">
+ <property name="text">
+ <string>Generate missing namespaces</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QRadioButton" name="radioButton_addUsingnamespace">
+ <property name="text">
+ <string>Add &quot;using namespace ...&quot;</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QRadioButton" name="radioButton_rewriteTypes">
+ <property name="text">
+ <string>Rewrite types to match the existing namespaces</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="groupBox_3">
+ <property name="title">
+ <string>Custom Getter Setter Templates</string>
+ </property>
+ <property name="checkable">
+ <bool>false</bool>
+ </property>
+ <layout class="QGridLayout" name="gridLayout_3" columnstretch="0,5">
+ <item row="1" column="1" rowspan="2">
+ <widget class="QGroupBox" name="groupBox_customTemplate">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="MinimumExpanding" vsizetype="Minimum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="title">
+ <string>Template</string>
+ </property>
+ <property name="checkable">
+ <bool>false</bool>
+ </property>
+ <layout class="QFormLayout" name="formLayout">
+ <item row="0" column="0">
+ <widget class="QLabel" name="label_22">
+ <property name="text">
+ <string>Types:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="lineEdit_customTemplateTypes">
+ <property name="toolTip">
+ <string>Separate the types by comma.</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label_23">
+ <property name="text">
+ <string>Comparison:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLineEdit" name="lineEdit_customTemplateComparison"/>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="label_24">
+ <property name="text">
+ <string>Assignment:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QLineEdit" name="lineEdit_customTemplateAssignment"/>
+ </item>
+ <item row="3" column="0">
+ <widget class="QLabel" name="label_25">
+ <property name="text">
+ <string>Return expression:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1">
+ <widget class="QLineEdit" name="lineEdit_customTemplateReturnExpression"/>
+ </item>
+ <item row="4" column="0">
+ <widget class="QLabel" name="label_26">
+ <property name="text">
+ <string>Return type:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="1">
+ <widget class="QLineEdit" name="lineEdit_customTemplateReturnType"/>
+ </item>
+ <item row="5" column="0" colspan="2">
+ <widget class="QLabel" name="label_27">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Expanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Use &lt;new&gt; and &lt;cur&gt; to access the parameter and current value. Use &lt;type&gt; to access the type and &lt;T&gt; for the template parameter.</string>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item row="1" column="0" rowspan="2">
+ <widget class="QWidget" name="widget_2" native="true">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>200</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_4">
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QListWidget" name="listWidget_customTemplates">
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Expanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_8">
+ <item>
+ <widget class="QPushButton" name="pushButton_addCustomTemplate">
+ <property name="text">
+ <string>Add</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="pushButton_removeCustomTemplate">
+ <property name="text">
+ <string>Remove</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="0" column="1">
+ <widget class="QListWidget" name="valueTypes">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>16777215</width>
+ <height>150</height>
+ </size>
+ </property>
+ <property name="toolTip">
+ <string>Normally arguments get passed by const reference. If the Type is one of the following ones, the argument gets passed by value. Namespaces and template arguments are removed. The real Type must contain the given Type. For example, &quot;int&quot; matches &quot;int32_t&quot; but not &quot;vector&lt;int&gt;&quot;. &quot;vector&quot; matches &quot;std::pmr::vector&lt;int&gt;&quot; but not &quot;std::optional&lt;vector&lt;int&gt;&gt;&quot;</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="0">
+ <widget class="QLabel" name="label_2">
+ <property name="minimumSize">
+ <size>
+ <width>212</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Value types:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <layout class="QHBoxLayout" name="horizontalLayout_3">
+ <item>
+ <widget class="QPushButton" name="pushButton_addValueType">
+ <property name="text">
+ <string>Add</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="pushButton_removeValueType">
+ <property name="text">
+ <string>Remove</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>checkBox_getterCpp</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>widget_getterCpp</receiver>
+ <slot>setEnabled(bool)</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>509</x>
+ <y>125</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>570</x>
+ <y>125</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>checkBox_getterOutside</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>widget_getterOutside</receiver>
+ <slot>setEnabled(bool)</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>509</x>
+ <y>91</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>570</x>
+ <y>91</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>checkBox_setterOutside</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>widget_setterOutside</receiver>
+ <slot>setEnabled(bool)</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>312</x>
+ <y>91</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>373</x>
+ <y>91</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>checkBox_setterCpp</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>widget_setterCpp</receiver>
+ <slot>setEnabled(bool)</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>312</x>
+ <y>125</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>373</x>
+ <y>125</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/src/plugins/cpptools/cppcodestylesettings.h b/src/plugins/cpptools/cppcodestylesettings.h
index 8b477be354..ec60659be1 100644
--- a/src/plugins/cpptools/cppcodestylesettings.h
+++ b/src/plugins/cpptools/cppcodestylesettings.h
@@ -83,6 +83,8 @@ public:
// b
bool alignAssignments = false;
+ // TODO only kept to allow conversion to the new setting getterNameTemplate in
+ // CppEditor/QuickFixSetting. Remove in 4.16
bool preferGetterNameWithoutGetPrefix = true;
void toSettings(const QString &category, QSettings *s) const;
diff --git a/src/plugins/cpptools/cppcodestylesettingspage.cpp b/src/plugins/cpptools/cppcodestylesettingspage.cpp
index 1f29bac9f1..4c4f2b8e58 100644
--- a/src/plugins/cpptools/cppcodestylesettingspage.cpp
+++ b/src/plugins/cpptools/cppcodestylesettingspage.cpp
@@ -157,8 +157,6 @@ CppCodeStylePreferencesWidget::CppCodeStylePreferencesWidget(QWidget *parent)
this, &CppCodeStylePreferencesWidget::slotCodeStyleSettingsChanged);
connect(m_ui->bindStarToRightSpecifier, &QCheckBox::toggled,
this, &CppCodeStylePreferencesWidget::slotCodeStyleSettingsChanged);
- connect(m_ui->preferGetterNamesWithoutGet, &QCheckBox::toggled,
- this, &CppCodeStylePreferencesWidget::slotCodeStyleSettingsChanged);
m_ui->categoryTab->setCurrentIndex(0);
}
@@ -216,7 +214,6 @@ CppCodeStyleSettings CppCodeStylePreferencesWidget::cppCodeStyleSettings() const
set.bindStarToRightSpecifier = m_ui->bindStarToRightSpecifier->isChecked();
set.extraPaddingForConditionsIfConfusingAlign = m_ui->extraPaddingConditions->isChecked();
set.alignAssignments = m_ui->alignAssignments->isChecked();
- set.preferGetterNameWithoutGetPrefix = m_ui->preferGetterNamesWithoutGet->isChecked();
return set;
}
@@ -250,7 +247,6 @@ void CppCodeStylePreferencesWidget::setCodeStyleSettings(const CppCodeStyleSetti
m_ui->bindStarToRightSpecifier->setChecked(s.bindStarToRightSpecifier);
m_ui->extraPaddingConditions->setChecked(s.extraPaddingForConditionsIfConfusingAlign);
m_ui->alignAssignments->setChecked(s.alignAssignments);
- m_ui->preferGetterNamesWithoutGet->setChecked(s.preferGetterNameWithoutGetPrefix);
m_blockUpdates = wasBlocked;
if (preview)
updatePreview();
diff --git a/src/plugins/cpptools/cppcodestylesettingspage.ui b/src/plugins/cpptools/cppcodestylesettingspage.ui
index 5bb0eff89c..c13f603cc8 100644
--- a/src/plugins/cpptools/cppcodestylesettingspage.ui
+++ b/src/plugins/cpptools/cppcodestylesettingspage.ui
@@ -433,33 +433,6 @@ if they would align to the next line</string>
</item>
</layout>
</widget>
- <widget class="QWidget" name="getterSetterTab">
- <attribute name="title">
- <string>Getter and Setter</string>
- </attribute>
- <layout class="QVBoxLayout" name="verticalLayout_7">
- <item>
- <widget class="QCheckBox" name="preferGetterNamesWithoutGet">
- <property name="text">
- <string>Prefer getter names without &quot;get&quot;</string>
- </property>
- </widget>
- </item>
- <item>
- <spacer name="verticalSpacer_7">
- <property name="orientation">
- <enum>Qt::Vertical</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>20</width>
- <height>40</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
- </widget>
</widget>
</item>
</layout>
diff --git a/src/plugins/texteditor/semantichighlighter.cpp b/src/plugins/texteditor/semantichighlighter.cpp
index 858f8bb8cd..22a5ecf3c9 100644
--- a/src/plugins/texteditor/semantichighlighter.cpp
+++ b/src/plugins/texteditor/semantichighlighter.cpp
@@ -30,25 +30,52 @@
#include <utils/qtcassert.h>
-#include <QTextDocument>
#include <QTextBlock>
+#include <QTextDocument>
+
+#include <algorithm>
using namespace TextEditor;
using namespace TextEditor::SemanticHighlighter;
namespace {
-QTextLayout::FormatRange rangeForResult(const HighlightingResult &result,
- const QHash<int, QTextCharFormat> &kindToFormat)
-{
+class Range {
+public:
QTextLayout::FormatRange formatRange;
+ QTextBlock block;
+};
+using Ranges = QVector<Range>;
- formatRange.start = int(result.column) - 1;
- formatRange.length = int(result.length);
- formatRange.format = result.useTextSyles
+Ranges rangesForResult(const HighlightingResult &result,
+ QTextDocument *doc,
+ const QHash<int, QTextCharFormat> &kindToFormat)
+{
+ const QTextCharFormat format = result.useTextSyles
? TextEditorSettings::fontSettings().toTextCharFormat(result.textStyles)
: kindToFormat.value(result.kind);
- return formatRange;
+ if (!format.isValid())
+ return {};
+
+ HighlightingResult curResult = result;
+ QTextBlock curBlock = doc->findBlockByNumber(curResult.line - 1);
+ Ranges ranges;
+ while (curBlock.isValid()) {
+ Range range;
+ range.block = curBlock;
+ range.formatRange.format = format;
+ range.formatRange.start = curResult.column - 1;
+ range.formatRange.length = std::min(curResult.length,
+ curBlock.length() - range.formatRange.start);
+ ranges << range;
+ if (range.formatRange.length == curResult.length)
+ break;
+ curBlock = curBlock.next();
+ curResult.column = 1;
+ curResult.length -= range.formatRange.length;
+ }
+
+ return ranges;
}
}
@@ -81,39 +108,22 @@ void SemanticHighlighter::incrementalApplyExtraAdditionalFormats(
QTextDocument *doc = highlighter->document();
QTC_ASSERT(currentBlockNumber < doc->blockCount(), return);
- QTextBlock b = doc->findBlockByNumber(currentBlockNumber);
+ QTextBlock currentBlock = doc->findBlockByNumber(currentBlockNumber);
- HighlightingResult result = future.resultAt(from);
- for (int i = from; i < to && b.isValid(); ) {
- const int blockNumber = int(result.line) - 1;
- QTC_ASSERT(blockNumber < doc->blockCount(), return);
-
- // clear formats of blocks until blockNumber
- while (currentBlockNumber < blockNumber) {
- highlighter->clearExtraFormats(b);
- b = b.next();
- ++currentBlockNumber;
- }
+ std::map<QTextBlock, QVector<QTextLayout::FormatRange>> formatRanges;
+ for (int i = from; i < to; ++i) {
+ const Ranges ranges = rangesForResult(future.resultAt(i), doc, kindToFormat);
+ for (const Range &range : ranges)
+ formatRanges[range.block].append(range.formatRange);
+ }
- // collect all the formats for the current line
- QVector<QTextLayout::FormatRange> formats;
- formats.reserve(to - from);
- forever {
- const QTextLayout::FormatRange formatRange = rangeForResult(result, kindToFormat);
- if (formatRange.format.isValid())
- formats.append(formatRange);
-
- ++i;
- if (i >= to)
- break;
- result = future.resultAt(i);
- const int nextBlockNumber = int(result.line) - 1;
- if (nextBlockNumber != blockNumber)
- break;
+ for (auto &[block, ranges] : formatRanges) {
+ while (currentBlock < block) {
+ highlighter->clearExtraFormats(currentBlock);
+ currentBlock = currentBlock.next();
}
- highlighter->setExtraFormats(b, std::move(formats));
- b = b.next();
- ++currentBlockNumber;
+ highlighter->setExtraFormats(block, std::move(ranges));
+ currentBlock = block.next();
}
}
@@ -128,21 +138,16 @@ void SemanticHighlighter::setExtraAdditionalFormats(SyntaxHighlighter *highlight
QTextDocument *doc = highlighter->document();
QTC_ASSERT(doc, return );
- QVector<QVector<QTextLayout::FormatRange>> ranges(doc->blockCount());
+ std::map<QTextBlock, QVector<QTextLayout::FormatRange>> formatRanges;
for (auto result : results) {
- const QTextLayout::FormatRange formatRange = rangeForResult(result, kindToFormat);
- if (formatRange.format.isValid())
- ranges[int(result.line) - 1].append(formatRange);
+ const Ranges ranges = rangesForResult(result, doc, kindToFormat);
+ for (const Range &range : ranges)
+ formatRanges[range.block].append(range.formatRange);
}
- for (int blockNumber = 0; blockNumber < ranges.count(); ++blockNumber) {
- if (!ranges[blockNumber].isEmpty()) {
- QTextBlock b = doc->findBlockByNumber(blockNumber);
- QTC_ASSERT(b.isValid(), return );
- highlighter->setExtraFormats(b, std::move(ranges[blockNumber]));
- }
- }
+ for (auto &[block, ranges] : formatRanges)
+ highlighter->setExtraFormats(block, std::move(ranges));
}
void SemanticHighlighter::clearExtraAdditionalFormatsUntilEnd(