LookupContext.cpp 66.5 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
13
14
** 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
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
15
16
**
** GNU Lesser General Public License Usage
hjk's avatar
hjk committed
17
18
19
20
21
22
23
24
25
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** 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
26
27
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
hjk's avatar
hjk committed
28
****************************************************************************/
29
30

#include "LookupContext.h"
31

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

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

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

using namespace CPlusPlus;
50

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

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

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

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

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

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

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

91
92
93
94
95
96
97
98
99
100
101
102
103
static bool isNestedInstantiationEnclosingTemplate(
        ClassOrNamespace *nestedClassOrNamespaceInstantiation,
        ClassOrNamespace *enclosingTemplateClassInstantiation)
{
    while (enclosingTemplateClassInstantiation) {
        if (enclosingTemplateClassInstantiation == nestedClassOrNamespaceInstantiation)
            return false;
        enclosingTemplateClassInstantiation = enclosingTemplateClassInstantiation->parent();
    }

    return true;
}

104
105
namespace CPlusPlus {

106
static inline bool compareName(const Name *name, const Name *other)
107
108
109
110
{
    if (name == other)
        return true;

111
    if (name && other) {
112
113
114
        const Identifier *id = name->identifier();
        const Identifier *otherId = other->identifier();

115
        if (id == otherId || (id && id->match(otherId)))
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
            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;
}

}

137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
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;
}
}
}

161
162
163
164
/////////////////////////////////////////////////////////////////////
// LookupContext
/////////////////////////////////////////////////////////////////////
LookupContext::LookupContext()
165
    : m_expandTemplates(false)
166
167
168
169
{ }

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

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

LookupContext::LookupContext(const LookupContext &other)
191
192
193
194
195
    : _expressionDocument(other._expressionDocument)
    , _thisDocument(other._thisDocument)
    , _snapshot(other._snapshot)
    , _bindings(other._bindings)
    , m_expandTemplates(other.m_expandTemplates)
196
197
{ }

198
LookupContext &LookupContext::operator=(const LookupContext &other)
199
200
201
202
203
{
    _expressionDocument = other._expressionDocument;
    _thisDocument = other._thisDocument;
    _snapshot = other._snapshot;
    _bindings = other._bindings;
204
    m_expandTemplates = other.m_expandTemplates;
205
206
207
    return *this;
}

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

QList<const Name *> LookupContext::path(Symbol *symbol)
216
217
{
    QList<const Name *> names;
218
    path_helper(symbol, &names);
219
220
221
    return names;
}

222
223
224
225
226
227
228
229
230
231
232
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());
}
233

234
const Name *LookupContext::minimalName(Symbol *symbol, ClassOrNamespace *target, Control *control)
235
{
236
237
238
239
240
241
    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);
242
        else
243
244
245
246
247
248
249
250
251
252
            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;
            }
        }
253
254
    }

255
    return n;
256
257
}

258
259
QList<LookupItem> LookupContext::lookupByUsing(const Name *name,
                                               ClassOrNamespace *bindingScope) const
260
261
262
{
    QList<LookupItem> candidates;
    // if it is a nameId there can be a using declaration for it
263
    if (name->isNameId() || name->isTemplateNameId()) {
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
        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);
                                    }
                                }
284
                            }
285
286
287
288
289
                        }
                    }
                }
            }
        }
290
    } else if (const QualifiedNameId *q = name->asQualifiedNameId()) {
291
292
293
294
295
296
297
298
299
        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;
            }
        }
300
301
302
303
    }
    return candidates;
}

304

305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
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();
}

322
ClassOrNamespace *LookupContext::lookupType(const Name *name, Scope *scope,
323
324
                                            ClassOrNamespace* enclosingTemplateInstantiation,
                                            QSet<const Declaration *> typedefsBeingResolved) const
325
{
326
    if (! scope || ! name) {
327
328
329
        return 0;
    } else if (Block *block = scope->asBlock()) {
        for (unsigned i = 0; i < block->memberCount(); ++i) {
330
331
            Symbol *m = block->memberAt(i);
            if (UsingNamespaceDirective *u = m->asUsingNamespaceDirective()) {
332
333
334
335
                if (ClassOrNamespace *uu = lookupType(u->name(), scope->enclosingNamespace())) {
                    if (ClassOrNamespace *r = uu->lookupType(name))
                        return r;
                }
336
            } else if (Declaration *d = m->asDeclaration()) {
337
                if (d->name() && d->name()->match(name->asNameId())) {
338
                    if (d->isTypedef() && d->type()) {
339
340
341
342
                        if (Q_UNLIKELY(debug)) {
                            Overview oo;
                            qDebug() << "Looks like" << oo(name) << "is a typedef for" << oo(d->type());
                        }
343
344
345
346
347
348
349
350
                        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);
                        }
351
352
                    }
                }
353
354
            } else if (UsingDeclaration *ud = m->asUsingDeclaration()) {
                if (name->isNameId()) {
355
356
                    if (const Name *usingDeclarationName = ud->name()) {
                        if (const QualifiedNameId *q = usingDeclarationName->asQualifiedNameId()) {
357
                            if (q->name() && q->name()->match(name))
358
                                return bindings()->globalNamespace()->lookupType(q);
359
360
361
                        }
                    }
                }
362
363
            }
        }
364
365
366
367
368
369
370
371
372
373
374
        // 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;

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

    return 0;
}

391
392
ClassOrNamespace *LookupContext::lookupType(Symbol *symbol,
                                            ClassOrNamespace* enclosingTemplateInstantiation) const
393
{
394
    return bindings()->lookupType(symbol, enclosingTemplateInstantiation);
395
396
}

397
QList<LookupItem> LookupContext::lookup(const Name *name, Scope *scope) const
398
{
399
    QList<LookupItem> candidates;
400
401
402
403

    if (! name)
        return candidates;

404
    for (; scope; scope = scope->enclosingScope()) {
405
        if (name->identifier() != 0 && scope->isBlock()) {
406
            bindings()->lookupInScope(name, scope, &candidates, /*templateId = */ 0, /*binding=*/ 0);
407

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

417
418
419
420
            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);
421

422
423
                        if (! candidates.isEmpty())
                            return candidates;
424
425
426
427
                    }
                }
            }

428
429
430
431
432
            if (ClassOrNamespace *bindingScope = bindings()->lookupType(scope)) {
                if (ClassOrNamespace *bindingBlock = bindingScope->findBlock(scope->asBlock())) {
                    candidates = lookupByUsing(name, bindingBlock);
                    if (! candidates.isEmpty())
                        return candidates;
433

434
                    candidates = bindingBlock->find(name);
435
436
437
438
439
440

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

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

444
445
446
447
448
449
450
451
            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;
            }
452
453

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

457
458
459
460
                    // try find this name in parent class
                    while (candidates.isEmpty() && (binding = binding->parent()))
                        candidates = binding->find(name);

461
462
463
                    if (! candidates.isEmpty())
                        return candidates;
                }
464
465
            }

466
            // continue, and look at the enclosing scope.
467

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

471
472
473
            if (! candidates.isEmpty())
                break; // it's a formal argument.

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

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

486
487
488
        } else if (scope->asNamespace()
                   || scope->asClass()
                   || (scope->asEnum() && scope->asEnum()->isScoped())) {
489

490
491
            if (ClassOrNamespace *bindingScope = bindings()->lookupType(scope)) {
                candidates = bindingScope->find(name);
492

493
494
495
496
497
498
499
                if (! candidates.isEmpty())
                    return candidates;

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

501
502
503
504
505
506
507
508
509
510
511
            // 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
512
513
        } else if (scope->isObjCClass() || scope->isObjCProtocol()) {
            if (ClassOrNamespace *binding = bindings()->lookupType(scope))
Roberto Raggi's avatar
Roberto Raggi committed
514
515
516
517
                candidates = binding->find(name);

                if (! candidates.isEmpty())
                    return candidates;
518
519
520
521
522
523
        }
    }

    return candidates;
}

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

    return binding;
}

537
ClassOrNamespace::ClassOrNamespace(CreateBindings *factory, ClassOrNamespace *parent)
538
539
540
541
542
    : _factory(factory)
    , _parent(parent)
    , _scopeLookupCache(0)
    , _templateId(0)
    , _instantiationOrigin(0)
543
    , _rootClass(0)
544
    , _name(0)
545
{
546
    Q_ASSERT(factory);
547
548
}

549
550
551
552
553
ClassOrNamespace::~ClassOrNamespace()
{
    delete _scopeLookupCache;
}

554
555
556
557
558
const TemplateNameId *ClassOrNamespace::templateId() const
{
    return _templateId;
}

559
560
561
562
563
ClassOrNamespace *ClassOrNamespace::instantiationOrigin() const
{
    return _instantiationOrigin;
}

564
565
566
567
568
ClassOrNamespace *ClassOrNamespace::parent() const
{
    return _parent;
}

569
570
571
572
573
574
QList<ClassOrNamespace *> ClassOrNamespace::usings() const
{
    const_cast<ClassOrNamespace *>(this)->flush();
    return _usings;
}

575
QList<Enum *> ClassOrNamespace::unscopedEnums() const
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
{
    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;
}

601
QList<LookupItem> ClassOrNamespace::find(const Name *name)
602
603
604
605
{
    return lookup_helper(name, false);
}

606
QList<LookupItem> ClassOrNamespace::lookup(const Name *name)
607
608
609
610
{
    return lookup_helper(name, true);
}

611
QList<LookupItem> ClassOrNamespace::lookup_helper(const Name *name, bool searchInEnclosingScope)
612
{
613
    QList<LookupItem> result;
614

615
    if (name) {
616

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

623
624
625
626
627
628
629
                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;
630
631
632
633
                for (ClassOrNamespace *parentBinding = binding->parent();
                        parentBinding && !match;
                        parentBinding = parentBinding->parent())
                    match = parentBinding->lookupInScope(fullName);
634
635
636
637
638
639
640
641

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

643
644
            return result;
        }
645

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

    return result;
}

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

665
666
        const Identifier *nameId = name->identifier();

667
        foreach (Symbol *s, binding->symbols()) {
668
669
            if (s->isFriend())
                continue;
670
671
            else if (s->isUsingNamespaceDirective())
                continue;
672

673

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

689
        foreach (Enum *e, binding->unscopedEnums())
Roberto Raggi's avatar
Roberto Raggi committed
690
            _factory->lookupInScope(name, e, result, templateId, binding);
691
692

        foreach (ClassOrNamespace *u, binding->usings())
693
            lookup_helper(name, u, result, processed, binding->_templateId);
694
695
696
697
698
699

        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();
700
            if (!binding->_declaredOrTypedefedAnonymouses.contains(anonymousNameId))
701
702
                lookup_helper(name, a, result, processed, binding->_templateId);
        }
703
704
705
    }
}

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

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

723
724
725
726
            LookupItem item;
            item.setDeclaration(s);
            item.setBinding(binding);
            result->append(item);
727
728
729
        }

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

740
741
742
743
744
            if (Q_UNLIKELY(debug)) {
                Overview oo;
                qDebug() << "Found" << id->chars() << "in"
                         << (binding ? oo(binding->_name) : QString::fromLatin1("<null>"));
            }
745

746
747
748
            LookupItem item;
            item.setDeclaration(s);
            item.setBinding(binding);
749

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

759
            if (templateId && (s->isDeclaration() || s->isFunction())) {
760
                FullySpecifiedType ty = DeprecatedGenTemplateInstance::instantiate(templateId, s, control());
761
                item.setType(ty); // override the type.
762
763
            }

764
765
766
767
768
769
770
771
772
773
            // 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.
            }

774
            result->append(item);
775
776
777
778
        }
    }
}

779
ClassOrNamespace *ClassOrNamespace::lookupType(const Name *name)
780
781
782
783
784
{
    if (! name)
        return 0;

    QSet<ClassOrNamespace *> processed;
785
    return lookupType_helper(name, &processed, /*searchInEnclosingScope =*/ true, this);
786
787
}

788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
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;
}

813
ClassOrNamespace *ClassOrNamespace::findType(const Name *name)
814
815
{
    QSet<ClassOrNamespace *> processed;
816
    return lookupType_helper(name, &processed, /*searchInEnclosingScope =*/ false, this);
817
818
}

819
820
821
822
823
ClassOrNamespace *ClassOrNamespace::findBlock(Block *block)
{
    flush();

    QHash<Block *, ClassOrNamespace *>::const_iterator citBlock = _blocks.find(block);
Orgad Shaneh's avatar
Orgad Shaneh committed
824
    if (citBlock != _blocks.end())
825
826
827
828
829
830
831
832
833
834
        return citBlock.value();

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

    return 0;
}

835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
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
853
ClassOrNamespace *ClassOrNamespace::lookupType_helper(const Name *name,
854
                                                      QSet<ClassOrNamespace *> *processed,
855
856
                                                      bool searchInEnclosingScope,
                                                      ClassOrNamespace *origin)
857
{
858
859
860
861
    if (Q_UNLIKELY(debug)) {
        Overview oo;
        qDebug() << "Looking up" << oo(name) << "in" << oo(_name);
    }
862

863
    if (const QualifiedNameId *q = name->asQualifiedNameId()) {
864

865
        QSet<ClassOrNamespace *> innerProcessed;
866
        if (! q->base())
867
            return globalNamespace()->lookupType_helper(q->name(), &innerProcessed, true, origin);
868

869
        if (ClassOrNamespace *binding = lookupType_helper(q->base(), processed, true, origin))
870
            return binding->lookupType_helper(q->name(), &innerProcessed, false, origin);
871

872
        return 0;
873

874
875
    } else if (! processed->contains(this)) {
        processed->insert(this);
876

877
        if (name->isNameId() || name->isTemplateNameId() || name->isAnonymousNameId()) {
878
            flush();
879

880
881
            foreach (Symbol *s, symbols()) {
                if (Class *klass = s->asClass()) {
882
                    if (klass->identifier() && klass->identifier()->match(name->identifier()))
883
884
885
                        return this;
                }
            }
886
            foreach (Enum *e, unscopedEnums()) {
887
                if (e->identifier() && e->identifier()->match(name->identifier()))
888
889
                    return this;
            }
890

891
            if (ClassOrNamespace *e = nestedType(name, origin))
892
893
                return e;

894
            if (_templateId) {
895
896
897
                if (_usings.size() == 1) {
                    ClassOrNamespace *delegate = _usings.first();

898
899
900
901
                    if (ClassOrNamespace *r = delegate->lookupType_helper(name,
                                                                          processed,
                                                                          /*searchInEnclosingScope = */ true,
                                                                          origin))
902
                        return r;
903
904
905
                } else if (Q_UNLIKELY(debug)) {
                    qWarning() << "expected one using declaration. Number of using declarations is:"
                               << _usings.size();
906
                }
907
908
            }

909
            foreach (ClassOrNamespace *u, usings()) {
910
911
912
913
                if (ClassOrNamespace *r = u->lookupType_helper(name,
                                                               processed,
                                                               /*searchInEnclosingScope =*/ false,
                                                               origin))
914
915
916
917
                    return r;
            }
        }

918
919
        if (_parent && searchInEnclosingScope)
            return _parent->lookupType_helper(name, processed, searchInEnclosingScope, origin);
920
921
922
923
924
    }

    return 0;
}

925
926
927
928
929
930
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
956
957
958
ClassOrNamespace *ClassOrNamespace::findSpecializationWithPointer(const TemplateNameId *templId,
                                                         const TemplateNameIdTable &specializations)
{
    // 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;
                }
            }
        }
    }

    return 0;
}

959
ClassOrNamespace *ClassOrNamespace::nestedType(const Name *name, ClassOrNamespace *origin)
960
{
961
    Q_ASSERT(name != 0);
962
    Q_ASSERT(name->isNameId() || name->isTemplateNameId() || name->isAnonymousNameId());
963

964
    const_cast<ClassOrNamespace *>(this)->flush();
965

966
967
968
969
970
971
972
973
    const AnonymousNameId *anonymousNameId = name->asAnonymousNameId();
    if (anonymousNameId) {
        QHash<const AnonymousNameId *, ClassOrNamespace *>::const_iterator cit
                = _anonymouses.find(anonymousNameId);
        if (cit != _anonymouses.end()) {
            return cit.value();
        } else {
            ClassOrNamespace *newAnonymous = _factory->allocClassOrNamespace(this);
974
975
            if (Q_UNLIKELY(debug))
                newAnonymous->_name = anonymousNameId;
976
977
978
979
980
            _anonymouses[anonymousNameId] = newAnonymous;
            return newAnonymous;
        }
    }

981
982
983
    Table::const_iterator it = _classOrNamespaces.find(name);
    if (it == _classOrNamespaces.end())
        return 0;
984

985
    ClassOrNamespace *reference = it->second;
986
    ClassOrNamespace *baseTemplateClassReference = reference;
987

988
989
    const TemplateNameId *templId = name->asTemplateNameId();
    if (templId) {
990
991
992
993
994
995
        // 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];

996
997
998
999
1000
1001
        // 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)
1002
1003
            TemplateNameIdTable::const_iterator cit
                    = reference->_specializations.find(templId);
1004
1005
1006
1007
            if (cit != reference->_specializations.end()) {
                return cit->second;
            } else {
                ClassOrNamespace *newSpecialization = _factory->allocClassOrNamespace(reference);
1008
1009
                if (Q_UNLIKELY(debug))
                    newSpecialization->_name = templId;
1010
1011
1012
1013
                reference->_specializations[templId] = newSpecialization;
                return newSpecialization;
            }
        } else {
1014
1015
1016
1017
            QMap<const TemplateNameId *, ClassOrNamespace *>::const_iterator citInstantiation
                    = reference->_instantiations.find(templId);
            if (citInstantiation != reference->_instantiations.end())
                return citInstantiation.value();
1018
1019
1020
1021
            TemplateNameId *nonConstTemplId = const_cast<TemplateNameId *>(templId);
            // make this instantiation looks like specialization which help to find
            // full specialization for this instantiation
            nonConstTemplId->setIsSpecialization(true);
1022
1023
1024
            const TemplateNameIdTable &specializations = reference->_specializations;
            TemplateNameIdTable::const_iterator cit = specializations.find(templId);
            if (cit != specializations.end()) {
1025
1026
1027
                // we found full specialization
                reference = cit->second;
            } else {
1028
1029
1030
1031
                ClassOrNamespace *specializationWithPointer
                        = findSpecializationWithPointer(templId, specializations);
                if (specializationWithPointer)
                    reference = specializationWithPointer;
1032
1033
1034
1035
1036
1037
1038
                // TODO: find the best specialization(probably partial) for this instantiation
            }
            // let's instantiation be instantiation
            nonConstTemplId->setIsSpecialization(false);
        }
    }