1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of Qt Creator.
7 **
8 ** Commercial License Usage
9 ** Licensees holding valid commercial Qt licenses may use this file in
10 ** accordance with the commercial license agreement provided with the
11 ** Software or, alternatively, in accordance with the terms contained in
12 ** a written agreement between you and The Qt Company. For licensing terms
13 ** and conditions see https://www.qt.io/terms-conditions. For further
14 ** information use the contact form at https://www.qt.io/contact-us.
15 **
16 ** GNU General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU
18 ** General Public License version 3 as published by the Free Software
19 ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
20 ** included in the packaging of this file. Please review the following
21 ** information to ensure the GNU General Public License requirements will
22 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
23 **
24 ****************************************************************************/
25
26 #include <QtTest>
27 #include <QDebug>
28 #include <QTextDocument>
29 #include <QTextCursor>
30
31 #include <cplusplus/AST.h>
32 #include <cplusplus/ASTVisitor.h>
33 #include <cplusplus/Bind.h>
34 #include <cplusplus/Control.h>
35 #include <cplusplus/CoreTypes.h>
36 #include <cplusplus/DeprecatedGenTemplateInstance.h>
37 #include <cplusplus/DiagnosticClient.h>
38 #include <cplusplus/ExpressionUnderCursor.h>
39 #include <cplusplus/Literals.h>
40 #include <cplusplus/Names.h>
41 #include <cplusplus/Names.h>
42 #include <cplusplus/Overview.h>
43 #include <cplusplus/Parser.h>
44 #include <cplusplus/Scope.h>
45 #include <cplusplus/Symbols.h>
46
47 //TESTED_COMPONENT=src/libs/cplusplus
48
49 #define NO_PARSER_OR_SEMANTIC_ERROR_MESSAGES
50
51 using namespace CPlusPlus;
52
53 // to use in tests directly w/o convertion to int
54 Q_DECLARE_METATYPE(Function::RefQualifier)
55
56 class tst_Semantic: public QObject
57 {
58 Q_OBJECT
59
60 QSharedPointer<Control> control;
61
62 public:
tst_Semantic()63 tst_Semantic()
64 : control(new Control)
65 { control->setDiagnosticClient(&diag); }
66
parse(const QByteArray & source,TranslationUnit::ParseMode mode,LanguageFeatures features)67 TranslationUnit *parse(const QByteArray &source,
68 TranslationUnit::ParseMode mode,
69 LanguageFeatures features)
70 {
71 const StringLiteral *fileId = control->stringLiteral("<stdin>");
72 TranslationUnit *unit = new TranslationUnit(control.data(), fileId);
73 unit->setSource(source.constData(), source.length());
74 unit->setLanguageFeatures(features);
75 unit->parse(mode);
76 return unit;
77 }
78
79 class Document {
80 Q_DISABLE_COPY(Document)
81
82 public:
Document(TranslationUnit * unit)83 Document(TranslationUnit *unit)
84 : unit(unit)
85 , globals(unit->control()->newNamespace(0, 0))
86 , errorCount(0)
87 { }
88
~Document()89 ~Document()
90 { }
91
check()92 void check()
93 {
94 QVERIFY(unit);
95 QVERIFY(unit->ast());
96 Bind bind(unit);
97 TranslationUnitAST *ast = unit->ast()->asTranslationUnit();
98 QVERIFY(ast);
99 bind(ast, globals);
100 }
101
102 TranslationUnit *unit;
103 Namespace *globals;
104 unsigned errorCount;
105 };
106
107 class Diagnostic: public DiagnosticClient {
108 public:
109 int errorCount;
110
Diagnostic()111 Diagnostic()
112 : errorCount(0)
113 { }
114
report(int,const StringLiteral * fileName,int line,int column,const char * format,va_list ap)115 virtual void report(int /*level*/,
116 const StringLiteral *fileName,
117 int line, int column,
118 const char *format, va_list ap)
119 {
120 ++errorCount;
121
122 #ifndef NO_PARSER_OR_SEMANTIC_ERROR_MESSAGES
123 qDebug() << fileName->chars()<<':'<<line<<':'<<column<<' ' << QString::vasprintf(format, ap);
124 #else
125 Q_UNUSED(fileName)
126 Q_UNUSED(line)
127 Q_UNUSED(column)
128 Q_UNUSED(format)
129 Q_UNUSED(ap)
130 #endif
131 }
132 };
133
134 Diagnostic diag;
135
136
document(const QByteArray & source,bool enableObjc=false,bool qtMocRun=false,bool enableCxx11=false)137 QSharedPointer<Document> document(const QByteArray &source, bool enableObjc = false, bool qtMocRun = false, bool enableCxx11 = false)
138 {
139 LanguageFeatures features;
140 features.objCEnabled = enableObjc;
141 features.qtEnabled = qtMocRun;
142 features.qtMocRunEnabled = qtMocRun;
143 features.qtKeywordsEnabled = qtMocRun;
144 features.cxx11Enabled = enableCxx11;
145 features.cxxEnabled = true;
146 diag.errorCount = 0; // reset the error count.
147 TranslationUnit *unit = parse(source, TranslationUnit::ParseTranlationUnit, features);
148 QSharedPointer<Document> doc(new Document(unit));
149 doc->check();
150 doc->errorCount = diag.errorCount;
151 return doc;
152 }
153
154 private slots:
155 void function_declaration_1();
156 void function_declaration_2();
157 void function_declaration_ref_qualifier_data();
158 void function_declaration_ref_qualifier();
159 void function_definition_1();
160 void nested_class_1();
161 void alias_declaration_1();
162 void typedef_1();
163 void typedef_2();
164 void typedef_3();
165 void const_1();
166 void const_2();
167 void pointer_to_function_1();
168
169 void template_instance_1();
170
171 void expression_under_cursor_1();
172
173 void bracketed_expression_under_cursor_1();
174 void bracketed_expression_under_cursor_2();
175 void bracketed_expression_under_cursor_3();
176 void bracketed_expression_under_cursor_4();
177
178 void objcClass_1();
179 void objcSelector_1();
180 void objcSelector_2();
181
182 void q_enum_1();
183
184 void lambda_1();
185 void lambda_2();
186
187 void diagnostic_error();
188
189 void enum_constantValue1();
190 void enum_constantValue2();
191 void enum_constantValue3();
192 void enum_constantValue4();
193 void enum_constantValue5();
194 void enum_constantValueNegative();
195 };
196
function_declaration_1()197 void tst_Semantic::function_declaration_1()
198 {
199 QSharedPointer<Document> doc = document("void foo();");
200 QCOMPARE(doc->errorCount, 0U);
201 QCOMPARE(doc->globals->memberCount(), 1);
202
203 Declaration *decl = doc->globals->memberAt(0)->asDeclaration();
204 QVERIFY(decl);
205
206 FullySpecifiedType declTy = decl->type();
207 Function *funTy = declTy->asFunctionType();
208 QVERIFY(funTy);
209 QVERIFY(funTy->returnType()->isVoidType());
210 QCOMPARE(funTy->argumentCount(), 0);
211 QCOMPARE(funTy->refQualifier(), Function::NoRefQualifier);
212
213 QVERIFY(decl->name()->isNameId());
214 const Identifier *funId = decl->name()->asNameId()->identifier();
215 QVERIFY(funId);
216
217 const QByteArray foo(funId->chars(), funId->size());
218 QCOMPARE(foo, QByteArray("foo"));
219 }
220
function_declaration_2()221 void tst_Semantic::function_declaration_2()
222 {
223 QSharedPointer<Document> doc = document("void foo(const QString &s);");
224 QCOMPARE(doc->errorCount, 0U);
225 QCOMPARE(doc->globals->memberCount(), 1);
226
227 Declaration *decl = doc->globals->memberAt(0)->asDeclaration();
228 QVERIFY(decl);
229
230 FullySpecifiedType declTy = decl->type();
231 Function *funTy = declTy->asFunctionType();
232 QVERIFY(funTy);
233 QVERIFY(funTy->returnType()->isVoidType());
234 QCOMPARE(funTy->argumentCount(), 1);
235 QCOMPARE(funTy->refQualifier(), Function::NoRefQualifier);
236
237 // check the formal argument.
238 Argument *arg = funTy->argumentAt(0)->asArgument();
239 QVERIFY(arg);
240 QVERIFY(arg->name());
241 QVERIFY(! arg->hasInitializer());
242
243 // check the argument's name.
244 const Identifier *argNameId = arg->name()->asNameId();
245 QVERIFY(argNameId);
246
247 const Identifier *argId = argNameId->identifier();
248 QVERIFY(argId);
249
250 QCOMPARE(QByteArray(argId->chars(), argId->size()), QByteArray("s"));
251
252 // check the type of the formal argument
253 FullySpecifiedType argTy = arg->type();
254 QVERIFY(argTy->isReferenceType());
255 QVERIFY(argTy->asReferenceType()->elementType().isConst());
256 NamedType *namedTy = argTy->asReferenceType()->elementType()->asNamedType();
257 QVERIFY(namedTy);
258 QVERIFY(namedTy->name());
259 const Identifier *namedTypeId = namedTy->name()->asNameId()->identifier();
260 QVERIFY(namedTypeId);
261 QCOMPARE(QByteArray(namedTypeId->chars(), namedTypeId->size()),
262 QByteArray("QString"));
263
264 QVERIFY(decl->name()->isNameId());
265 const Identifier *funId = decl->name()->asNameId()->identifier();
266 QVERIFY(funId);
267
268 const QByteArray foo(funId->chars(), funId->size());
269 QCOMPARE(foo, QByteArray("foo"));
270 }
271
function_declaration_ref_qualifier_data()272 void tst_Semantic::function_declaration_ref_qualifier_data()
273 {
274 QTest::addColumn<QString>("code");
275 QTest::addColumn<bool>("success");
276 QTest::addColumn<Function::RefQualifier>("refQualifier");
277
278 QTest::newRow("no")
279 << "void f();" << true << Function::NoRefQualifier;
280
281 QTest::newRow("no_const")
282 << "void f() const;" << true << Function::NoRefQualifier;
283
284 QTest::newRow("no_const_noexcept")
285 << "void f() const noexcept;" << true << Function::NoRefQualifier;
286
287 QTest::newRow("lvalue")
288 << "void f() &;" << true << Function::LvalueRefQualifier;
289
290 QTest::newRow("lvalue_const")
291 << "void f() const &;" << true << Function::LvalueRefQualifier;
292
293 QTest::newRow("lvalue_const_noexcept")
294 << "void f() const & noexcept;" << true << Function::LvalueRefQualifier;
295
296 QTest::newRow("rvalue")
297 << "void f() &&;" << true << Function::RvalueRefQualifier;
298
299 QTest::newRow("rvalue_const")
300 << "void f() const &&;" << true << Function::RvalueRefQualifier;
301
302 QTest::newRow("rvalue_const_noexcept")
303 << "void f() const && noexcept;" << true << Function::RvalueRefQualifier;
304
305 QTest::newRow("lvalue_more_spaces")
306 << "void f() const &;" << true << Function::LvalueRefQualifier;
307
308 QTest::newRow("rvalue_more_spaces")
309 << "void f() && noexcept;" << true << Function::RvalueRefQualifier;
310
311 QTest::newRow("lvalue_more_newline")
312 << "void f() const\n&;" << true << Function::LvalueRefQualifier;
313
314 QTest::newRow("rvalue_more_newline")
315 << "void f() const\n&&;" << true << Function::RvalueRefQualifier;
316
317 QTest::newRow("lvalue_no_space")
318 << "void f() const& noexcept;" << true << Function::LvalueRefQualifier;
319
320 QTest::newRow("rvalue_no_space")
321 << "void f() const&& noexcept;" << true << Function::RvalueRefQualifier;
322
323 QTest::newRow("lvalue_before_const")
324 << "void f() & const;" << false << Function::NoRefQualifier;
325
326 QTest::newRow("rvalue_before_const")
327 << "void f() && const;" << false << Function::NoRefQualifier;
328
329 QTest::newRow("lvalue_after_noexcept")
330 << "void f() const noexcept &;" << false << Function::NoRefQualifier;
331
332 QTest::newRow("rvalue_after_noexcept")
333 << "void f() const noexcept &&;" << false << Function::NoRefQualifier;
334
335 QTest::newRow("lvalue_double")
336 << "void f() const & & noexcept;" << false << Function::NoRefQualifier;
337
338 QTest::newRow("rvalue_double")
339 << "void f() const && && noexcept;" << false << Function::NoRefQualifier;
340 }
341
function_declaration_ref_qualifier()342 void tst_Semantic::function_declaration_ref_qualifier()
343 {
344 QFETCH(QString, code);
345 QFETCH(bool, success);
346 QFETCH(Function::RefQualifier, refQualifier);
347
348 QSharedPointer<Document> doc = document(code.toUtf8(), false, false, true);
349 if (!success) {
350 QVERIFY(doc->errorCount > 0);
351 return;
352 }
353 QCOMPARE(doc->errorCount, 0U);
354 QCOMPARE(doc->globals->memberCount(), 1);
355
356 Declaration *decl = doc->globals->memberAt(0)->asDeclaration();
357 QVERIFY(decl);
358
359 FullySpecifiedType declTy = decl->type();
360 Function *funTy = declTy->asFunctionType();
361 QVERIFY(funTy);
362 QVERIFY(funTy->returnType()->isVoidType());
363 QCOMPARE(funTy->argumentCount(), 0);
364
365 // check the ref-qualifier
366 QCOMPARE(funTy->refQualifier(), refQualifier);
367 }
368
function_definition_1()369 void tst_Semantic::function_definition_1()
370 {
371 QSharedPointer<Document> doc = document("void foo() {}");
372 QCOMPARE(doc->errorCount, 0U);
373 QCOMPARE(doc->globals->memberCount(), 1);
374
375 Function *funTy = doc->globals->memberAt(0)->asFunction();
376 QVERIFY(funTy);
377 QVERIFY(funTy->returnType()->isVoidType());
378 QCOMPARE(funTy->argumentCount(), 0);
379 QCOMPARE(funTy->refQualifier(), Function::NoRefQualifier);
380
381 QVERIFY(funTy->name()->isNameId());
382 const Identifier *funId = funTy->name()->asNameId()->identifier();
383 QVERIFY(funId);
384
385 const QByteArray foo(funId->chars(), funId->size());
386 QCOMPARE(foo, QByteArray("foo"));
387 }
388
nested_class_1()389 void tst_Semantic::nested_class_1()
390 {
391 QSharedPointer<Document> doc = document(
392 "class Object {\n"
393 " class Data;\n"
394 " Data *d;\n"
395 "};\n"
396 "class Object::Data {\n"
397 " Object *q;\n"
398 "};\n"
399 );
400 QCOMPARE(doc->errorCount, 0U);
401 QCOMPARE(doc->globals->memberCount(), 2);
402
403 Class *classObject = doc->globals->memberAt(0)->asClass();
404 QVERIFY(classObject);
405 QVERIFY(classObject->name());
406 const Identifier *classObjectNameId = classObject->name()->asNameId();
407 QVERIFY(classObjectNameId);
408 const Identifier *objectId = classObjectNameId->identifier();
409 QCOMPARE(QByteArray(objectId->chars(), objectId->size()), QByteArray("Object"));
410 QCOMPARE(classObject->baseClassCount(), 0);
411 QCOMPARE(classObject->memberCount(), 2);
412
413 Class *classObjectData = doc->globals->memberAt(1)->asClass();
414 QVERIFY(classObjectData);
415 QVERIFY(classObjectData->name());
416 const QualifiedNameId *q = classObjectData->name()->asQualifiedNameId();
417 QVERIFY(q);
418 QVERIFY(q->base());
419 QVERIFY(q->base()->asNameId());
420 QCOMPARE(q->base(), classObject->name());
421 QVERIFY(q->name());
422 QVERIFY(q->name()->asNameId());
423 QCOMPARE(doc->globals->find(q->base()->asNameId()->identifier()), classObject);
424
425 Declaration *decl = classObjectData->memberAt(0)->asDeclaration();
426 QVERIFY(decl);
427 PointerType *ptrTy = decl->type()->asPointerType();
428 QVERIFY(ptrTy);
429 NamedType *namedTy = ptrTy->elementType()->asNamedType();
430 QVERIFY(namedTy);
431 QVERIFY(namedTy->name()->asNameId());
432 QCOMPARE(namedTy->name()->asNameId()->identifier(), objectId);
433 }
434
alias_declaration_1()435 void tst_Semantic::alias_declaration_1()
436 {
437 QSharedPointer<Document> doc = document(
438 "using wobble = int;\n"
439 , false, false, true);
440
441 QCOMPARE(doc->errorCount, 0U);
442 QCOMPARE(doc->globals->memberCount(), 1);
443
444 Declaration *decl = doc->globals->memberAt(0)->asDeclaration();
445 QVERIFY(decl->name());
446 QVERIFY(decl->name()->identifier());
447 QCOMPARE(decl->name()->identifier()->chars(), "wobble");
448
449 QVERIFY(decl->isTypedef());
450 QVERIFY(decl->type().isTypedef());
451 QVERIFY(decl->type()->isIntegerType());
452 }
453
typedef_1()454 void tst_Semantic::typedef_1()
455 {
456 QSharedPointer<Document> doc = document(
457 "typedef struct {\n"
458 " int x, y;\n"
459 "} Point;\n"
460 "int main() {\n"
461 " Point pt;\n"
462 " pt.x = 1;\n"
463 "}\n"
464 );
465
466 QCOMPARE(doc->errorCount, 0U);
467 QCOMPARE(doc->globals->memberCount(), 3);
468
469 Class *anonStruct = doc->globals->memberAt(0)->asClass();
470 QVERIFY(anonStruct);
471 QCOMPARE(anonStruct->memberCount(), 2);
472
473 Declaration *typedefPointDecl = doc->globals->memberAt(1)->asDeclaration();
474 QVERIFY(typedefPointDecl);
475 QVERIFY(typedefPointDecl->isTypedef());
476 QCOMPARE(typedefPointDecl->type()->asClassType(), anonStruct);
477
478 Function *mainFun = doc->globals->memberAt(2)->asFunction();
479 QVERIFY(mainFun);
480 }
481
typedef_2()482 void tst_Semantic::typedef_2()
483 {
484 QSharedPointer<Document> doc = document(
485 "struct _Point {\n"
486 " int x, y;\n"
487 "};\n"
488 "typedef _Point Point;\n"
489 "int main() {\n"
490 " Point pt;\n"
491 " pt.x = 1;\n"
492 "}\n"
493 );
494
495 QCOMPARE(doc->errorCount, 0U);
496 QCOMPARE(doc->globals->memberCount(), 3);
497
498 Class *_pointStruct= doc->globals->memberAt(0)->asClass();
499 QVERIFY(_pointStruct);
500 QCOMPARE(_pointStruct->memberCount(), 2);
501
502 Declaration *typedefPointDecl = doc->globals->memberAt(1)->asDeclaration();
503 QVERIFY(typedefPointDecl);
504 QVERIFY(typedefPointDecl->isTypedef());
505 QVERIFY(typedefPointDecl->type()->isNamedType());
506 QCOMPARE(typedefPointDecl->type()->asNamedType()->name(), _pointStruct->name());
507
508 Function *mainFun = doc->globals->memberAt(2)->asFunction();
509 QVERIFY(mainFun);
510 }
511
typedef_3()512 void tst_Semantic::typedef_3()
513 {
514 QSharedPointer<Document> doc = document(
515 "typedef struct {\n"
516 " int x, y;\n"
517 "} *PointPtr;\n"
518 );
519
520 QCOMPARE(doc->errorCount, 0U);
521 QCOMPARE(doc->globals->memberCount(), 2);
522
523 Class *_pointStruct= doc->globals->memberAt(0)->asClass();
524 QVERIFY(_pointStruct);
525 QCOMPARE(_pointStruct->memberCount(), 2);
526
527 Declaration *typedefPointDecl = doc->globals->memberAt(1)->asDeclaration();
528 QVERIFY(typedefPointDecl);
529 QVERIFY(typedefPointDecl->isTypedef());
530 QVERIFY(typedefPointDecl->type()->isPointerType());
531 QCOMPARE(typedefPointDecl->type()->asPointerType()->elementType()->asClassType(),
532 _pointStruct);
533 }
534
const_1()535 void tst_Semantic::const_1()
536 {
537 QSharedPointer<Document> doc = document("\n"
538 "int foo(const int *s);\n"
539 );
540
541 QCOMPARE(doc->errorCount, 0U);
542 QCOMPARE(doc->globals->memberCount(), 1);
543
544 Declaration *decl = doc->globals->memberAt(0)->asDeclaration();
545 QVERIFY(decl);
546 QVERIFY(decl->type()->isFunctionType());
547 Function *funTy = decl->type()->asFunctionType();
548 QVERIFY(funTy->returnType()->isIntegerType());
549 QCOMPARE(funTy->argumentCount(), 1);
550 Argument *arg = funTy->argumentAt(0)->asArgument();
551 QVERIFY(arg);
552 QVERIFY(! arg->type().isConst());
553 QVERIFY(arg->type()->isPointerType());
554 QVERIFY(arg->type()->asPointerType()->elementType().isConst());
555 QVERIFY(arg->type()->asPointerType()->elementType()->isIntegerType());
556 }
557
const_2()558 void tst_Semantic::const_2()
559 {
560 QSharedPointer<Document> doc = document("\n"
561 "int foo(char * const s);\n"
562 );
563
564 QCOMPARE(doc->errorCount, 0U);
565 QCOMPARE(doc->globals->memberCount(), 1);
566
567 Declaration *decl = doc->globals->memberAt(0)->asDeclaration();
568 QVERIFY(decl);
569 QVERIFY(decl->type()->isFunctionType());
570 Function *funTy = decl->type()->asFunctionType();
571 QVERIFY(funTy->returnType()->isIntegerType());
572 QCOMPARE(funTy->argumentCount(), 1);
573 Argument *arg = funTy->argumentAt(0)->asArgument();
574 QVERIFY(arg);
575 QVERIFY(arg->type().isConst());
576 QVERIFY(arg->type()->isPointerType());
577 QVERIFY(! arg->type()->asPointerType()->elementType().isConst());
578 QVERIFY(arg->type()->asPointerType()->elementType()->isIntegerType());
579 }
580
pointer_to_function_1()581 void tst_Semantic::pointer_to_function_1()
582 {
583 QSharedPointer<Document> doc = document("void (*QtSomething)();");
584 QCOMPARE(doc->errorCount, 0U);
585 QCOMPARE(doc->globals->memberCount(), 1);
586
587 Declaration *decl = doc->globals->memberAt(0)->asDeclaration();
588 QVERIFY(decl);
589
590 PointerType *ptrTy = decl->type()->asPointerType();
591 QVERIFY(ptrTy);
592
593 Function *funTy = ptrTy->elementType()->asFunctionType();
594 QVERIFY(funTy);
595
596 QEXPECT_FAIL("", "Requires initialize enclosing scope of pointer-to-function symbols", Continue);
597 QVERIFY(funTy->enclosingScope());
598
599 QEXPECT_FAIL("", "Requires initialize enclosing scope of pointer-to-function symbols", Continue);
600 QCOMPARE(funTy->enclosingScope(), decl->enclosingScope());
601 }
602
template_instance_1()603 void tst_Semantic::template_instance_1()
604 {
605 QSharedPointer<Document> doc = document("template <typename _Tp> class QList { void append(const _Tp &value); };");
606 QCOMPARE(doc->errorCount, 0U);
607 QCOMPARE(doc->globals->memberCount(), 1);
608
609 Template *templ = doc->globals->memberAt(0)->asTemplate();
610 QVERIFY(templ);
611
612 Declaration *decl = templ->memberAt(1)->asClass()->memberAt(0)->asDeclaration();
613 QVERIFY(decl);
614
615 TemplateArgument templArgs[] = {FullySpecifiedType(control->integerType(IntegerType::Int))};
616 const Name *templId = control->templateNameId(control->identifier("QList"), false, templArgs, 1);
617
618 FullySpecifiedType genTy = DeprecatedGenTemplateInstance::instantiate(templId, decl, control);
619
620 Overview oo;
621 oo.showReturnTypes = true;
622
623 const QString genDecl = oo.prettyType(genTy);
624 QCOMPARE(genDecl, QString::fromLatin1("void (const int &)"));
625 }
626
expression_under_cursor_1()627 void tst_Semantic::expression_under_cursor_1()
628 {
629 const QString plainText = "void *ptr = foo(10, bar";
630
631 QTextDocument textDocument;
632 textDocument.setPlainText(plainText);
633
634 QTextCursor tc(&textDocument);
635 tc.movePosition(QTextCursor::End);
636
637 ExpressionUnderCursor expressionUnderCursor(LanguageFeatures::defaultFeatures());
638 const QString expression = expressionUnderCursor(tc);
639
640 QCOMPARE(expression, QString("bar"));
641 }
642
bracketed_expression_under_cursor_1()643 void tst_Semantic::bracketed_expression_under_cursor_1()
644 {
645 const QString plainText = "int i = 0, j[1], k = j[i";
646
647 QTextDocument textDocument;
648 textDocument.setPlainText(plainText);
649
650 QTextCursor tc(&textDocument);
651 tc.movePosition(QTextCursor::End);
652
653 ExpressionUnderCursor expressionUnderCursor(LanguageFeatures::defaultFeatures());
654 const QString expression = expressionUnderCursor(tc);
655
656 QCOMPARE(expression, QString("i"));
657 }
658
bracketed_expression_under_cursor_2()659 void tst_Semantic::bracketed_expression_under_cursor_2()
660 {
661 const QString plainText = "[receiver msg";
662
663 QTextDocument textDocument;
664 textDocument.setPlainText(plainText);
665
666 QTextCursor tc(&textDocument);
667 tc.movePosition(QTextCursor::End);
668
669 ExpressionUnderCursor expressionUnderCursor(LanguageFeatures::defaultFeatures());
670 const QString expression = expressionUnderCursor(tc);
671
672 QCOMPARE(expression, plainText);
673 }
674
bracketed_expression_under_cursor_3()675 void tst_Semantic::bracketed_expression_under_cursor_3()
676 {
677 const QString plainText = "if ([receiver message";
678
679 QTextDocument textDocument;
680 textDocument.setPlainText(plainText);
681
682 QTextCursor tc(&textDocument);
683 tc.movePosition(QTextCursor::End);
684
685 ExpressionUnderCursor expressionUnderCursor(LanguageFeatures::defaultFeatures());
686 const QString expression = expressionUnderCursor(tc);
687
688 QCOMPARE(expression, QString("[receiver message"));
689 }
690
bracketed_expression_under_cursor_4()691 void tst_Semantic::bracketed_expression_under_cursor_4()
692 {
693 const QString plainText = "int i = 0, j[1], k = j[(i == 0) ? 0 : i";
694
695 QTextDocument textDocument;
696 textDocument.setPlainText(plainText);
697
698 QTextCursor tc(&textDocument);
699 tc.movePosition(QTextCursor::End);
700
701 ExpressionUnderCursor expressionUnderCursor(LanguageFeatures::defaultFeatures());
702 const QString expression = expressionUnderCursor(tc);
703
704 QCOMPARE(expression, QString("i"));
705 }
706
objcClass_1()707 void tst_Semantic::objcClass_1()
708 {
709 QSharedPointer<Document> doc = document("\n"
710 "@interface Zoo {} +(id)alloc;-(id)init;@end\n"
711 "@implementation Zoo\n"
712 "+(id)alloc{}\n"
713 "-(id)init{}\n"
714 "-(void)dealloc{}\n"
715 "@end\n",
716 true);
717
718 QCOMPARE(doc->errorCount, 0U);
719 QCOMPARE(doc->globals->memberCount(), 2);
720
721 ObjCClass *iface = doc->globals->memberAt(0)->asObjCClass();
722 QVERIFY(iface);
723 QVERIFY(iface->isInterface());
724 QCOMPARE(iface->memberCount(), 2);
725
726 ObjCClass *impl = doc->globals->memberAt(1)->asObjCClass();
727 QVERIFY(impl);
728 QVERIFY(!impl->isInterface());
729 QCOMPARE(impl->memberCount(), 3);
730
731 ObjCMethod *allocMethod = impl->memberAt(0)->asObjCMethod();
732 QVERIFY(allocMethod);
733 QVERIFY(allocMethod->name() && allocMethod->name()->identifier());
734 QCOMPARE(QLatin1String(allocMethod->name()->identifier()->chars()), QLatin1String("alloc"));
735 QVERIFY(allocMethod->isStatic());
736
737 ObjCMethod *deallocMethod = impl->memberAt(2)->asObjCMethod();
738 QVERIFY(deallocMethod);
739 QVERIFY(deallocMethod->name() && deallocMethod->name()->identifier());
740 QCOMPARE(QLatin1String(deallocMethod->name()->identifier()->chars()), QLatin1String("dealloc"));
741 QVERIFY(!deallocMethod->isStatic());
742 }
743
objcSelector_1()744 void tst_Semantic::objcSelector_1()
745 {
746 QSharedPointer<Document> doc = document("\n"
747 "@interface A {}\n"
748 "-(void) a:(int)a b:(int)b c:(int)c;\n"
749 "@end\n",
750 true);
751
752 QCOMPARE(doc->errorCount, 0U);
753 QCOMPARE(doc->globals->memberCount(), 1);
754
755 ObjCClass *iface = doc->globals->memberAt(0)->asObjCClass();
756 QVERIFY(iface);
757 QVERIFY(iface->isInterface());
758 QCOMPARE(iface->memberCount(), 1);
759
760 Declaration *decl = iface->memberAt(0)->asDeclaration();
761 QVERIFY(decl);
762 QVERIFY(decl->name());
763 const SelectorNameId *selId = decl->name()->asSelectorNameId();
764 QVERIFY(selId);
765 QCOMPARE(selId->nameCount(), 3);
766 QCOMPARE(selId->nameAt(0)->identifier()->chars(), "a");
767 QCOMPARE(selId->nameAt(1)->identifier()->chars(), "b");
768 QCOMPARE(selId->nameAt(2)->identifier()->chars(), "c");
769 }
770
771 class CollectSelectors: public ASTVisitor
772 {
773 public:
CollectSelectors(TranslationUnit * xUnit)774 CollectSelectors(TranslationUnit *xUnit): ASTVisitor(xUnit) {}
775
operator ()()776 QList<ObjCSelectorAST *> operator()() {
777 selectors.clear();
778 accept(translationUnit()->ast());
779 return selectors;
780 }
781
visit(ObjCSelectorAST * ast)782 virtual bool visit(ObjCSelectorAST *ast) {selectors.append(ast); return false;}
783
784 private:
785 QList<ObjCSelectorAST *> selectors;
786 };
787
objcSelector_2()788 void tst_Semantic::objcSelector_2()
789 {
790 QSharedPointer<Document> doc = document("\n"
791 "@implementation A {}\n"
792 "-(SEL)x {\n"
793 " return @selector(a:b:c:);\n"
794 "}\n"
795 "@end\n",
796 true);
797
798 QCOMPARE(doc->errorCount, 0U);
799 QCOMPARE(doc->globals->memberCount(), 1);
800
801 ObjCClass *iface = doc->globals->memberAt(0)->asObjCClass();
802 QVERIFY(iface);
803 QCOMPARE(iface->memberCount(), 1);
804
805 QList<ObjCSelectorAST*>selectors = CollectSelectors(doc->unit)();
806 QCOMPARE(selectors.size(), 2);
807
808 ObjCSelectorAST *sel = selectors.at(1)->asObjCSelector();
809 QVERIFY(sel);
810
811 const SelectorNameId *selId = sel->name->asSelectorNameId();
812 QVERIFY(selId);
813 QCOMPARE(selId->nameCount(), 3);
814 QCOMPARE(selId->nameAt(0)->identifier()->chars(), "a");
815 QCOMPARE(selId->nameAt(1)->identifier()->chars(), "b");
816 QCOMPARE(selId->nameAt(2)->identifier()->chars(), "c");
817 }
818
q_enum_1()819 void tst_Semantic::q_enum_1()
820 {
821 QSharedPointer<Document> doc = document("\n"
822 "class Tst {\n"
823 "Q_ENUMS(e)\n"
824 "public:\n"
825 "enum e { x, y };\n"
826 "};\n",
827 false, true);
828
829 QCOMPARE(doc->errorCount, 0U);
830 QCOMPARE(doc->globals->memberCount(), 1);
831 QVERIFY(doc->unit);
832 TranslationUnitAST *xUnit = doc->unit->ast()->asTranslationUnit();
833 QVERIFY(xUnit);
834 SimpleDeclarationAST *tstDecl = xUnit->declaration_list->value->asSimpleDeclaration();
835 QVERIFY(tstDecl);
836 ClassSpecifierAST *tst = tstDecl->decl_specifier_list->value->asClassSpecifier();
837 QVERIFY(tst);
838 QtEnumDeclarationAST *qtEnum = tst->member_specifier_list->value->asQtEnumDeclaration();
839 QVERIFY(qtEnum);
840 SimpleNameAST *e = qtEnum->enumerator_list->value->asSimpleName();
841 QVERIFY(e);
842 QCOMPARE(doc->unit->spell(e->identifier_token), "e");
843 QCOMPARE(e->name->identifier()->chars(), "e");
844 }
845
lambda_1()846 void tst_Semantic::lambda_1()
847 {
848 QSharedPointer<Document> doc = document("\n"
849 "void f() {\n"
850 " auto func = [](int a, int b) {return a + b;};\n"
851 "}\n", false, false, true);
852
853 QCOMPARE(doc->errorCount, 0U);
854 QCOMPARE(doc->globals->memberCount(), 1);
855 }
856
lambda_2()857 void tst_Semantic::lambda_2()
858 {
859 QSharedPointer<Document> doc = document(
860 "\n"
861 "class A {\n"
862 " void f(int i = [](){});\n"
863 "};\n"
864 , false, false, true);
865
866 QCOMPARE(doc->errorCount, 0U);
867 QCOMPARE(doc->globals->memberCount(), 1);
868 Class *A = doc->globals->memberAt(0)->asClass();
869 QVERIFY(A);
870 QCOMPARE(A->memberCount(), 1);
871 Declaration *d = A->memberAt(0)->asDeclaration();
872 QCOMPARE(d->name()->identifier()->chars(), "f");
873 Function *ty = d->type()->asFunctionType();
874 QVERIFY(ty);
875 QCOMPARE(ty->argumentCount(), 1);
876 Argument *arg = ty->argumentAt(0)->asArgument();
877 QVERIFY(arg);
878 const StringLiteral *init = arg->initializer();
879 QVERIFY(init);
880 QCOMPARE(init->chars(), "[](){}");
881 }
882
883
diagnostic_error()884 void tst_Semantic::diagnostic_error()
885 {
886 QSharedPointer<Document> doc = document("\n"
887 "class Foo {}\n",
888 false, false);
889
890 QCOMPARE(doc->errorCount, 1U);
891 QCOMPARE(doc->globals->memberCount(), 1);
892 }
893
894 namespace {
testEnumaratorDeclarator(Enum * e,int enumDeclIndex,const char * expectedConstantValue)895 void testEnumaratorDeclarator(Enum *e, int enumDeclIndex, const char *expectedConstantValue)
896 {
897 Declaration *enumMemberDeclaration = e->memberAt(enumDeclIndex)->asDeclaration();
898 QVERIFY(enumMemberDeclaration);
899 EnumeratorDeclaration *enumeratorDeclaration = enumMemberDeclaration->asEnumeratorDeclarator();
900 QVERIFY(enumeratorDeclaration);
901 if (const StringLiteral *constantValue = enumeratorDeclaration->constantValue())
902 QCOMPARE(constantValue->chars(), expectedConstantValue);
903 else
904 QVERIFY(!expectedConstantValue);
905 }
906 } // anonymous
907
enum_constantValue1()908 void tst_Semantic::enum_constantValue1()
909 {
910 QSharedPointer<Document> doc = document("\n"
911 "enum {\n"
912 "E1,\n"
913 "E2,\n"
914 "E3\n"
915 "};\n"
916 );
917
918 QCOMPARE(doc->errorCount, 0U);
919 QCOMPARE(doc->globals->memberCount(), 1);
920 Enum *e = doc->globals->memberAt(0)->asEnum();
921 QVERIFY(e);
922 QCOMPARE(e->memberCount(), 3);
923
924 testEnumaratorDeclarator(e, 0, "0");
925 testEnumaratorDeclarator(e, 1, "1");
926 testEnumaratorDeclarator(e, 2, "2");
927 }
928
enum_constantValue2()929 void tst_Semantic::enum_constantValue2()
930 {
931 QSharedPointer<Document> doc = document("\n"
932 "enum {\n"
933 "E1=10,\n"
934 "E2,\n"
935 "E3\n"
936 "};\n"
937 );
938
939 QCOMPARE(doc->errorCount, 0U);
940 QCOMPARE(doc->globals->memberCount(), 1);
941 Enum *e = doc->globals->memberAt(0)->asEnum();
942 QVERIFY(e);
943 QCOMPARE(e->memberCount(), 3);
944
945 testEnumaratorDeclarator(e, 0, "10");
946 testEnumaratorDeclarator(e, 1, "11");
947 testEnumaratorDeclarator(e, 2, "12");
948 }
949
enum_constantValue3()950 void tst_Semantic::enum_constantValue3()
951 {
952 QSharedPointer<Document> doc = document("\n"
953 "enum {\n"
954 "E1,\n"
955 "E2=10,\n"
956 "E3\n"
957 "};\n"
958 );
959
960 QCOMPARE(doc->errorCount, 0U);
961 QCOMPARE(doc->globals->memberCount(), 1);
962 Enum *e = doc->globals->memberAt(0)->asEnum();
963 QVERIFY(e);
964 QCOMPARE(e->memberCount(), 3);
965
966 testEnumaratorDeclarator(e, 0, "0");
967 testEnumaratorDeclarator(e, 1, "10");
968 testEnumaratorDeclarator(e, 2, "11");
969 }
970
enum_constantValue4()971 void tst_Semantic::enum_constantValue4()
972 {
973 QSharedPointer<Document> doc = document("\n"
974 "enum {\n"
975 "E1,\n"
976 "E2=E1+10,\n"
977 "E3,\n"
978 "E4=10,\n"
979 "E5\n"
980 "};\n"
981 );
982
983 QCOMPARE(doc->errorCount, 0U);
984 QCOMPARE(doc->globals->memberCount(), 1);
985 Enum *e = doc->globals->memberAt(0)->asEnum();
986 QVERIFY(e);
987 QCOMPARE(e->memberCount(), 5);
988
989 testEnumaratorDeclarator(e, 0, "0");
990 testEnumaratorDeclarator(e, 1, "E1+10");
991 testEnumaratorDeclarator(e, 2, NULL);
992 testEnumaratorDeclarator(e, 3, "10");
993 testEnumaratorDeclarator(e, 4, "11");
994 }
995
enum_constantValue5()996 void tst_Semantic::enum_constantValue5()
997 {
998 QSharedPointer<Document> doc = document("\n"
999 "enum {\n"
1000 "E1,\n"
1001 "E2=E1,\n"
1002 "E3,\n"
1003 "E4=E3,\n"
1004 "E5\n"
1005 "};\n"
1006 );
1007
1008 QCOMPARE(doc->errorCount, 0U);
1009 QCOMPARE(doc->globals->memberCount(), 1);
1010 Enum *e = doc->globals->memberAt(0)->asEnum();
1011 QVERIFY(e);
1012 QCOMPARE(e->memberCount(), 5);
1013
1014 testEnumaratorDeclarator(e, 0, "0");
1015 testEnumaratorDeclarator(e, 1, "0");
1016 testEnumaratorDeclarator(e, 2, "1");
1017 testEnumaratorDeclarator(e, 3, "1");
1018 testEnumaratorDeclarator(e, 4, "2");
1019 }
1020
enum_constantValueNegative()1021 void tst_Semantic::enum_constantValueNegative()
1022 {
1023 QSharedPointer<Document> doc = document(
1024 "enum {\n"
1025 " E1=-2,\n"
1026 " E2,\n"
1027 " E3,\n"
1028 " E4\n"
1029 "};\n"
1030 );
1031
1032 QCOMPARE(doc->errorCount, 0U);
1033 QCOMPARE(doc->globals->memberCount(), 1);
1034 Enum *e = doc->globals->memberAt(0)->asEnum();
1035 QVERIFY(e);
1036 QCOMPARE(e->memberCount(), 4);
1037
1038 testEnumaratorDeclarator(e, 0, "-2");
1039 testEnumaratorDeclarator(e, 1, "-1");
1040 testEnumaratorDeclarator(e, 2, "0");
1041 testEnumaratorDeclarator(e, 3, "1");
1042 }
1043
1044 QTEST_MAIN(tst_Semantic)
1045 #include "tst_semantic.moc"
1046