Merge #16348: qt: Assert QMetaObject::invokeMethod result

64fee48944 qt: Assert QMetaObject::invokeMethod result (João Barbosa)
f27bd96b5f gui: Fix missing qRegisterMetaType(WalletModel*) (João Barbosa)

Pull request description:

  Invalid/wrong dynamic calls aren't verified by the compiler. This PR asserts those dynamic calls. Once we bump Qt to at least 5.10 these can be refactored to use the `invokeMethod` overload that allows connecting to lambdas or member pointers, which are compile checked.

  For reference, one of the overloaded versions is https://doc.qt.io/qt-5/qmetaobject.html#invokeMethod-5.

ACKs for top commit:
  laanwj:
    ACK 64fee48944

Tree-SHA512: d332e5d7eb2c7be5d3fe90e2e4ff20a67800b9664f6637c122a23647a964f7915703d3f086e2de440f695cfe14de268ff581d0092b7736e911952a4f4d248e25
pull/16349/head
Wladimir J. van der Laan 5 years ago
commit 8046a3e0be
No known key found for this signature in database
GPG Key ID: 1E4AED62986CD25D

@ -448,6 +448,9 @@ int GuiMain(int argc, char* argv[])
// Register meta types used for QMetaObject::invokeMethod // Register meta types used for QMetaObject::invokeMethod
qRegisterMetaType< bool* >(); qRegisterMetaType< bool* >();
#ifdef ENABLE_WALLET
qRegisterMetaType<WalletModel*>();
#endif
// Need to pass name here as CAmount is a typedef (see http://qt-project.org/doc/qt-5/qmetatype.html#qRegisterMetaType) // Need to pass name here as CAmount is a typedef (see http://qt-project.org/doc/qt-5/qmetatype.html#qRegisterMetaType)
// IMPORTANT if it is no longer a typedef use the normal variant above // IMPORTANT if it is no longer a typedef use the normal variant above
qRegisterMetaType< CAmount >("CAmount"); qRegisterMetaType< CAmount >("CAmount");

@ -1375,12 +1375,13 @@ static bool ThreadSafeMessageBox(BitcoinGUI* gui, const std::string& message, co
style &= ~CClientUIInterface::SECURE; style &= ~CClientUIInterface::SECURE;
bool ret = false; bool ret = false;
// In case of modal message, use blocking connection to wait for user to click a button // In case of modal message, use blocking connection to wait for user to click a button
QMetaObject::invokeMethod(gui, "message", bool invoked = QMetaObject::invokeMethod(gui, "message",
modal ? GUIUtil::blockingGUIThreadConnection() : Qt::QueuedConnection, modal ? GUIUtil::blockingGUIThreadConnection() : Qt::QueuedConnection,
Q_ARG(QString, QString::fromStdString(caption)), Q_ARG(QString, QString::fromStdString(caption)),
Q_ARG(QString, QString::fromStdString(message)), Q_ARG(QString, QString::fromStdString(message)),
Q_ARG(unsigned int, style), Q_ARG(unsigned int, style),
Q_ARG(bool*, &ret)); Q_ARG(bool*, &ret));
assert(invoked);
return ret; return ret;
} }

@ -184,34 +184,39 @@ void ClientModel::updateBanlist()
static void ShowProgress(ClientModel *clientmodel, const std::string &title, int nProgress) static void ShowProgress(ClientModel *clientmodel, const std::string &title, int nProgress)
{ {
// emits signal "showProgress" // emits signal "showProgress"
QMetaObject::invokeMethod(clientmodel, "showProgress", Qt::QueuedConnection, bool invoked = QMetaObject::invokeMethod(clientmodel, "showProgress", Qt::QueuedConnection,
Q_ARG(QString, QString::fromStdString(title)), Q_ARG(QString, QString::fromStdString(title)),
Q_ARG(int, nProgress)); Q_ARG(int, nProgress));
assert(invoked);
} }
static void NotifyNumConnectionsChanged(ClientModel *clientmodel, int newNumConnections) static void NotifyNumConnectionsChanged(ClientModel *clientmodel, int newNumConnections)
{ {
// Too noisy: qDebug() << "NotifyNumConnectionsChanged: " + QString::number(newNumConnections); // Too noisy: qDebug() << "NotifyNumConnectionsChanged: " + QString::number(newNumConnections);
QMetaObject::invokeMethod(clientmodel, "updateNumConnections", Qt::QueuedConnection, bool invoked = QMetaObject::invokeMethod(clientmodel, "updateNumConnections", Qt::QueuedConnection,
Q_ARG(int, newNumConnections)); Q_ARG(int, newNumConnections));
assert(invoked);
} }
static void NotifyNetworkActiveChanged(ClientModel *clientmodel, bool networkActive) static void NotifyNetworkActiveChanged(ClientModel *clientmodel, bool networkActive)
{ {
QMetaObject::invokeMethod(clientmodel, "updateNetworkActive", Qt::QueuedConnection, bool invoked = QMetaObject::invokeMethod(clientmodel, "updateNetworkActive", Qt::QueuedConnection,
Q_ARG(bool, networkActive)); Q_ARG(bool, networkActive));
assert(invoked);
} }
static void NotifyAlertChanged(ClientModel *clientmodel) static void NotifyAlertChanged(ClientModel *clientmodel)
{ {
qDebug() << "NotifyAlertChanged"; qDebug() << "NotifyAlertChanged";
QMetaObject::invokeMethod(clientmodel, "updateAlert", Qt::QueuedConnection); bool invoked = QMetaObject::invokeMethod(clientmodel, "updateAlert", Qt::QueuedConnection);
assert(invoked);
} }
static void BannedListChanged(ClientModel *clientmodel) static void BannedListChanged(ClientModel *clientmodel)
{ {
qDebug() << QString("%1: Requesting update for peer banlist").arg(__func__); qDebug() << QString("%1: Requesting update for peer banlist").arg(__func__);
QMetaObject::invokeMethod(clientmodel, "updateBanlist", Qt::QueuedConnection); bool invoked = QMetaObject::invokeMethod(clientmodel, "updateBanlist", Qt::QueuedConnection);
assert(invoked);
} }
static void BlockTipChanged(ClientModel *clientmodel, bool initialSync, int height, int64_t blockTime, double verificationProgress, bool fHeader) static void BlockTipChanged(ClientModel *clientmodel, bool initialSync, int height, int64_t blockTime, double verificationProgress, bool fHeader)
@ -233,11 +238,12 @@ static void BlockTipChanged(ClientModel *clientmodel, bool initialSync, int heig
// if we are in-sync or if we notify a header update, update the UI regardless of last update time // if we are in-sync or if we notify a header update, update the UI regardless of last update time
if (fHeader || !initialSync || now - nLastUpdateNotification > MODEL_UPDATE_DELAY) { if (fHeader || !initialSync || now - nLastUpdateNotification > MODEL_UPDATE_DELAY) {
//pass an async signal to the UI thread //pass an async signal to the UI thread
QMetaObject::invokeMethod(clientmodel, "numBlocksChanged", Qt::QueuedConnection, bool invoked = QMetaObject::invokeMethod(clientmodel, "numBlocksChanged", Qt::QueuedConnection,
Q_ARG(int, height), Q_ARG(int, height),
Q_ARG(QDateTime, QDateTime::fromTime_t(blockTime)), Q_ARG(QDateTime, QDateTime::fromTime_t(blockTime)),
Q_ARG(double, verificationProgress), Q_ARG(double, verificationProgress),
Q_ARG(bool, fHeader)); Q_ARG(bool, fHeader));
assert(invoked);
nLastUpdateNotification = now; nLastUpdateNotification = now;
} }
} }

@ -156,11 +156,12 @@ void SplashScreen::finish()
static void InitMessage(SplashScreen *splash, const std::string &message) static void InitMessage(SplashScreen *splash, const std::string &message)
{ {
QMetaObject::invokeMethod(splash, "showMessage", bool invoked = QMetaObject::invokeMethod(splash, "showMessage",
Qt::QueuedConnection, Qt::QueuedConnection,
Q_ARG(QString, QString::fromStdString(message)), Q_ARG(QString, QString::fromStdString(message)),
Q_ARG(int, Qt::AlignBottom|Qt::AlignHCenter), Q_ARG(int, Qt::AlignBottom|Qt::AlignHCenter),
Q_ARG(QColor, QColor(55,55,55))); Q_ARG(QColor, QColor(55,55,55)));
assert(invoked);
} }
static void ShowProgress(SplashScreen *splash, const std::string &title, int nProgress, bool resume_possible) static void ShowProgress(SplashScreen *splash, const std::string &title, int nProgress, bool resume_possible)

@ -68,7 +68,8 @@ uint256 SendCoins(CWallet& wallet, SendCoinsDialog& sendCoinsDialog, const CTxDe
if (status == CT_NEW) txid = hash; if (status == CT_NEW) txid = hash;
})); }));
ConfirmSend(); ConfirmSend();
QMetaObject::invokeMethod(&sendCoinsDialog, "on_sendButton_clicked"); bool invoked = QMetaObject::invokeMethod(&sendCoinsDialog, "on_sendButton_clicked");
assert(invoked);
return txid; return txid;
} }

@ -687,10 +687,11 @@ public:
{ {
QString strHash = QString::fromStdString(hash.GetHex()); QString strHash = QString::fromStdString(hash.GetHex());
qDebug() << "NotifyTransactionChanged: " + strHash + " status= " + QString::number(status); qDebug() << "NotifyTransactionChanged: " + strHash + " status= " + QString::number(status);
QMetaObject::invokeMethod(ttm, "updateTransaction", Qt::QueuedConnection, bool invoked = QMetaObject::invokeMethod(ttm, "updateTransaction", Qt::QueuedConnection,
Q_ARG(QString, strHash), Q_ARG(QString, strHash),
Q_ARG(int, status), Q_ARG(int, status),
Q_ARG(bool, showTransaction)); Q_ARG(bool, showTransaction));
assert(invoked);
} }
private: private:
uint256 hash; uint256 hash;
@ -725,12 +726,16 @@ static void ShowProgress(TransactionTableModel *ttm, const std::string &title, i
if (nProgress == 100) if (nProgress == 100)
{ {
fQueueNotifications = false; fQueueNotifications = false;
if (vQueueNotifications.size() > 10) // prevent balloon spam, show maximum 10 balloons if (vQueueNotifications.size() > 10) { // prevent balloon spam, show maximum 10 balloons
QMetaObject::invokeMethod(ttm, "setProcessingQueuedTransactions", Qt::QueuedConnection, Q_ARG(bool, true)); bool invoked = QMetaObject::invokeMethod(ttm, "setProcessingQueuedTransactions", Qt::QueuedConnection, Q_ARG(bool, true));
assert(invoked);
}
for (unsigned int i = 0; i < vQueueNotifications.size(); ++i) for (unsigned int i = 0; i < vQueueNotifications.size(); ++i)
{ {
if (vQueueNotifications.size() - i <= 10) if (vQueueNotifications.size() - i <= 10) {
QMetaObject::invokeMethod(ttm, "setProcessingQueuedTransactions", Qt::QueuedConnection, Q_ARG(bool, false)); bool invoked = QMetaObject::invokeMethod(ttm, "setProcessingQueuedTransactions", Qt::QueuedConnection, Q_ARG(bool, false));
assert(invoked);
}
vQueueNotifications[i].invoke(ttm); vQueueNotifications[i].invoke(ttm);
} }

@ -124,7 +124,8 @@ WalletModel* WalletController::getOrCreateWallet(std::unique_ptr<interfaces::Wal
} else { } else {
// Handler callback runs in a different thread so fix wallet model thread affinity. // Handler callback runs in a different thread so fix wallet model thread affinity.
wallet_model->moveToThread(thread()); wallet_model->moveToThread(thread());
QMetaObject::invokeMethod(this, "addWallet", Qt::QueuedConnection, Q_ARG(WalletModel*, wallet_model)); bool invoked = QMetaObject::invokeMethod(this, "addWallet", Qt::QueuedConnection, Q_ARG(WalletModel*, wallet_model));
assert(invoked);
} }
return wallet_model; return wallet_model;

@ -374,13 +374,15 @@ bool WalletModel::changePassphrase(const SecureString &oldPass, const SecureStri
static void NotifyUnload(WalletModel* walletModel) static void NotifyUnload(WalletModel* walletModel)
{ {
qDebug() << "NotifyUnload"; qDebug() << "NotifyUnload";
QMetaObject::invokeMethod(walletModel, "unload"); bool invoked = QMetaObject::invokeMethod(walletModel, "unload");
assert(invoked);
} }
static void NotifyKeyStoreStatusChanged(WalletModel *walletmodel) static void NotifyKeyStoreStatusChanged(WalletModel *walletmodel)
{ {
qDebug() << "NotifyKeyStoreStatusChanged"; qDebug() << "NotifyKeyStoreStatusChanged";
QMetaObject::invokeMethod(walletmodel, "updateStatus", Qt::QueuedConnection); bool invoked = QMetaObject::invokeMethod(walletmodel, "updateStatus", Qt::QueuedConnection);
assert(invoked);
} }
static void NotifyAddressBookChanged(WalletModel *walletmodel, static void NotifyAddressBookChanged(WalletModel *walletmodel,
@ -392,38 +394,43 @@ static void NotifyAddressBookChanged(WalletModel *walletmodel,
QString strPurpose = QString::fromStdString(purpose); QString strPurpose = QString::fromStdString(purpose);
qDebug() << "NotifyAddressBookChanged: " + strAddress + " " + strLabel + " isMine=" + QString::number(isMine) + " purpose=" + strPurpose + " status=" + QString::number(status); qDebug() << "NotifyAddressBookChanged: " + strAddress + " " + strLabel + " isMine=" + QString::number(isMine) + " purpose=" + strPurpose + " status=" + QString::number(status);
QMetaObject::invokeMethod(walletmodel, "updateAddressBook", Qt::QueuedConnection, bool invoked = QMetaObject::invokeMethod(walletmodel, "updateAddressBook", Qt::QueuedConnection,
Q_ARG(QString, strAddress), Q_ARG(QString, strAddress),
Q_ARG(QString, strLabel), Q_ARG(QString, strLabel),
Q_ARG(bool, isMine), Q_ARG(bool, isMine),
Q_ARG(QString, strPurpose), Q_ARG(QString, strPurpose),
Q_ARG(int, status)); Q_ARG(int, status));
assert(invoked);
} }
static void NotifyTransactionChanged(WalletModel *walletmodel, const uint256 &hash, ChangeType status) static void NotifyTransactionChanged(WalletModel *walletmodel, const uint256 &hash, ChangeType status)
{ {
Q_UNUSED(hash); Q_UNUSED(hash);
Q_UNUSED(status); Q_UNUSED(status);
QMetaObject::invokeMethod(walletmodel, "updateTransaction", Qt::QueuedConnection); bool invoked = QMetaObject::invokeMethod(walletmodel, "updateTransaction", Qt::QueuedConnection);
assert(invoked);
} }
static void ShowProgress(WalletModel *walletmodel, const std::string &title, int nProgress) static void ShowProgress(WalletModel *walletmodel, const std::string &title, int nProgress)
{ {
// emits signal "showProgress" // emits signal "showProgress"
QMetaObject::invokeMethod(walletmodel, "showProgress", Qt::QueuedConnection, bool invoked = QMetaObject::invokeMethod(walletmodel, "showProgress", Qt::QueuedConnection,
Q_ARG(QString, QString::fromStdString(title)), Q_ARG(QString, QString::fromStdString(title)),
Q_ARG(int, nProgress)); Q_ARG(int, nProgress));
assert(invoked);
} }
static void NotifyWatchonlyChanged(WalletModel *walletmodel, bool fHaveWatchonly) static void NotifyWatchonlyChanged(WalletModel *walletmodel, bool fHaveWatchonly)
{ {
QMetaObject::invokeMethod(walletmodel, "updateWatchOnlyFlag", Qt::QueuedConnection, bool invoked = QMetaObject::invokeMethod(walletmodel, "updateWatchOnlyFlag", Qt::QueuedConnection,
Q_ARG(bool, fHaveWatchonly)); Q_ARG(bool, fHaveWatchonly));
assert(invoked);
} }
static void NotifyCanGetAddressesChanged(WalletModel* walletmodel) static void NotifyCanGetAddressesChanged(WalletModel* walletmodel)
{ {
QMetaObject::invokeMethod(walletmodel, "canGetAddressesChanged"); bool invoked = QMetaObject::invokeMethod(walletmodel, "canGetAddressesChanged");
assert(invoked);
} }
void WalletModel::subscribeToCoreSignals() void WalletModel::subscribeToCoreSignals()

Loading…
Cancel
Save