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