LookupContext.cpp 68.8 KB
Newer Older
hjk's avatar
hjk committed
1
/****************************************************************************
2
**
3
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
hjk's avatar
hjk committed
4
** Contact: http://www.qt-project.org/legal
5
**
hjk's avatar
hjk committed
6
** This file is part of Qt Creator.
7
**
hjk's avatar
hjk committed
8
9
10
11
12
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
Eike Ziller's avatar
Eike Ziller committed
13
14
** conditions see http://www.qt.io/licensing.  For further information
** use the contact form at http://www.qt.io/contact-us.
15
16
**
** GNU Lesser General Public License Usage
hjk's avatar
hjk committed
17
** Alternatively, this file may be used under the terms of the GNU Lesser
Eike Ziller's avatar
Eike Ziller committed
18
19
20
21
22
23
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file.  Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
hjk's avatar
hjk committed
24
25
26
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
con's avatar
con committed
27
28
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
hjk's avatar
hjk committed
29
****************************************************************************/
30
31

#include "LookupContext.h"
32

33
34
#include "ResolveExpression.h"
#include "Overview.h"
35
#include "DeprecatedGenTemplateInstance.h"
36
#include "CppRewriter.h"
37

38
39
40
41
42
43
#include <cplusplus/CoreTypes.h>
#include <cplusplus/Symbols.h>
#include <cplusplus/Literals.h>
#include <cplusplus/Names.h>
#include <cplusplus/Scope.h>
#include <cplusplus/Control.h>
44

45
46
47
#include <QStack>
#include <QHash>
#include <QVarLengthArray>
hjk's avatar
hjk committed
48
#include <QDebug>
49
50

using namespace CPlusPlus;
51

52
static const bool debug = ! qgetenv("QTC_LOOKUPCONTEXT_DEBUG").isEmpty();
53

54
static void addNames(const Name *name, QList<const Name *> *names, bool addAllNames = false)
55
56
57
{
    if (! name)
        return;
58
    if (const QualifiedNameId *q = name->asQualifiedNameId()) {
59
        addNames(q->base(), names);
60
        addNames(q->name(), names, addAllNames);
61
    } else if (addAllNames || name->isNameId() || name->isTemplateNameId() || name->isAnonymousNameId()) {
62
        names->append(name);
63
64
65
    }
}

66
static void path_helper(Symbol *symbol, QList<const Name *> *names)
67
68
69
70
{
    if (! symbol)
        return;

71
    path_helper(symbol->enclosingScope(), names);
72

73
74
    if (symbol->name()) {
        if (symbol->isClass() || symbol->isNamespace()) {
75
            addNames(symbol->name(), names);
76

77
        } else if (symbol->isObjCClass() || symbol->isObjCBaseClass() || symbol->isObjCProtocol()
78
79
                || symbol->isObjCForwardClassDeclaration() || symbol->isObjCForwardProtocolDeclaration()
                || symbol->isForwardClassDeclaration()) {
80
81
            addNames(symbol->name(), names);

82
        } else if (symbol->isFunction()) {
83
84
            if (const QualifiedNameId *q = symbol->name()->asQualifiedNameId())
                addNames(q->base(), names);
85
86
87
        } else if (Enum *e = symbol->asEnum()) {
            if (e->isScoped())
                addNames(symbol->name(), names);
88
89
90
91
        }
    }
}

92
93
94
95
static bool isNestedInstantiationEnclosingTemplate(
        ClassOrNamespace *nestedClassOrNamespaceInstantiation,
        ClassOrNamespace *enclosingTemplateClassInstantiation)
{
96
97
98
99
    QList<ClassOrNamespace *> processed;
    while (enclosingTemplateClassInstantiation
           && !processed.contains(enclosingTemplateClassInstantiation)) {
        processed.append(enclosingTemplateClassInstantiation);
100
101
102
103
104
105
106
107
        if (enclosingTemplateClassInstantiation == nestedClassOrNamespaceInstantiation)
            return false;
        enclosingTemplateClassInstantiation = enclosingTemplateClassInstantiation->parent();
    }

    return true;
}

108
109
namespace CPlusPlus {

110
static inline bool compareName(const Name *name, const Name *other)
111
112
113
114
{
    if (name == other)
        return true;

115
    if (name && other) {
116
117
118
        const Identifier *id = name->identifier();
        const Identifier *otherId = other->identifier();

119
        if (id == otherId || (id && id->match(otherId)))
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
            return true;
    }

    return false;
}

bool compareFullyQualifiedName(const QList<const Name *> &path, const QList<const Name *> &other)
{
    if (path.length() != other.length())
        return false;

    for (int i = 0; i < path.length(); ++i) {
        if (! compareName(path.at(i), other.at(i)))
            return false;
    }

    return true;
}

}

141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
namespace CPlusPlus {
namespace Internal {

bool operator==(const FullyQualifiedName &left, const FullyQualifiedName &right)
{
    return compareFullyQualifiedName(left.fqn, right.fqn);
}

uint qHash(const FullyQualifiedName &fullyQualifiedName)
{
    uint h = 0;
    for (int i = 0; i < fullyQualifiedName.fqn.size(); ++i) {
        if (const Name *n = fullyQualifiedName.fqn.at(i)) {
            if (const Identifier *id = n->identifier()) {
                h <<= 1;
                h += id->hashCode();
            }
        }
    }
    return h;
}
}
}

165
166
167
168
/////////////////////////////////////////////////////////////////////
// LookupContext
/////////////////////////////////////////////////////////////////////
LookupContext::LookupContext()
169
    : m_expandTemplates(false)
170
171
172
173
{ }

LookupContext::LookupContext(Document::Ptr thisDocument,
                             const Snapshot &snapshot)
174
175
176
    : _expressionDocument(Document::create(QLatin1String("<LookupContext>")))
    , _thisDocument(thisDocument)
    , _snapshot(snapshot)
177
    , _bindings(new CreateBindings(thisDocument, snapshot))
178
    , m_expandTemplates(false)
179
180
181
182
183
{
}

LookupContext::LookupContext(Document::Ptr expressionDocument,
                             Document::Ptr thisDocument,
184
185
                             const Snapshot &snapshot,
                             QSharedPointer<CreateBindings> bindings)
186
187
188
    : _expressionDocument(expressionDocument)
    , _thisDocument(thisDocument)
    , _snapshot(snapshot)
189
    , _bindings(bindings)
190
    , m_expandTemplates(false)
191
192
193
194
{
}

LookupContext::LookupContext(const LookupContext &other)
195
196
197
198
199
    : _expressionDocument(other._expressionDocument)
    , _thisDocument(other._thisDocument)
    , _snapshot(other._snapshot)
    , _bindings(other._bindings)
    , m_expandTemplates(other.m_expandTemplates)
200
201
{ }

202
LookupContext &LookupContext::operator=(const LookupContext &other)
203
204
205
206
207
{
    _expressionDocument = other._expressionDocument;
    _thisDocument = other._thisDocument;
    _snapshot = other._snapshot;
    _bindings = other._bindings;
208
    m_expandTemplates = other.m_expandTemplates;
209
210
211
    return *this;
}

212
QList<const Name *> LookupContext::fullyQualifiedName(Symbol *symbol)
213
{
214
    QList<const Name *> qualifiedName = path(symbol->enclosingScope());
215
216
217
218
219
    addNames(symbol->name(), &qualifiedName, /*add all names*/ true);
    return qualifiedName;
}

QList<const Name *> LookupContext::path(Symbol *symbol)
220
221
{
    QList<const Name *> names;
222
    path_helper(symbol, &names);
223
224
225
    return names;
}

226
227
228
229
230
231
232
233
234
235
236
static bool symbolIdentical(Symbol *s1, Symbol *s2)
{
    if (!s1 || !s2)
        return false;
    if (s1->line() != s2->line())
        return false;
    if (s1->column() != s2->column())
        return false;

    return QByteArray(s1->fileName()) == QByteArray(s2->fileName());
}
237

238
const Name *LookupContext::minimalName(Symbol *symbol, ClassOrNamespace *target, Control *control)
239
{
240
241
242
243
244
245
    const Name *n = 0;
    QList<const Name *> names = LookupContext::fullyQualifiedName(symbol);

    for (int i = names.size() - 1; i >= 0; --i) {
        if (! n)
            n = names.at(i);
246
        else
247
248
249
250
251
252
253
254
255
256
            n = control->qualifiedNameId(names.at(i), n);

        // once we're qualified enough to get the same symbol, break
        if (target) {
            const QList<LookupItem> tresults = target->lookup(n);
            foreach (const LookupItem &tr, tresults) {
                if (symbolIdentical(tr.declaration(), symbol))
                    return n;
            }
        }
257
258
    }

259
    return n;
260
261
}

262
263
QList<LookupItem> LookupContext::lookupByUsing(const Name *name,
                                               ClassOrNamespace *bindingScope) const
264
265
266
{
    QList<LookupItem> candidates;
    // if it is a nameId there can be a using declaration for it
267
    if (name->isNameId() || name->isTemplateNameId()) {
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
        foreach (Symbol *s, bindingScope->symbols()) {
            if (Scope *scope = s->asScope()) {
                for (unsigned i = 0, count = scope->memberCount(); i < count; ++i) {
                    if (UsingDeclaration *u = scope->memberAt(i)->asUsingDeclaration()) {
                        if (const Name *usingDeclarationName = u->name()) {
                            if (const QualifiedNameId *q
                                    = usingDeclarationName->asQualifiedNameId()) {
                                if (q->name() && q->identifier() && name->identifier()
                                        && q->name()->identifier()->match(name->identifier())) {
                                    candidates = bindings()->globalNamespace()->find(q);

                                    // if it is not a global scope(scope of scope is not equal 0)
                                    // then add current using declaration as a candidate
                                    if (scope->enclosingScope()) {
                                        LookupItem item;
                                        item.setDeclaration(u);
                                        item.setScope(scope);
                                        candidates.append(item);
                                    }
                                }
288
                            }
289
290
291
292
293
                        }
                    }
                }
            }
        }
294
    } else if (const QualifiedNameId *q = name->asQualifiedNameId()) {
295
296
297
298
299
300
301
302
303
        foreach (Symbol *s, bindingScope->symbols()) {
            if (Scope *scope = s->asScope()) {
                ClassOrNamespace *base = lookupType(q->base(), scope);
                if (base)
                    candidates = lookupByUsing(q->name(), base);
                if (!candidates.isEmpty())
                    return candidates;
            }
        }
304
305
306
307
    }
    return candidates;
}

308

309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
Document::Ptr LookupContext::expressionDocument() const
{ return _expressionDocument; }

Document::Ptr LookupContext::thisDocument() const
{ return _thisDocument; }

Document::Ptr LookupContext::document(const QString &fileName) const
{ return _snapshot.document(fileName); }

Snapshot LookupContext::snapshot() const
{ return _snapshot; }

ClassOrNamespace *LookupContext::globalNamespace() const
{
    return bindings()->globalNamespace();
}

326
ClassOrNamespace *LookupContext::lookupType(const Name *name, Scope *scope,
327
328
                                            ClassOrNamespace* enclosingTemplateInstantiation,
                                            QSet<const Declaration *> typedefsBeingResolved) const
329
{
330
    if (! scope || ! name) {
331
332
333
        return 0;
    } else if (Block *block = scope->asBlock()) {
        for (unsigned i = 0; i < block->memberCount(); ++i) {
334
335
            Symbol *m = block->memberAt(i);
            if (UsingNamespaceDirective *u = m->asUsingNamespaceDirective()) {
336
337
338
339
                if (ClassOrNamespace *uu = lookupType(u->name(), scope->enclosingNamespace())) {
                    if (ClassOrNamespace *r = uu->lookupType(name))
                        return r;
                }
340
            } else if (Declaration *d = m->asDeclaration()) {
341
                if (d->name() && d->name()->match(name->asNameId())) {
342
                    if (d->isTypedef() && d->type()) {
343
344
345
346
                        if (Q_UNLIKELY(debug)) {
                            Overview oo;
                            qDebug() << "Looks like" << oo(name) << "is a typedef for" << oo(d->type());
                        }
347
348
349
350
351
352
353
354
                        if (const NamedType *namedTy = d->type()->asNamedType()) {
                            // Stop on recursive typedef declarations
                            if (typedefsBeingResolved.contains(d))
                                return 0;
                            return lookupType(namedTy->name(), scope, 0,
                                              QSet<const Declaration *>(typedefsBeingResolved)
                                                << d);
                        }
355
356
                    }
                }
357
358
            } else if (UsingDeclaration *ud = m->asUsingDeclaration()) {
                if (name->isNameId()) {
359
360
                    if (const Name *usingDeclarationName = ud->name()) {
                        if (const QualifiedNameId *q = usingDeclarationName->asQualifiedNameId()) {
361
                            if (q->name() && q->name()->match(name))
362
                                return bindings()->globalNamespace()->lookupType(q);
363
364
365
                        }
                    }
                }
366
367
            }
        }
368
369
370
371
372
373
374
375
376
377
378
        // try to find it in block (rare case but has priority before enclosing scope)
        // e.g.: void foo() { struct S {};  S s; }
        if (ClassOrNamespace *b = bindings()->lookupType(scope, enclosingTemplateInstantiation)) {
            if (ClassOrNamespace *classOrNamespaceNestedInNestedBlock = b->lookupType(name, block))
                return classOrNamespaceNestedInNestedBlock;
        }

        // try to find type in enclosing scope(typical case)
        if (ClassOrNamespace *found = lookupType(name, scope->enclosingScope()))
            return found;

379
    } else if (ClassOrNamespace *b = bindings()->lookupType(scope, enclosingTemplateInstantiation)) {
380
        return b->lookupType(name);
381
382
383
384
385
386
387
388
389
    } else if (Class *scopeAsClass = scope->asClass()) {
        if (scopeAsClass->enclosingScope()->isBlock()) {
            if (ClassOrNamespace *b = lookupType(scopeAsClass->name(),
                                                 scopeAsClass->enclosingScope(),
                                                 enclosingTemplateInstantiation,
                                                 typedefsBeingResolved)) {
                return b->lookupType(name);
            }
        }
390
    }
391
392
393
394

    return 0;
}

395
396
ClassOrNamespace *LookupContext::lookupType(Symbol *symbol,
                                            ClassOrNamespace* enclosingTemplateInstantiation) const
397
{
398
    return bindings()->lookupType(symbol, enclosingTemplateInstantiation);
399
400
}

401
QList<LookupItem> LookupContext::lookup(const Name *name, Scope *scope) const
402
{
403
    QList<LookupItem> candidates;
404
405
406
407

    if (! name)
        return candidates;

408
    for (; scope; scope = scope->enclosingScope()) {
409
        if (name->identifier() != 0 && scope->isBlock()) {
410
            bindings()->lookupInScope(name, scope, &candidates, /*templateId = */ 0, /*binding=*/ 0);
411

412
413
414
415
416
417
418
419
            if (! candidates.isEmpty()) {
                // it's a local.
                //for qualified it can be outside of the local scope
                if (name->isQualifiedNameId())
                    continue;
                else
                    break;
            }
420

421
422
423
424
            for (unsigned i = 0; i < scope->memberCount(); ++i) {
                if (UsingNamespaceDirective *u = scope->memberAt(i)->asUsingNamespaceDirective()) {
                    if (ClassOrNamespace *uu = lookupType(u->name(), scope->enclosingNamespace())) {
                        candidates = uu->find(name);
425

426
427
                        if (! candidates.isEmpty())
                            return candidates;
428
429
430
431
                    }
                }
            }

432
433
434
435
436
            if (ClassOrNamespace *bindingScope = bindings()->lookupType(scope)) {
                if (ClassOrNamespace *bindingBlock = bindingScope->findBlock(scope->asBlock())) {
                    candidates = lookupByUsing(name, bindingBlock);
                    if (! candidates.isEmpty())
                        return candidates;
437

438
                    candidates = bindingBlock->find(name);
439
440
441
442
443
444

                    if (! candidates.isEmpty())
                        return candidates;
                }
            }

Roberto Raggi's avatar
Roberto Raggi committed
445
446
        } else if (Function *fun = scope->asFunction()) {
            bindings()->lookupInScope(name, fun, &candidates, /*templateId = */ 0, /*binding=*/ 0);
447

448
449
450
451
452
453
454
455
            if (! candidates.isEmpty()) {
                // it's an argument or a template parameter.
                //for qualified it can be outside of the local scope
                if (name->isQualifiedNameId())
                    continue;
                else
                    break;
            }
456
457

            if (fun->name() && fun->name()->isQualifiedNameId()) {
458
                if (ClassOrNamespace *binding = bindings()->lookupType(fun)) {
Roberto Raggi's avatar
Roberto Raggi committed
459
                    candidates = binding->find(name);
460

461
462
463
464
                    // try find this name in parent class
                    while (candidates.isEmpty() && (binding = binding->parent()))
                        candidates = binding->find(name);

465
466
467
                    if (! candidates.isEmpty())
                        return candidates;
                }
468
469
            }

470
            // continue, and look at the enclosing scope.
471

Roberto Raggi's avatar
Roberto Raggi committed
472
473
        } else if (ObjCMethod *method = scope->asObjCMethod()) {
            bindings()->lookupInScope(name, method, &candidates, /*templateId = */ 0, /*binding=*/ 0);
474

475
476
477
            if (! candidates.isEmpty())
                break; // it's a formal argument.

478
479
        } else if (Template *templ = scope->asTemplate()) {
            bindings()->lookupInScope(name, templ, &candidates, /*templateId = */ 0, /*binding=*/ 0);
480

481
482
483
484
485
486
487
488
            if (! candidates.isEmpty()) {
                // it's a template parameter.
                //for qualified it can be outside of the local scope
                if (name->isQualifiedNameId())
                    continue;
                else
                    break;
            }
489

490
491
492
        } else if (scope->asNamespace()
                   || scope->asClass()
                   || (scope->asEnum() && scope->asEnum()->isScoped())) {
493

494
495
            if (ClassOrNamespace *bindingScope = bindings()->lookupType(scope)) {
                candidates = bindingScope->find(name);
496

497
498
499
500
501
502
503
                if (! candidates.isEmpty())
                    return candidates;

                candidates = lookupByUsing(name, bindingScope);
                if (!candidates.isEmpty())
                    return candidates;
            }
Roberto Raggi's avatar
Roberto Raggi committed
504

505
506
507
508
509
510
511
512
513
514
515
            // the scope can be defined inside a block, try to find it
            if (Block *block = scope->enclosingBlock()) {
                if (ClassOrNamespace *b = bindings()->lookupType(block)) {
                    if (ClassOrNamespace *classOrNamespaceNestedInNestedBlock = b->lookupType(scope->name(), block))
                        candidates = classOrNamespaceNestedInNestedBlock->find(name);
                }
            }

            if (! candidates.isEmpty())
                return candidates;

Roberto Raggi's avatar
Roberto Raggi committed
516
517
        } else if (scope->isObjCClass() || scope->isObjCProtocol()) {
            if (ClassOrNamespace *binding = bindings()->lookupType(scope))
Roberto Raggi's avatar
Roberto Raggi committed
518
519
520
521
                candidates = binding->find(name);

                if (! candidates.isEmpty())
                    return candidates;
522
523
524
525
526
527
        }
    }

    return candidates;
}

528
529
ClassOrNamespace *LookupContext::lookupParent(Symbol *symbol) const
{
530
    QList<const Name *> fqName = path(symbol);
531
532
533
534
535
536
537
538
539
540
    ClassOrNamespace *binding = globalNamespace();
    foreach (const Name *name, fqName) {
        binding = binding->findType(name);
        if (!binding)
            return 0;
    }

    return binding;
}

541
ClassOrNamespace::ClassOrNamespace(CreateBindings *factory, ClassOrNamespace *parent)
542
543
544
545
546
    : _factory(factory)
    , _parent(parent)
    , _scopeLookupCache(0)
    , _templateId(0)
    , _instantiationOrigin(0)
547
    , _rootClass(0)
548
    , _name(0)
549
{
550
    Q_ASSERT(factory);
551
552
}

553
554
555
556
557
ClassOrNamespace::~ClassOrNamespace()
{
    delete _scopeLookupCache;
}

558
559
560
561
562
const TemplateNameId *ClassOrNamespace::templateId() const
{
    return _templateId;
}

563
564
565
566
567
ClassOrNamespace *ClassOrNamespace::instantiationOrigin() const
{
    return _instantiationOrigin;
}

568
569
570
571
572
ClassOrNamespace *ClassOrNamespace::parent() const
{
    return _parent;
}

573
574
575
576
577
578
QList<ClassOrNamespace *> ClassOrNamespace::usings() const
{
    const_cast<ClassOrNamespace *>(this)->flush();
    return _usings;
}

579
QList<Enum *> ClassOrNamespace::unscopedEnums() const
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
{
    const_cast<ClassOrNamespace *>(this)->flush();
    return _enums;
}

QList<Symbol *> ClassOrNamespace::symbols() const
{
    const_cast<ClassOrNamespace *>(this)->flush();
    return _symbols;
}

ClassOrNamespace *ClassOrNamespace::globalNamespace() const
{
    ClassOrNamespace *e = const_cast<ClassOrNamespace *>(this);

    do {
        if (! e->_parent)
            break;

        e = e->_parent;
    } while (e);

    return e;
}

605
QList<LookupItem> ClassOrNamespace::find(const Name *name)
606
607
608
609
{
    return lookup_helper(name, false);
}

610
QList<LookupItem> ClassOrNamespace::lookup(const Name *name)
611
612
613
614
{
    return lookup_helper(name, true);
}

615
QList<LookupItem> ClassOrNamespace::lookup_helper(const Name *name, bool searchInEnclosingScope)
616
{
617
    QList<LookupItem> result;
618

619
    if (name) {
620

621
        if (const QualifiedNameId *q = name->asQualifiedNameId()) {
622
            if (! q->base()) { // e.g. ::std::string
623
                result = globalNamespace()->find(q->name());
624
            } else if (ClassOrNamespace *binding = lookupType(q->base())) {
625
                result = binding->find(q->name());
626

627
628
629
630
631
632
633
                QList<const Name *> fullName;
                addNames(name, &fullName);

                // It's also possible that there are matches in the parent binding through
                // a qualified name. For instance, a nested class which is forward declared
                // in the class but defined outside it - we should capture both.
                Symbol *match = 0;
634
635
636
637
                for (ClassOrNamespace *parentBinding = binding->parent();
                        parentBinding && !match;
                        parentBinding = parentBinding->parent())
                    match = parentBinding->lookupInScope(fullName);
638
639
640
641
642
643
644
645

                if (match) {
                    LookupItem item;
                    item.setDeclaration(match);
                    item.setBinding(binding);
                    result.append(item);
                }
            }
646

647
648
            return result;
        }
649

650
        QSet<ClassOrNamespace *> processed;
651
652
653
654
655
656
        ClassOrNamespace *binding = this;
        do {
            lookup_helper(name, binding, &result, &processed, /*templateId = */ 0);
            binding = binding->_parent;
        } while (searchInEnclosingScope && binding);
    }
657
658
659
660
661

    return result;
}

void ClassOrNamespace::lookup_helper(const Name *name, ClassOrNamespace *binding,
662
663
664
                                          QList<LookupItem> *result,
                                          QSet<ClassOrNamespace *> *processed,
                                          const TemplateNameId *templateId)
665
{
Roberto Raggi's avatar
Roberto Raggi committed
666
    if (binding && ! processed->contains(binding)) {
667
668
        processed->insert(binding);

669
670
        const Identifier *nameId = name->identifier();

671
        foreach (Symbol *s, binding->symbols()) {
672
673
            if (s->isFriend())
                continue;
674
675
            else if (s->isUsingNamespaceDirective())
                continue;
676

677

Roberto Raggi's avatar
Roberto Raggi committed
678
679
            if (Scope *scope = s->asScope()) {
                if (Class *klass = scope->asClass()) {
680
                    if (const Identifier *id = klass->identifier()) {
681
                        if (nameId && nameId->match(id)) {
682
683
684
685
686
                            LookupItem item;
                            item.setDeclaration(klass);
                            item.setBinding(binding);
                            result->append(item);
                        }
687
688
                    }
                }
Roberto Raggi's avatar
Roberto Raggi committed
689
                _factory->lookupInScope(name, scope, result, templateId, binding);
690
            }
691
692
        }

693
        foreach (Enum *e, binding->unscopedEnums())
Roberto Raggi's avatar
Roberto Raggi committed
694
            _factory->lookupInScope(name, e, result, templateId, binding);
695
696

        foreach (ClassOrNamespace *u, binding->usings())
697
            lookup_helper(name, u, result, processed, binding->_templateId);
698
699
700
701
702
703

        Anonymouses::const_iterator cit = binding->_anonymouses.begin();
        Anonymouses::const_iterator citEnd = binding->_anonymouses.end();
        for (; cit != citEnd; ++cit) {
            const AnonymousNameId *anonymousNameId = cit.key();
            ClassOrNamespace *a = cit.value();
704
            if (!binding->_declaredOrTypedefedAnonymouses.contains(anonymousNameId))
705
706
                lookup_helper(name, a, result, processed, binding->_templateId);
        }
707
708
709
    }
}

Roberto Raggi's avatar
Roberto Raggi committed
710
void CreateBindings::lookupInScope(const Name *name, Scope *scope,
711
712
713
                                   QList<LookupItem> *result,
                                   const TemplateNameId *templateId,
                                   ClassOrNamespace *binding)
714
715
716
717
718
{
    if (! name) {
        return;

    } else if (const OperatorNameId *op = name->asOperatorNameId()) {
Roberto Raggi's avatar
Roberto Raggi committed
719
        for (Symbol *s = scope->find(op->kind()); s; s = s->next()) {
720
721
            if (! s->name())
                continue;
722
723
            else if (s->isFriend())
                continue;
724
            else if (! s->name()->match(op))
725
                continue;
726

727
728
729
730
            LookupItem item;
            item.setDeclaration(s);
            item.setBinding(binding);
            result->append(item);
731
732
733
        }

    } else if (const Identifier *id = name->identifier()) {
Roberto Raggi's avatar
Roberto Raggi committed
734
        for (Symbol *s = scope->find(id); s; s = s->next()) {
735
736
            if (s->isFriend())
                continue; // skip friends
737
738
            else if (s->isUsingNamespaceDirective())
                continue; // skip using namespace directives
739
            else if (! id->match(s->identifier()))
740
                continue;
741
            else if (s->name() && s->name()->isQualifiedNameId())
Roberto Raggi's avatar
Roberto Raggi committed
742
                continue; // skip qualified ids.
743

744
745
746
747
748
            if (Q_UNLIKELY(debug)) {
                Overview oo;
                qDebug() << "Found" << id->chars() << "in"
                         << (binding ? oo(binding->_name) : QString::fromLatin1("<null>"));
            }
749

750
751
752
            LookupItem item;
            item.setDeclaration(s);
            item.setBinding(binding);
753

754
755
            if (s->asNamespaceAlias() && binding) {
                ClassOrNamespace *targetNamespaceBinding = binding->lookupType(name);
756
757
                //there can be many namespace definitions
                if (targetNamespaceBinding && targetNamespaceBinding->symbols().size() > 0) {
758
759
760
761
762
                    Symbol *resolvedSymbol = targetNamespaceBinding->symbols().first();
                    item.setType(resolvedSymbol->type()); // override the type
                }
            }

763
            if (templateId && (s->isDeclaration() || s->isFunction())) {
764
                FullySpecifiedType ty = DeprecatedGenTemplateInstance::instantiate(templateId, s, control());
765
                item.setType(ty); // override the type.
766
767
            }

768
769
770
771
772
773
774
775
776
777
            // instantiate function template
            if (name->isTemplateNameId() && s->isTemplate() && s->asTemplate()->declaration()
                    && s->asTemplate()->declaration()->isFunction()) {
                const TemplateNameId *instantiation = name->asTemplateNameId();
                Template *specialization = s->asTemplate();
                Symbol *instantiatedFunctionTemplate = instantiateTemplateFunction(instantiation,
                                                                                   specialization);
                item.setType(instantiatedFunctionTemplate->type()); // override the type.
            }

778
            result->append(item);
779
780
781
782
        }
    }
}

783
ClassOrNamespace *ClassOrNamespace::lookupType(const Name *name)
784
785
786
787
788
{
    if (! name)
        return 0;

    QSet<ClassOrNamespace *> processed;
789
    return lookupType_helper(name, &processed, /*searchInEnclosingScope =*/ true, this);
790
791
}

792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
ClassOrNamespace *ClassOrNamespace::lookupType(const Name *name, Block *block)
{
    flush();

    QHash<Block *, ClassOrNamespace *>::const_iterator citBlock = _blocks.find(block);
    if (citBlock != _blocks.end()) {
        ClassOrNamespace *nestedBlock = citBlock.value();
        QSet<ClassOrNamespace *> processed;
        if (ClassOrNamespace *foundInNestedBlock
                = nestedBlock->lookupType_helper(name,
                                                 &processed,
                                                 /*searchInEnclosingScope = */ true,
                                                 this)) {
            return foundInNestedBlock;
        }
    }

    for (citBlock = _blocks.begin(); citBlock != _blocks.end(); ++citBlock) {
        if (ClassOrNamespace *foundNestedBlock = citBlock.value()->lookupType(name, block))
            return foundNestedBlock;
    }

    return 0;
}

817
ClassOrNamespace *ClassOrNamespace::findType(const Name *name)
818
819
{
    QSet<ClassOrNamespace *> processed;
820
    return lookupType_helper(name, &processed, /*searchInEnclosingScope =*/ false, this);
821
822
}

823
824
825
826
ClassOrNamespace *ClassOrNamespace::findBlock(Block *block)
{
    flush();

827
828
829
830
831
832
833
834
835
    for (ClassOrNamespace *binding = this; binding; binding = binding->_parent) {
        QHash<Block *, ClassOrNamespace *>::const_iterator citBlock = binding->_blocks.find(block);
        if (citBlock != binding->_blocks.end())
            return citBlock.value();

        for (citBlock = binding->_blocks.begin(); citBlock != binding->_blocks.end(); ++citBlock) {
            if (ClassOrNamespace *foundNestedBlock = citBlock.value()->findBlock(block))
                return foundNestedBlock;
        }
836
837
838
839
840
    }

    return 0;
}

841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
Symbol *ClassOrNamespace::lookupInScope(const QList<const Name *> &fullName)
{
    if (!_scopeLookupCache) {
        _scopeLookupCache = new QHash<Internal::FullyQualifiedName, Symbol *>;

        for (int j = 0; j < symbols().size(); ++j) {
            if (Scope *scope = symbols().at(j)->asScope()) {
                for (unsigned i = 0; i < scope->memberCount(); ++i) {
                    Symbol *s = scope->memberAt(i);
                    _scopeLookupCache->insert(LookupContext::fullyQualifiedName(s), s);
                }
            }
        }
    }

    return _scopeLookupCache->value(fullName, 0);
}

Roberto Raggi's avatar
Roberto Raggi committed
859
ClassOrNamespace *ClassOrNamespace::lookupType_helper(const Name *name,
860
                                                      QSet<ClassOrNamespace *> *processed,
861
862
                                                      bool searchInEnclosingScope,
                                                      ClassOrNamespace *origin)
863
{
864
865
866
867
    if (Q_UNLIKELY(debug)) {
        Overview oo;
        qDebug() << "Looking up" << oo(name) << "in" << oo(_name);
    }
868

869
    if (const QualifiedNameId *q = name->asQualifiedNameId()) {
870

871
        QSet<ClassOrNamespace *> innerProcessed;
872
        if (! q->base())
873
            return globalNamespace()->lookupType_helper(q->name(), &innerProcessed, true, origin);
874

875
        if (ClassOrNamespace *binding = lookupType_helper(q->base(), processed, true, origin))
876
            return binding->lookupType_helper(q->name(), &innerProcessed, false, origin);
877

878
        return 0;
879

880
881
    } else if (! processed->contains(this)) {
        processed->insert(this);
882

883
        if (name->isNameId() || name->isTemplateNameId() || name->isAnonymousNameId()) {
884
            flush();
885

886
887
            foreach (Symbol *s, symbols()) {
                if (Class *klass = s->asClass()) {
888
                    if (klass->identifier() && klass->identifier()->match(name->identifier()))
889
890
891
                        return this;
                }
            }
892
            foreach (Enum *e, unscopedEnums()) {
893
                if (e->identifier() && e->identifier()->match(name->identifier()))
894
895
                    return this;
            }
896

897
            if (ClassOrNamespace *e = nestedType(name, origin))
898
899
                return e;

900
            if (_templateId) {
901
902
903
                if (_usings.size() == 1) {
                    ClassOrNamespace *delegate = _usings.first();

904
905
906
907
                    if (ClassOrNamespace *r = delegate->lookupType_helper(name,
                                                                          processed,
                                                                          /*searchInEnclosingScope = */ true,
                                                                          origin))
908
                        return r;
909
910
911
                } else if (Q_UNLIKELY(debug)) {
                    qWarning() << "expected one using declaration. Number of using declarations is:"
                               << _usings.size();
912
                }
913
914
            }

915
            foreach (ClassOrNamespace *u, usings()) {
916
917
918
919
                if (ClassOrNamespace *r = u->lookupType_helper(name,
                                                               processed,
                                                               /*searchInEnclosingScope =*/ false,
                                                               origin))
920
921
922
923
                    return r;
            }
        }

924
925
        if (_parent && searchInEnclosingScope)
            return _parent->lookupType_helper(name, processed, searchInEnclosingScope, origin);
926
927
928
929
930
    }

    return 0;
}

931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
static ClassOrNamespace *findSpecializationWithMatchingTemplateArgument(const Name *argumentName,
                                                                        ClassOrNamespace *reference)
{
    foreach (Symbol *s, reference->symbols()) {
        if (Class *clazz = s->asClass()) {
            if (Template *templateSpecialization = clazz->enclosingTemplate()) {
                const unsigned argumentCountOfSpecialization
                                    = templateSpecialization->templateParameterCount();
                for (unsigned i = 0; i < argumentCountOfSpecialization; ++i) {
                    if (TypenameArgument *tParam
                            = templateSpecialization->templateParameterAt(i)->asTypenameArgument()) {
                        if (const Name *name = tParam->name()) {
                            if (compareName(name, argumentName))
                                return reference;
                        }
                    }
                }
            }
        }
    }
    return 0;
}

ClassOrNamespace *ClassOrNamespace::findSpecialization(const TemplateNameId *templId,
                                                       const TemplateNameIdTable &specializations)
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
{
    // we go through all specialization and try to find that one with template argument as pointer
    for (TemplateNameIdTable::const_iterator cit = specializations.begin();
         cit != specializations.end(); ++cit) {
        const TemplateNameId *specializationNameId = cit->first;
        const unsigned specializationTemplateArgumentCount
                = specializationNameId->templateArgumentCount();
        const unsigned initializationTemplateArgumentCount
                = templId->templateArgumentCount();
        // for now it works only when we have the same number of arguments in specialization
        // and initialization(in future it should be more clever)
        if (specializationTemplateArgumentCount == initializationTemplateArgumentCount) {
            for (unsigned i = 0; i < initializationTemplateArgumentCount; ++i) {
                const FullySpecifiedType &specializationTemplateArgument
                        = specializationNameId->templateArgumentAt(i);
                const FullySpecifiedType &initializationTemplateArgument
                        = templId->templateArgumentAt(i);
                PointerType *specPointer
                        = specializationTemplateArgument.type()->asPointerType();
                // specialization and initialization argument have to be a pointer
                // additionally type of pointer argument of specialization has to be namedType
                if (specPointer && initializationTemplateArgument.type()->isPointerType()
                        && specPointer->elementType().type()->isNamedType()) {
                    return cit->second;
                }
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995

                ArrayType *specArray
                        = specializationTemplateArgument.type()->asArrayType();
                if (specArray && initializationTemplateArgument.type()->isArrayType()) {
                    if (const NamedType *argumentNamedType
                            = specArray->elementType().type()->asNamedType()) {
                        if (const Name *argumentName = argumentNamedType->name()) {
                            if (ClassOrNamespace *reference
                                    = findSpecializationWithMatchingTemplateArgument(
                                            argumentName, cit->second)) {
                                return reference;
                            }
                        }
                    }
                }
996
997
998
999
1000
1001
1002
            }
        }
    }

    return 0;
}

1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
ClassOrNamespace *ClassOrNamespace::findOrCreateNestedAnonymousType(
        const AnonymousNameId *anonymousNameId)
{
    QHash<const AnonymousNameId *, ClassOrNamespace *>::const_iterator cit
            = _anonymouses.find(anonymousNameId);
    if (cit != _anonymouses.end()) {
        return cit.value();
    } else {
        ClassOrNamespace *newAnonymous = _factory->allocClassOrNamespace(this);
        if (Q_UNLIKELY(debug))
            newAnonymous->_name = anonymousNameId;
        _anonymouses[anonymousNameId] = newAnonymous;
        return newAnonymous;
    }
}

1019
ClassOrNamespace *ClassOrNamespace::nestedType(const Name *name, ClassOrNamespace *origin)
1020
{
1021
    Q_ASSERT(name != 0);
1022
    Q_ASSERT(name->isNameId() || name->isTemplateNameId() || name->isAnonymousNameId());
1023

1024
    const_cast<ClassOrNamespace *>(this)->flush();
1025

1026
1027
    if (const AnonymousNameId *anonymousNameId = name->asAnonymousNameId())
        return findOrCreateNestedAnonymousType(anonymousNameId);
1028

1029
1030
1031
    Table::const_iterator it = _classOrNamespaces.find(name);
    if (it == _classOrNamespaces.end())
        return 0;
1032

1033
    ClassOrNamespace *reference = it->second;
1034
    ClassOrNamespace *baseTemplateClassReference = reference;
1035

1036
1037
    const TemplateNameId *templId = name->asTemplateNameId();
    if (templId) {
1038
1039
1040
1041
1042
1043
        // for "using" we should use the real one ClassOrNamespace(it should be the first
        // one item from usings list)
        // we indicate that it is a 'using' by checking number of symbols(it should be 0)
        if (reference->symbols().count() == 0 && reference->usings().count() != 0)
            reference = reference->_usings[0];

1044
1045
1046
1047
1048
1049
        // if it is a TemplateNameId it could be a specialization(full or partial) or
        // instantiation of one of the specialization(reference->_specialization) or
        // base class(reference)
        if (templId->isSpecialization()) {
            // if it is a specialization we try to find or create new one and
            // add to base class(reference)
1050
1051
            TemplateNameIdTable::const_iterator cit
                    = reference->_specializations.find(templId);
1052
1053
1054
1055
            if (cit != reference->_specializations.end()) {
                return cit->second;
            } else {
                ClassOrNamespace *newSpecialization = _factory->allocClassOrNamespace(reference);
1056
1057
                if (Q_UNLIKELY(debug))
                    newSpecialization->_name = templId;
1058
1059
1060
1061
                reference->_specializations[templId] = newSpecialization;
                return newSpecialization;
            }
        } else {
1062
1063
1064
1065
            QMap<const TemplateNameId *, ClassOrNamespace *>::const_iterator citInstantiation
                    = reference->_instantiations.find(templId);
            if (citInstantiation != reference->_instantiations.end())
                return citInstantiation.value();
1066
1067
1068
1069
            TemplateNameId *nonConstTemplId = const_cast<TemplateNameId *>(templId);
            // make this instantiation looks like specialization which help to find
            // full specialization for this instantiation
            nonConstTemplId->setIsSpecialization(true);
1070
1071
1072
            const TemplateNameIdTable &specializations = reference->_specializations;
            TemplateNameIdTable::const_iterator cit = specializations.find(templId);
            if (cit != specializations.end()) {
1073
1074
1075
                // we found full specialization
                reference = cit->second;
            } else {
1076
                ClassOrNamespace *specializationWithPointer
1077
                        = findSpecialization(templId, specializations);
1078
1079
                if (specializationWithPointer)
                    reference = specializationWithPointer;
1080
1081
1082
1083
1084
1085
1086
                // TODO: find the best specialization(probably partial) for this instantiation
            }
            // let's instantiation be instantiation
            nonConstTemplId->setIsSpecialization(false);
        }
    }

1087
1088
1089
1090
1091
    // The reference binding might still be missing some of its base classes in the case they
    // are templates. We need to collect them now. First, we track the bases which are already
    // part of the binding so we can identify the missings ones later.

    Class *referenceClass = 0;
1092
    QList<const Name *> allBases;
1093
1094
1095
1096
    foreach (Symbol *s, reference->symbols()) {
        if (Class *clazz = s->asClass()) {
            for (unsigned i = 0; i < clazz->baseClassCount(); ++i) {
                BaseClass *baseClass = clazz->baseClassAt(i);
1097
1098
                if (baseClass->name())
                    allBases.append(baseClass->name());
1099
1100
1101
1102
1103
1104
1105
1106
1107
            }
            referenceClass = clazz;
            break;
        }
    }

    if (!referenceClass)
        return reference;

1108
    if ((! templId && _alreadyConsideredClasses.contains(referenceClass)) ||
1109
1110
1111
1112
1113
1114
1115
1116
            (templId &&
            _alreadyConsideredTemplates.contains(templId))) {
            return reference;
    }

    if (!name->isTemplateNameId())
        _alreadyConsideredClasses.insert(referenceClass);

1117
1118
    QSet<ClassOrNamespace *> knownUsings = reference->usings().toSet();

1119
1120
    // If we are dealling with a template type, more work is required, since we need to
    // construct all instantiation data.
1121
1122
    if (templId) {
        _alreadyConsideredTemplates.insert(templId);
1123
        ClassOrNamespace *instantiation = _factory->allocClassOrNamespace(baseTemplateClassReference);