From 0c9d1f99dac5c118d49e7f2b04f70eae3ba7b837 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Nowacki?= Date: Thu, 30 Oct 2014 13:24:22 +0100 Subject: Fix moc preprocessor When tokenizing, after macro expansion, moc needs to concatenate subsequent string literals, because parser do not check for such expressions. Change-Id: Icc4f01395a5a7b67368eb8341a45ee74ade7d7f5 Reviewed-by: Olivier Goffart --- src/tools/moc/preprocessor.cpp | 31 +++++++++++++++++++++++++++++++ tests/auto/tools/moc/tst_moc.cpp | 40 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+) diff --git a/src/tools/moc/preprocessor.cpp b/src/tools/moc/preprocessor.cpp index ff435085b4..7642ca220b 100644 --- a/src/tools/moc/preprocessor.cpp +++ b/src/tools/moc/preprocessor.cpp @@ -972,6 +972,36 @@ static QByteArray readOrMapFile(QFile *file) return rawInput ? QByteArray::fromRawData(rawInput, size) : file->readAll(); } +static void mergeStringLiterals(Symbols *_symbols) +{ + Symbols &symbols = *_symbols; + for (Symbols::iterator i = symbols.begin(); i != symbols.end(); ++i) { + if (i->token == STRING_LITERAL) { + Symbols::Iterator mergeSymbol = i; + int literalsLength = mergeSymbol->len; + while (++i != symbols.end() && i->token == STRING_LITERAL) + literalsLength += i->len - 2; // no quotes + + if (literalsLength != mergeSymbol->len) { + QByteArray mergeSymbolOriginalLexem = mergeSymbol->unquotedLexem(); + QByteArray &mergeSymbolLexem = mergeSymbol->lex; + mergeSymbolLexem.resize(0); + mergeSymbolLexem.reserve(literalsLength); + mergeSymbolLexem.append('"'); + mergeSymbolLexem.append(mergeSymbolOriginalLexem); + for (Symbols::const_iterator j = mergeSymbol + 1; j != i; ++j) + mergeSymbolLexem.append(j->lex.constData() + j->from + 1, j->len - 2); // append j->unquotedLexem() + mergeSymbolLexem.append('"'); + mergeSymbol->len = mergeSymbol->lex.length(); + mergeSymbol->from = 0; + i = symbols.erase(mergeSymbol + 1, i); + } + if (i == symbols.end()) + break; + } + } +} + void Preprocessor::preprocess(const QByteArray &filename, Symbols &preprocessed) { currentFilenames.push(filename); @@ -1190,6 +1220,7 @@ Symbols Preprocessor::preprocessed(const QByteArray &filename, QFile *file) // phase 3: preprocess conditions and substitute macros Symbols result; preprocess(filename, result); + mergeStringLiterals(&result); #if 0 for (int j = 0; j < result.size(); ++j) diff --git a/tests/auto/tools/moc/tst_moc.cpp b/tests/auto/tools/moc/tst_moc.cpp index 13e786cd20..965a16e7c2 100644 --- a/tests/auto/tools/moc/tst_moc.cpp +++ b/tests/auto/tools/moc/tst_moc.cpp @@ -572,6 +572,7 @@ private slots: void relatedMetaObjectsInGadget(); void relatedMetaObjectsNameConflict_data(); void relatedMetaObjectsNameConflict(); + void strignLiteralsInMacroExtension(); signals: void sigWithUnsignedArg(unsigned foo); @@ -3269,6 +3270,45 @@ void tst_Moc::relatedMetaObjectsNameConflict() QCOMPARE(dependency.size(), relatedMetaObjects.size()); } +class StringLiteralsInMacroExtension: public QObject +{ + Q_OBJECT +#define Macro(F) F " " F + Q_CLASSINFO(Macro("String"), Macro("Literal")) +#undef Macro + +#define Macro(F) F + Q_CLASSINFO("String" Macro("!"), "Literal" Macro("!")) + Q_CLASSINFO(Macro("!") "String", Macro("!") "Literal") +#undef Macro + +#define Macro "foo" + Q_CLASSINFO("String" Macro, "Literal" Macro) + Q_CLASSINFO(Macro "String", Macro "Literal") +#undef Macro +}; + +void tst_Moc::strignLiteralsInMacroExtension() +{ + const QMetaObject *mobj = &StringLiteralsInMacroExtension::staticMetaObject; + QCOMPARE(mobj->classInfoCount(), 5); + + QCOMPARE(mobj->classInfo(0).name(), "String String"); + QCOMPARE(mobj->classInfo(0).value(), "Literal Literal"); + + QCOMPARE(mobj->classInfo(1).name(), "String!"); + QCOMPARE(mobj->classInfo(1).value(), "Literal!"); + + QCOMPARE(mobj->classInfo(2).name(), "!String"); + QCOMPARE(mobj->classInfo(2).value(), "!Literal"); + + QCOMPARE(mobj->classInfo(3).name(), "Stringfoo"); + QCOMPARE(mobj->classInfo(3).value(), "Literalfoo"); + + QCOMPARE(mobj->classInfo(4).name(), "fooString"); + QCOMPARE(mobj->classInfo(4).value(), "fooLiteral"); +} + QTEST_MAIN(tst_Moc) // the generated code must compile with QT_NO_KEYWORDS -- cgit v1.2.3