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