From 4dbac23e5354638224d8d99ba3342067c015a04b Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Wed, 11 Dec 2019 18:13:28 +0100 Subject: [PATCH] Normalize types at compile time This also fix the normalization algorithm: - Some 'const' after pointers were not removed as they should. - No need to keep the space in '> >' and '< :' in C++11 anymore - Fix normalization of 'long unsigned int' and similar Change-Id: I2b72f0fede96c1063e7b155d9f25a85fccfc7bf9 Reviewed-by: Simon Hausmann --- src/corelib/kernel/qmetaobject.cpp | 12 +- src/corelib/kernel/qmetaobject_moc_p.h | 167 +------- src/corelib/kernel/qmetatype.h | 366 +++++++++++++++++- src/tools/moc/moc.cpp | 25 +- .../kernel/qmetaobject/tst_qmetaobject.cpp | 56 ++- .../kernel/qmetatype/tst_qmetatype.cpp | 52 ++- .../selftests/expected_signaldumper.junitxml | 4 +- .../selftests/expected_signaldumper.lightxml | 2 +- .../selftests/expected_signaldumper.tap | 2 +- .../selftests/expected_signaldumper.teamcity | 2 +- .../selftests/expected_signaldumper.txt | 2 +- .../selftests/expected_signaldumper.xml | 2 +- tests/auto/tools/moc/allmocs_baseline_in.json | 12 +- tests/auto/tools/moc/tst_moc.cpp | 4 +- 14 files changed, 474 insertions(+), 234 deletions(-) diff --git a/src/corelib/kernel/qmetaobject.cpp b/src/corelib/kernel/qmetaobject.cpp index f4d0a88529..62de104c30 100644 --- a/src/corelib/kernel/qmetaobject.cpp +++ b/src/corelib/kernel/qmetaobject.cpp @@ -1315,17 +1315,7 @@ static char *qNormalizeType(char *d, int &templdepth, QByteArray &result) */ QByteArray QMetaObject::normalizedType(const char *type) { - QByteArray result; - - if (!type || !*type) - return result; - - QVarLengthArray stackbuf(qstrlen(type) + 1); - qRemoveWhitespace(type, stackbuf.data()); - int templdepth = 0; - qNormalizeType(stackbuf.data(), templdepth, result); - - return result; + return normalizeTypeInternal(type, type + qstrlen(type)); } /*! diff --git a/src/corelib/kernel/qmetaobject_moc_p.h b/src/corelib/kernel/qmetaobject_moc_p.h index 471e43f85b..9770d9c576 100644 --- a/src/corelib/kernel/qmetaobject_moc_p.h +++ b/src/corelib/kernel/qmetaobject_moc_p.h @@ -52,170 +52,19 @@ // We mean it. // -#include +#include QT_BEGIN_NAMESPACE // This function is shared with moc.cpp. This file should be included where needed. -static QByteArray normalizeTypeInternal(const char *t, const char *e, bool fixScope = false, bool adjustConst = true) +static QByteArray normalizeTypeInternal(const char *t, const char *e) { - int len = e - t; - /* - Convert 'char const *' into 'const char *'. Start at index 1, - not 0, because 'const char *' is already OK. - */ - QByteArray constbuf; - for (int i = 1; i < len; i++) { - if ( t[i] == 'c' - && strncmp(t + i + 1, "onst", 4) == 0 - && (i + 5 >= len || !is_ident_char(t[i + 5])) - && !is_ident_char(t[i-1]) - ) { - constbuf = QByteArray(t, len); - if (is_space(t[i-1])) - constbuf.remove(i-1, 6); - else - constbuf.remove(i, 5); - constbuf.prepend("const "); - t = constbuf.data(); - e = constbuf.data() + constbuf.length(); - break; - } - /* - We mustn't convert 'char * const *' into 'const char **' - and we must beware of 'Bar'. - */ - if (t[i] == '&' || t[i] == '*' ||t[i] == '<') - break; - } - if (adjustConst && e > t + 6 && strncmp("const ", t, 6) == 0) { - if (*(e-1) == '&') { // treat const reference as value - t += 6; - --e; - } else if (is_ident_char(*(e-1)) || *(e-1) == '>') { // treat const value as value - t += 6; - } - } - QByteArray result; - result.reserve(len); - -#if 1 - // consume initial 'const ' - if (strncmp("const ", t, 6) == 0) { - t+= 6; - result += "const "; - } -#endif - - // some type substitutions for 'unsigned x' - if (strncmp("unsigned", t, 8) == 0) { - // make sure "unsigned" is an isolated word before making substitutions - if (!t[8] || !is_ident_char(t[8])) { - if (strncmp(" int", t+8, 4) == 0) { - t += 8+4; - result += "uint"; - } else if (strncmp(" long", t+8, 5) == 0) { - if ((strlen(t + 8 + 5) < 4 || strncmp(t + 8 + 5, " int", 4) != 0) // preserve '[unsigned] long int' - && (strlen(t + 8 + 5) < 5 || strncmp(t + 8 + 5, " long", 5) != 0) // preserve '[unsigned] long long' - ) { - t += 8+5; - result += "ulong"; - } - } else if (strncmp(" short", t+8, 6) != 0 // preserve unsigned short - && strncmp(" char", t+8, 5) != 0) { // preserve unsigned char - // treat rest (unsigned) as uint - t += 8; - result += "uint"; - } - } - } else { - // discard 'struct', 'class', and 'enum'; they are optional - // and we don't want them in the normalized signature - struct { - const char *keyword; - int len; - } optional[] = { - { "struct ", 7 }, - { "class ", 6 }, - { "enum ", 5 }, - { nullptr, 0 } - }; - int i = 0; - do { - if (strncmp(optional[i].keyword, t, optional[i].len) == 0) { - t += optional[i].len; - break; - } - } while (optional[++i].keyword != nullptr); - } - - bool star = false; - while (t != e) { - char c = *t++; - if (fixScope && c == ':' && *t == ':' ) { - ++t; - c = *t++; - int i = result.size() - 1; - while (i >= 0 && is_ident_char(result.at(i))) - --i; - result.resize(i + 1); - } - star = star || c == '*'; - result += c; - if (c == '<') { - //template recursion - const char* tt = t; - int templdepth = 1; - int scopeDepth = 0; - while (t != e) { - c = *t++; - if (c == '{' || c == '(' || c == '[') - ++scopeDepth; - if (c == '}' || c == ')' || c == ']') - --scopeDepth; - if (scopeDepth == 0) { - if (c == '<') - ++templdepth; - if (c == '>') - --templdepth; - if (templdepth == 0 || (templdepth == 1 && c == ',')) { - result += normalizeTypeInternal(tt, t-1, fixScope, false); - result += c; - if (templdepth == 0) { - if (*t == '>') - result += ' '; // avoid >> - break; - } - tt = t; - } - } - } - } - - // cv qualifers can appear after the type as well - if (!is_ident_char(c) && t != e && (e - t >= 5 && strncmp("const", t, 5) == 0) - && (e - t == 5 || !is_ident_char(t[5]))) { - t += 5; - while (t != e && is_space(*t)) - ++t; - if (adjustConst && t != e && *t == '&') { - // treat const ref as value - ++t; - } else if (adjustConst && !star) { - // treat const as value - } else if (!star) { - // move const to the front (but not if const comes after a *) - result.prepend("const "); - } else { - // keep const after a * - result += "const"; - } - } - } - - // Qt 5 compatibility, make sure we use the correct type name for QList - result.replace("QList<", "QVector<"); - + int len = QtPrivate::qNormalizeType(t, e, nullptr); + if (len == 0) + return QByteArray(); + QByteArray result(len, Qt::Uninitialized); + len = QtPrivate::qNormalizeType(t, e, result.data()); + Q_ASSERT(len == result.size()); return result; } diff --git a/src/corelib/kernel/qmetatype.h b/src/corelib/kernel/qmetatype.h index b89f5cff00..7ee6a2662d 100644 --- a/src/corelib/kernel/qmetatype.h +++ b/src/corelib/kernel/qmetatype.h @@ -50,8 +50,9 @@ #ifndef QT_NO_QOBJECT #include #endif -#include +#include +#include #include #include #include @@ -1741,17 +1742,14 @@ namespace QtPrivate { } template -int qRegisterNormalizedMetaType(const QT_PREPEND_NAMESPACE(QByteArray) &_normalizedTypeName +int qRegisterNormalizedMetaType(const QT_PREPEND_NAMESPACE(QByteArray) &normalizedTypeName #ifndef Q_CLANG_QDOC , T * = 0 , typename QtPrivate::MetaTypeDefinedHelper::Defined && !QMetaTypeId2::IsBuiltIn>::DefinedType = QtPrivate::MetaTypeDefinedHelper::Defined && !QMetaTypeId2::IsBuiltIn>::Defined #endif ) { - auto normalizedTypeName = _normalizedTypeName; #ifndef QT_NO_QOBJECT - // FIXME currently not normalized because we don't do compile time normalization - normalizedTypeName = QMetaObject::normalizedType(_normalizedTypeName.constData()); Q_ASSERT_X(normalizedTypeName == QMetaObject::normalizedType(normalizedTypeName.constData()), "qRegisterNormalizedMetaType", "qRegisterNormalizedMetaType was called with a not normalized type name, please call qRegisterMetaType instead."); #endif @@ -2014,8 +2012,6 @@ struct QMetaTypeId< SINGLE_ARG_TEMPLATE > \ typeName.reserve(int(sizeof(#SINGLE_ARG_TEMPLATE)) + 1 + tNameLen + 1 + 1); \ typeName.append(#SINGLE_ARG_TEMPLATE, int(sizeof(#SINGLE_ARG_TEMPLATE)) - 1) \ .append('<').append(tName, tNameLen); \ - if (typeName.endsWith('>')) \ - typeName.append(' '); \ typeName.append('>'); \ const int newId = qRegisterNormalizedMetaType< SINGLE_ARG_TEMPLATE >( \ typeName, \ @@ -2056,8 +2052,6 @@ struct QMetaTypeId< DOUBLE_ARG_TEMPLATE > \ typeName.reserve(int(sizeof(#DOUBLE_ARG_TEMPLATE)) + 1 + tNameLen + 1 + uNameLen + 1 + 1); \ typeName.append(#DOUBLE_ARG_TEMPLATE, int(sizeof(#DOUBLE_ARG_TEMPLATE)) - 1) \ .append('<').append(tName, tNameLen).append(',').append(uName, uNameLen); \ - if (typeName.endsWith('>')) \ - typeName.append(' '); \ typeName.append('>'); \ const int newId = qRegisterNormalizedMetaType< DOUBLE_ARG_TEMPLATE >(\ typeName, \ @@ -2284,20 +2278,360 @@ public: LegacyRegisterOp legacyRegisterOp; }; +struct QTypeNormalizer +{ + char *output; + int len = 0; + char last = 0; + +private: + static constexpr bool is_ident_char(char s) + { + return ((s >= 'a' && s <= 'z') || (s >= 'A' && s <= 'Z') || (s >= '0' && s <= '9') + || s == '_'); + } + static constexpr bool is_space(char s) { return (s == ' ' || s == '\t' || s == '\n'); } + static constexpr bool is_number(char s) { return s >= '0' && s <= '9'; }; + static constexpr bool starts_with_token(const char *b, const char *e, const char *token, + bool msvcKw = false) + { + while (b != e && *token && *b == *token) { + b++; + token++; + } + if (*token) + return false; +#ifdef Q_CC_MSVC + /// On MSVC, keywords like class or struct are not separated with spaces in constexpr + /// context + if (msvcKw) + return true; +#endif + Q_UNUSED(msvcKw); + return b == e || !is_ident_char(*b); + } + static constexpr bool skipToken(const char *&x, const char *e, const char *token, + bool msvcKw = false) + { + if (!starts_with_token(x, e, token, msvcKw)) + return false; + while (*token++) + x++; + while (x != e && is_space(*x)) + x++; + return true; + } + static constexpr const char *skipString(const char *x, const char *e) + { + char delim = *x; + x++; + while (x != e && *x != delim) { + if (*x == '\\') { + x++; + if (x == e) + return e; + } + x++; + } + if (x != e) + x++; + return x; + }; + static constexpr const char *skipTemplate(const char *x, const char *e, bool stopAtComa = false) + { + int scopeDepth = 0; + int templateDepth = 0; + while (x != e) { + switch (*x) { + case '<': + if (!scopeDepth) + templateDepth++; + break; + case ',': + if (stopAtComa && !scopeDepth && !templateDepth) + return x; + break; + case '>': + if (!scopeDepth) + if (--templateDepth < 0) + return x; + break; + case '(': + case '[': + case '{': + scopeDepth++; + break; + case '}': + case ']': + case ')': + scopeDepth--; + break; + case '\'': + if (is_number(x[-1])) + break; + Q_FALLTHROUGH(); + case '\"': + x = skipString(x, e); + continue; + } + x++; + } + return x; + }; + + constexpr void append(char x) + { + last = x; + len++; + if (output) + *output++ = x; + } + + constexpr void appendStr(const char *x) + { + while (*x) + append(*x++); + }; + +public: + constexpr int normalizeType(const char *begin, const char *end, bool adjustConst = true) + { + // Trim spaces + while (begin != end && is_space(*begin)) + begin++; + while (begin != end && is_space(*(end - 1))) + end--; + + // Convert 'char const *' into 'const char *'. Start at index 1, + // not 0, because 'const char *' is already OK. + const char *cst = begin + 1; + if (*begin == '\'' || *begin == '"') + cst = skipString(begin, end); + bool seenStar = false; + bool hasMiddleConst = false; + while (cst < end) { + if (*cst == '\"' || (*cst == '\'' && !is_number(cst[-1]))) { + cst = skipString(cst, end); + if (cst == end) + break; + } + + // We mustn't convert 'char * const *' into 'const char **' + // and we must beware of 'Bar'. + if (*cst == '&' || *cst == '*' || *cst == '[') { + seenStar = *cst != '&' || cst != (end - 1); + break; + } + if (*cst == '<') { + cst = skipTemplate(cst + 1, end); + if (cst == end) + break; + } + cst++; + const char *skipedCst = cst; + if (!is_ident_char(*(cst - 1)) && skipToken(skipedCst, end, "const")) { + const char *testEnd = end; + while (skipedCst < testEnd--) { + if (*testEnd == '*' || *testEnd == '[' + || (*testEnd == '&' && testEnd != (end - 1))) { + seenStar = true; + break; + } + if (*testEnd == '>') + break; + } + if (adjustConst && !seenStar) { + if (*(end - 1) == '&') + end--; + } else { + appendStr("const "); + } + normalizeType(begin, cst, false); + begin = skipedCst; + hasMiddleConst = true; + break; + } + } + if (skipToken(begin, end, "const")) { + if (adjustConst && !seenStar) { + if (*(end - 1) == '&') + end--; + } else { + appendStr("const "); + } + } + if (seenStar && adjustConst) { + const char *e = end; + if (*(end - 1) == '&' && *(end - 2) != '&') + e--; + while (begin != e && is_space(*(e - 1))) + e--; + const char *token = "tsnoc"; // 'const' reverse, to check if it ends with const + while (*token && begin != e && *(--e) == *token++) + ; + if (!*token && begin != e && !is_ident_char(*(e - 1))) { + while (begin != e && is_space(*(e - 1))) + e--; + end = e; + } + } + + // discard 'struct', 'class', and 'enum'; they are optional + // and we don't want them in the normalized signature + skipToken(begin, end, "struct", true) || skipToken(begin, end, "class", true) + || skipToken(begin, end, "enum", true); + +#ifdef QT_NAMESPACE + const char *nsbeg = begin; + if (skipToken(nsbeg, end, QT_STRINGIFY(QT_NAMESPACE)) && nsbeg + 2 < end && nsbeg[0] == ':' + && nsbeg[1] == ':') { + begin = nsbeg + 2; + while (begin != end && is_space(*begin)) + begin++; + } +#endif + + if (skipToken(begin, end, "QList")) { + // Replace QList by QVector + appendStr("QVector"); + } + if (!hasMiddleConst) { + // Normalize the integer types + int numLong = 0; + int numSigned = 0; + int numUnsigned = 0; + int numInt = 0; + int numShort = 0; + int numChar = 0; + while (begin < end) { + if (skipToken(begin, end, "long")) { + numLong++; + continue; + } + if (skipToken(begin, end, "int")) { + numInt++; + continue; + } + if (skipToken(begin, end, "short")) { + numShort++; + continue; + } + if (skipToken(begin, end, "unsigned")) { + numUnsigned++; + continue; + } + if (skipToken(begin, end, "signed")) { + numSigned++; + continue; + } + if (skipToken(begin, end, "char")) { + numChar++; + continue; + } + break; + } + if (numChar || numShort) { + if (numSigned && numChar) + appendStr("signed "); + if (numUnsigned) + appendStr("unsigned "); + if (numChar) + appendStr("char"); + else + appendStr("short"); + } else if (numLong) { + if (numLong == 1) { + if (numUnsigned) + append('u'); + appendStr("long"); + } else { + if (numUnsigned) + appendStr("unsigned "); + appendStr("long long"); + } + } else if (numUnsigned || numSigned || numInt) { + if (numUnsigned) + append('u'); + appendStr("int"); + } + } + + bool spaceSkiped = true; + while (begin != end) { + char c = *begin++; + if (is_space(c)) { + spaceSkiped = true; + } else if ((c == '\'' && !is_number(last)) || c == '\"') { + begin--; + auto x = skipString(begin, end); + while (begin < x) + append(*begin++); + } else { + if (spaceSkiped && is_ident_char(last) && is_ident_char(c)) + append(' '); + append(c); + spaceSkiped = false; + if (c == '<') { + do { + // template recursion + const char *tpl = skipTemplate(begin, end, true); + normalizeType(begin, tpl, false); + if (tpl == end) + return len; + append(*tpl); + begin = tpl; + } while (*begin++ == ','); + } + } + } + return len; + } +}; + +// Normalize the type between begin and end, and store the data in the output. Returns the length. +// The idea is to first run this function with nullptr as output to allocate the output with the +// size +constexpr int qNormalizeType(const char *begin, const char *end, char *output) +{ + return QTypeNormalizer { output }.normalizeType(begin, end); +} + template constexpr auto typenameHelper() { constexpr auto prefix = sizeof( -#ifdef Q_CC_CLANG - "auto QtPrivate::typenameHelper() [T = ") - 1; -#else - "constexpr auto QtPrivate::typenameHelper() [with T = ") - 1; +#ifdef QT_NAMESPACE + QT_STRINGIFY(QT_NAMESPACE) "::" #endif +#ifdef Q_CC_MSVC + "auto __cdecl QtPrivate::typenameHelper<" +#elif defined(Q_CC_CLANG) + "auto QtPrivate::typenameHelper() [T = " +#else + "constexpr auto QtPrivate::typenameHelper() [with T = " +#endif + ) - 1; +#ifdef Q_CC_MSVC + constexpr int suffix = sizeof(">(void)"); +#else constexpr int suffix = sizeof("]"); - constexpr int len = sizeof(__PRETTY_FUNCTION__) - prefix - suffix; +#endif + +#if !(defined(Q_CC_GNU) && !defined(Q_CC_INTEL) && !defined(Q_CC_CLANG)) + constexpr auto func = Q_FUNC_INFO; + constexpr const char *begin = func + prefix; + constexpr const char *end = func + sizeof(Q_FUNC_INFO) - suffix; + constexpr int len = qNormalizeType(begin, end, nullptr); +#else // GCC < 8.1 did not have Q_FUNC_INFO as constexpr, and GCC 9 has a precompiled header bug + auto func = Q_FUNC_INFO; + const char *begin = func + prefix; + const char *end = func + sizeof(Q_FUNC_INFO) - suffix; + // This is an upper bound of the size since the normalized signature should always be smaller + // (Unless there is a QList -> QVector change, but that should not happen) + constexpr int len = sizeof(Q_FUNC_INFO) - suffix - prefix; +#endif std::array result {}; - for (int i = 0; i < len; ++i) - result[i] = __PRETTY_FUNCTION__[prefix + i]; + qNormalizeType(begin, end, result.data()); return result; } diff --git a/src/tools/moc/moc.cpp b/src/tools/moc/moc.cpp index 5e2e492f94..b37674320d 100644 --- a/src/tools/moc/moc.cpp +++ b/src/tools/moc/moc.cpp @@ -43,30 +43,9 @@ QT_BEGIN_NAMESPACE // only moc needs this function -static QByteArray normalizeType(const QByteArray &ba, bool fixScope = false) +static QByteArray normalizeType(const QByteArray &ba) { - const char *s = ba.constData(); - int len = ba.size(); - char stackbuf[64]; - char *buf = (len >= 64 ? new char[len + 1] : stackbuf); - char *d = buf; - char last = 0; - while(*s && is_space(*s)) - s++; - while (*s) { - while (*s && !is_space(*s)) - last = *d++ = *s++; - while (*s && is_space(*s)) - s++; - if (*s && ((is_ident_char(*s) && is_ident_char(last)) - || ((*s == ':') && (last == '<')))) { - last = *d++ = ' '; - } - } - *d = '\0'; - QByteArray result = normalizeTypeInternal(buf, d, fixScope); - if (buf != stackbuf) - delete [] buf; + QByteArray result = normalizeTypeInternal(ba.constBegin(), ba.constEnd()); return result; } diff --git a/tests/auto/corelib/kernel/qmetaobject/tst_qmetaobject.cpp b/tests/auto/corelib/kernel/qmetaobject/tst_qmetaobject.cpp index c83e7af503..bcd4a66782 100644 --- a/tests/auto/corelib/kernel/qmetaobject/tst_qmetaobject.cpp +++ b/tests/auto/corelib/kernel/qmetaobject/tst_qmetaobject.cpp @@ -1332,7 +1332,7 @@ void tst_QMetaObject::normalizedSignature_data() QTest::newRow("const ref") << "const QString &foo()" << "const QString&foo()"; QTest::newRow("reference") << "QString &foo()" << "QString&foo()"; QTest::newRow("const1") << "void foo(QString const *)" << "void foo(const QString*)"; - QTest::newRow("const2") << "void foo(QString * const)" << "void foo(QString*const)"; + QTest::newRow("const2") << "void foo(QString * const)" << "void foo(QString*)"; QTest::newRow("const3") << "void foo(QString const &)" << "void foo(QString)"; QTest::newRow("const4") << "void foo(const int)" << "void foo(int)"; QTest::newRow("const5") << "void foo(const int, int const, const int &, int const &)" @@ -1342,11 +1342,16 @@ void tst_QMetaObject::normalizedSignature_data() QTest::newRow("const8") << "void foo(QVector)" << "void foo(QVector)"; QTest::newRow("const9") << "void foo(const Foo)" << "void foo(Foo)"; QTest::newRow("const10") << "void foo(Fooconst)" << "void foo(Foo)"; - QTest::newRow("const11") << "void foo(Foo *const)" << "void foo(Foo*const)"; - QTest::newRow("const12") << "void foo(Fooconst*const *const)" << "void foo(Foo*const*const)"; + QTest::newRow("const11") << "void foo(Foo *const)" << "void foo(Foo*)"; + QTest::newRow("const12") << "void foo(Fooconst*const *const)" << "void foo(const Foo*const*)"; QTest::newRow("const13") << "void foo(const Foo&)" << "void foo(Foo)"; QTest::newRow("const14") << "void foo(Fooconst&)" << "void foo(Foo)"; QTest::newRow("QList") << "void foo(QList)" << "void foo(QVector)"; + QTest::newRow("QList1") << "void foo(const Template)" + << "void foo(Template)"; + + QTest::newRow("refref") << "const char* foo(const X &&,X const &&, const X* &&) && " + << "const char*foo(const X&&,const X&&,const X*&&)&&"; QTest::newRow("invalid1") << "a( b" << "a(b"; } @@ -1372,23 +1377,59 @@ void tst_QMetaObject::normalizedType_data() QTest::newRow("template2") << "QVector" << "QVector"; QTest::newRow("template3") << "QMap" << "QMap"; QTest::newRow("template4") << "const QMap &" << "QMap"; - QTest::newRow("template5") << "QVector< ::Foo::Bar>" << "QVector< ::Foo::Bar>"; + QTest::newRow("template5") << "QVector< ::Foo::Bar>" << "QVector<::Foo::Bar>"; QTest::newRow("template6") << "QVector<::Foo::Bar>" << "QVector<::Foo::Bar>"; - QTest::newRow("template7") << "QVector >" << "QVector >"; + QTest::newRow("template7") << "QVector >" << "QVector>"; QTest::newRow("template8") << "QMap" << "QMap"; - QTest::newRow("template9") << "QPair , QPair > >" << "QPair,QPair > >"; + QTest::newRow("template9") << "QPair , QPair > >" << "QPair,QPair>>"; + QTest::newRow("template10") << "QList const" << "QVector"; + QTest::newRow("template11") << " QSharedPointer> 2 )> > const & " + << "QSharedPointer>2)>>"; + QTest::newRow("template_sub") << "X<( Y < 8), (Y >6)> const & " << "X<(Y<8),(Y>6)>"; QTest::newRow("value1") << "const QString &" << "QString"; QTest::newRow("value2") << "QString const &" << "QString"; QTest::newRow("constInName1") << "constconst" << "constconst"; QTest::newRow("constInName2") << "constconst*" << "constconst*"; QTest::newRow("constInName3") << "const constconst&" << "constconst"; - QTest::newRow("constInName4") << "constconst const*const" << "constconst*const"; + QTest::newRow("constInName4") << "constconst const*const" << "const constconst*"; QTest::newRow("class") << "const class foo&" << "foo"; QTest::newRow("struct") << "const struct foo*" << "const foo*"; QTest::newRow("struct2") << "struct foo const*" << "const foo*"; QTest::newRow("enum") << "enum foo" << "foo"; QTest::newRow("void") << "void" << "void"; QTest::newRow("QList") << "QList" << "QVector"; + QTest::newRow("refref") << "X const*const&&" << "const X*const&&"; + QTest::newRow("refref2") << "const X&&" << "const X&&"; + QTest::newRow("long1") << "long unsigned int long" << "unsigned long long"; + QTest::newRow("long2") << "int signed long" << "long"; + QTest::newRow("long3") << "long unsigned" << "ulong"; + QTest::newRow("long double") << " long double" << "long double"; + QTest::newRow("signed char") << "char signed" << "signed char"; + QTest::newRow("unsigned char") << "char unsigned" << "unsigned char"; + QTest::newRow("signed short") << "short signed" << "short"; + QTest::newRow("unsigned shot") << "short unsigned" << "unsigned short"; + QTest::newRow("unsigned shot") << "short unsigned" << "unsigned short"; + QTest::newRow("array1") << "unsigned int [4]" << "uint[4]"; + QTest::newRow("array2") << "unsigned int const [4][5]" << "const uint[4][5]"; + QTest::newRow("array3") << "unsigned[] const" << "uint[]"; + QTest::newRow("nttp1") << "S<'>', int const> const" + << "S<'>',const int>"; + QTest::newRow("nttp2") << "S< \"> \\\">const * \\\\\" , int const> const" + << "S<\"> \\\">const * \\\\\",const int>"; + QTest::newRow("nttp3") << "S<\"Q <\" , int const> const*" + << "const S<\"Q <\",const int>*"; + QTest::newRow("nttp4") << "S< 1'2 , int const> const" + << "S<1'2,const int>"; + QTest::newRow("invalid") << "'const" + << "'const"; + QTest::newRow("anonym1") << "XX::" + << "XX::"; + QTest::newRow("anonym2") << "XX::{unnamed type#1}" + << "XX::{unnamed type#1}"; + QTest::newRow("anonym3") << "struct XX::" + << "XX::"; + QTest::newRow("anonym4") << "XX::(anonymous struct at ./example.cpp:10:13)" + << "XX::(anonymous struct at./example.cpp:10:13)"; } void tst_QMetaObject::normalizedType() @@ -1397,6 +1438,7 @@ void tst_QMetaObject::normalizedType() QFETCH(QString, result); QCOMPARE(QMetaObject::normalizedType(type.toLatin1()), result.toLatin1()); + QCOMPARE(QMetaObject::normalizedType(result.toLatin1()), result.toLatin1()); } void tst_QMetaObject::customPropertyType() diff --git a/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp b/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp index 04c4777e07..0d9dfc1c4c 100644 --- a/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp +++ b/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp @@ -124,6 +124,8 @@ private slots: void customDebugStream(); void unknownType(); void fromType(); + void operatorEq_data(); + void operatorEq(); }; struct BaseGenericType @@ -579,11 +581,11 @@ void tst_QMetaType::typeName_data() // automatic registration QTest::newRow("QHash") << ::qMetaTypeId >() << QString::fromLatin1("QHash"); QTest::newRow("QMap") << ::qMetaTypeId >() << QString::fromLatin1("QMap"); - QTest::newRow("QVector>") << ::qMetaTypeId > >() << QString::fromLatin1("QVector >"); + QTest::newRow("QVector>") << ::qMetaTypeId > >() << QString::fromLatin1("QVector>"); // automatic registration with automatic QList to QVector aliasing QTest::newRow("QList") << ::qMetaTypeId >() << QString::fromLatin1("QVector"); - QTest::newRow("QVector>") << ::qMetaTypeId > >() << QString::fromLatin1("QVector >"); + QTest::newRow("QVector>") << ::qMetaTypeId > >() << QString::fromLatin1("QVector>"); QTest::newRow("CustomQObject*") << ::qMetaTypeId() << QString::fromLatin1("CustomQObject*"); QTest::newRow("CustomGadget") << ::qMetaTypeId() << QString::fromLatin1("CustomGadget"); @@ -1745,7 +1747,7 @@ void tst_QMetaType::automaticTemplateRegistration() PRINT_2ARG_TEMPLATE ) - CREATE_AND_VERIFY_CONTAINER(QList, QList > >) + CREATE_AND_VERIFY_CONTAINER(QList, QList > > >) CREATE_AND_VERIFY_CONTAINER(QVector, void*) CREATE_AND_VERIFY_CONTAINER(QVector, const void*) CREATE_AND_VERIFY_CONTAINER(QList, void*) @@ -2527,6 +2529,50 @@ void tst_QMetaType::fromType() #undef FROMTYPE_CHECK } +template +struct CharTemplate +{ + struct + { + int a; + } x; +}; + +void tst_QMetaType::operatorEq_data() +{ + QTest::addColumn("typeA"); + QTest::addColumn("typeB"); + QTest::addColumn("eq"); + + QTest::newRow("String") << QMetaType(QMetaType::QString) + << QMetaType::fromType() << true; + QTest::newRow("void1") << QMetaType(QMetaType::UnknownType) << QMetaType::fromType() + << true; + QTest::newRow("void2") << QMetaType::fromType() << QMetaType::fromType() + << true; + QTest::newRow("vec1") << QMetaType::fromType>() + << QMetaType::fromType>() << true; + QTest::newRow("vec2") << QMetaType::fromType>() + << QMetaType::fromType>() << false; + QTest::newRow("char1") << QMetaType::fromType'>>() + << QMetaType::fromType', void>>() << true; + QTest::newRow("annon1") << QMetaType::fromType'>::x)>() + << QMetaType::fromType'>::x)>() << true; + QTest::newRow("annon2") << QMetaType::fromType'>::x)>() + << QMetaType::fromType::x)>() << false; +} + +void tst_QMetaType::operatorEq() +{ + QFETCH(QMetaType, typeA); + QFETCH(QMetaType, typeB); + QFETCH(bool, eq); + + QCOMPARE(typeA == typeB, eq); + QCOMPARE(typeB == typeA, eq); + QCOMPARE(typeA != typeB, !eq); + QCOMPARE(typeB != typeA, !eq); +} // Compile-time test, it should be possible to register function pointer types class Undefined; diff --git a/tests/auto/testlib/selftests/expected_signaldumper.junitxml b/tests/auto/testlib/selftests/expected_signaldumper.junitxml index 6609f518a2..0c03988879 100644 --- a/tests/auto/testlib/selftests/expected_signaldumper.junitxml +++ b/tests/auto/testlib/selftests/expected_signaldumper.junitxml @@ -147,7 +147,7 @@ - + @@ -279,7 +279,7 @@ &)@_POINTER_)]]> ())]]> *)_POINTER_)]]> - +*)_POINTER_)]]> diff --git a/tests/auto/testlib/selftests/expected_signaldumper.lightxml b/tests/auto/testlib/selftests/expected_signaldumper.lightxml index 8ce57e4b84..d29319841c 100644 --- a/tests/auto/testlib/selftests/expected_signaldumper.lightxml +++ b/tests/auto/testlib/selftests/expected_signaldumper.lightxml @@ -557,7 +557,7 @@ *)_POINTER_)]]> - + *)_POINTER_)]]> diff --git a/tests/auto/testlib/selftests/expected_signaldumper.tap b/tests/auto/testlib/selftests/expected_signaldumper.tap index 39419280d4..bbaaa025c3 100644 --- a/tests/auto/testlib/selftests/expected_signaldumper.tap +++ b/tests/auto/testlib/selftests/expected_signaldumper.tap @@ -139,7 +139,7 @@ ok 18 - slotEmittingSignalOldSyntax(queued) # Signal: SignalSlotClass(_POINTER_) qVectorRefSignal ((QVector&)@_POINTER_) # Signal: SignalSlotClass(_POINTER_) qVectorConstRefSignal (QVector()) # Signal: SignalSlotClass(_POINTER_) qVectorConstPointerSignal ((const QVector*)_POINTER_) -# Signal: SignalSlotClass(_POINTER_) qVectorPointerConstSignal () +# Signal: SignalSlotClass(_POINTER_) qVectorPointerConstSignal ((QVector*)_POINTER_) # Signal: SignalSlotClass(_POINTER_) qVariantSignal (QVariant()) # Signal: SignalSlotClass(_POINTER_) qVariantSignal (QVariant()) ok 19 - variousTypes() diff --git a/tests/auto/testlib/selftests/expected_signaldumper.teamcity b/tests/auto/testlib/selftests/expected_signaldumper.teamcity index 15bb4ddfe1..dee5aa70ef 100644 --- a/tests/auto/testlib/selftests/expected_signaldumper.teamcity +++ b/tests/auto/testlib/selftests/expected_signaldumper.teamcity @@ -54,7 +54,7 @@ ##teamcity[testStdOut name='slotEmittingSignalOldSyntax(queued)' out='INFO: Signal: SignalSlotClass(_POINTER_) signalWithoutParameters ()|nINFO: Signal: QEventDispatcherPlatform(_POINTER_) awake ()|nINFO: Signal: SignalSlotClass(_POINTER_) nestedSignal ()' flowId='tst_Signaldumper'] ##teamcity[testFinished name='slotEmittingSignalOldSyntax(queued)' flowId='tst_Signaldumper'] ##teamcity[testStarted name='variousTypes()' flowId='tst_Signaldumper'] -##teamcity[testStdOut name='variousTypes()' out='INFO: Signal: SignalSlotClass(_POINTER_) qStringSignal (QString(Test string))|nINFO: Signal: SignalSlotClass(_POINTER_) qStringRefSignal ((QString&)@_POINTER_)|nINFO: Signal: SignalSlotClass(_POINTER_) qStringConstRefSignal (QString(Test string))|nINFO: Signal: SignalSlotClass(_POINTER_) qByteArraySignal (QByteArray(Test bytearray))|nINFO: Signal: SignalSlotClass(_POINTER_) qListSignal (QVector())|nINFO: Signal: SignalSlotClass(_POINTER_) qVectorSignal (QVector())|nINFO: Signal: SignalSlotClass(_POINTER_) qVectorRefSignal ((QVector&)@_POINTER_)|nINFO: Signal: SignalSlotClass(_POINTER_) qVectorConstRefSignal (QVector())|nINFO: Signal: SignalSlotClass(_POINTER_) qVectorConstPointerSignal ((const QVector*)_POINTER_)|nINFO: Signal: SignalSlotClass(_POINTER_) qVectorPointerConstSignal ()|nINFO: Signal: SignalSlotClass(_POINTER_) qVariantSignal (QVariant())|nINFO: Signal: SignalSlotClass(_POINTER_) qVariantSignal (QVariant())' flowId='tst_Signaldumper'] +##teamcity[testStdOut name='variousTypes()' out='INFO: Signal: SignalSlotClass(_POINTER_) qStringSignal (QString(Test string))|nINFO: Signal: SignalSlotClass(_POINTER_) qStringRefSignal ((QString&)@_POINTER_)|nINFO: Signal: SignalSlotClass(_POINTER_) qStringConstRefSignal (QString(Test string))|nINFO: Signal: SignalSlotClass(_POINTER_) qByteArraySignal (QByteArray(Test bytearray))|nINFO: Signal: SignalSlotClass(_POINTER_) qListSignal (QVector())|nINFO: Signal: SignalSlotClass(_POINTER_) qVectorSignal (QVector())|nINFO: Signal: SignalSlotClass(_POINTER_) qVectorRefSignal ((QVector&)@_POINTER_)|nINFO: Signal: SignalSlotClass(_POINTER_) qVectorConstRefSignal (QVector())|nINFO: Signal: SignalSlotClass(_POINTER_) qVectorConstPointerSignal ((const QVector*)_POINTER_)|nINFO: Signal: SignalSlotClass(_POINTER_) qVectorPointerConstSignal ((QVector*)_POINTER_)|nINFO: Signal: SignalSlotClass(_POINTER_) qVariantSignal (QVariant())|nINFO: Signal: SignalSlotClass(_POINTER_) qVariantSignal (QVariant())' flowId='tst_Signaldumper'] ##teamcity[testFinished name='variousTypes()' flowId='tst_Signaldumper'] ##teamcity[testStarted name='deletingSender()' flowId='tst_Signaldumper'] ##teamcity[testStdOut name='deletingSender()' out='INFO: Signal: SignalSlotClass(_POINTER_) signalWithoutParameters ()' flowId='tst_Signaldumper'] diff --git a/tests/auto/testlib/selftests/expected_signaldumper.txt b/tests/auto/testlib/selftests/expected_signaldumper.txt index 92d609d14c..86d817cd5f 100644 --- a/tests/auto/testlib/selftests/expected_signaldumper.txt +++ b/tests/auto/testlib/selftests/expected_signaldumper.txt @@ -139,7 +139,7 @@ INFO : tst_Signaldumper::variousTypes() Signal: SignalSlotClass(_POINTER_) qVe INFO : tst_Signaldumper::variousTypes() Signal: SignalSlotClass(_POINTER_) qVectorRefSignal ((QVector&)@_POINTER_) INFO : tst_Signaldumper::variousTypes() Signal: SignalSlotClass(_POINTER_) qVectorConstRefSignal (QVector()) INFO : tst_Signaldumper::variousTypes() Signal: SignalSlotClass(_POINTER_) qVectorConstPointerSignal ((const QVector*)_POINTER_) -INFO : tst_Signaldumper::variousTypes() Signal: SignalSlotClass(_POINTER_) qVectorPointerConstSignal () +INFO : tst_Signaldumper::variousTypes() Signal: SignalSlotClass(_POINTER_) qVectorPointerConstSignal ((QVector*)_POINTER_) INFO : tst_Signaldumper::variousTypes() Signal: SignalSlotClass(_POINTER_) qVariantSignal (QVariant()) INFO : tst_Signaldumper::variousTypes() Signal: SignalSlotClass(_POINTER_) qVariantSignal (QVariant()) PASS : tst_Signaldumper::variousTypes() diff --git a/tests/auto/testlib/selftests/expected_signaldumper.xml b/tests/auto/testlib/selftests/expected_signaldumper.xml index 01b0471268..c61832ec4a 100644 --- a/tests/auto/testlib/selftests/expected_signaldumper.xml +++ b/tests/auto/testlib/selftests/expected_signaldumper.xml @@ -559,7 +559,7 @@ *)_POINTER_)]]> - + *)_POINTER_)]]> diff --git a/tests/auto/tools/moc/allmocs_baseline_in.json b/tests/auto/tools/moc/allmocs_baseline_in.json index 0ce464a709..4f57fad5a8 100644 --- a/tests/auto/tools/moc/allmocs_baseline_in.json +++ b/tests/auto/tools/moc/allmocs_baseline_in.json @@ -1305,7 +1305,7 @@ "type": "int" }, { - "type": "QObject*const" + "type": "QObject*" } ], "name": "slot", @@ -2586,7 +2586,7 @@ "access": "public", "arguments": [ { - "type": "QVector >" + "type": "QVector>" } ], "name": "foo", @@ -2596,7 +2596,7 @@ "access": "public", "arguments": [ { - "type": "QVector >" + "type": "QVector>" } ], "name": "foo2", @@ -2606,7 +2606,7 @@ "access": "public", "arguments": [ { - "type": "QVector< ::AAA::BaseA*>" + "type": "QVector<::AAA::BaseA*>" } ], "name": "bar", @@ -2616,7 +2616,7 @@ "access": "public", "arguments": [ { - "type": "QVector< ::AAA::BaseA*>" + "type": "QVector<::AAA::BaseA*>" } ], "name": "bar2", @@ -2626,7 +2626,7 @@ "access": "public", "arguments": [ { - "type": "QVector" + "type": "QVector" } ], "name": "bar3", diff --git a/tests/auto/tools/moc/tst_moc.cpp b/tests/auto/tools/moc/tst_moc.cpp index be86fc8e21..08c604e37e 100644 --- a/tests/auto/tools/moc/tst_moc.cpp +++ b/tests/auto/tools/moc/tst_moc.cpp @@ -1827,8 +1827,8 @@ void tst_Moc::QTBUG12260_defaultTemplate() { QVERIFY(QTBUG12260_defaultTemplate_Object::staticMetaObject.indexOfSlot("doSomething(QHash)") != -1); QVERIFY(QTBUG12260_defaultTemplate_Object::staticMetaObject.indexOfSlot("doAnotherThing(bool,bool)") != -1); - QVERIFY(QTBUG12260_defaultTemplate_Object::staticMetaObject.indexOfSlot("doSomethingElse(QSharedPointer>2)> >)") != -1); - QVERIFY(QTBUG12260_defaultTemplate_Object::staticMetaObject.indexOfSlot("performSomething(QVector >,QHash >)") != -1); + QVERIFY(QTBUG12260_defaultTemplate_Object::staticMetaObject.indexOfSlot("doSomethingElse(QSharedPointer>2)>>)") != -1); + QVERIFY(QTBUG12260_defaultTemplate_Object::staticMetaObject.indexOfSlot("performSomething(QVector>,QHash>)") != -1); } void tst_Moc::notifyError()