summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrett Stottlemyer <bstottle@ford.com>2019-12-26 19:40:37 -0500
committerBrett Stottlemyer <bstottle@ford.com>2021-09-07 12:26:30 -0400
commit045cbcbc50d51640142691c8cd78dd868e03ba1b (patch)
treed66f2e9c8b69e5b5b620bb05bc66232a9868e5e2
parent73c2fe37405aac88664681163560d60a17000863 (diff)
Allow PODs to include enums/flags
The goal is to allow a new syntax: POD myPOD{ ENUM MyEnum {FOO, BAR} MyEnum myEnum, QString myString }, in addition to the current syntax POD myPOD(QString myString) The challenge is that the parsing simplified the detection of parameter types and parameter names by grabbing everything between the parentheses and having a separate chunk of code split that up. The new POD syntax requires the parser to detect and handle parameter types (including templated types) and handle that syntax. This converts the enum parsing to use new symbol and value tokens, rather than the enum_param token, which is necessary to enable a more generic type detection. The pod2 type has comparable syntax to the previous version, but uses brackets ('{' and '}') instead of parentheses for the definition. While this code detects the parameter type and parameter name distinctly, it currently merges all of the parameter content into a single string for processing using the original postprocess method. This ensures the capture is correct and there aren't any regressions. The tests were modified for the new POD syntax. The new code normalizes whitespace, rather than keeping the source formatting. Pick-to: 6.2 Change-Id: I671b23852fc2b515bcaea1ed389cfbde122683bd Reviewed-by: Michael Brasser <michael.brasser@live.com>
-rw-r--r--src/remoteobjects/qremoteobjectpacket.cpp48
-rw-r--r--src/remoteobjects/qtremoteobjectglobal.cpp23
-rw-r--r--src/repparser/parser.g237
-rw-r--r--tests/auto/proxy_multiprocess/shared.h4
-rw-r--r--tests/auto/proxy_multiprocess/subclass.rep6
-rw-r--r--tests/auto/repparser/tst_parser.cpp57
-rw-r--r--tools/repc/repcodegenerator.cpp50
7 files changed, 371 insertions, 54 deletions
diff --git a/src/remoteobjects/qremoteobjectpacket.cpp b/src/remoteobjects/qremoteobjectpacket.cpp
index 50f6d57..16a5e31 100644
--- a/src/remoteobjects/qremoteobjectpacket.cpp
+++ b/src/remoteobjects/qremoteobjectpacket.cpp
@@ -38,6 +38,7 @@
****************************************************************************/
#include <QtCore/qabstractitemmodel.h>
+#include <QtCore/qbytearrayview.h>
#include "qremoteobjectcontainers_p.h"
#include "qremoteobjectpendingcall.h"
@@ -441,16 +442,34 @@ static ObjectType getObjectType(const QString &typeName)
return ObjectType::CLASS;
}
-// Same method as in QVariant.cpp, as it isn't publicly exposed...
+static QByteArrayView resolveEnumName(QMetaType t, bool &isFlag)
+{
+ // Takes types like `MyPOD::Position` or `QFlags<MyPOD::Position>` and returns 'Position`
+ QByteArrayView enumName(t.name());
+ isFlag = enumName.startsWith("QFlags<");
+ auto lastColon = enumName.lastIndexOf(':');
+ if (lastColon >= 0)
+ enumName = QByteArrayView(t.name() + lastColon + 1);
+ if (isFlag)
+ enumName.chop(1);
+ return enumName;
+}
+
static QMetaEnum metaEnumFromType(QMetaType t)
{
- if (t.flags() & QMetaType::IsEnumeration) {
- if (const QMetaObject *metaObject = t.metaObject()) {
- const char *enumName = t.name();
- const char *lastColon = std::strrchr(enumName, ':');
- if (lastColon)
- enumName = lastColon + 1;
- return metaObject->enumerator(metaObject->indexOfEnumerator(enumName));
+ if (t.flags().testFlag(QMetaType::IsEnumeration)) {
+ if (const QMetaObject *m = t.metaObject()) {
+ bool isFlag;
+ auto enumName = resolveEnumName(t, isFlag);
+ if (isFlag) {
+ for (int i = m->enumeratorOffset(); i < m->enumeratorCount(); i++) {
+ auto testType = m->enumerator(i);
+ if (testType.isFlag() &&
+ enumName.compare(QByteArrayView(testType.enumName())) == 0)
+ return testType;
+ }
+ }
+ return m->enumerator(m->indexOfEnumerator(enumName.data()));
}
}
return QMetaEnum();
@@ -624,7 +643,7 @@ static void serializeGadgets(QDataStream &ds, const QSet<const QMetaObject *> &g
int propertyCount = gadgets.contains(meta) ? meta->propertyCount() : 0;
ds << quint32(propertyCount);
#ifdef QTRO_VERBOSE_PROTOCOL
- qDebug(" Gadget %d (name = %s, # properties = %d, # enums = %d):", i++, meta->className(), propertyCount, meta->enumeratorCount());
+ qDebug(" Gadget %d (name = %s, # properties = %d, # enums = %d):", i++, meta->className(), propertyCount, meta->enumeratorCount() - meta->enumeratorOffset());
#endif
for (int j = 0; j < propertyCount; j++) {
auto prop = meta->property(j);
@@ -634,9 +653,9 @@ static void serializeGadgets(QDataStream &ds, const QSet<const QMetaObject *> &g
ds << QByteArray::fromRawData(prop.name(), qsizetype(qstrlen(prop.name())));
ds << QByteArray::fromRawData(prop.typeName(), qsizetype(qstrlen(prop.typeName())));
}
- int enumCount = meta->enumeratorCount();
+ int enumCount = meta->enumeratorCount() - meta->enumeratorOffset();
ds << quint32(enumCount);
- for (int j = 0; j < enumCount; j++) {
+ for (int j = meta->enumeratorOffset(); j < meta->enumeratorCount(); j++) {
auto const enumMeta = meta->enumerator(j);
serializeEnum(ds, enumMeta);
}
@@ -915,7 +934,12 @@ QRO_::QRO_(const QVariant &value)
out << QByteArray::fromRawData(property.name(), qsizetype(qstrlen(property.name())));
out << QByteArray::fromRawData(property.typeName(), qsizetype(qstrlen(property.typeName())));
}
- out << quint32(0); // PODs have no enums
+ int enumCount = meta->enumeratorCount() - meta->enumeratorOffset();
+ out << quint32(enumCount);
+ for (int j = meta->enumeratorOffset(); j < meta->enumeratorCount(); j++) {
+ auto const enumMeta = meta->enumerator(j);
+ serializeEnum(out, enumMeta);
+ }
QDataStream ds(&parameters, QIODevice::WriteOnly);
ds << value;
#ifdef QTRO_VERBOSE_PROTOCOL
diff --git a/src/remoteobjects/qtremoteobjectglobal.cpp b/src/remoteobjects/qtremoteobjectglobal.cpp
index 8eca928..f83db9b 100644
--- a/src/remoteobjects/qtremoteobjectglobal.cpp
+++ b/src/remoteobjects/qtremoteobjectglobal.cpp
@@ -38,6 +38,7 @@
****************************************************************************/
#include "qtremoteobjectglobal.h"
+#include "qremoteobjectpacket_p.h"
#include <QtCore/qdatastream.h>
#include <QtCore/qmetaobject.h>
@@ -76,7 +77,6 @@ namespace QtRemoteObjects {
void copyStoredProperties(const QMetaObject *mo, const void *src, void *dst)
{
-#if (QT_VERSION >= QT_VERSION_CHECK(5, 5, 0))
if (!src) {
qCWarning(QT_REMOTEOBJECT) << Q_FUNC_INFO << ": trying to copy from a null source";
return;
@@ -90,16 +90,10 @@ void copyStoredProperties(const QMetaObject *mo, const void *src, void *dst)
const QMetaProperty mp = mo->property(i);
mp.writeOnGadget(dst, mp.readOnGadget(src));
}
-#else
- Q_UNUSED(mo)
- Q_UNUSED(src)
- Q_UNUSED(dst)
-#endif
}
void copyStoredProperties(const QMetaObject *mo, const void *src, QDataStream &dst)
{
-#if (QT_VERSION >= QT_VERSION_CHECK(5, 5, 0))
if (!src) {
qCWarning(QT_REMOTEOBJECT) << Q_FUNC_INFO << ": trying to copy from a null source";
return;
@@ -107,18 +101,12 @@ void copyStoredProperties(const QMetaObject *mo, const void *src, QDataStream &d
for (int i = 0, end = mo->propertyCount(); i != end; ++i) {
const QMetaProperty mp = mo->property(i);
- dst << mp.readOnGadget(src);
+ dst << QRemoteObjectPackets::encodeVariant(mp.readOnGadget(src));
}
-#else
- Q_UNUSED(mo)
- Q_UNUSED(src)
- Q_UNUSED(dst)
-#endif
}
void copyStoredProperties(const QMetaObject *mo, QDataStream &src, void *dst)
{
-#if (QT_VERSION >= QT_VERSION_CHECK(5, 5, 0))
if (!dst) {
qCWarning(QT_REMOTEOBJECT) << Q_FUNC_INFO << ": trying to copy to a null destination";
return;
@@ -128,13 +116,8 @@ void copyStoredProperties(const QMetaObject *mo, QDataStream &src, void *dst)
const QMetaProperty mp = mo->property(i);
QVariant v;
src >> v;
- mp.writeOnGadget(dst, v);
+ mp.writeOnGadget(dst, QRemoteObjectPackets::decodeVariant(std::move(v), mp.metaType()));
}
-#else
- Q_UNUSED(mo)
- Q_UNUSED(src)
- Q_UNUSED(dst)
-#endif
}
} // namespace QtRemoteObjects
diff --git a/src/repparser/parser.g b/src/repparser/parser.g
index 48fe32a..77ed224 100644
--- a/src/repparser/parser.g
+++ b/src/repparser/parser.g
@@ -45,22 +45,29 @@
%token semicolon "[semicolon];"
%token class "[class]class[ \\t]+(?<name>[A-Za-z_][A-Za-z0-9_]+)[ \\t]*"
%token pod "[pod]POD[ \\t]*(?<name>[A-Za-z_][A-Za-z0-9_]+)[ \\t]*\\((?<types>[^\\)]*)\\);?[ \\t]*"
+%token pod2 "[pod2]POD[ \\t]*(?<name>[A-Za-z_][A-Za-z0-9_]+)[ \\t]*"
%token flag "[flag][ \\t]*FLAG[ \t]*\\([ \t]*(?<name>[A-Za-z_][A-Za-z0-9_]*)[ \t]+(?<enum>[A-Za-z_][A-Za-z0-9_]*)[ \t]*\\)[ \t]*"
%token enum "[enum][ \\t]*ENUM[ \t]+(?:(?<class>class[ \t]+))?(?<name>[A-Za-z_][A-Za-z0-9_]*)[ \t]*(?::[ \t]*(?<type>[a-zA-Z0-9 _:]*[a-zA-Z0-9_])[ \t]*)?"
-%token enum_param "[enum_param][ \\t]*(?<name>[A-Za-z_][A-Za-z0-9_]*)[ \\t]*(=[ \\t]*(?<value>-\\d+|0[xX][0-9A-Fa-f]+|\\d+))?[ \\t]*"
%token prop "[prop][ \\t]*PROP[ \\t]*\\((?<args>[^\\)]+)\\);?[ \\t]*"
%token use_enum "[use_enum]USE_ENUM[ \\t]*\\((?<name>[^\\)]*)\\);?[ \\t]*"
%token signal "[signal][ \\t]*SIGNAL[ \\t]*\\([ \\t]*(?<name>\\S+)[ \\t]*\\((?<args>[^\\)]*)\\)[ \\t]*\\);?[ \\t]*"
%token slot "[slot][ \\t]*SLOT[ \\t]*\\((?<type>[^\\(]*)\\((?<args>[^\\)]*)\\)[ \\t]*\\);?[ \\t]*"
%token model "[model][ \\t]*MODEL[ \\t]+(?<name>[A-Za-z_][A-Za-z0-9_]+)\\((?<args>[^\\)]+)\\)[ \\t]*;?[ \\t]*"
%token childrep "[childrep][ \\t]*CLASS[ \\t]+(?<name>[A-Za-z_][A-Za-z0-9_]+)\\((?<type>[^\\)]+)\\)[ \\t]*;?[ \\t]*"
+%token qualifier "[qualifier][ \\t]*(?<value>const|unsigned|signed)[ \\t]*"
+%token passbyqual "[passbyqual][ \\t]*(?<value>&)[ \\t]*"
+%token symbol "[symbol][ \\t]*(?<symbol>[A-Za-z_][A-Za-z0-9_]*)[ \\t]*"
+%token value "[value][ \\t]*(?<value>-\\d+|0[xX][0-9A-Fa-f]+|\\d+)[ \\t]*"
%token start "[start][ \\t]*\\{[ \\t]*"
%token stop "[stop][ \\t]*\\};?[ \\t]*"
%token comma "[comma],"
+%token equals "[equals]="
%token comment "[comment](?<comment>[ \\t]*//[^\\n]*\\n)"
%token mcomment "[mcomment,M](?<comment>/\\*(.*?)\\*/)"
%token preprocessor_directive "[preprocessor_directive](?<preprocessor_directive>#[ \\t]*[^\\n]*\\n)"
%token newline "[newline](\\r)?\\n"
+%token tstart "[tstart]<"
+%token tstop "[tstop]>[ \\t]*"
%start TopLevel
@@ -262,6 +269,8 @@ struct POD : public SignedType
void signature_impl(const AST &ast, QCryptographicHash &checksum) override;
QList<PODAttribute> attributes;
+ QList<ASTEnum> enums;
+ QList<ASTFlag> flags;
};
Q_DECLARE_TYPEINFO(POD, Q_RELOCATABLE_TYPE);
@@ -314,6 +323,9 @@ private:
AST m_ast;
ASTClass m_astClass;
+ POD m_astPod;
+ QString m_symbol;
+ QString m_argString;
ASTEnum m_astEnum;
int m_astEnumValue;
};
@@ -609,6 +621,8 @@ void RepParser::reset()
{
m_ast = AST();
m_astClass = ASTClass();
+ m_astPod = POD();
+ m_argString.clear();
m_astEnum = ASTEnum();
//setDebug();
}
@@ -870,6 +884,7 @@ Comments: Comment | Comment Comments;
Comment: comment | comment Newlines | mcomment | mcomment Newlines;
Type: PreprocessorDirective | PreprocessorDirective Newlines;
Type: Pod | Pod Newlines;
+Type: Pod2;
Type: Class;
Type: UseEnum | UseEnum Newlines;
Type: Comments | Comments Newlines;
@@ -886,6 +901,8 @@ Type: Flag | Flag Newlines;
Comma: comma | comma Newlines;
+Equals: equals;
+
PreprocessorDirective: preprocessor_directive;
/.
case $rule_number:
@@ -907,6 +924,10 @@ Pod: pod;
qWarning() << "[repc] - Ignoring POD with no data members. POD name: " << qPrintable(pod.name);
return true;
}
+ if (argString.contains(QLatin1String("ENUM"))) {
+ setErrorString(QLatin1String("ENUMs are only available in PODs using bracket syntax ('{'), not parentheses"));
+ return false;
+ }
RepParser::TypeParser parseType;
parseType.parseArguments(argString);
@@ -948,6 +969,126 @@ ClassType: Enum;
break;
./
+Pod2: PodStart Start PodTypes Stop;
+/.
+ case $rule_number:
+./
+Pod2: PodStart Start Comments Stop;
+/.
+ case $rule_number:
+./
+Pod2: PodStart Start Stop;
+/.
+ case $rule_number:
+ {
+ RepParser::TypeParser parseType;
+ parseType.parseArguments(m_argString);
+ parseType.appendPods(m_astPod);
+ m_astPod.generateSignature(m_ast);
+ m_ast.pods.append(m_astPod);
+ }
+ break;
+./
+
+PodTypes: PodType | PodType Newlines | PodType CaptureComma PodTypes | PodType PodTypes | PodType Newlines PodTypes;
+PodType: DecoratedPODFlag | Comments;
+PodType: Enum;
+/.
+ case $rule_number:
+ {
+ m_astEnum.generateSignature(m_ast);
+ m_astPod.enums.append(m_astEnum);
+ }
+ break;
+./
+
+PodType: Parameter;
+Parameter: DecoratedParameterType ParameterName;
+
+DecoratedParameterType: ParameterType | Qualified ParameterType | ParameterType PassByReference | Qualified ParameterType PassByReference;
+
+ParameterType: SimpleType | TemplateType;
+
+TemplateType: TemplateTypename TStart ParameterTypes TStop;
+
+TemplateTypename: Symbol;
+/.
+ case $rule_number:
+ {
+ m_argString += m_symbol;
+ }
+ break;
+./
+
+TStart: tstart;
+/.
+ case $rule_number:
+ {
+ m_argString += QLatin1Char('<');
+ }
+ break;
+./
+
+TStop: tstop;
+/.
+ case $rule_number:
+ {
+ m_argString += QLatin1Char('>');
+ }
+ break;
+./
+
+Qualified: qualifier;
+/.
+ case $rule_number:
+ {
+ m_argString += captured().value(QLatin1String("value")).trimmed() + QLatin1Char(' ');
+ }
+ break;
+./
+
+PassByReference: passbyqual;
+/.
+ case $rule_number:
+ {
+ m_argString += QLatin1Char(' ') + captured().value(QLatin1String("value")).trimmed();
+ }
+ break;
+./
+
+ParameterTypes: DecoratedParameterType | DecoratedParameterType CaptureComma ParameterTypes;
+
+CaptureComma: comma;
+/.
+ case $rule_number:
+./
+CaptureComma: comma Newlines;
+/.
+ case $rule_number:
+ {
+ m_argString += QLatin1Char(',');
+ }
+ break;
+./
+
+SimpleType: Symbol;
+/.
+ case $rule_number:
+ {
+ m_argString += m_symbol;
+ }
+ break;
+./
+
+ParameterName: Symbol;
+/.
+ case $rule_number:
+ {
+ m_argString += QLatin1Char(' ') + m_symbol;
+ }
+ break;
+./
+
DecoratedSlot: Slot | Comments Slot | Slot Newlines | Comments Slot Newlines;
DecoratedSignal: Signal | Comments Signal | Signal Newlines | Comments Signal Newlines;
DecoratedProp: Prop | Comments Prop | Prop Newlines | Comments Prop Newlines;
@@ -956,6 +1097,8 @@ DecoratedClass: ChildRep | Comments ChildRep | ChildRep Newlines | Comments Chil
DecoratedEnumParam: EnumParam | Comments EnumParam | EnumParam Newlines | Comments EnumParam Newlines;
DecoratedClassFlag: ClassFlag | Comments ClassFlag | ClassFlag Newlines | Comments ClassFlag Newlines;
+DecoratedPODFlag: PODFlag | Comments PODFlag | PODFlag Newlines | Comments PODFlag Newlines;
+
Start: start | Comments start | start Newlines | Comments start Newlines;
Stop: stop | stop Newlines;
@@ -983,21 +1126,27 @@ EnumStart: enum;
EnumParams: DecoratedEnumParam | DecoratedEnumParam Comma EnumParams;
-EnumParam: enum_param;
+EnumParam: Symbol;
/.
case $rule_number:
{
ASTEnumParam param;
- param.name = captured().value(QStringLiteral("name")).trimmed();
- QString value = captured().value(QStringLiteral("value"));
- value.remove(QLatin1Char('='));
- value = value.trimmed();
- if (value.isEmpty())
- param.value = ++m_astEnumValue;
- else if (value.startsWith(QLatin1String("0x"), Qt::CaseInsensitive))
- param.value = m_astEnumValue = value.toInt(0,16);
- else
- param.value = m_astEnumValue = value.toInt();
+ param.name = m_symbol;
+ param.value = ++m_astEnumValue;
+ if (m_astEnum.max < param.value)
+ m_astEnum.max = param.value;
+ m_astEnum.params << param;
+ }
+ break;
+./
+
+EnumParam: Symbol Equals Value;
+/.
+ case $rule_number:
+ {
+ ASTEnumParam param;
+ param.name = m_symbol;
+ param.value = m_astEnumValue;
if (param.value < 0) {
m_astEnum.isSigned = true;
if (m_astEnum.max < -param.value)
@@ -1009,6 +1158,28 @@ EnumParam: enum_param;
break;
./
+Symbol: symbol;
+/.
+ case $rule_number:
+ {
+ m_symbol = captured().value(QStringLiteral("symbol")).trimmed();
+ }
+ break;
+./
+
+Value: value;
+/.
+ case $rule_number:
+ {
+ QString value = captured().value(QStringLiteral("value")).trimmed();
+ if (value.startsWith(QLatin1String("0x"), Qt::CaseInsensitive))
+ m_astEnumValue = value.toInt(0,16);
+ else
+ m_astEnumValue = value.toInt();
+ }
+ break;
+./
+
ClassFlag: flag;
/.
case $rule_number:
@@ -1035,6 +1206,32 @@ ClassFlag: flag;
break;
./
+PODFlag: flag;
+/.
+ case $rule_number:
+ {
+ const QString name = captured().value(QLatin1String("name"));
+ const QString _enum = captured().value(QLatin1String("enum"));
+ int enumIndex = 0;
+ for (auto &en : m_astPod.enums) {
+ if (en.name == _enum) {
+ en.flagIndex = m_astPod.flags.count();
+ break;
+ }
+ enumIndex++;
+ }
+ if (enumIndex == m_astPod.enums.count()) {
+ setErrorString(QLatin1String("FLAG: Unknown (pod) enum: %1").arg(_enum));
+ return false;
+ }
+ auto flag = ASTFlag(name, _enum);
+ flag.scope = m_astPod.name;
+ flag.generateSignature(m_ast);
+ m_astPod.flags.append(flag);
+ }
+ break;
+./
+
Prop: prop;
/.
case $rule_number:
@@ -1137,6 +1334,22 @@ ClassStart: class;
break;
./
+PodStart: pod2;
+/.
+ case $rule_number:
+./
+PodStart: pod2 Newlines;
+/.
+ case $rule_number:
+ {
+ // new POD declaration
+ m_astPod = POD();
+ m_astPod.name = captured().value(QLatin1String("name")).trimmed();
+ m_argString.clear();
+ }
+ break;
+./
+
UseEnum: use_enum;
/.
case $rule_number:
diff --git a/tests/auto/proxy_multiprocess/shared.h b/tests/auto/proxy_multiprocess/shared.h
index c3bd763..e0a0a73 100644
--- a/tests/auto/proxy_multiprocess/shared.h
+++ b/tests/auto/proxy_multiprocess/shared.h
@@ -1,5 +1,5 @@
-const MyPOD initialValue(42, 3.14, QStringLiteral("SubClass"));
-const MyPOD updatedValue(-1, 123.456, QStringLiteral("Updated"));
+const MyPOD initialValue(MyPOD::Position::position1, 3.14, QStringLiteral("SubClass"));
+const MyPOD updatedValue(MyPOD::Position::position2 | MyPOD::Position::position3, 123.456, QStringLiteral("Updated"));
const VariantPOD podValue(10, 11);
const int initialI = 100;
const int updatedI = 200;
diff --git a/tests/auto/proxy_multiprocess/subclass.rep b/tests/auto/proxy_multiprocess/subclass.rep
index ae756e2..5fb03d3 100644
--- a/tests/auto/proxy_multiprocess/subclass.rep
+++ b/tests/auto/proxy_multiprocess/subclass.rep
@@ -5,7 +5,11 @@ USE_ENUM(Qt::DateFormat)
USE_ENUM(NS::NamespaceEnum)
USE_ENUM(NS2::NamespaceEnum)
-POD MyPOD(int i, float f, QString s)
+POD MyPOD{
+ ENUM class Position : unsigned short {position1=1, position2=2, position3=4}
+ FLAG (ActivePositions Position)
+ ActivePositions positions, float f, QString s
+}
POD VariantPOD(int i, int j)
class SubClass
diff --git a/tests/auto/repparser/tst_parser.cpp b/tests/auto/repparser/tst_parser.cpp
index 5d2e818..14b93dd 100644
--- a/tests/auto/repparser/tst_parser.cpp
+++ b/tests/auto/repparser/tst_parser.cpp
@@ -49,6 +49,8 @@ private Q_SLOTS:
void testSignals();
void testPods_data();
void testPods();
+ void testPods2_data();
+ void testPods2();
void testEnums_data();
void testEnums();
void testTypedEnums_data();
@@ -321,6 +323,61 @@ void tst_Parser::testPods()
}
}
+void tst_Parser::testPods2_data()
+{
+ QTest::addColumn<QString>("podsdeclaration");
+ QTest::addColumn<QString>("expectedtypes");
+ QTest::addColumn<QString>("expectedvariables");
+
+ //Variable/Type separate by ";"
+ QTest::newRow("one pod") << "POD preset{int presetNumber}" << "int" << "presetNumber";
+ QTest::newRow("two pod") << "POD preset{int presetNumber, double foo}" << "int;double" << "presetNumber;foo";
+ QTest::newRow("two pod with space") << "POD preset { int presetNumber , double foo } " << "int;double" << "presetNumber;foo";
+ QTest::newRow("two pod multiline") << "POD preset{\nint presetNumber,\ndouble foo\n}" << "int;double" << "presetNumber;foo";
+ //Template
+ QTest::newRow("pod template") << "POD preset{QMap<QString,int> foo} " << "QMap<QString,int>" << "foo";
+ QTest::newRow("pod template (QList)") << "POD preset{QList<QString> foo} " << "QList<QString>" << "foo";
+ QTest::newRow("two pod template") << "POD preset{QMap<QString,int> foo, QMap<double,int> bla} " << "QMap<QString,int>;QMap<double,int>" << "foo;bla";
+ QTest::newRow("two pod template with space") << "POD preset{ QMap<QString , int > foo , QMap< double , int > bla } " << "QMap<QString,int>;QMap<double,int>" << "foo;bla";
+ //Enum
+ QTest::newRow("enum multiline") << "POD preset{ENUM val {val1 = 1,\nval2,\nval3=12}\nval value,\ndouble foo\n}" << "val;double" << "value;foo";
+
+}
+
+void tst_Parser::testPods2()
+{
+ QFETCH(QString, podsdeclaration);
+ QFETCH(QString, expectedtypes);
+ QFETCH(QString, expectedvariables);
+
+ QTemporaryFile file;
+ file.open();
+ QTextStream stream(&file);
+ stream << podsdeclaration << Qt::endl;
+ stream << "class TestClass" << Qt::endl;
+ stream << "{" << Qt::endl;
+ stream << "};" << Qt::endl;
+ file.seek(0);
+
+ RepParser parser(file);
+ QVERIFY(parser.parse());
+
+ const AST ast = parser.ast();
+ QCOMPARE(ast.classes.count(), 1);
+
+ QCOMPARE(ast.pods.count(), 1);
+ const POD pods = ast.pods.first();
+ const QVector<PODAttribute> podsList = pods.attributes;
+ const QStringList typeList = expectedtypes.split(QLatin1Char(';'));
+ const QStringList variableList = expectedvariables.split(QLatin1Char(';'));
+ QVERIFY(typeList.count() == variableList.count());
+ QVERIFY(podsList.count() == variableList.count());
+ for (int i=0; i < podsList.count(); ++i) {
+ QCOMPARE(podsList.at(i).name, variableList.at(i));
+ QCOMPARE(podsList.at(i).type, typeList.at(i));
+ }
+}
+
void tst_Parser::testEnums_data()
{
QTest::addColumn<QString>("enumdeclaration");
diff --git a/tools/repc/repcodegenerator.cpp b/tools/repc/repcodegenerator.cpp
index 71be53a..175ac43 100644
--- a/tools/repc/repcodegenerator.cpp
+++ b/tools/repc/repcodegenerator.cpp
@@ -84,6 +84,17 @@ static bool hasScopedEnum(const ASTClass &classContext)
return false;
}
+static bool hasScopedEnum(const POD &pod)
+{
+ for (const ASTEnum &astEnum : pod.enums) {
+ if (astEnum.isScoped) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
static QString fullyQualifiedName(const ASTClass& classContext, const QString &className,
const QString &typeName)
{
@@ -156,10 +167,26 @@ void RepCodeGenerator::generate(Mode mode, QString fileName)
generatePOD(pod);
QSet<QString> metaTypes;
+ QSet<QString> enumTypes;
for (const POD &pod : m_ast.pods) {
metaTypes << pod.name;
- for (const PODAttribute &attribute : pod.attributes)
- metaTypes << attribute.type;
+ // We register from within the code generated for classes, not PODs
+ // Thus, for enums/flags in PODs, we need the to prefix with the POD
+ // name. The enumTypes set is used to make sure we don't try to
+ // register the non-prefixed name if it is used as a member variable
+ // type.
+ for (const ASTEnum &en : pod.enums) {
+ metaTypes << QLatin1String("%1::%2").arg(pod.name, en.name);
+ enumTypes << en.name;
+ }
+ for (const ASTFlag &flag : pod.flags) {
+ metaTypes << QLatin1String("%1::%2").arg(pod.name, flag.name);
+ enumTypes << flag.name;
+ }
+ for (const PODAttribute &attribute : pod.attributes) {
+ if (!enumTypes.contains(attribute.type))
+ metaTypes << attribute.type;
+ }
}
const QString metaTypeRegistrationCode = generateMetaTypeRegistration(metaTypes);
@@ -409,9 +436,16 @@ void RepCodeGenerator::generatePOD(const POD &pod)
"{\n"
" Q_GADGET\n"
<< "\n"
- << formatQPropertyDeclarations(pod)
- << "public:\n"
- << formatConstructors(pod)
+ << formatQPropertyDeclarations(pod);
+ if (hasScopedEnum(pod)) // See https://bugreports.qt.io/browse/QTBUG-73360
+ m_stream << " Q_CLASSINFO(\"RegisterEnumClassesUnscoped\", \"false\")\n";
+ m_stream << "public:\n";
+ generateDeclarationsForEnums(pod.enums);
+ for (auto &flag : pod.flags) {
+ m_stream << " Q_DECLARE_FLAGS(" << flag.name << ", " << flag._enum << ")\n";
+ m_stream << " Q_FLAG(" << flag.name << ")\n";
+ }
+ m_stream << formatConstructors(pod)
<< formatPropertyGettersAndSetters(pod)
<< "private:\n"
<< formatDataMembers(pod)
@@ -427,8 +461,10 @@ void RepCodeGenerator::generatePOD(const POD &pod)
<< "}\n"
<< "\n"
<< formatDebugOperator(pod)
- << formatMarshallingOperators(pod)
- << "\n\n";
+ << formatMarshallingOperators(pod);
+ for (auto &flag : pod.flags)
+ m_stream << "Q_DECLARE_OPERATORS_FOR_FLAGS(" << pod.name << "::" << flag.name << ")\n";
+ m_stream << "\n";
}
QString getEnumType(const ASTEnum &en)