moc: Handle attributes after meta-method tag
We so far only handled them if they came at the very start of the method declaration. This patch ensures that we also handle them after the meta-method tag (but before the actual type). Unifying parseFunction and parseMaybeFunction to avoid the need to munally keep them in sync is left for another day. Fixes: QTBUG-111330 Change-Id: Ic94edb69f04b9150aea2c8e6d004a8b9e5cf12ec Reviewed-by: Thiago Macieira <thiago.macieira@intel.com> (cherry picked from commit 44b5ad01f0da55a351e0855e1173acfbef77221d) Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
This commit is contained in:
parent
c63a3a46be
commit
838f66be51
@ -409,8 +409,7 @@ bool Moc::parseFunction(FunctionDef *def, bool inMacro)
|
|||||||
def->isVirtual = false;
|
def->isVirtual = false;
|
||||||
def->isStatic = false;
|
def->isStatic = false;
|
||||||
//skip modifiers and attributes
|
//skip modifiers and attributes
|
||||||
while (test(INLINE) || (test(STATIC) && (def->isStatic = true) == true) ||
|
while (testForFunctionModifiers(def)
|
||||||
(test(VIRTUAL) && (def->isVirtual = true) == true) //mark as virtual
|
|
||||||
|| skipCxxAttributes() || testFunctionAttribute(def) || testFunctionRevision(def)) {}
|
|| skipCxxAttributes() || testFunctionAttribute(def) || testFunctionRevision(def)) {}
|
||||||
bool templateFunction = (lookup() == TEMPLATE);
|
bool templateFunction = (lookup() == TEMPLATE);
|
||||||
def->type = parseType();
|
def->type = parseType();
|
||||||
@ -426,6 +425,10 @@ bool Moc::parseFunction(FunctionDef *def, bool inMacro)
|
|||||||
scopedFunctionName = def->type.isScoped;
|
scopedFunctionName = def->type.isScoped;
|
||||||
def->type = Type("int");
|
def->type = Type("int");
|
||||||
} else {
|
} else {
|
||||||
|
// we might have modifiers and attributes after a tag
|
||||||
|
// note that testFunctionAttribute is handled further below,
|
||||||
|
// and revisions and attributes must come first
|
||||||
|
while (testForFunctionModifiers(def)) {}
|
||||||
Type tempType = parseType();;
|
Type tempType = parseType();;
|
||||||
while (!tempType.name.isEmpty() && lookup() != LPAREN) {
|
while (!tempType.name.isEmpty() && lookup() != LPAREN) {
|
||||||
if (testFunctionAttribute(def->type.firstToken, def))
|
if (testFunctionAttribute(def->type.firstToken, def))
|
||||||
@ -509,14 +512,20 @@ bool Moc::parseFunction(FunctionDef *def, bool inMacro)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Moc::testForFunctionModifiers(FunctionDef *def)
|
||||||
|
{
|
||||||
|
return test(EXPLICIT) || test(INLINE) ||
|
||||||
|
(test(STATIC) && (def->isStatic = true)) ||
|
||||||
|
(test(VIRTUAL) && (def->isVirtual = true));
|
||||||
|
}
|
||||||
|
|
||||||
// like parseFunction, but never aborts with an error
|
// like parseFunction, but never aborts with an error
|
||||||
bool Moc::parseMaybeFunction(const ClassDef *cdef, FunctionDef *def)
|
bool Moc::parseMaybeFunction(const ClassDef *cdef, FunctionDef *def)
|
||||||
{
|
{
|
||||||
def->isVirtual = false;
|
def->isVirtual = false;
|
||||||
def->isStatic = false;
|
def->isStatic = false;
|
||||||
//skip modifiers and attributes
|
//skip modifiers and attributes
|
||||||
while (test(EXPLICIT) || test(INLINE) || (test(STATIC) && (def->isStatic = true) == true) ||
|
while (testForFunctionModifiers(def)
|
||||||
(test(VIRTUAL) && (def->isVirtual = true) == true) //mark as virtual
|
|
||||||
|| skipCxxAttributes() || testFunctionAttribute(def) || testFunctionRevision(def)) {}
|
|| skipCxxAttributes() || testFunctionAttribute(def) || testFunctionRevision(def)) {}
|
||||||
bool tilde = test(TILDE);
|
bool tilde = test(TILDE);
|
||||||
def->type = parseType();
|
def->type = parseType();
|
||||||
@ -534,6 +543,10 @@ bool Moc::parseMaybeFunction(const ClassDef *cdef, FunctionDef *def)
|
|||||||
def->type = Type("int");
|
def->type = Type("int");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
// ### TODO: The condition before testForFunctionModifiers shoulnd't be necessary,
|
||||||
|
// but otherwise we end up with misparses
|
||||||
|
if (def->isSlot || def->isSignal || def->isInvokable)
|
||||||
|
while (testForFunctionModifiers(def)) {}
|
||||||
Type tempType = parseType();;
|
Type tempType = parseType();;
|
||||||
while (!tempType.name.isEmpty() && lookup() != LPAREN) {
|
while (!tempType.name.isEmpty() && lookup() != LPAREN) {
|
||||||
if (testFunctionAttribute(def->type.firstToken, def))
|
if (testFunctionAttribute(def->type.firstToken, def))
|
||||||
|
@ -280,6 +280,7 @@ public:
|
|||||||
|
|
||||||
void checkSuperClasses(ClassDef *def);
|
void checkSuperClasses(ClassDef *def);
|
||||||
void checkProperties(ClassDef* cdef);
|
void checkProperties(ClassDef* cdef);
|
||||||
|
bool testForFunctionModifiers(FunctionDef *def);
|
||||||
};
|
};
|
||||||
|
|
||||||
inline QByteArray noRef(const QByteArray &type)
|
inline QByteArray noRef(const QByteArray &type)
|
||||||
|
@ -83,6 +83,19 @@ Q_DECLARE_METATYPE(const QMetaObject*);
|
|||||||
|
|
||||||
#define TESTEXPORTMACRO Q_DECL_EXPORT
|
#define TESTEXPORTMACRO Q_DECL_EXPORT
|
||||||
|
|
||||||
|
#if !defined(Q_MOC_RUN) && !defined(Q_NOREPLY)
|
||||||
|
# define Q_NOREPLY
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct TagTest : QObject {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
Q_INVOKABLE Q_NOREPLY inline int test() {return 0;}
|
||||||
|
public slots:
|
||||||
|
Q_NOREPLY virtual inline void pamOpen(int){}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
namespace TestNonQNamespace {
|
namespace TestNonQNamespace {
|
||||||
|
|
||||||
struct TestGadget {
|
struct TestGadget {
|
||||||
@ -787,6 +800,7 @@ private slots:
|
|||||||
void privateQPropertyShim();
|
void privateQPropertyShim();
|
||||||
void readWriteThroughBindable();
|
void readWriteThroughBindable();
|
||||||
void invokableCtors();
|
void invokableCtors();
|
||||||
|
void virtualInlineTaggedSlot();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void sigWithUnsignedArg(unsigned foo);
|
void sigWithUnsignedArg(unsigned foo);
|
||||||
@ -4575,6 +4589,20 @@ void tst_Moc::invokableCtors()
|
|||||||
QCOMPARE(result2.m_thing, 17);
|
QCOMPARE(result2.m_thing, 17);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tst_Moc::virtualInlineTaggedSlot()
|
||||||
|
{
|
||||||
|
auto mo = TagTest::staticMetaObject;
|
||||||
|
auto idx = mo.indexOfMethod("pamOpen(int)");
|
||||||
|
auto method = mo.method(idx);
|
||||||
|
QVERIFY(method.isValid()); // fails!
|
||||||
|
QCOMPARE(method.tag(), "Q_NOREPLY");
|
||||||
|
idx = mo.indexOfMethod("test()");
|
||||||
|
method = mo.method(idx);
|
||||||
|
QVERIFY(method.isValid());
|
||||||
|
QCOMPARE(method.tag(), "Q_NOREPLY");
|
||||||
|
QCOMPARE(method.returnMetaType(), QMetaType::fromType<int>());
|
||||||
|
}
|
||||||
|
|
||||||
QTEST_MAIN(tst_Moc)
|
QTEST_MAIN(tst_Moc)
|
||||||
|
|
||||||
// the generated code must compile with QT_NO_KEYWORDS
|
// the generated code must compile with QT_NO_KEYWORDS
|
||||||
|
Loading…
x
Reference in New Issue
Block a user