~ubuntu-branches/debian/sid/kdevelop/sid

« back to all changes in this revision

Viewing changes to languages/cpp/parser/tests/test_parser.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Jeremy Lainé
  • Date: 2010-05-05 07:21:55 UTC
  • mfrom: (1.2.3 upstream) (5.1.2 squeeze)
  • Revision ID: james.westby@ubuntu.com-20100505072155-h78lx19pu04sbhtn
Tags: 4:4.0.0-2
* Upload to unstable (Closes: #579947, #481832).
* Acknowledge obsolete NMU fixes (Closes: #562410, #546961).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#include <QtTest/QtTest>
 
2
 
 
3
#define private public
 
4
#include "ast.h"
 
5
#undef private
 
6
 
 
7
#include "parser.h"
 
8
#include "rpp/preprocessor.h"
 
9
#include "control.h"
 
10
#include "dumptree.h"
 
11
#include "tokens.h"
 
12
#include "parsesession.h"
 
13
#include "commentformatter.h"
 
14
 
 
15
#include "testconfig.h"
 
16
 
 
17
#include <QByteArray>
 
18
#include <QDataStream>
 
19
#include <QFile>
 
20
 
 
21
#include <iostream>
 
22
#include <rpp/chartools.h>
 
23
#include <rpp/pp-engine.h>
 
24
 
 
25
 
 
26
bool hasKind(AST*, AST::NODE_KIND);
 
27
AST* getAST(AST*, AST::NODE_KIND, int num = 0);
 
28
 
 
29
class TestParser : public QObject
 
30
{
 
31
  Q_OBJECT
 
32
 
 
33
  Control control;
 
34
  DumpTree dumper;
 
35
 
 
36
public:
 
37
  TestParser()
 
38
  {
 
39
  }
 
40
 
 
41
private slots:
 
42
 
 
43
  void initTestCase()
 
44
  {
 
45
  }
 
46
 
 
47
  void testSymbolTable()
 
48
  {
 
49
    NameTable table;
 
50
    table.findOrInsert("Ideal::MainWindow", sizeof("Ideal::MainWindow"));
 
51
    table.findOrInsert("QMainWindow", sizeof("QMainWindow"));
 
52
    table.findOrInsert("KXmlGuiWindow", sizeof("KXmlGuiWindow"));
 
53
    QCOMPARE(table.count(), size_t(3));
 
54
    const NameSymbol *s = table.findOrInsert("QMainWindow", sizeof("QMainWindow"));
 
55
    QCOMPARE(QString(s->data), QString("QMainWindow"));
 
56
    QCOMPARE(table.count(), size_t(3));
 
57
  }
 
58
 
 
59
  ///@todo reenable
 
60
//   void testControlContexts()
 
61
//   {
 
62
//     Control control;
 
63
//     const NameSymbol *n1 = control.findOrInsertName("a", 1);
 
64
//     int *type1 = new int(1); // don't care much about types
 
65
//     control.declare(n1, (Type*)type1);
 
66
//
 
67
//     control.pushContext();
 
68
//     int *type2 = new int(2);
 
69
//     const NameSymbol *n2 = control.findOrInsertName("b", 1);
 
70
//     control.declare(n2, (Type*)type2);
 
71
//
 
72
//     QCOMPARE(control.lookupType(n1), (Type*)type1);
 
73
//     QCOMPARE(control.lookupType(n2), (Type*)type2);
 
74
//
 
75
//     control.popContext();
 
76
//     QCOMPARE(control.lookupType(n1), (Type*)type1);
 
77
//     QCOMPARE(control.lookupType(n2), (Type*)0);
 
78
//   }
 
79
 
 
80
  void testTokenTable()
 
81
  {
 
82
    QCOMPARE(token_name(Token_EOF), "eof");
 
83
    QCOMPARE(token_name('a'), "a");
 
84
    QCOMPARE(token_name(Token_delete), "delete");
 
85
  }
 
86
 
 
87
///@todo reenable
 
88
//   void testLexer()
 
89
//   {
 
90
//     QByteArray code("#include <foo.h>");
 
91
//     TokenStream token_stream;
 
92
//     LocationTable location_table;
 
93
//     LocationTable line_table;
 
94
//     Control control;
 
95
//
 
96
//     Lexer lexer(token_stream, location_table, line_table, &control);
 
97
//     lexer.tokenize(code, code.size()+1);
 
98
//     QCOMPARE(control.problem(0).message(), QString("expected end of line"));
 
99
//
 
100
//     QByteArray code2("class Foo { int foo() {} }; ");
 
101
//     lexer.tokenize(code2, code2.size()+1);
 
102
//     QCOMPARE(control.problemCount(), 1);    //we still have the old problem in the list
 
103
//   }
 
104
 
 
105
  void testParser()
 
106
  {
 
107
    QByteArray clazz("struct A { int i; A() : i(5) { } virtual void test() = 0; };");
 
108
    pool mem_pool;
 
109
    TranslationUnitAST* ast = parse(clazz, &mem_pool);
 
110
    QVERIFY(ast != 0);
 
111
    QVERIFY(ast->declarations != 0);
 
112
  }
 
113
  
 
114
  void testTemplateArguments()
 
115
  {
 
116
    QByteArray templatetest("template <int N, int M> struct SeriesAdder{ enum { value = N + SeriesAdder< 0 >::value }; };");
 
117
    pool mem_pool;
 
118
    TranslationUnitAST* ast = parse(templatetest, &mem_pool);
 
119
    QVERIFY(ast != 0);
 
120
    QVERIFY(ast->declarations != 0);
 
121
    for (int i = 0; i < control.problems().count(); i++)
 
122
    {
 
123
      QVERIFY(control.problems().at(i)->description() == "Unexpected end of file");
 
124
    }
 
125
  }
 
126
  
 
127
  void testManyComparisons()
 
128
  {
 
129
    //Should not crash
 
130
    {
 
131
      QByteArray clazz("void test() { if(val < f && val < val1 && val < val2 && val < val3 ){ } }");
 
132
      pool mem_pool;
 
133
      TranslationUnitAST* ast = parse(clazz, &mem_pool);
 
134
      QVERIFY(ast != 0);
 
135
      QVERIFY(ast->declarations != 0);
 
136
      dumper.dump(ast, lastSession->token_stream);
 
137
    }
 
138
    {
 
139
      QByteArray clazz("void test() { if(val < f && val < val1 && val < val2 && val < val3 && val < val4 && val < val5 && val < val6 && val < val7 && val < val8 && val < val9 && val < val10 && val < val11 && val < val12 && val < val13 && val < val14 && val < val15 && val < val16 && val < val17 && val < val18 && val < val19 && val < val20 && val < val21 && val < val22 && val < val23 && val < val24 && val < val25 && val < val26){ } }");
 
140
      pool mem_pool;
 
141
      TranslationUnitAST* ast = parse(clazz, &mem_pool);
 
142
      QVERIFY(ast != 0);
 
143
      QVERIFY(ast->declarations != 0);
 
144
    }
 
145
  }
 
146
  
 
147
  void testParserFail()
 
148
  {
 
149
    QByteArray stuff("foo bar !!! nothing that really looks like valid c++ code");
 
150
    pool mem_pool;
 
151
    TranslationUnitAST *ast = parse(stuff, &mem_pool);
 
152
    QVERIFY(ast->declarations == 0);
 
153
    QVERIFY(control.problems().count() > 3);
 
154
  }
 
155
 
 
156
  void testPartialParseFail() {
 
157
    {
 
158
    QByteArray method("struct C { Something invalid is here };");
 
159
    pool mem_pool;
 
160
    TranslationUnitAST* ast = parse(method, &mem_pool);
 
161
    QVERIFY(ast != 0);
 
162
    QVERIFY(hasKind(ast, AST::Kind_ClassSpecifier));
 
163
    }
 
164
    {
 
165
    QByteArray method("void test() { Something invalid is here };");
 
166
    pool mem_pool;
 
167
    TranslationUnitAST* ast = parse(method, &mem_pool);
 
168
    QVERIFY(ast != 0);
 
169
    QVERIFY(hasKind(ast, AST::Kind_FunctionDefinition));
 
170
    }
 
171
    {
 
172
    QByteArray method("void test() { {Something invalid is here };");
 
173
    pool mem_pool;
 
174
    TranslationUnitAST* ast = parse(method, &mem_pool);
 
175
    QVERIFY(ast != 0);
 
176
    QVERIFY(hasKind(ast, AST::Kind_FunctionDefinition));
 
177
    QVERIFY(ast->hadMissingCompoundTokens);
 
178
    }
 
179
    {
 
180
    QByteArray method("void test() { case:{};");
 
181
    pool mem_pool;
 
182
    TranslationUnitAST* ast = parse(method, &mem_pool);
 
183
    QVERIFY(ast != 0);
 
184
    QVERIFY(hasKind(ast, AST::Kind_FunctionDefinition));
 
185
    QVERIFY(ast->hadMissingCompoundTokens);
 
186
    }
 
187
  }
 
188
 
 
189
  void testParseMethod()
 
190
  {
 
191
    QByteArray method("void A::test() {  }");
 
192
    pool mem_pool;
 
193
    TranslationUnitAST* ast = parse(method, &mem_pool);
 
194
    QVERIFY(ast != 0);
 
195
    QVERIFY(hasKind(ast, AST::Kind_FunctionDefinition));
 
196
  }
 
197
 
 
198
///@todo reenable
 
199
//   void testMethodArgs()
 
200
//   {
 
201
//     QByteArray method("int A::test(int primitive, B* pointer) { return primitive; }");
 
202
//     pool mem_pool;
 
203
//     Parser parser(&control);
 
204
//     TranslationUnitAST* ast = parser.parse(method.constData(),
 
205
//                                         method.size() + 1, &mem_pool);
 
206
//     // return type
 
207
//     SimpleTypeSpecifierAST* retType = static_cast<SimpleTypeSpecifierAST*>
 
208
//       (getAST(ast, AST::Kind_SimpleTypeSpecifier));
 
209
//     QCOMPARE((TOKEN_KIND)parser.token_stream.kind(retType->start_token),
 
210
//          Token_int);
 
211
//
 
212
//     // first param
 
213
//     ParameterDeclarationAST* param = static_cast<ParameterDeclarationAST*>
 
214
//       (getAST(ast, AST::Kind_ParameterDeclaration));
 
215
//     SimpleTypeSpecifierAST* paramType = static_cast<SimpleTypeSpecifierAST*>
 
216
//       (getAST(param, AST::Kind_SimpleTypeSpecifier));
 
217
//     QCOMPARE((TOKEN_KIND)parser.token_stream.kind(paramType->start_token),
 
218
//          Token_int);
 
219
//     UnqualifiedNameAST* argName  = static_cast<UnqualifiedNameAST*>
 
220
//       (getAST(param, AST::Kind_UnqualifiedName));
 
221
//     QCOMPARE(parser.token_stream.symbol(argName->id)->as_string(),
 
222
//          QString("primitive"));
 
223
//
 
224
//     // second param
 
225
//     param = static_cast<ParameterDeclarationAST*>
 
226
//       (getAST(ast, AST::Kind_ParameterDeclaration, 1));
 
227
//     UnqualifiedNameAST* argType = static_cast<UnqualifiedNameAST*>
 
228
//       (getAST(param, AST::Kind_UnqualifiedName));
 
229
//     QCOMPARE(parser.token_stream.symbol(argType->id)->as_string(),
 
230
//          QString("B"));
 
231
//
 
232
//     // pointer operator
 
233
//     QVERIFY(hasKind(param, AST::Kind_PtrOperator));
 
234
//
 
235
//     argName = static_cast<UnqualifiedNameAST*>
 
236
//       (getAST(param, AST::Kind_UnqualifiedName, 1));
 
237
//     QCOMPARE(parser.token_stream.symbol(argName->id)->as_string(),
 
238
//          QString("pointer"));
 
239
//
 
240
//   }
 
241
 
 
242
  void testForStatements()
 
243
  {
 
244
    QByteArray method("void A::t() { for (int i = 0; i < 10; i++) { ; }}");
 
245
    pool mem_pool;
 
246
    TranslationUnitAST* ast = parse(method, &mem_pool);
 
247
 
 
248
    QVERIFY(ast != 0);
 
249
    QVERIFY(hasKind(ast, AST::Kind_ForStatement));
 
250
    QVERIFY(hasKind(ast, AST::Kind_Condition));
 
251
    QVERIFY(hasKind(ast, AST::Kind_IncrDecrExpression));
 
252
    QVERIFY(hasKind(ast, AST::Kind_SimpleDeclaration));
 
253
 
 
254
    QByteArray emptyFor("void A::t() { for (;;) { } }");
 
255
    ast = parse(emptyFor, &mem_pool);
 
256
    QVERIFY(ast != 0);
 
257
    QVERIFY(hasKind(ast, AST::Kind_ForStatement));
 
258
    QVERIFY(!hasKind(ast, AST::Kind_Condition));
 
259
    QVERIFY(!hasKind(ast, AST::Kind_SimpleDeclaration));
 
260
  }
 
261
 
 
262
  void testIfStatements()
 
263
  {
 
264
    QByteArray method("void A::t() { if (1 < 2) { } }");
 
265
    pool mem_pool;
 
266
    TranslationUnitAST* ast = parse(method, &mem_pool);
 
267
    QVERIFY(hasKind(ast, AST::Kind_Condition));
 
268
    QVERIFY(hasKind(ast, AST::Kind_BinaryExpression));
 
269
  }
 
270
 
 
271
  void testComments()
 
272
  {
 
273
    QByteArray method("//TranslationUnitComment\n//Hello\nint A; //behind\n /*between*/\n /*Hello2*/\n class B{}; //behind\n//Hello3\n //beforeTest\nvoid test(); //testBehind");
 
274
    pool mem_pool;
 
275
    TranslationUnitAST* ast = parse(method, &mem_pool);
 
276
 
 
277
    QCOMPARE(CommentFormatter::formatComment(ast->comments, lastSession), QByteArray("TranslationUnitComment")); //The comments were merged
 
278
 
 
279
    const ListNode<DeclarationAST*>* it = ast->declarations;
 
280
    QVERIFY(it);
 
281
    it = it->next;
 
282
    QVERIFY(it);
 
283
    QCOMPARE(CommentFormatter::formatComment(it->element->comments, lastSession), QByteArray("Hello\n(behind)"));
 
284
 
 
285
    it = it->next;
 
286
    QVERIFY(it);
 
287
    QCOMPARE(CommentFormatter::formatComment(it->element->comments, lastSession), QByteArray("between\nHello2\n(behind)"));
 
288
 
 
289
    it = it->next;
 
290
    QVERIFY(it);
 
291
    QCOMPARE(CommentFormatter::formatComment(it->element->comments, lastSession), QByteArray("Hello3\nbeforeTest\n(testBehind)"));
 
292
  }
 
293
 
 
294
  void testComments2()
 
295
  {
 
296
    QByteArray method("enum Enum\n {//enumerator1Comment\nenumerator1, //enumerator1BehindComment\n /*enumerator2Comment*/ enumerator2 /*enumerator2BehindComment*/};");
 
297
    pool mem_pool;
 
298
    TranslationUnitAST* ast = parse(method, &mem_pool);
 
299
 
 
300
    const ListNode<DeclarationAST*>* it = ast->declarations;
 
301
    QVERIFY(it);
 
302
    it = it->next;
 
303
    QVERIFY(it);
 
304
    const SimpleDeclarationAST* simpleDecl = static_cast<const SimpleDeclarationAST*>(it->element);
 
305
    QVERIFY(simpleDecl);
 
306
 
 
307
    const EnumSpecifierAST* enumSpec = (const EnumSpecifierAST*)simpleDecl->type_specifier;
 
308
    QVERIFY(enumSpec);
 
309
 
 
310
    const ListNode<EnumeratorAST*> *enumerator = enumSpec->enumerators;
 
311
    QVERIFY(enumerator);
 
312
    enumerator = enumerator->next;
 
313
    QVERIFY(enumerator);
 
314
 
 
315
    QCOMPARE(CommentFormatter::formatComment(enumerator->element->comments, lastSession), QByteArray("enumerator1Comment\n(enumerator1BehindComment)"));
 
316
 
 
317
    enumerator = enumerator->next;
 
318
    QVERIFY(enumerator);
 
319
 
 
320
    QCOMPARE(CommentFormatter::formatComment(enumerator->element->comments, lastSession), QByteArray("enumerator2Comment\n(enumerator2BehindComment)"));
 
321
  }
 
322
 
 
323
  void testComments3()
 
324
  {
 
325
    QByteArray method("class Class{\n//Comment\n int val;};");
 
326
    pool mem_pool;
 
327
    TranslationUnitAST* ast = parse(method, &mem_pool);
 
328
 
 
329
    const ListNode<DeclarationAST*>* it = ast->declarations;
 
330
    QVERIFY(it);
 
331
    it = it->next;
 
332
    QVERIFY(it);
 
333
    const SimpleDeclarationAST* simpleDecl = static_cast<const SimpleDeclarationAST*>(it->element);
 
334
    QVERIFY(simpleDecl);
 
335
 
 
336
    const ClassSpecifierAST* classSpec = (const ClassSpecifierAST*)simpleDecl->type_specifier;
 
337
    QVERIFY(classSpec);
 
338
 
 
339
    const ListNode<DeclarationAST*> *members = classSpec->member_specs;
 
340
    QVERIFY(members);
 
341
    members = members->next;
 
342
    QVERIFY(members);
 
343
 
 
344
    QCOMPARE(CommentFormatter::formatComment(members->element->comments, lastSession), QByteArray("Comment"));
 
345
  }
 
346
 
 
347
  void testComments4()
 
348
  {
 
349
    QByteArray method("//TranslationUnitComment\n//Comment\ntemplate<class C> class Class{};");
 
350
    pool mem_pool;
 
351
    TranslationUnitAST* ast = parse(method, &mem_pool);
 
352
 
 
353
    const ListNode<DeclarationAST*>* it = ast->declarations;
 
354
    QVERIFY(it);
 
355
    it = it->next;
 
356
    QVERIFY(it);
 
357
    const TemplateDeclarationAST* templDecl = static_cast<const TemplateDeclarationAST*>(it->element);
 
358
    QVERIFY(templDecl);
 
359
    QVERIFY(templDecl->declaration);
 
360
 
 
361
    //QCOMPARE(CommentFormatter::formatComment(templDecl->declaration->comments, lastSession), QString("Comment"));
 
362
  }
 
363
 
 
364
  QString preprocess(const QString& contents) {
 
365
    rpp::Preprocessor preprocessor;
 
366
    rpp::pp pp(&preprocessor);
 
367
    return QString::fromUtf8(stringFromContents(pp.processFile("anonymous", contents.toUtf8())));
 
368
  }
 
369
 
 
370
  void testPreprocessor() {
 
371
    rpp::Preprocessor preprocessor;
 
372
    //QCOMPARE(preprocess("#define TEST (1L<<10)\nTEST").trimmed(), QString("(1L<<10)"));
 
373
    QCOMPARE(preprocess("#define TEST //Comment\nTEST 1").trimmed(), QString("1")); //Comments are not included in macros
 
374
    QCOMPARE(preprocess("#define TEST /*Comment\n*/\nTEST 1").trimmed(), QString("1")); //Comments are not included in macros
 
375
 
 
376
  }
 
377
 
 
378
  void testStringConcatenation()
 
379
  {
 
380
    rpp::Preprocessor preprocessor;
 
381
    QCOMPARE(preprocess("Hello##You"), QString("HelloYou"));
 
382
    QCOMPARE(preprocess("#define CONCAT(Var1, Var2) Var1##Var2 Var2##Var1\nCONCAT(      Hello      ,      You     )").simplified(), QString("\nHelloYou YouHello").simplified());
 
383
  }
 
384
 
 
385
  void testCondition()
 
386
  {
 
387
    QByteArray method("bool i = (small < big || big > small);");
 
388
    pool mem_pool;
 
389
    TranslationUnitAST* ast = parse(method, &mem_pool);
 
390
    dumper.dump(ast, lastSession->token_stream);
 
391
    ///@todo make this work, it should yield something like TranslationUnit -> SimpleDeclaration -> InitDeclarator -> BinaryExpression
 
392
  }
 
393
 
 
394
  void testNonTemplateDeclaration()
 
395
  {
 
396
    /*{
 
397
      QByteArray templateMethod("template <int> class a {}; int main() { const int b = 1; const int c = 2; a<b|c> d; }");
 
398
      pool mem_pool;
 
399
      TranslationUnitAST* ast = parse(templateMethod, &mem_pool);
 
400
      dumper.dump(ast, lastSession->token_stream);
 
401
    }*/
 
402
 
 
403
    //int a, b, c, d; bool e;
 
404
    QByteArray declaration("void expression() { if (a < b || c > d) {} }");
 
405
    pool mem_pool;
 
406
    TranslationUnitAST* ast = parse(declaration, &mem_pool);
 
407
    dumper.dump(ast, lastSession->token_stream);
 
408
  }
 
409
 
 
410
  void testInitListTrailingComma()
 
411
  {
 
412
    //see bug https://bugs.kde.org/show_bug.cgi?id=233328
 
413
 
 
414
    QByteArray code("const int foo [] = {1,};");
 
415
    pool memPool;
 
416
    TranslationUnitAST* ast = parse(code, &memPool);
 
417
    dumper.dump(ast, lastSession->token_stream);
 
418
 
 
419
    QCOMPARE(ast->declarations->count(), 1);
 
420
    SimpleDeclarationAST* simpleDecl = reinterpret_cast<SimpleDeclarationAST*>(ast->declarations->at(0)->element);
 
421
    QVERIFY(simpleDecl);
 
422
 
 
423
    QCOMPARE(simpleDecl->init_declarators->count(), 1);
 
424
  }
 
425
 
 
426
  /*void testParseFile()
 
427
  {
 
428
     QFile file(TEST_FILE);
 
429
     QVERIFY(file.open(QFile::ReadOnly));
 
430
     QByteArray contents = file.readAll();
 
431
     file.close();
 
432
     pool mem_pool;
 
433
     Parser parser(&control);
 
434
     ParseSession session;
 
435
     session.setContents(contents);
 
436
     TranslationUnitAST* ast = parser.parse(&session);
 
437
     QVERIFY(ast != 0);
 
438
     QVERIFY(ast->declarations != 0);
 
439
   }*/
 
440
 
 
441
private:
 
442
  ParseSession* lastSession;
 
443
 
 
444
  TranslationUnitAST* parse(const QByteArray& unit, pool* mem_pool)
 
445
  {
 
446
    Parser parser(&control);
 
447
    lastSession = new ParseSession();
 
448
    lastSession->setContentsAndGenerateLocationTable(tokenizeFromByteArray(unit));
 
449
    return  parser.parse(lastSession);
 
450
  }
 
451
 
 
452
 
 
453
 
 
454
};
 
455
 
 
456
struct HasKindVisitor : protected DefaultVisitor
 
457
{
 
458
 
 
459
  AST::NODE_KIND kind;
 
460
  AST* ast;
 
461
  int num;
 
462
 
 
463
  HasKindVisitor(AST::NODE_KIND kind, int num = 0)
 
464
    : kind(kind), ast(0), num(num)
 
465
  {
 
466
  }
 
467
 
 
468
  bool hasKind() const
 
469
  {
 
470
    return ast != 0;
 
471
  }
 
472
 
 
473
  void visit(AST* node)
 
474
  {
 
475
    if (!ast && node) {
 
476
      if (node->kind == kind && --num < 0) {
 
477
        ast = node;
 
478
      }
 
479
      else {
 
480
        DefaultVisitor::visit(node);
 
481
      }
 
482
    }
 
483
  }
 
484
};
 
485
 
 
486
bool hasKind(AST* ast, AST::NODE_KIND kind)
 
487
{
 
488
  HasKindVisitor visitor(kind);
 
489
  visitor.visit(ast);
 
490
  return visitor.hasKind();
 
491
}
 
492
 
 
493
AST* getAST(AST* ast, AST::NODE_KIND kind, int num)
 
494
{
 
495
  HasKindVisitor visitor(kind, num);
 
496
  visitor.visit(ast);
 
497
  return visitor.ast;
 
498
}
 
499
 
 
500
 
 
501
#include "test_parser.moc"
 
502
 
 
503
QTEST_MAIN(TestParser)