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 <QObject>
28
29 #include <cplusplus/AST.h>
30 #include <cplusplus/ASTVisitor.h>
31 #include <cplusplus/CppDocument.h>
32 #include <cplusplus/Literals.h>
33 #include <cplusplus/LookupContext.h>
34 #include <cplusplus/Name.h>
35 #include <cplusplus/NamePrettyPrinter.h>
36 #include <cplusplus/Overview.h>
37 #include <cplusplus/ResolveExpression.h>
38 #include <cplusplus/Symbols.h>
39 #include <cplusplus/TranslationUnit.h>
40
41 //TESTED_COMPONENT=src/libs/cplusplus
42 using namespace CPlusPlus;
43
44 template<typename _T1, typename _T2>
invert(const QMap<_T1,_T2> & m)45 QMultiMap<_T2, _T1> invert(const QMap<_T1, _T2> &m)
46 {
47 QMultiMap<_T2, _T1> i;
48 typename QMap<_T1, _T2>::const_iterator it = m.constBegin();
49 for (; it != m.constEnd(); ++it) {
50 i.insert(it.value(), it.key());
51 }
52 return i;
53 }
54
55 class ClassSymbols: protected ASTVisitor,
56 public QMap<ClassSpecifierAST *, Class *>
57 {
58 public:
ClassSymbols(TranslationUnit * translationUnit)59 ClassSymbols(TranslationUnit *translationUnit)
60 : ASTVisitor(translationUnit)
61 { }
62
asMap() const63 QMap<ClassSpecifierAST *, Class *> asMap() const
64 { return *this; }
65
operator ()(AST * ast)66 void operator()(AST *ast)
67 { accept(ast); }
68
69 protected:
visit(ClassSpecifierAST * ast)70 virtual bool visit(ClassSpecifierAST *ast)
71 {
72 Class *classSymbol = ast->symbol;
73 Q_ASSERT(classSymbol != 0);
74
75 insert(ast, classSymbol);
76
77 return true;
78 }
79 };
80
81 class tst_Lookup: public QObject
82 {
83 Q_OBJECT
84
85 private slots:
86 void base_class_defined_1();
87
88 void document_functionAt_data();
89 void document_functionAt();
90
91 // Objective-C
92 void simple_class_1();
93 void class_with_baseclass();
94 void class_with_protocol_with_protocol();
95 void iface_impl_scoping();
96
97 // template instantiation:
98 void templates_1();
99 void templates_2();
100 void templates_3();
101 void templates_4();
102 void templates_5();
103
104 void minimalname_data();
105 void minimalname();
106 };
107
base_class_defined_1()108 void tst_Lookup::base_class_defined_1()
109 {
110 Overview overview;
111
112 const QByteArray source = "\n"
113 "class base {};\n"
114 "class derived: public base {};\n";
115
116 Document::Ptr doc = Document::create("base_class_defined_1");
117 doc->setUtf8Source(source);
118 doc->parse();
119 doc->check();
120
121 QVERIFY(doc->diagnosticMessages().isEmpty());
122 QCOMPARE(doc->globalSymbolCount(), 2);
123
124 Snapshot snapshot;
125 snapshot.insert(doc);
126
127 Class *baseClass = doc->globalSymbolAt(0)->asClass();
128 QVERIFY(baseClass);
129
130 Class *derivedClass = doc->globalSymbolAt(1)->asClass();
131 QVERIFY(derivedClass);
132
133 const LookupContext ctx(doc, snapshot);
134
135 ClassOrNamespace *klass = ctx.lookupType(derivedClass->baseClassAt(0)->name(), derivedClass->enclosingScope());
136 QVERIFY(klass != 0);
137
138 QCOMPARE(klass->symbols().size(), 1);
139 QCOMPARE(klass->symbols().first(), baseClass);
140
141 TranslationUnit *unit = doc->translationUnit();
142 QVERIFY(unit != 0);
143
144 TranslationUnitAST *ast = unit->ast()->asTranslationUnit();
145 QVERIFY(ast != 0);
146
147 ClassSymbols classSymbols(unit);
148 classSymbols(ast);
149
150 QCOMPARE(classSymbols.size(), 2);
151
152 const QMultiMap<Class *, ClassSpecifierAST *> classToAST = invert(classSymbols.asMap());
153
154 QVERIFY(!classToAST.values(baseClass).isEmpty());
155 QVERIFY(!classToAST.values(derivedClass).isEmpty());
156 }
157
document_functionAt_data()158 void tst_Lookup::document_functionAt_data()
159 {
160 QTest::addColumn<QByteArray>("source");
161 QTest::addColumn<int>("line");
162 QTest::addColumn<int>("column");
163 QTest::addColumn<QString>("expectedFunction");
164 QTest::addColumn<int>("expectedOpeningDeclaratorParenthesisLine");
165 QTest::addColumn<int>("expectedClosingBraceLine");
166
167 QByteArray source = "\n"
168 "void Foo::Bar() {\n" // line 1
169 " \n"
170 " for (int i=0; i < 10; ++i) {\n" // line 3
171 " \n"
172 " }\n" // line 5
173 "}\n";
174 QString expectedFunction = QString::fromLatin1("Foo::Bar");
175 QTest::newRow("nonInline1") << source << 1 << 2 << QString() << -1 << -1;
176 QTest::newRow("nonInline2") << source << 1 << 11 << expectedFunction << 1 << 6;
177 QTest::newRow("nonInline3") << source << 2 << 2 << expectedFunction << 1 << 6;
178 QTest::newRow("nonInline4") << source << 3 << 10 << expectedFunction << 1 << 6;
179 QTest::newRow("nonInline5") << source << 4 << 3 << expectedFunction << 1 << 6;
180 QTest::newRow("nonInline6") << source << 6 << 1 << expectedFunction << 1 << 6;
181
182 source = "\n"
183 "namespace N {\n" // line 1
184 "class C {\n"
185 " void f()\n" // line 3
186 " {\n"
187 " }\n" // line 5
188 "};\n"
189 "}\n"; // line 7
190 expectedFunction = QString::fromLatin1("N::C::f");
191 QTest::newRow("inline1") << source << 1 << 2 << QString() << -1 << -1;
192 QTest::newRow("inline2") << source << 2 << 10 << QString() << -1 << -1;
193 QTest::newRow("inline2") << source << 3 << 10 << expectedFunction << 3 << 5;
194
195 source = "\n"
196 "void f(Helper helper = [](){})\n" // line 1
197 "{\n"
198 "}\n"; // line 3
199 expectedFunction = QString::fromLatin1("f");
200 QTest::newRow("inlineWithLambdaArg1") << source << 2 << 1 << expectedFunction << 1 << 3;
201
202 source = "\n"
203 "int g_global = 456;\n" // line 1
204 "int foo()\n" // line 2
205 "{\n"
206 " g_global = 89;\n" // line 4
207 " std::function<int(int)> cb = [](int) { return 1; };\n"
208 " g_global = 222;\n"
209 "}\n"; // line 7
210 expectedFunction = QString::fromLatin1("foo");
211 QTest::newRow("inlineWithLambda1") << source << 4 << 1 << expectedFunction << 2 << 7;
212 QTest::newRow("inlineWithLambda2") << source << 6 << 1 << expectedFunction << 2 << 7;
213 }
214
document_functionAt()215 void tst_Lookup::document_functionAt()
216 {
217 QFETCH(QByteArray, source);
218 QFETCH(int, line);
219 QFETCH(int, column);
220 QFETCH(QString, expectedFunction);
221 QFETCH(int, expectedOpeningDeclaratorParenthesisLine);
222 QFETCH(int, expectedClosingBraceLine);
223
224 Document::Ptr doc = Document::create("document_functionAt");
225 doc->setUtf8Source(source);
226 doc->parse();
227 doc->check();
228 QVERIFY(doc->diagnosticMessages().isEmpty());
229
230 int actualOpeningDeclaratorParenthesisLine = -1;
231 int actualClosingBraceLine = -1;
232 const QString actualFunction = doc->functionAt(line, column,
233 &actualOpeningDeclaratorParenthesisLine,
234 &actualClosingBraceLine);
235 QCOMPARE(actualFunction, expectedFunction);
236 QCOMPARE(actualOpeningDeclaratorParenthesisLine, expectedOpeningDeclaratorParenthesisLine);
237 QCOMPARE(actualClosingBraceLine, expectedClosingBraceLine);
238 }
239
simple_class_1()240 void tst_Lookup::simple_class_1()
241 {
242 const QByteArray source = "\n"
243 "@interface Zoo {} +(id)alloc; -(id)init; @end\n"
244 "@implementation Zoo +(id)alloc{} -(id)init{} -(void)dealloc{} @end\n";
245
246 Document::Ptr doc = Document::create("simple_class_1");
247 doc->setUtf8Source(source);
248 doc->parse();
249 doc->check();
250
251 QVERIFY(doc->diagnosticMessages().isEmpty());
252 QCOMPARE(doc->globalSymbolCount(), 2);
253
254 Snapshot snapshot;
255 snapshot.insert(doc);
256
257 ObjCClass *iface = doc->globalSymbolAt(0)->asObjCClass();
258 QVERIFY(iface);
259 QVERIFY(iface->isInterface());
260 QCOMPARE(iface->memberCount(), 2);
261
262 ObjCClass *impl = doc->globalSymbolAt(1)->asObjCClass();
263 QVERIFY(impl);
264 QVERIFY(!impl->isInterface());
265 QCOMPARE(impl->memberCount(), 3);
266
267 Declaration *allocMethodIface = iface->memberAt(0)->asDeclaration();
268 QVERIFY(allocMethodIface);
269 QVERIFY(allocMethodIface->name() && allocMethodIface->name()->identifier());
270 QCOMPARE(QLatin1String(allocMethodIface->name()->identifier()->chars()), QLatin1String("alloc"));
271
272 ObjCMethod *allocMethodImpl = impl->memberAt(0)->asObjCMethod();
273 QVERIFY(allocMethodImpl);
274 QVERIFY(allocMethodImpl->name() && allocMethodImpl->name()->identifier());
275 QCOMPARE(QLatin1String(allocMethodImpl->name()->identifier()->chars()), QLatin1String("alloc"));
276
277 ObjCMethod *deallocMethod = impl->memberAt(2)->asObjCMethod();
278 QVERIFY(deallocMethod);
279 QVERIFY(deallocMethod->name() && deallocMethod->name()->identifier());
280 QCOMPARE(QLatin1String(deallocMethod->name()->identifier()->chars()), QLatin1String("dealloc"));
281
282 const LookupContext context(doc, snapshot);
283
284 // check class resolving:
285 ClassOrNamespace *klass = context.lookupType(impl->name(), impl->enclosingScope());
286 QVERIFY(klass != 0);
287 QCOMPARE(klass->symbols().size(), 2);
288 QVERIFY(klass->symbols().contains(iface));
289 QVERIFY(klass->symbols().contains(impl));
290
291 // check method resolving:
292 QList<LookupItem> results = context.lookup(allocMethodImpl->name(), impl);
293 QCOMPARE(results.size(), 2);
294 QCOMPARE(results.at(0).declaration(), allocMethodIface);
295 QCOMPARE(results.at(1).declaration(), allocMethodImpl);
296
297 results = context.lookup(deallocMethod->name(), impl);
298 QCOMPARE(results.size(), 1);
299 QCOMPARE(results.at(0).declaration(), deallocMethod);
300 }
301
class_with_baseclass()302 void tst_Lookup::class_with_baseclass()
303 {
304 const QByteArray source = "\n"
305 "@implementation BaseZoo {} -(void)baseDecl; -(void)baseMethod{} @end\n"
306 "@interface Zoo: BaseZoo {} +(id)alloc; -(id)init; @end\n"
307 "@implementation Zoo +(id)alloc{} -(id)init{} -(void)dealloc{} @end\n";
308
309 Document::Ptr doc = Document::create("class_with_baseclass");
310 doc->setUtf8Source(source);
311 doc->parse();
312 doc->check();
313
314 QVERIFY(doc->diagnosticMessages().isEmpty());
315 QCOMPARE(doc->globalSymbolCount(), 3);
316
317 Snapshot snapshot;
318 snapshot.insert(doc);
319
320 Document::Ptr emptyDoc = Document::create("<empty>");
321
322 ObjCClass *baseZoo = doc->globalSymbolAt(0)->asObjCClass();
323 QVERIFY(baseZoo);
324 QVERIFY(!baseZoo->isInterface());
325 QCOMPARE(baseZoo->memberCount(), 2);
326
327 ObjCClass *zooIface = doc->globalSymbolAt(1)->asObjCClass();
328 QVERIFY(zooIface);
329 QVERIFY(zooIface->isInterface());
330 QVERIFY(zooIface->baseClass()->name() == baseZoo->name());
331
332 ObjCClass *zooImpl = doc->globalSymbolAt(2)->asObjCClass();
333 QVERIFY(zooImpl);
334 QVERIFY(!zooImpl->isInterface());
335 QCOMPARE(zooImpl->memberCount(), 3);
336
337 Declaration *baseDecl = baseZoo->memberAt(0)->asDeclaration();
338 QVERIFY(baseDecl);
339 QVERIFY(baseDecl->name() && baseDecl->name()->identifier());
340 QCOMPARE(QLatin1String(baseDecl->name()->identifier()->chars()), QLatin1String("baseDecl"));
341
342 ObjCMethod *baseMethod = baseZoo->memberAt(1)->asObjCMethod();
343 QVERIFY(baseMethod);
344 QVERIFY(baseMethod->name() && baseMethod->name()->identifier());
345 QCOMPARE(QLatin1String(baseMethod->name()->identifier()->chars()), QLatin1String("baseMethod"));
346
347 const LookupContext context(doc, snapshot);
348
349 ClassOrNamespace *objClass = context.lookupType(baseZoo->name(), zooImpl->enclosingScope());
350 QVERIFY(objClass != 0);
351 QVERIFY(objClass->symbols().contains(baseZoo));
352
353 QList<LookupItem> results = context.lookup(baseDecl->name(), zooImpl);
354 QCOMPARE(results.size(), 1);
355 QCOMPARE(results.at(0).declaration(), baseDecl);
356
357 results = context.lookup(baseMethod->name(), zooImpl);
358 QCOMPARE(results.size(), 1);
359 QCOMPARE(results.at(0).declaration(), baseMethod);
360 }
361
class_with_protocol_with_protocol()362 void tst_Lookup::class_with_protocol_with_protocol()
363 {
364 const QByteArray source = "\n"
365 "@protocol P1 -(void)p1method; @end\n"
366 "@protocol P2 <P1> -(void)p2method; @end\n"
367 "@interface Zoo <P2> {} +(id)alloc; -(id)init; @end\n"
368 "@implementation Zoo +(id)alloc{} -(id)init{} -(void)dealloc{} @end\n";
369
370 Document::Ptr doc = Document::create("class_with_protocol_with_protocol");
371 doc->setUtf8Source(source);
372 doc->parse();
373 doc->check();
374
375 QVERIFY(doc->diagnosticMessages().isEmpty());
376 QCOMPARE(doc->globalSymbolCount(), 4);
377
378 Snapshot snapshot;
379 snapshot.insert(doc);
380
381 ObjCProtocol *P1 = doc->globalSymbolAt(0)->asObjCProtocol();
382 QVERIFY(P1);
383 QCOMPARE(P1->memberCount(), 1);
384 QCOMPARE(P1->protocolCount(), 0);
385
386 Declaration *p1method = P1->memberAt(0)->asDeclaration();
387 QVERIFY(p1method);
388 QCOMPARE(QLatin1String(p1method->name()->identifier()->chars()), QLatin1String("p1method"));
389
390 ObjCProtocol *P2 = doc->globalSymbolAt(1)->asObjCProtocol();
391 QVERIFY(P2);
392 QCOMPARE(P2->memberCount(), 1);
393 QCOMPARE(P2->protocolCount(), 1);
394 QCOMPARE(QLatin1String(P2->protocolAt(0)->name()->identifier()->chars()), QLatin1String("P1"));
395
396 ObjCClass *zooImpl = doc->globalSymbolAt(3)->asObjCClass();
397 QVERIFY(zooImpl);
398
399 const LookupContext context(doc, snapshot);
400
401 {
402 const QList<LookupItem> candidates = context.lookup(P1->name(), zooImpl->enclosingScope());
403 QCOMPARE(candidates.size(), 1);
404 QVERIFY(candidates.at(0).declaration() == P1);
405 }
406
407 {
408 const QList<LookupItem> candidates = context.lookup(P2->protocolAt(0)->name(), zooImpl->enclosingScope());
409 QCOMPARE(candidates.size(), 1);
410 QVERIFY(candidates.first().declaration() == P1);
411 }
412
413 QList<LookupItem> results = context.lookup(p1method->name(), zooImpl);
414 QCOMPARE(results.size(), 1);
415 QCOMPARE(results.at(0).declaration(), p1method);
416 }
417
iface_impl_scoping()418 void tst_Lookup::iface_impl_scoping()
419 {
420 const QByteArray source = "\n"
421 "@interface Scooping{}-(int)method1:(int)arg;-(void)method2;@end\n"
422 "@implementation Scooping-(int)method1:(int)arg{return arg;}@end\n";
423
424 Document::Ptr doc = Document::create("class_with_protocol_with_protocol");
425 doc->setUtf8Source(source);
426 doc->parse();
427 doc->check();
428
429 QVERIFY(doc->diagnosticMessages().isEmpty());
430 QCOMPARE(doc->globalSymbolCount(), 2);
431
432 Snapshot snapshot;
433 snapshot.insert(doc);
434
435 ObjCClass *iface = doc->globalSymbolAt(0)->asObjCClass();
436 QVERIFY(iface);
437 QVERIFY(iface->isInterface());
438 ObjCClass *impl = doc->globalSymbolAt(1)->asObjCClass();
439 QVERIFY(impl);
440 QVERIFY(!impl->isInterface());
441
442 QCOMPARE(iface->memberCount(), 2);
443 QCOMPARE(impl->memberCount(), 1);
444
445 ObjCMethod *method1Impl = impl->memberAt(0)->asObjCMethod();
446 QVERIFY(method1Impl);
447 QCOMPARE(method1Impl->identifier()->chars(), "method1");
448
449 // get the body of method1
450 QCOMPARE(method1Impl->memberCount(), 2);
451 Argument *method1Arg = method1Impl->memberAt(0)->asArgument();
452 QVERIFY(method1Arg);
453 QCOMPARE(method1Arg->identifier()->chars(), "arg");
454 QVERIFY(method1Arg->type()->isIntegerType());
455
456 Block *method1Body = method1Impl->memberAt(1)->asBlock();
457 QVERIFY(method1Body);
458
459 const LookupContext context(doc, snapshot);
460
461 { // verify if we can resolve "arg" in the body
462 QCOMPARE(method1Impl->argumentCount(), 1);
463 Argument *arg = method1Impl->argumentAt(0)->asArgument();
464 QVERIFY(arg);
465 QVERIFY(arg->name());
466 QVERIFY(arg->name()->identifier());
467 QCOMPARE(arg->name()->identifier()->chars(), "arg");
468 QVERIFY(arg->type()->isIntegerType());
469
470 const QList<LookupItem> candidates = context.lookup(arg->name(), method1Body->enclosingScope());
471 QCOMPARE(candidates.size(), 1);
472 QVERIFY(candidates.at(0).declaration()->type()->asIntegerType());
473 }
474
475 Declaration *method2 = iface->memberAt(1)->asDeclaration();
476 QVERIFY(method2);
477 QCOMPARE(method2->identifier()->chars(), "method2");
478
479 { // verify if we can resolve "method2" in the body
480 const QList<LookupItem> candidates = context.lookup(method2->name(), method1Body->enclosingScope());
481 QCOMPARE(candidates.size(), 1);
482 QCOMPARE(candidates.at(0).declaration(), method2);
483 }
484 }
485
templates_1()486 void tst_Lookup::templates_1()
487 {
488 const QByteArray source = "\n"
489 "namespace std {\n"
490 " template <typename T>\n"
491 " struct _List_iterator {\n"
492 " T data;\n"
493 " };\n"
494 "\n"
495 " template <typename T>\n"
496 " struct list {\n"
497 " typedef _List_iterator<T> iterator;\n"
498 "\n"
499 " iterator begin();\n"
500 " _List_iterator<T> end();\n"
501 " };\n"
502 "}\n"
503 "\n"
504 "struct Point {\n"
505 " int x, y;\n"
506 "};\n"
507 "\n"
508 "int main()\n"
509 "{\n"
510 " std::list<Point> l;\n"
511 " l.begin(); // std::_List_iterator<Point> .. and not only _List_iterator<Point>\n"
512 " l.end(); // std::_List_iterator<Point>\n"
513 "}\n";
514 Document::Ptr doc = Document::create("templates_1");
515 doc->setUtf8Source(source);
516 doc->parse();
517 doc->check();
518
519 QVERIFY(doc->diagnosticMessages().isEmpty());
520 }
521
templates_2()522 void tst_Lookup::templates_2()
523 {
524 const QByteArray source = "\n"
525 "template <typename T1>\n"
526 "struct Node {\n"
527 " T1 value;\n"
528 " Node *next;\n"
529 " Node<T1> *other_next;\n"
530 "};\n"
531 "\n"
532 "template <typename T2>\n"
533 "struct List {\n"
534 " Node<T2> *elements;\n"
535 "};\n"
536 "\n"
537 "int main()\n"
538 "{\n"
539 " List<int> *e;\n"
540 " e->elements; // Node<int> *\n"
541 " e->elements->next; // Node<int> *\n"
542 " e->elements->other_next; // Node<int> *\n"
543 "}\n"
544 ;
545 Document::Ptr doc = Document::create("templates_2");
546 doc->setUtf8Source(source);
547 doc->parse();
548 doc->check();
549
550 QVERIFY(doc->diagnosticMessages().isEmpty());
551 }
552
templates_3()553 void tst_Lookup::templates_3()
554 {
555 const QByteArray source = "\n"
556 "struct Point {\n"
557 " int x, y;\n"
558 "};\n"
559 "\n"
560 "template <typename T = Point>\n"
561 "struct List {\n"
562 " const T &at(int);\n"
563 "};\n"
564 "\n"
565 "int main()\n"
566 "{\n"
567 " List<> l;\n"
568 " l.at(0); // const Point &\n"
569 "}\n";
570 Document::Ptr doc = Document::create("templates_3");
571 doc->setUtf8Source(source);
572 doc->parse();
573 doc->check();
574
575 QVERIFY(doc->diagnosticMessages().isEmpty());
576 }
577
templates_4()578 void tst_Lookup::templates_4()
579 {
580 const QByteArray source = "\n"
581 "template <typename T>\n"
582 "struct Allocator {\n"
583 " typedef T *pointer_type;\n"
584 " typedef T &reference_type;\n"
585 "};\n"
586 "\n"
587 "template <typename T>\n"
588 "struct SharedPtr {\n"
589 " typedef typename Allocator<T>::pointer_type pointer_type;\n"
590 " typedef typename Allocator<T>::reference_type reference_type;\n"
591 "\n"
592 " pointer_type operator->();\n"
593 " reference_type operator*();\n"
594 "\n"
595 " pointer_type data();\n"
596 " reference_type get();\n"
597 "\n"
598 "};\n"
599 "\n"
600 "struct Point {\n"
601 " int x,y;\n"
602 "};\n"
603 "\n"
604 "int main()\n"
605 "{\n"
606 " SharedPtr<Point> l;\n"
607 "\n"
608 " l->x; // int\n"
609 " (*l); // Point &\n"
610 "}\n";
611 Document::Ptr doc = Document::create("templates_4");
612 doc->setUtf8Source(source);
613 doc->parse();
614 doc->check();
615
616 QVERIFY(doc->diagnosticMessages().isEmpty());
617 }
618
templates_5()619 void tst_Lookup::templates_5()
620 {
621 const QByteArray source = "\n"
622 "struct Point {\n"
623 " int x,y;\n"
624 "};\n"
625 "\n"
626 "template <typename _Tp>\n"
627 "struct Allocator {\n"
628 " typedef const _Tp &const_reference;\n"
629 "\n"
630 " const_reference get();\n"
631 "};\n"
632 "\n"
633 "int main()\n"
634 "{\n"
635 " Allocator<Point>::const_reference r = pt;\n"
636 " //r.; // const Point &\n"
637 "\n"
638 " Allocator<Point> a;\n"
639 " a.get(); // const Point &\n"
640 "}\n";
641 Document::Ptr doc = Document::create("templates_5");
642 doc->setUtf8Source(source);
643 doc->parse();
644 doc->check();
645
646 QVERIFY(doc->diagnosticMessages().isEmpty());
647 }
648
minimalname_data()649 void tst_Lookup::minimalname_data()
650 {
651 QTest::addColumn<QByteArray>("source");
652 QTest::addColumn<int>("index");
653
654 QTest::newRow("inlineNamespace1")
655 << QByteArray("namespace std { inline namespace __cxx11 { class string{}; } }\n")
656 << 0;
657
658 // This case is extracted from libstdc++ 5.4.0.
659 // The inline namespace is re-opened as non-inline, which is not standard
660 // compliant. However, gcc does this and clang only issues a warning.
661 QTest::newRow("inlineNamespace2")
662 << QByteArray("namespace std { inline namespace __cxx11 {} }\n"
663 "namespace std { namespace __cxx11 { class string{}; } }\n")
664 << 1;
665 }
666
minimalname()667 void tst_Lookup::minimalname()
668 {
669 QFETCH(QByteArray, source);
670 QFETCH(int, index);
671
672 Document::Ptr doc = Document::create("minimalname");
673 doc->setUtf8Source(source);
674 doc->parse();
675 doc->check();
676
677 Snapshot snapshot;
678 snapshot.insert(doc);
679 LookupContext ctx(doc, snapshot);
680 Control control;
681 Symbol *symbol = doc->globalSymbolAt(unsigned(index))
682 ->asNamespace()->memberAt(0)->asNamespace()->memberAt(0);
683
684 const Name *minimalName = LookupContext::minimalName(symbol, ctx.globalNamespace(), &control);
685
686 Overview oo;
687 const QString minimalNameAsString = NamePrettyPrinter(&oo)(minimalName);
688 QCOMPARE(minimalNameAsString, QString::fromUtf8("std::string"));
689 }
690
691 QTEST_APPLESS_MAIN(tst_Lookup)
692 #include "tst_lookup.moc"
693