summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/tools/uic/cpp/cppwriteinitialization.cpp19
-rw-r--r--src/tools/uic/customwidgetsinfo.cpp86
-rw-r--r--src/tools/uic/customwidgetsinfo.h5
-rw-r--r--src/tools/uic/shared/language.cpp63
-rw-r--r--tests/auto/tools/uic/baseline/qoverload.ui93
-rw-r--r--tests/auto/tools/uic/baseline/qoverload.ui.h98
6 files changed, 335 insertions, 29 deletions
diff --git a/src/tools/uic/cpp/cppwriteinitialization.cpp b/src/tools/uic/cpp/cppwriteinitialization.cpp
index c1e3e98f43b..893cc5b8ecd 100644
--- a/src/tools/uic/cpp/cppwriteinitialization.cpp
+++ b/src/tools/uic/cpp/cppwriteinitialization.cpp
@@ -2698,10 +2698,6 @@ ConnectionSyntax WriteInitialization::connectionSyntax(const language::SignalSlo
return ConnectionSyntax::StringBased;
}
- // QTBUG-110952, ambiguous overloads of display()
- if (receiver.className == u"QLCDNumber" && receiver.signature.startsWith(u"display("))
- return ConnectionSyntax::StringBased;
-
if ((sender.name == m_mainFormVarName && m_customSignals.contains(sender.signature))
|| (receiver.name == m_mainFormVarName && m_customSlots.contains(receiver.signature))) {
return ConnectionSyntax::StringBased;
@@ -2729,14 +2725,21 @@ void WriteInitialization::acceptConnection(DomConnection *connection)
return;
}
const QString senderSignature = connection->elementSignal();
+ const QString slotSignature = connection->elementSlot();
+ const bool senderAmbiguous = m_uic->customWidgetsInfo()->isAmbiguousSignal(senderDecl.className,
+ senderSignature);
+ const bool slotAmbiguous = m_uic->customWidgetsInfo()->isAmbiguousSlot(receiverDecl.className,
+ slotSignature);
+
language::SignalSlotOptions signalOptions;
- if (m_uic->customWidgetsInfo()->isAmbiguousSignal(senderDecl.className, senderSignature))
- signalOptions.setFlag(language::SignalSlotOption::Ambiguous);
+ signalOptions.setFlag(language::SignalSlotOption::Ambiguous, senderAmbiguous);
+ language::SignalSlotOptions slotOptions;
+ slotOptions.setFlag(language::SignalSlotOption::Ambiguous, slotAmbiguous);
language::SignalSlot theSignal{senderDecl.name, senderSignature,
senderDecl.className, signalOptions};
- language::SignalSlot theSlot{receiverDecl.name, connection->elementSlot(),
- receiverDecl.className, {}};
+ language::SignalSlot theSlot{receiverDecl.name, slotSignature,
+ receiverDecl.className, slotOptions};
m_output << m_indent;
language::formatConnection(m_output, theSignal, theSlot,
diff --git a/src/tools/uic/customwidgetsinfo.cpp b/src/tools/uic/customwidgetsinfo.cpp
index 169cdad618c..6ec418634c2 100644
--- a/src/tools/uic/customwidgetsinfo.cpp
+++ b/src/tools/uic/customwidgetsinfo.cpp
@@ -78,19 +78,89 @@ bool CustomWidgetsInfo::isCustomWidgetContainer(const QString &className) const
return false;
}
+// FIXME in 7.0 - QTBUG-124241
+// Remove isAmbiguous logic when widget slots have been disambiguated.
+bool CustomWidgetsInfo::isAmbiguous(const QString &className, const QString &signature,
+ QMetaMethod::MethodType type) const
+{
+ using TypeMap = QHash<QString, QMetaMethod::MethodType>;
+ struct AmbiguousInClass {
+ QLatin1StringView className;
+ TypeMap methodMap;
+ };
+
+ static const QList<AmbiguousInClass> ambiguousList = {
+
+ {"QAction"_L1, {{"triggered"_L1, QMetaMethod::Signal}}},
+ {"QCommandLinkButton"_L1, {{"triggered"_L1, QMetaMethod::Signal},
+ {"clicked"_L1, QMetaMethod::Signal}}},
+ {"QPushButton"_L1, {{"triggered"_L1, QMetaMethod::Signal},
+ {"clicked"_L1, QMetaMethod::Signal}}},
+ {"QCheckBox"_L1, {{"triggered"_L1, QMetaMethod::Signal},
+ {"clicked"_L1, QMetaMethod::Signal}}},
+ {"QRadioButton"_L1, {{"triggered"_L1, QMetaMethod::Signal},
+ {"clicked"_L1, QMetaMethod::Signal}}},
+ {"QToolButton"_L1, {{"triggered"_L1, QMetaMethod::Signal},
+ {"clicked"_L1, QMetaMethod::Signal}}},
+ {"QLabel"_L1, {{"setNum"_L1, QMetaMethod::Slot}}},
+ {"QGraphicsView"_L1, {{"invalidateScene"_L1, QMetaMethod::Slot}}},
+ {"QListView"_L1, {{"dataChanged"_L1, QMetaMethod::Slot}}},
+ {"QColumnView"_L1, {{"dataChanged"_L1, QMetaMethod::Slot}}},
+ {"QListWidget"_L1, {{"dataChanged"_L1, QMetaMethod::Slot},
+ {"scrollToItem"_L1, QMetaMethod::Slot}}},
+ {"QTableView"_L1, {{"dataChanged"_L1, QMetaMethod::Slot}}},
+ {"QTableWidget"_L1, {{"dataChanged"_L1, QMetaMethod::Slot},
+ {"scrollToItem"_L1, QMetaMethod::Slot}}},
+ {"QTreeView"_L1, {{"dataChanged"_L1, QMetaMethod::Slot},
+ {"verticalScrollbarValueChanged"_L1, QMetaMethod::Slot},
+ {"expandRecursively"_L1, QMetaMethod::Slot}}},
+ {"QTreeWidget"_L1, {{"dataChanged"_L1, QMetaMethod::Slot},
+ {"verticalScrollbarValueChanged"_L1, QMetaMethod::Slot}
+ ,{"expandRecursively"_L1, QMetaMethod::Slot}
+ ,{"scrollToItem"_L1, QMetaMethod::Slot}}},
+ {"QUndoView"_L1, {{"dataChanged"_L1, QMetaMethod::Slot}}},
+ {"QLCDNumber"_L1, {{"display"_L1, QMetaMethod::Slot}}},
+ {"QMenuBar"_L1, {{"setVisible"_L1, QMetaMethod::Slot}}},
+ {"QTextBrowser"_L1, {{"setSource"_L1, QMetaMethod::Slot}}},
+
+ /*
+ The following widgets with ambiguities are not used in the widget designer:
+
+ {"QSplashScreen"_L1, {{"showMessage"_L1, QMetaMethod::Slot}}},
+ {"QCompleter"_L1, {{"activated"_L1, QMetaMethod::Signal},
+ {"highlighted"_L1, QMetaMethod::Signal}}},
+ {"QSystemTrayIcon"_L1, {{"showMessage"_L1, QMetaMethod::Slot}}},
+ {"QStyledItemDelegate"_L1, {{"closeEditor"_L1, QMetaMethod::Signal}}},
+ {"QErrorMessage"_L1, {{"showMessage"_L1, QMetaMethod::Slot}}},
+ {"QGraphicsDropShadowEffect"_L1, {{"setOffset"_L1, QMetaMethod::Slot}}},
+ {"QGraphicsScene"_L1, {{"invalidate"_L1, QMetaMethod::Slot}}},
+ {"QItemDelegate"_L1, {{"closeEditor"_L1, QMetaMethod::Signal}}}
+ */
+ };
+
+ for (auto it = ambiguousList.constBegin(); it != ambiguousList.constEnd(); ++it) {
+ if (extends(className, it->className)) {
+ const qsizetype pos = signature.indexOf(u'(');
+ const QString method = signature.left(pos);
+ const auto methodIterator = it->methodMap.find(method);
+ return methodIterator != it->methodMap.constEnd() && type == methodIterator.value();
+ }
+ }
+ return false;
+}
+
// Is it ambiguous, resulting in different signals for Python
// "QAbstractButton::clicked(checked=false)"
bool CustomWidgetsInfo::isAmbiguousSignal(const QString &className,
const QString &signalSignature) const
{
- if (signalSignature.startsWith(u"triggered") && extends(className, "QAction"))
- return true;
- if (signalSignature.startsWith(u"clicked(")
- && extendsOneOf(className, {u"QCommandLinkButton"_s, u"QCheckBox"_s,
- u"QPushButton"_s, u"QRadioButton"_s, u"QToolButton"_s})) {
- return true;
- }
- return false;
+ return isAmbiguous(className, signalSignature, QMetaMethod::Signal);
+}
+
+bool CustomWidgetsInfo::isAmbiguousSlot(const QString &className,
+ const QString &signalSignature) const
+{
+ return isAmbiguous(className, signalSignature, QMetaMethod::Slot);
}
QString CustomWidgetsInfo::realClassName(const QString &className) const
diff --git a/src/tools/uic/customwidgetsinfo.h b/src/tools/uic/customwidgetsinfo.h
index 4bd004bdc72..f336292f2ac 100644
--- a/src/tools/uic/customwidgetsinfo.h
+++ b/src/tools/uic/customwidgetsinfo.h
@@ -7,6 +7,7 @@
#include "treewalker.h"
#include <qstringlist.h>
#include <qmap.h>
+#include <QtCore/qmetaobject.h>
QT_BEGIN_NAMESPACE
@@ -38,10 +39,14 @@ public:
bool isAmbiguousSignal(const QString &className,
const QString &signalSignature) const;
+ bool isAmbiguousSlot(const QString &className,
+ const QString &slotSignature) const;
private:
using NameCustomWidgetMap = QMap<QString, DomCustomWidget*>;
NameCustomWidgetMap m_customWidgets;
+ bool isAmbiguous(const QString &className, const QString &signature,
+ QMetaMethod::MethodType type) const;
};
QT_END_NAMESPACE
diff --git a/src/tools/uic/shared/language.cpp b/src/tools/uic/shared/language.cpp
index bfdce0bc4c3..d59688e3466 100644
--- a/src/tools/uic/shared/language.cpp
+++ b/src/tools/uic/shared/language.cpp
@@ -4,6 +4,7 @@
#include "language.h"
#include <QtCore/qtextstream.h>
+#include <QtCore/QList>
namespace language {
@@ -370,17 +371,40 @@ void _formatStackVariable(QTextStream &str, const char *className, QStringView v
}
}
-enum OverloadUse {
- UseOverload,
- UseOverloadWhenNoArguments, // Use overload only when the argument list is empty,
- // in this case there is no chance of connecting
- // mismatching T against const T &
- DontUseOverload
+enum class OverloadUse {
+ Always,
+ WhenAmbiguousOrEmpty, // Use overload if
+ // - signal/slot is ambiguous
+ // - argument list is empty (chance of connecting mismatching T against const T &)
+ Never,
};
// Format a member function for a signal slot connection
-static void formatMemberFnPtr(QTextStream &str, const SignalSlot &s,
- OverloadUse useQOverload = DontUseOverload)
+static bool isConstRef(const QStringView &arg)
+{
+ return arg.startsWith(u'Q') && arg != "QPoint"_L1 && arg != "QSize"_L1;
+}
+
+static QString formatOverload(const QStringView &parameters)
+{
+ QString result = "qOverload<"_L1;
+ const auto args = QStringView{parameters}.split(u',');
+ for (qsizetype i = 0, size = args.size(); i < size; ++i) {
+ const auto &arg = args.at(i);
+ if (i > 0)
+ result += u',';
+ const bool constRef = isConstRef(arg);
+ if (constRef)
+ result += "const "_L1;
+ result += arg;
+ if (constRef)
+ result += u'&';
+ }
+ result += u'>';
+ return result;
+}
+
+static void formatMemberFnPtr(QTextStream &str, const SignalSlot &s, OverloadUse useQOverload)
{
const qsizetype parenPos = s.signature.indexOf(u'(');
Q_ASSERT(parenPos >= 0);
@@ -388,11 +412,24 @@ static void formatMemberFnPtr(QTextStream &str, const SignalSlot &s,
const auto parameters = QStringView{s.signature}.mid(parenPos + 1,
s.signature.size() - parenPos - 2);
- const bool withOverload = useQOverload == UseOverload ||
- (useQOverload == UseOverloadWhenNoArguments && parameters.isEmpty());
+
+ const bool isAmbiguous = s.options.testFlag(SignalSlotOption::Ambiguous);
+ bool withOverload = false; // just to silence the compiler
+
+ switch (useQOverload) {
+ case OverloadUse::Always:
+ withOverload = true;
+ break;
+ case OverloadUse::Never:
+ withOverload = false;
+ break;
+ case OverloadUse::WhenAmbiguousOrEmpty:
+ withOverload = parameters.empty() || isAmbiguous;
+ break;
+ }
if (withOverload)
- str << "qOverload<" << parameters << ">(";
+ str << formatOverload(parameters) << '(';
str << '&' << s.className << "::" << functionName;
@@ -405,9 +442,9 @@ static void formatMemberFnPtrConnection(QTextStream &str,
const SignalSlot &receiver)
{
str << "QObject::connect(" << sender.name << ", ";
- formatMemberFnPtr(str, sender);
+ formatMemberFnPtr(str, sender, OverloadUse::Never);
str << ", " << receiver.name << ", ";
- formatMemberFnPtr(str, receiver, UseOverloadWhenNoArguments);
+ formatMemberFnPtr(str, receiver, OverloadUse::WhenAmbiguousOrEmpty);
str << ')';
}
diff --git a/tests/auto/tools/uic/baseline/qoverload.ui b/tests/auto/tools/uic/baseline/qoverload.ui
new file mode 100644
index 00000000000..fb9e5294b7d
--- /dev/null
+++ b/tests/auto/tools/uic/baseline/qoverload.ui
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>MainWindow</class>
+ <widget class="QMainWindow" name="MainWindow">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>MainWindow</string>
+ </property>
+ <widget class="QWidget" name="centralWidget">
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QSlider" name="horizontalSlider">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>TextLabel</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLCDNumber" name="lcdNumber"/>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QMenuBar" name="menuBar">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>29</height>
+ </rect>
+ </property>
+ </widget>
+ <widget class="QToolBar" name="mainToolBar">
+ <attribute name="toolBarArea">
+ <enum>TopToolBarArea</enum>
+ </attribute>
+ <attribute name="toolBarBreak">
+ <bool>false</bool>
+ </attribute>
+ </widget>
+ <widget class="QStatusBar" name="statusBar"/>
+ </widget>
+ <layoutdefault spacing="6" margin="11"/>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>horizontalSlider</sender>
+ <signal>valueChanged(int)</signal>
+ <receiver>label</receiver>
+ <slot>setNum(int)</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>199</x>
+ <y>67</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>199</x>
+ <y>172</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>label</sender>
+ <signal>linkActivated(QString)</signal>
+ <receiver>lcdNumber</receiver>
+ <slot>display(QString)</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>199</x>
+ <y>126</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>199</x>
+ <y>218</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/tests/auto/tools/uic/baseline/qoverload.ui.h b/tests/auto/tools/uic/baseline/qoverload.ui.h
new file mode 100644
index 00000000000..4ab0e37d1f3
--- /dev/null
+++ b/tests/auto/tools/uic/baseline/qoverload.ui.h
@@ -0,0 +1,98 @@
+/********************************************************************************
+** Form generated from reading UI file 'qoverload.ui'
+**
+** Created by: Qt User Interface Compiler version 6.8.0
+**
+** WARNING! All changes made in this file will be lost when recompiling UI file!
+********************************************************************************/
+
+#ifndef QOVERLOAD_H
+#define QOVERLOAD_H
+
+#include <QtCore/QVariant>
+#include <QtWidgets/QApplication>
+#include <QtWidgets/QLCDNumber>
+#include <QtWidgets/QLabel>
+#include <QtWidgets/QMainWindow>
+#include <QtWidgets/QMenuBar>
+#include <QtWidgets/QSlider>
+#include <QtWidgets/QStatusBar>
+#include <QtWidgets/QToolBar>
+#include <QtWidgets/QVBoxLayout>
+#include <QtWidgets/QWidget>
+
+QT_BEGIN_NAMESPACE
+
+class Ui_MainWindow
+{
+public:
+ QWidget *centralWidget;
+ QVBoxLayout *verticalLayout;
+ QSlider *horizontalSlider;
+ QLabel *label;
+ QLCDNumber *lcdNumber;
+ QMenuBar *menuBar;
+ QToolBar *mainToolBar;
+ QStatusBar *statusBar;
+
+ void setupUi(QMainWindow *MainWindow)
+ {
+ if (MainWindow->objectName().isEmpty())
+ MainWindow->setObjectName("MainWindow");
+ MainWindow->resize(400, 300);
+ centralWidget = new QWidget(MainWindow);
+ centralWidget->setObjectName("centralWidget");
+ verticalLayout = new QVBoxLayout(centralWidget);
+ verticalLayout->setSpacing(6);
+ verticalLayout->setContentsMargins(11, 11, 11, 11);
+ verticalLayout->setObjectName("verticalLayout");
+ horizontalSlider = new QSlider(centralWidget);
+ horizontalSlider->setObjectName("horizontalSlider");
+ horizontalSlider->setOrientation(Qt::Horizontal);
+
+ verticalLayout->addWidget(horizontalSlider);
+
+ label = new QLabel(centralWidget);
+ label->setObjectName("label");
+
+ verticalLayout->addWidget(label);
+
+ lcdNumber = new QLCDNumber(centralWidget);
+ lcdNumber->setObjectName("lcdNumber");
+
+ verticalLayout->addWidget(lcdNumber);
+
+ MainWindow->setCentralWidget(centralWidget);
+ menuBar = new QMenuBar(MainWindow);
+ menuBar->setObjectName("menuBar");
+ menuBar->setGeometry(QRect(0, 0, 400, 29));
+ MainWindow->setMenuBar(menuBar);
+ mainToolBar = new QToolBar(MainWindow);
+ mainToolBar->setObjectName("mainToolBar");
+ MainWindow->addToolBar(Qt::ToolBarArea::TopToolBarArea, mainToolBar);
+ statusBar = new QStatusBar(MainWindow);
+ statusBar->setObjectName("statusBar");
+ MainWindow->setStatusBar(statusBar);
+
+ retranslateUi(MainWindow);
+ QObject::connect(horizontalSlider, &QSlider::valueChanged, label, qOverload<int>(&QLabel::setNum));
+ QObject::connect(label, &QLabel::linkActivated, lcdNumber, qOverload<const QString&>(&QLCDNumber::display));
+
+ QMetaObject::connectSlotsByName(MainWindow);
+ } // setupUi
+
+ void retranslateUi(QMainWindow *MainWindow)
+ {
+ MainWindow->setWindowTitle(QCoreApplication::translate("MainWindow", "MainWindow", nullptr));
+ label->setText(QCoreApplication::translate("MainWindow", "TextLabel", nullptr));
+ } // retranslateUi
+
+};
+
+namespace Ui {
+ class MainWindow: public Ui_MainWindow {};
+} // namespace Ui
+
+QT_END_NAMESPACE
+
+#endif // QOVERLOAD_H