首页 > 其他分享 >bool QMetaMethod::invoke

bool QMetaMethod::invoke

时间:2024-10-27 09:59:59浏览次数:1  
标签:return invoke idx InvokeFailReason name bool metaTypes QMetaMethod priv

bool QMetaMethod::invoke(QObject *object,
                         Qt::ConnectionType connectionType,
                         QGenericReturnArgument returnValue,
                         QGenericArgument val0,
                         QGenericArgument val1,
                         QGenericArgument val2,
                         QGenericArgument val3,
                         QGenericArgument val4,
                         QGenericArgument val5,
                         QGenericArgument val6,
                         QGenericArgument val7,
                         QGenericArgument val8,
                         QGenericArgument val9) const
{
    if (!object || !mobj)
        return false;

    // check argument count (we don't allow invoking a method if given too few arguments)
    const char *typeNames[] = {
        returnValue.name(),
        val0.name(),
        val1.name(),
        val2.name(),
        val3.name(),
        val4.name(),
        val5.name(),
        val6.name(),
        val7.name(),
        val8.name(),
        val9.name()
    };
    void *param[] = {
        returnValue.data(),
        val0.data(),
        val1.data(),
        val2.data(),
        val3.data(),
        val4.data(),
        val5.data(),
        val6.data(),
        val7.data(),
        val8.data(),
        val9.data()
    };

    int paramCount;
    for (paramCount = 1; paramCount < MaximumParamCount; ++paramCount) {
        if (qstrlen(typeNames[paramCount]) <= 0)
            break;
    }
    return invokeImpl(*this, object, connectionType, paramCount, param, typeNames, nullptr);
}

bool QMetaMethod::invokeImpl(QMetaMethod self, void *target, Qt::ConnectionType connectionType,
                             qsizetype paramCount, const void *const *parameters,
                             const char *const *typeNames,
                             const QtPrivate::QMetaTypeInterface *const *metaTypes)
{
    if (!target || !self.mobj)
        return false;
    QMetaMethodPrivate::InvokeFailReason r =
            QMetaMethodPrivate::invokeImpl(self, target, connectionType, paramCount, parameters,
                                           typeNames, metaTypes);
    if (Q_LIKELY(r == QMetaMethodPrivate::InvokeFailReason::None))
        return true;

    if (int(r) >= int(QMetaMethodPrivate::InvokeFailReason::FormalParameterMismatch)) {
        int n = int(r) - int(QMetaMethodPrivate::InvokeFailReason::FormalParameterMismatch);
        qWarning("QMetaMethod::invoke: cannot convert formal parameter %d from %s in call to %s::%s",
                 n, typeNames[n + 1] ? typeNames[n + 1] : metaTypes[n + 1]->name,
                 self.mobj->className(), self.methodSignature().constData());
    }
    if (r == QMetaMethodPrivate::InvokeFailReason::TooFewArguments) {
        qWarning("QMetaMethod::invoke: too few arguments (%d) in call to %s::%s",
                 int(paramCount), self.mobj->className(), self.methodSignature().constData());
    }
    return false;
}

auto QMetaMethodInvoker::invokeImpl(QMetaMethod self, void *target,
                                    Qt::ConnectionType connectionType,
                                    qsizetype paramCount, const void *const *parameters,
                                    const char *const *typeNames,
                                    const QtPrivate::QMetaTypeInterface *const *metaTypes) -> InvokeFailReason
{
    auto object = static_cast<QObject *>(target);
    auto priv = QMetaMethodPrivate::get(&self);
    constexpr bool MetaTypesAreOptional = QT_VERSION < QT_VERSION_CHECK(7, 0, 0);
    auto methodMetaTypes = priv->parameterMetaTypeInterfaces();
    auto param = const_cast<void **>(parameters);

    Q_ASSERT(priv->mobj);
    Q_ASSERT(self.methodType() == Constructor || object);
    Q_ASSERT(self.methodType() == Constructor || connectionType == Qt::ConnectionType(-1) ||
             priv->mobj->cast(object));
    Q_ASSERT(paramCount >= 1);  // includes the return type
    Q_ASSERT(parameters);
    Q_ASSERT(typeNames);
    Q_ASSERT(MetaTypesAreOptional || metaTypes);

    if ((paramCount - 1) < qsizetype(priv->data.argc()))
        return InvokeFailReason::TooFewArguments;

    // 0 is the return type, 1 is the first formal parameter
    auto checkTypesAreCompatible = [=](int idx) {
        uint typeInfo = priv->parameterTypeInfo(idx - 1);
        QLatin1StringView userTypeName(typeNames[idx] ? typeNames[idx] : metaTypes[idx]->name);

        if ((typeInfo & IsUnresolvedType) == 0) {
            // this is a built-in type
            if (MetaTypesAreOptional && !metaTypes)
                return int(typeInfo) == QMetaType::fromName(userTypeName).id();
            return int(typeInfo) == metaTypes[idx]->typeId;
        }

        QLatin1StringView methodTypeName = stringDataView(priv->mobj, typeInfo & TypeNameIndexMask);
        if ((MetaTypesAreOptional && !metaTypes) || !metaTypes[idx]) {
            // compatibility call, compare strings
            if (methodTypeName == userTypeName)
                return true;

            // maybe the user type needs normalization
            QByteArray normalized = normalizeTypeInternal(userTypeName.begin(), userTypeName.end());
            return methodTypeName == QLatin1StringView(normalized);
        }

        QMetaType userType(metaTypes[idx]);
        Q_ASSERT(userType.isValid());
        if (QMetaType(methodMetaTypes[idx - 1]) == userType)
            return true;

        // if the parameter type was NOT only forward-declared, it MUST have
        // matched
        if (methodMetaTypes[idx - 1])
            return false;

        // resolve from the name moc stored for us
        QMetaType resolved = QMetaType::fromName(methodTypeName);
        return resolved == userType;
    };

    // force all types to be registered, just in case
    for (qsizetype i = 0; metaTypes && i < paramCount; ++i)
        QMetaType(metaTypes[i]).registerType();

    // check formal parameters first (overload set)
    for (qsizetype i = 1; i < paramCount; ++i) {
        if (!checkTypesAreCompatible(i))
            return InvokeFailReason(int(InvokeFailReason::FormalParameterMismatch) + i - 1);
    }

    // handle constructors first
    if (self.methodType() == Constructor) {
        if (object) {
            qWarning("QMetaMethod::invokeMethod: cannot call constructor %s on object %p",
                     self.methodSignature().constData(), object);
            return InvokeFailReason::ConstructorCallOnObject;
        }

        if (!parameters[0]) {
            qWarning("QMetaMethod::invokeMethod: constructor call to %s must assign a return type",
                     self.methodSignature().constData());
            return InvokeFailReason::ConstructorCallWithoutResult;
        }

        if (!MetaTypesAreOptional || metaTypes) {
            if (metaTypes[0]->typeId != QMetaType::QObjectStar) {
                qWarning("QMetaMethod::invokeMethod: cannot convert QObject* to %s on constructor call %s",
                         metaTypes[0]->name, self.methodSignature().constData());
                return InvokeFailReason::ReturnTypeMismatch;
            }
        }

        int idx = priv->ownConstructorMethodIndex();
        if (priv->mobj->static_metacall(QMetaObject::CreateInstance, idx, param) >= 0)
            return InvokeFailReason::ConstructorCallFailed;
        return {};
    }

    // regular type - check return type
    if (parameters[0]) {
        if (!checkTypesAreCompatible(0)) {
            const char *retType = typeNames[0] ? typeNames[0] : metaTypes[0]->name;
            qWarning("QMetaMethod::invokeMethod: return type mismatch for method %s::%s:"
                     " cannot convert from %s to %s during invocation",
                     priv->mobj->className(), priv->methodSignature().constData(),
                     priv->rawReturnTypeName(), retType);
            return InvokeFailReason::ReturnTypeMismatch;
        }
    }

    Qt::HANDLE currentThreadId = nullptr;
    QThread *objectThread = nullptr;
    auto receiverInSameThread = [&]() {
        if (!currentThreadId) {
            currentThreadId = QThread::currentThreadId();
            objectThread = object->thread();
        }
        if (objectThread)
            return currentThreadId == QThreadData::get2(objectThread)->threadId.loadRelaxed();
        return false;
    };

    // check connection type
    if (connectionType == Qt::AutoConnection)
        connectionType = receiverInSameThread() ? Qt::DirectConnection : Qt::QueuedConnection;
    else if (connectionType == Qt::ConnectionType(-1))
        connectionType = Qt::DirectConnection;

#if !QT_CONFIG(thread)
    if (connectionType == Qt::BlockingQueuedConnection) {
        connectionType = Qt::DirectConnection;
    }
#endif

    // invoke!
    int idx_relative = priv->ownMethodIndex();
    int idx_offset = priv->mobj->methodOffset();
    QObjectPrivate::StaticMetaCallFunction callFunction = priv->mobj->d.static_metacall;

    if (connectionType == Qt::DirectConnection) {
        if (callFunction)
            callFunction(object, QMetaObject::InvokeMetaMethod, idx_relative, param);
        else if (QMetaObject::metacall(object, QMetaObject::InvokeMetaMethod, idx_relative + idx_offset, param) >= 0)
            return InvokeFailReason::CallViaVirtualFailed;
    } else if (connectionType == Qt::QueuedConnection) {
        if (parameters[0]) {
            qWarning("QMetaMethod::invoke: Unable to invoke methods with return values in "
                     "queued connections");
            return InvokeFailReason::CouldNotQueueParameter;
        }

        auto event = std::make_unique<QMetaCallEvent>(idx_offset, idx_relative, callFunction, nullptr, -1, paramCount);
        QMetaType *types = event->types();
        void **args = event->args();

        // fill in the meta types first
        for (int i = 1; i < paramCount; ++i) {
            types[i] = QMetaType(methodMetaTypes[i - 1]);
            if (!types[i].iface() && (!MetaTypesAreOptional || metaTypes))
                types[i] = QMetaType(metaTypes[i]);
            if (!types[i].iface())
                types[i] = priv->parameterMetaType(i - 1);
            if (!types[i].iface() && typeNames[i])
                types[i] = QMetaType::fromName(typeNames[i]);
            if (!types[i].iface()) {
                qWarning("QMetaMethod::invoke: Unable to handle unregistered datatype '%s'",
                         typeNames[i]);
                return InvokeFailReason(int(InvokeFailReason::CouldNotQueueParameter) - i);
            }
        }

        // now create copies of our parameters using those meta types
        for (int i = 1; i < paramCount; ++i)
            args[i] = types[i].create(parameters[i]);

        QCoreApplication::postEvent(object, event.release());
    } else { // blocking queued connection
#if QT_CONFIG(thread)
        if (receiverInSameThread()) {
            qWarning("QMetaMethod::invoke: Dead lock detected in BlockingQueuedConnection: "
                     "Receiver is %s(%p)", priv->mobj->className(), object);
            return InvokeFailReason::DeadLockDetected;
        }

        QSemaphore semaphore;
        QCoreApplication::postEvent(object, new QMetaCallEvent(idx_offset, idx_relative, callFunction,
                                                        nullptr, -1, param, &semaphore));
        semaphore.acquire();
#endif // QT_CONFIG(thread)
    }
    return {};
}

标签:return,invoke,idx,InvokeFailReason,name,bool,metaTypes,QMetaMethod,priv
From: https://www.cnblogs.com/DesertCactus/p/18507903

相关文章

  • 【API文档】apache.的BooleanUtils类
    org.apache.commons.lang3.BooleanUtils类方法分析方法签名功能或适用场景入参详细解释publicstaticbooleanand(finalboolean...array)对一组boolean值进行与操作array:一组boolean值publicstaticBooleanand(finalBoolean...array)对一组Boolean对象进......
  • 【API文档】apache的BooleanUtils类
    org.apache.commons.lang3.StringUtils类提供的方法列表:方法签名功能描述参数解释booleancontains(CharSequenceseq,intsearchChar)检查字符序列中是否包含指定的字符。seq:要检查的字符序列。searchChar:要查找的字符。booleancontains(CharSequenceseq......
  • 学习011-08-05 Boolean Properties(布尔属性)
    BooleanProperties(布尔属性)InXAF,thefollowingcontrolscandisplayBooleanandNullableBooleanproperties:在XAF中,以下控件可以显示布尔和Nullable布尔属性:Acheckboxcontrol(default).复选框控件(默认)。Adrop-downcontrolthatdisplaysBooleanvaluesa......
  • WPF Click Window show XY coordinates in MVVM via InvokeCommandAction of behavior
    1.Install Microsoft.Xaml.Behaviors.Wpf  2.<behavior:Interaction.Triggers><behavior:EventTriggerEventName="MouseDown"><behavior:InvokeCommandActionCommand="{BindingClickCommand}"......
  • WPF MVVM behavior CallMethodAction InvokeCommandAction
    1.Install  Microsoft.Xaml.Behaviors.Wpf 2.xmlns:behavior="http://schemas.microsoft.com/xaml/behaviors"<behavior:Interaction.Triggers><behavior:EventTriggerEventName="KeyDown"><behavior:CallMet......
  • lombok~避免Boolean属性使用默认的方法
    前言前端与后端在进行交互时,前端传的对象中,有的属性是int,boolean这些类型,它们是有默认值的,当前端不转它们时,后端也会接收到默认值,如int为0,boolean为false,这就给后端代码带来不确定性;比如要有个put更新用户的方法,有个用户对象如下@DatapublicclassUserAccountResponseimplem......
  • 兼收并蓄 TypeScript - 基础: boolean
    源码https://github.com/webabcd/TypeScriptDemo作者webabcd兼收并蓄TypeScript-基础:boolean示例如下:basic\boolean.ts{leta=true;console.log(a);//true//将指定类型的数据转换为boolean类型console.log(Boolean(100),Boolean(......
  • WPF behavior InvokeCommandAction CommadParameter pass selectedItem of currentcon
    <ListBoxx:Name="lbx"SelectedIndex="0"ItemsSource="{BindingBooksCollection,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"VirtualizingPanel.IsContainerVirtualizable="True"......
  • WPF behavior InvokeCommandAction CommandParameter
    <ListBoxx:Name="lbx"SelectedIndex="0"ItemsSource="{BindingBooksCollection,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"VirtualizingPanel.IsContainerVirtualizable="True"......
  • WPF behavior InvokeCommndAction PassEventArgsToCommand
    //xaml<ListBoxx:Name="lbx"SelectedIndex="0"ItemsSource="{BindingBooksCollection,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"VirtualizingPanel.IsContainerVirtualizable="Tru......