summaryrefslogtreecommitdiffstats
path: root/src/remoteobjects/qremoteobjectrepparser.cpp
blob: e4f5486bc421d0bb832bba93bb86741fecc47acf (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
// 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 &param : 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<bool, bool, bool> 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<bool, bool, bool> 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<std::tuple<bool, bool, bool>(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