// Copyright (C) 2024 Ford Motor Company // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #include "qremoteobjectnode_p.h" #include "qremoteobjectrepparser_p.h" #include "qremoteobjectstructs_p.h" QT_BEGIN_NAMESPACE using namespace QRemoteObjectInternalTypes; // Make a central function to convert QStrings to QByteArrays in case we need // to change how this is done. auto toQBA = [](const QString &string) { return string.toUtf8(); }; static QByteArray capName(const QString &name) { /* * Helper method to capitalize the first letter of a QString and return * the result as a QByteArray */ return toQBA(name.at(0).toUpper() + name.mid(1)); } static QByteArrayList toByteArrayList(const QStringList &stringList) { /* * Helper method to convert a list of strings into a list of QByteArrays */ QByteArrayList byteArrayList(stringList.size()); for (const QString &str : stringList) byteArrayList.append(toQBA(str)); return byteArrayList; }; static EnumData enumToDefinition(const ASTEnum &astEnum) { EnumData enumEntry; enumEntry.name = toQBA(astEnum.name); enumEntry.isFlag = false; enumEntry.isScoped = astEnum.isScoped; enumEntry.keyCount = astEnum.params.size(); enumEntry.size = sizeof(int); if (!astEnum.type.isEmpty()) { auto metaType = QMetaType::fromName(toQBA(astEnum.type)); if (metaType.isValid()) enumEntry.size = metaType.sizeOf(); } for (const auto ¶m : astEnum.params) { EnumPair pair; pair.name = toQBA(param.name); pair.value = param.value; enumEntry.values.append(pair); } return enumEntry; } static GadgetData podToGadget(const POD &pod) { // This class converts the AST for a POD into a GadgetData structure GadgetData gadgetData; for (const auto &attribute : pod.attributes) { GadgetProperty property; property.name = toQBA(attribute.name); property.type = toQBA(attribute.type); gadgetData.properties.append(property); } for (const auto &_enum : pod.enums) gadgetData.enums.append(enumToDefinition(_enum)); // TODO: Fix support for Flags - don't think this currently works for dynamic gadgets // Unclear what the TypeInfo would be for a Flag - it relies on a template type // Should this error out with a warning? /* for (const auto &flag : pod.flags) { EnumData enumEntry; enumEntry.name = toQBA(flag.name); enumEntry.isFlag = true; auto it = std::find_if(gadgetData.enums.begin(), gadgetData.enums.end(), [&flag](const EnumData &enumData) { return enumData.name == toQBA(flag._enum); }); if (it != gadgetData.enums.end()) { it->isFlag = true; } gadgetData.enums.append(enumEntry); } */ return gadgetData; } QMetaObject *createAndRegisterMetaTypeFromPOD(const POD &pod, QObject *reference) { auto gadget = podToGadget(pod); return registerGadget(reference, gadget, toQBA(pod.name)); } static std::tuple sourceModifiers(ASTProperty::Modifier modifier) { /* * Helper method to set several variables appropriately for a Source object type, * based on the modifier set on the property in the .rep file. */ bool isWritable = modifier == ASTProperty::ReadWrite || modifier == ASTProperty::ReadPush || modifier == ASTProperty::SourceOnlySetter; bool hasNotify = modifier != ASTProperty::Constant; bool hasPush = modifier == ASTProperty::ReadPush; return std::make_tuple(isWritable, hasNotify, hasPush); }; static std::tuple replicaModifiers(ASTProperty::Modifier modifier) { /* * Helper method to set several variables appropriately for a Replica object type, * based on the modifier set on the property in the .rep file. */ bool isWritable = modifier == ASTProperty::ReadWrite; bool hasNotify = true; bool hasPush = modifier == ASTProperty::ReadPush; return std::make_tuple(isWritable, hasNotify, hasPush); }; static ClassData classToDefinition(const ASTClass &astClass, bool isSource=false) { std::function(ASTProperty::Modifier)> modifiers = isSource ? sourceModifiers : replicaModifiers; // This class converts the AST for a Class into a ClassData structure ClassData classData(isSource); classData.type = toQBA(astClass.name); for (const auto &prop : astClass.properties) { auto [isWritable, hasNotify, hasPush] = modifiers(prop.modifier); ClassProperty property; property.name = toQBA(prop.name); property.typeName = toQBA(prop.type); property.isWritable = isWritable; if (hasNotify) { QByteArray signature = property.name + "Changed(" + property.typeName + ")"; classData._signals.append({signature, QByteArrayList() << property.name}); property.signalName = signature; } if (hasPush) { ClassSlot classSlot; classSlot.signature = QByteArray("push") + capName(prop.name) + '(' + toQBA(prop.type) + ')'; classSlot.parameterNames = QByteArrayList() << toQBA(prop.name); classData._slots.append(classSlot); } classData.properties.append(property); } for (const auto &signal : astClass.signalsList) { ClassSignal classSignal; classSignal.signature = toQBA(signal.name) + '(' + toQBA(signal.paramsAsString(ASTFunction::Normalized)) + ')'; classSignal.parameterNames = toByteArrayList(signal.paramNames()); classData._signals.append(classSignal); } for (const auto &slot : astClass.slotsList) { ClassSlot classSlot; classSlot.signature = toQBA(slot.name) + '(' + toQBA(slot.paramsAsString(ASTFunction::Normalized)) + ')'; const bool isVoid = slot.returnType.isEmpty() || slot.returnType == QStringLiteral("void"); if (!isVoid) { if (isSource) classSlot.returnType = toQBA(slot.returnType); else classSlot.returnType = QByteArrayLiteral("QRemoteObjectPendingCall"); } classSlot.parameterNames = toByteArrayList(slot.paramNames()); classData._slots.append(classSlot); } for (const auto &_enum : astClass.enums) classData.enums.append(enumToDefinition(_enum)); // TODO: Fix support for Flags - don't think this currently works for dynamic gadgets // Unclear what the TypeInfo would be for a Flag - it relies on a template type // Should this error out with a warning? /* for (const auto &flag : pod.flags) { EnumData enumEntry; enumEntry.name = toQBA(flag.name); enumEntry.isFlag = true; auto it = std::find_if(gadgetData.enums.begin(), gadgetData.enums.end(), [&flag](const EnumData &enumData) { return enumData.name == toQBA(flag._enum); }); if (it != gadgetData.enums.end()) { it->isFlag = true; } gadgetData.enums.append(enumEntry); } */ return classData; } QMetaObject *createAndRegisterReplicaFromASTClass(const ASTClass &astClass, QObject *reference) { auto classDef = classToDefinition(astClass); return registerAndTrackDefinition(classDef, reference); } QMetaObject *createAndRegisterSourceFromASTClass(const ASTClass &astClass, QObject *reference) { auto classDef = classToDefinition(astClass, true); return registerAndTrackDefinition(classDef, reference); } bool addTracker(const QByteArray &typeName, QObject *reference) { /* * Helper method to add additional QObject pointers as a reference to a type. * Memory will be freed when the last reference is destroyed. */ return trackAdditionalReference(reference, typeName); } QT_END_NAMESPACE