Make parsing of template arguments more robust.

At first, my goal was just to fix Moc::until() to parse properly
template arguments containing expressions containing > or >>
such as Foo<(8>>2)>

But with the test, I realized that normalizeType also requires change
not to split the > > too much.

And QMetaObjectPrivate::decodeMethodSignature should not interpret
the ) within the template parameter as the end of the function.

Change-Id: Ia9d3a2a786368aeda1edcf66280d70f64cf05070
Reviewed-by: Lars Knoll <lars.knoll@digia.com>
This commit is contained in:
Olivier Goffart 2013-03-04 16:52:12 +01:00 committed by The Qt Project
parent 8e261ac756
commit 2b26f801b5
4 changed files with 62 additions and 28 deletions

View File

@ -677,7 +677,7 @@ QByteArray QMetaObjectPrivate::decodeMethodSignature(
const char *lparens = strchr(signature, '(');
if (!lparens)
return QByteArray();
const char *rparens = strchr(lparens + 1, ')');
const char *rparens = strrchr(lparens + 1, ')');
if (!rparens || *(rparens+1))
return QByteArray();
int nameLength = lparens - signature;

View File

@ -155,21 +155,28 @@ static QByteArray normalizeTypeInternal(const char *t, const char *e, bool fixSc
//template recursion
const char* tt = t;
int templdepth = 1;
int scopeDepth = 0;
while (t != e) {
c = *t++;
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;
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;
}
tt = t;
}
}
}

View File

@ -224,14 +224,7 @@ Type Moc::parseType()
;
}
if (test(LANGLE)) {
QByteArray templ = lexemUntil(RANGLE);
for (int i = 0; i < templ.size(); ++i) {
type.name += templ.at(i);
if ((templ.at(i) == '<' && i+1 < templ.size() && templ.at(i+1) == ':')
|| (templ.at(i) == '>' && i+1 < templ.size() && templ.at(i+1) == '>')) {
type.name += ' ';
}
}
type.name += lexemUntil(RANGLE);
}
if (test(SCOPE)) {
type.name += lexem();
@ -1395,10 +1388,14 @@ QByteArray Moc::lexemUntil(Token target)
QByteArray s;
while (from <= index) {
QByteArray n = symbols.at(from++-1).lexem();
if (s.size() && n.size()
&& is_ident_char(s.at(s.size()-1))
&& is_ident_char(n.at(0)))
s += ' ';
if (s.size() && n.size()) {
char prev = s.at(s.size()-1);
char next = n.at(0);
if ((is_ident_char(prev) && is_ident_char(next))
|| (prev == '<' && next == ':')
|| (prev == '>' && next == '>'))
s += ' ';
}
s += n;
}
return s;
@ -1433,9 +1430,20 @@ bool Moc::until(Token target) {
case RBRACK: --brackCount; break;
case LPAREN: ++parenCount; break;
case RPAREN: --parenCount; break;
case LANGLE: ++angleCount; break;
case RANGLE: --angleCount; break;
case GTGT: angleCount -= 2; t = RANGLE; break;
case LANGLE:
if (parenCount == 0 && braceCount == 0 && parenCount == 0)
++angleCount;
break;
case RANGLE:
if (parenCount == 0 && braceCount == 0)
--angleCount;
break;
case GTGT:
if (parenCount == 0 && braceCount == 0) {
angleCount -= 2;
t = RANGLE;
}
break;
default: break;
}
if (t == target

View File

@ -1538,13 +1538,30 @@ class QTBUG12260_defaultTemplate_Object : public QObject
public slots:
#if !(defined(Q_CC_GNU) && __GNUC__ == 4 && __GNUC_MINOR__ <= 3) || defined(Q_MOC_RUN)
void doSomething(QHash<QString, QVariant> values = QHash<QString, QVariant>() ) { Q_UNUSED(values); }
void doSomethingElse(QSharedPointer<QVarLengthArray<QString, (16 >> 2)> > val
= QSharedPointer<QVarLengthArray<QString, (16 >> 2)> >() )
{ Q_UNUSED(val); }
#else
// we want to test the previous function, but gcc < 4.4 seemed to have a bug similar to the one moc has.
typedef QHash<QString, QVariant> WorkaroundGCCBug;
void doSomething(QHash<QString, QVariant> values = WorkaroundGCCBug() ) { Q_UNUSED(values); }
void doSomethingElse(QSharedPointer<QVarLengthArray<QString, (16 >> 2)> > val
= (QSharedPointer<QVarLengthArray<QString, (16 >> 2)> >()) )
{ Q_UNUSED(val); }
#endif
void doAnotherThing(bool a = (1 < 3), bool b = (1 > 4)) { Q_UNUSED(a); Q_UNUSED(b); }
#if defined(Q_MOC_RUN) || (defined(Q_COMPILER_AUTO_TYPE) && !(defined(Q_CC_CLANG) && (__clang_major__ * 100) + __clang_minor__) < 304)
// There is no Q_COMPILER_>> but if compiler support auto, it should also support >>
void performSomething(QVector<QList<QString>> e = QVector<QList<QString>>(8 < 1),
QHash<int, QVector<QString>> h = QHash<int, QVector<QString>>())
{ Q_UNUSED(e); Q_UNUSED(h); }
#else
void performSomething(QVector<QList<QString> > e = QVector<QList<QString> >(),
QHash<int, QVector<QString> > h = (QHash<int, QVector<QString> >()))
{ Q_UNUSED(e); Q_UNUSED(h); }
#endif
};
@ -1552,6 +1569,8 @@ void tst_Moc::QTBUG12260_defaultTemplate()
{
QVERIFY(QTBUG12260_defaultTemplate_Object::staticMetaObject.indexOfSlot("doSomething(QHash<QString,QVariant>)") != -1);
QVERIFY(QTBUG12260_defaultTemplate_Object::staticMetaObject.indexOfSlot("doAnotherThing(bool,bool)") != -1);
QVERIFY(QTBUG12260_defaultTemplate_Object::staticMetaObject.indexOfSlot("doSomethingElse(QSharedPointer<QVarLengthArray<QString,(16>>2)> >)") != -1);
QVERIFY(QTBUG12260_defaultTemplate_Object::staticMetaObject.indexOfSlot("performSomething(QVector<QList<QString> >,QHash<int,QVector<QString> >)") != -1);
}
void tst_Moc::notifyError()