forked from qt-creator/qt-creator
Add test case to preprocessor.
- This enables some tests which had been unexpectedly disabled in earlier test. - Tests to show issue QTCREATORBUG-7225. - Tests which validates somehow behavior of preprocessor for QTCREATORBUG-7217: the test passes, so the problem is likely not in the startExpandingMacro() notification. Change-Id: Ib7c1433e4dcdd8c1d19fa117371f94c1645ec3fb Reviewed-by: Roberto Raggi <roberto.raggi@nokia.com>
This commit is contained in:
committed by
Roberto Raggi
parent
5c7bc3949c
commit
1a10bcdaad
@@ -109,12 +109,15 @@ public:
|
|||||||
virtual void passedMacroDefinitionCheck(unsigned /*offset*/, const Macro &/*macro*/) {}
|
virtual void passedMacroDefinitionCheck(unsigned /*offset*/, const Macro &/*macro*/) {}
|
||||||
virtual void failedMacroDefinitionCheck(unsigned /*offset*/, const QByteArray &/*name*/) {}
|
virtual void failedMacroDefinitionCheck(unsigned /*offset*/, const QByteArray &/*name*/) {}
|
||||||
|
|
||||||
virtual void startExpandingMacro(unsigned /*offset*/,
|
virtual void startExpandingMacro(unsigned offset,
|
||||||
const Macro &/*macro*/,
|
const Macro &/*macro*/,
|
||||||
const QByteArray &originalText,
|
const QByteArray &originalText,
|
||||||
const QVector<MacroArgumentReference> &/*actuals*/
|
const QVector<MacroArgumentReference> &/*actuals*/
|
||||||
= QVector<MacroArgumentReference>())
|
= QVector<MacroArgumentReference>())
|
||||||
{ m_expandedMacros.append(originalText); }
|
{
|
||||||
|
m_expandedMacros.append(originalText);
|
||||||
|
m_expandedMacrosOffset.append(offset);
|
||||||
|
}
|
||||||
|
|
||||||
virtual void stopExpandingMacro(unsigned /*offset*/,
|
virtual void stopExpandingMacro(unsigned /*offset*/,
|
||||||
const Macro &/*macro*/) {}
|
const Macro &/*macro*/) {}
|
||||||
@@ -210,6 +213,9 @@ public:
|
|||||||
QList<QByteArray> expandedMacros() const
|
QList<QByteArray> expandedMacros() const
|
||||||
{ return m_expandedMacros; }
|
{ return m_expandedMacros; }
|
||||||
|
|
||||||
|
QList<unsigned> expandedMacrosOffset() const
|
||||||
|
{ return m_expandedMacrosOffset; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Environment *m_env;
|
Environment *m_env;
|
||||||
QByteArray *m_output;
|
QByteArray *m_output;
|
||||||
@@ -219,8 +225,34 @@ private:
|
|||||||
QList<Block> m_skippedBlocks;
|
QList<Block> m_skippedBlocks;
|
||||||
QList<Include> m_recordedIncludes;
|
QList<Include> m_recordedIncludes;
|
||||||
QList<QByteArray> m_expandedMacros;
|
QList<QByteArray> m_expandedMacros;
|
||||||
|
QList<unsigned> m_expandedMacrosOffset;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
namespace QTest {
|
||||||
|
template<> char *toString(const QList<unsigned> &list)
|
||||||
|
{
|
||||||
|
QByteArray ba = "QList<unsigned>(";
|
||||||
|
foreach (const unsigned& item, list) {
|
||||||
|
ba += QTest::toString(item);
|
||||||
|
ba += ',';
|
||||||
|
}
|
||||||
|
if (!list.isEmpty())
|
||||||
|
ba[ba.size() - 1] = ')';
|
||||||
|
return qstrdup(ba.data());
|
||||||
|
}
|
||||||
|
template<> char *toString(const QList<QByteArray> &list)
|
||||||
|
{
|
||||||
|
QByteArray ba = "QList<QByteArray>(";
|
||||||
|
foreach (const QByteArray& item, list) {
|
||||||
|
ba += QTest::toString(item);
|
||||||
|
ba += ',';
|
||||||
|
}
|
||||||
|
if (!list.isEmpty())
|
||||||
|
ba[ba.size() - 1] = ')';
|
||||||
|
return qstrdup(ba.data());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QDebug &operator<<(QDebug& d, const MockClient::Block &b) { d << '[' << b.start << ',' << b.end << ']'; return d; }
|
QDebug &operator<<(QDebug& d, const MockClient::Block &b) { d << '[' << b.start << ',' << b.end << ']'; return d; }
|
||||||
|
|
||||||
class tst_Preprocessor: public QObject
|
class tst_Preprocessor: public QObject
|
||||||
@@ -236,9 +268,12 @@ protected:
|
|||||||
client.sourceNeeded("data/" + fileName, nolines);
|
client.sourceNeeded("data/" + fileName, nolines);
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
static QString simplified(QByteArray buf);
|
||||||
|
|
||||||
private /* not corrected yet */:
|
private /* not corrected yet */:
|
||||||
void macro_definition_lineno();
|
void macro_definition_lineno();
|
||||||
|
void param_expanding_as_multiple_params();
|
||||||
|
void macro_argument_expansion();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void va_args();
|
void va_args();
|
||||||
@@ -246,6 +281,7 @@ private slots:
|
|||||||
void first_empty_macro_arg();
|
void first_empty_macro_arg();
|
||||||
void invalid_param_count();
|
void invalid_param_count();
|
||||||
void objmacro_expanding_as_fnmacro_notification();
|
void objmacro_expanding_as_fnmacro_notification();
|
||||||
|
void macro_uses();
|
||||||
void macro_arguments_notificatin();
|
void macro_arguments_notificatin();
|
||||||
void unfinished_function_like_macro_call();
|
void unfinished_function_like_macro_call();
|
||||||
void nasty_macro_expansion();
|
void nasty_macro_expansion();
|
||||||
@@ -259,6 +295,30 @@ private slots:
|
|||||||
void comparisons();
|
void comparisons();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Remove all #... lines, and 'simplify' string, to allow easily comparing the result
|
||||||
|
// Also, remove all unneeded spaces: keep only to ensure identifiers are separated.
|
||||||
|
// NOTE: may not correctly handle underscore in identifiers
|
||||||
|
QString tst_Preprocessor::simplified(QByteArray buf)
|
||||||
|
{
|
||||||
|
QString out;
|
||||||
|
QList<QByteArray> lines = buf.split('\n');
|
||||||
|
foreach (QByteArray line, lines)
|
||||||
|
if (!line.startsWith('#')) {
|
||||||
|
out.append(' ');
|
||||||
|
out.append(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
out = out.simplified();
|
||||||
|
for (int i=1; i<out.length()-1; ) {
|
||||||
|
if (out.at(i).isSpace() && !(out.at(i-1).isLetterOrNumber() && out.at(i+1).isLetterOrNumber()))
|
||||||
|
out.remove(i,1);
|
||||||
|
else
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
void tst_Preprocessor::va_args()
|
void tst_Preprocessor::va_args()
|
||||||
{
|
{
|
||||||
Client *client = 0; // no client.
|
Client *client = 0; // no client.
|
||||||
@@ -275,9 +335,7 @@ void tst_Preprocessor::va_args()
|
|||||||
|
|
||||||
preprocessed = preprocessed.simplified();
|
preprocessed = preprocessed.simplified();
|
||||||
// DUMP_OUTPUT(preprocessed);
|
// DUMP_OUTPUT(preprocessed);
|
||||||
QVERIFY(preprocessed.contains("int f();"));
|
QCOMPARE(simplified(preprocessed), QString("int f();int f(int a);int f(int a,int b);"));
|
||||||
QVERIFY(preprocessed.contains("int f( int a );"));
|
|
||||||
QVERIFY(preprocessed.contains("int f( int a, int b );"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void tst_Preprocessor::named_va_args()
|
void tst_Preprocessor::named_va_args()
|
||||||
@@ -294,9 +352,7 @@ void tst_Preprocessor::named_va_args()
|
|||||||
true, false);
|
true, false);
|
||||||
|
|
||||||
preprocessed = preprocessed.simplified();
|
preprocessed = preprocessed.simplified();
|
||||||
QVERIFY(preprocessed.contains("int f();"));
|
QCOMPARE(simplified(preprocessed), QString("int f();int f(int a);int f(int a,int b);"));
|
||||||
QVERIFY(preprocessed.contains("int f( int a );"));
|
|
||||||
QVERIFY(preprocessed.contains("int f( int a, int b );"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void tst_Preprocessor::first_empty_macro_arg()
|
void tst_Preprocessor::first_empty_macro_arg()
|
||||||
@@ -314,9 +370,7 @@ void tst_Preprocessor::first_empty_macro_arg()
|
|||||||
|
|
||||||
preprocessed = preprocessed.simplified();
|
preprocessed = preprocessed.simplified();
|
||||||
// DUMP_OUTPUT(preprocessed);
|
// DUMP_OUTPUT(preprocessed);
|
||||||
QVERIFY(preprocessed.contains("const int cVal ;"));
|
QCOMPARE(simplified(preprocessed), QString("const int cVal;int Val;int Val2;"));
|
||||||
QVERIFY(preprocessed.contains("int Val ;"));
|
|
||||||
QVERIFY(preprocessed.contains("int Val2 ;"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void tst_Preprocessor::invalid_param_count()
|
void tst_Preprocessor::invalid_param_count()
|
||||||
@@ -335,6 +389,55 @@ void tst_Preprocessor::invalid_param_count()
|
|||||||
// do not verify the output: it's illegal, so anything might be outputted.
|
// do not verify the output: it's illegal, so anything might be outputted.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tst_Preprocessor::param_expanding_as_multiple_params()
|
||||||
|
{
|
||||||
|
Client *client = 0; // no client.
|
||||||
|
Environment env;
|
||||||
|
|
||||||
|
Preprocessor preprocess(client, &env);
|
||||||
|
QByteArray preprocessed = preprocess(QLatin1String("<stdin>"),
|
||||||
|
QByteArray("\n#define foo(a,b) int f(a,b);"
|
||||||
|
"\n#define ARGS(t) t a,t b"
|
||||||
|
"\nfoo(ARGS(int))"));
|
||||||
|
QCOMPARE(simplified(preprocessed), QString("int f(int a,int b);"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_Preprocessor::macro_argument_expansion() //QTCREATORBUG-7225
|
||||||
|
{
|
||||||
|
Client *client = 0; // no client.
|
||||||
|
Environment env;
|
||||||
|
|
||||||
|
Preprocessor preprocess(client, &env);
|
||||||
|
QByteArray preprocessed = preprocess(QLatin1String("<stdin>"),
|
||||||
|
QByteArray("\n#define BAR1 2,3,4"
|
||||||
|
"\n#define FOO1(a,b,c) a+b+c"
|
||||||
|
"\nvoid test2(){"
|
||||||
|
"\nint x=FOO1(BAR1);"
|
||||||
|
"\n}"));
|
||||||
|
QCOMPARE(simplified(preprocessed), QString("void test2(){int x=2+3+4;}"));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_Preprocessor::macro_uses()
|
||||||
|
{
|
||||||
|
QByteArray buffer = QByteArray("\n#define FOO 8"
|
||||||
|
"\n#define BAR 9"
|
||||||
|
"\nvoid test(){"
|
||||||
|
"\n\tint x=FOO;"
|
||||||
|
"\n\tint y=BAR;"
|
||||||
|
"\n}");
|
||||||
|
|
||||||
|
QByteArray output;
|
||||||
|
Environment env;
|
||||||
|
MockClient client(&env, &output);
|
||||||
|
|
||||||
|
Preprocessor preprocess(&client, &env);
|
||||||
|
QByteArray preprocessed = preprocess(QLatin1String("<stdin>"), buffer);
|
||||||
|
QCOMPARE(simplified(preprocessed), QString("void test(){int x=8;int y=9;}"));
|
||||||
|
QCOMPARE(client.expandedMacros(), QList<QByteArray>() << QByteArray("FOO") << QByteArray("BAR"));
|
||||||
|
QCOMPARE(client.expandedMacrosOffset(), QList<unsigned>() << buffer.indexOf("FOO;") << buffer.indexOf("BAR;"));
|
||||||
|
}
|
||||||
|
|
||||||
void tst_Preprocessor::macro_definition_lineno()
|
void tst_Preprocessor::macro_definition_lineno()
|
||||||
{
|
{
|
||||||
Client *client = 0; // no client.
|
Client *client = 0; // no client.
|
||||||
@@ -343,30 +446,30 @@ void tst_Preprocessor::macro_definition_lineno()
|
|||||||
QByteArray preprocessed = preprocess(QLatin1String("<stdin>"),
|
QByteArray preprocessed = preprocess(QLatin1String("<stdin>"),
|
||||||
QByteArray("#define foo(ARGS) int f(ARGS)\n"
|
QByteArray("#define foo(ARGS) int f(ARGS)\n"
|
||||||
"foo(int a);\n"));
|
"foo(int a);\n"));
|
||||||
QVERIFY(preprocessed.contains("#gen true\n# 2 "));
|
QVERIFY(preprocessed.contains("#gen true\n# 2 \"<stdin>\"\nint f"));
|
||||||
|
|
||||||
preprocessed = preprocess(QLatin1String("<stdin>"),
|
preprocessed = preprocess(QLatin1String("<stdin>"),
|
||||||
QByteArray("#define foo(ARGS) int f(ARGS)\n"
|
QByteArray("#define foo(ARGS) int f(ARGS)\n"
|
||||||
"foo(int a)\n"
|
"foo(int a)\n"
|
||||||
";\n"));
|
";\n"));
|
||||||
QVERIFY(preprocessed.contains("#gen true\n# 2 "));
|
QVERIFY(preprocessed.contains("#gen true\n# 2 \"<stdin>\"\nint f"));
|
||||||
|
|
||||||
preprocessed = preprocess(QLatin1String("<stdin>"),
|
preprocessed = preprocess(QLatin1String("<stdin>"),
|
||||||
QByteArray("#define foo(ARGS) int f(ARGS)\n"
|
QByteArray("#define foo(ARGS) int f(ARGS)\n"
|
||||||
"foo(int \n"
|
"foo(int \n"
|
||||||
" a);\n"));
|
" a);\n"));
|
||||||
QVERIFY(preprocessed.contains("#gen true\n# 2 "));
|
QVERIFY(preprocessed.contains("#gen true\n# 2 \"<stdin>\"\nint f"));
|
||||||
|
|
||||||
preprocessed = preprocess(QLatin1String("<stdin>"),
|
preprocessed = preprocess(QLatin1String("<stdin>"),
|
||||||
QByteArray("#define foo int f\n"
|
QByteArray("#define foo int f\n"
|
||||||
"foo;\n"));
|
"foo;\n"));
|
||||||
QVERIFY(preprocessed.contains("#gen true\n# 2 "));
|
QVERIFY(preprocessed.contains("#gen true\n# 2 \"<stdin>\"\nint f"));
|
||||||
|
|
||||||
preprocessed = preprocess(QLatin1String("<stdin>"),
|
preprocessed = preprocess(QLatin1String("<stdin>"),
|
||||||
QByteArray("#define foo int f\n"
|
QByteArray("#define foo int f\n"
|
||||||
"foo\n"
|
"foo\n"
|
||||||
";\n"));
|
";\n"));
|
||||||
QVERIFY(preprocessed.contains("#gen true\n# 2 "));
|
QVERIFY(preprocessed.contains("#gen true\n# 2 \"<stdin>\"\nint f"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void tst_Preprocessor::objmacro_expanding_as_fnmacro_notification()
|
void tst_Preprocessor::objmacro_expanding_as_fnmacro_notification()
|
||||||
@@ -523,7 +626,6 @@ void tst_Preprocessor::test_file_builtin()
|
|||||||
|
|
||||||
void tst_Preprocessor::comparisons_data()
|
void tst_Preprocessor::comparisons_data()
|
||||||
{
|
{
|
||||||
/*
|
|
||||||
QTest::addColumn<QString>("infile");
|
QTest::addColumn<QString>("infile");
|
||||||
QTest::addColumn<QString>("outfile");
|
QTest::addColumn<QString>("outfile");
|
||||||
QTest::addColumn<QString>("errorfile");
|
QTest::addColumn<QString>("errorfile");
|
||||||
@@ -541,7 +643,6 @@ void tst_Preprocessor::comparisons_data()
|
|||||||
QTest::newRow("macro-test") << "macro-test.cpp" << "macro-test.out.cpp" << "";
|
QTest::newRow("macro-test") << "macro-test.cpp" << "macro-test.out.cpp" << "";
|
||||||
QTest::newRow("empty-macro") << "empty-macro.cpp" << "empty-macro.out.cpp" << "";
|
QTest::newRow("empty-macro") << "empty-macro.cpp" << "empty-macro.out.cpp" << "";
|
||||||
QTest::newRow("empty-macro 2") << "empty-macro.2.cpp" << "empty-macro.2.out.cpp" << "";
|
QTest::newRow("empty-macro 2") << "empty-macro.2.cpp" << "empty-macro.2.out.cpp" << "";
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void tst_Preprocessor::comparisons()
|
void tst_Preprocessor::comparisons()
|
||||||
|
Reference in New Issue
Block a user