LookupContext.cpp 68.5 KB
Newer Older
hjk's avatar
hjk committed
1
/****************************************************************************
2
**
Eike Ziller's avatar
Eike Ziller committed
3
4
** Copyright (C) 2015 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing
5
**
hjk's avatar
hjk committed
6
** This file is part of Qt Creator.
7
**
hjk's avatar
hjk committed
8
9
10
11
** 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
Eike Ziller's avatar
Eike Ziller committed
12
13
** a written agreement between you and The Qt Company.  For licensing terms and
** conditions see http://www.qt.io/terms-conditions.  For further information
Eike Ziller's avatar
Eike Ziller committed
14
** 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
**
Eike Ziller's avatar
Eike Ziller committed
25
26
** In addition, as a special exception, The Qt Company gives you certain additional
** rights.  These rights are described in The Qt Company 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 "CppRewriter.h"
36
#include "TypeResolver.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>
Orgad Shaneh's avatar
Orgad Shaneh committed
44
#include <cplusplus/cppassert.h>
45

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

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

53
54
namespace CPlusPlus {

55
typedef QSet<Internal::LookupScopePrivate *> ProcessedSet;
Orgad Shaneh's avatar
Orgad Shaneh committed
56

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

69
static void path_helper(Symbol *symbol, QList<const Name *> *names)
70
71
72
73
{
    if (! symbol)
        return;

74
    path_helper(symbol->enclosingScope(), names);
75

76
77
    if (symbol->name()) {
        if (symbol->isClass() || symbol->isNamespace()) {
78
            addNames(symbol->name(), names);
79

80
        } else if (symbol->isObjCClass() || symbol->isObjCBaseClass() || symbol->isObjCProtocol()
81
82
                || symbol->isObjCForwardClassDeclaration() || symbol->isObjCForwardProtocolDeclaration()
                || symbol->isForwardClassDeclaration()) {
83
84
            addNames(symbol->name(), names);

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

95
static inline bool compareName(const Name *name, const Name *other)
96
97
98
99
{
    if (name == other)
        return true;

100
    if (name && other) {
101
102
103
        const Identifier *id = name->identifier();
        const Identifier *otherId = other->identifier();

104
        if (id == otherId || (id && id->match(otherId)))
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
            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;
}

124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
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;
}
}

146
147
148
149
/////////////////////////////////////////////////////////////////////
// LookupContext
/////////////////////////////////////////////////////////////////////
LookupContext::LookupContext()
150
    : m_expandTemplates(false)
151
152
153
154
{ }

LookupContext::LookupContext(Document::Ptr thisDocument,
                             const Snapshot &snapshot)
155
156
157
    : _expressionDocument(Document::create(QLatin1String("<LookupContext>")))
    , _thisDocument(thisDocument)
    , _snapshot(snapshot)
158
    , _bindings(new CreateBindings(thisDocument, snapshot))
159
    , m_expandTemplates(false)
160
161
162
163
164
{
}

LookupContext::LookupContext(Document::Ptr expressionDocument,
                             Document::Ptr thisDocument,
165
                             const Snapshot &snapshot,
166
                             CreateBindings::Ptr bindings)
167
168
169
    : _expressionDocument(expressionDocument)
    , _thisDocument(thisDocument)
    , _snapshot(snapshot)
170
    , _bindings(bindings)
171
    , m_expandTemplates(false)
172
173
174
175
{
}

LookupContext::LookupContext(const LookupContext &other)
176
177
178
179
180
    : _expressionDocument(other._expressionDocument)
    , _thisDocument(other._thisDocument)
    , _snapshot(other._snapshot)
    , _bindings(other._bindings)
    , m_expandTemplates(other.m_expandTemplates)
181
182
{ }

183
LookupContext &LookupContext::operator=(const LookupContext &other)
184
185
186
187
188
{
    _expressionDocument = other._expressionDocument;
    _thisDocument = other._thisDocument;
    _snapshot = other._snapshot;
    _bindings = other._bindings;
189
    m_expandTemplates = other.m_expandTemplates;
190
191
192
    return *this;
}

193
QList<const Name *> LookupContext::fullyQualifiedName(Symbol *symbol)
194
{
195
    QList<const Name *> qualifiedName = path(symbol->enclosingScope());
196
197
198
199
200
    addNames(symbol->name(), &qualifiedName, /*add all names*/ true);
    return qualifiedName;
}

QList<const Name *> LookupContext::path(Symbol *symbol)
201
202
{
    QList<const Name *> names;
203
    path_helper(symbol, &names);
204
205
206
    return names;
}

207
208
209
210
211
212
213
214
215
216
217
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());
}
218

219
const Name *LookupContext::minimalName(Symbol *symbol, LookupScope *target, Control *control)
220
{
221
222
223
224
225
226
    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);
227
        else
228
229
230
231
232
233
234
235
236
237
            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;
            }
        }
238
239
    }

240
    return n;
241
242
}

243
QList<LookupItem> LookupContext::lookupByUsing(const Name *name,
244
                                               LookupScope *bindingScope) const
245
246
247
{
    QList<LookupItem> candidates;
    // if it is a nameId there can be a using declaration for it
248
    if (name->isNameId() || name->isTemplateNameId()) {
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
        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);
                                    }
                                }
269
                            }
270
271
272
273
274
                        }
                    }
                }
            }
        }
275
    } else if (const QualifiedNameId *q = name->asQualifiedNameId()) {
276
277
        foreach (Symbol *s, bindingScope->symbols()) {
            if (Scope *scope = s->asScope()) {
278
                LookupScope *base = lookupType(q->base(), scope);
279
280
281
282
283
284
                if (base)
                    candidates = lookupByUsing(q->name(), base);
                if (!candidates.isEmpty())
                    return candidates;
            }
        }
285
286
287
288
    }
    return candidates;
}

289

290
291
292
293
294
295
296
297
298
299
300
301
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; }

302
LookupScope *LookupContext::globalNamespace() const
303
304
305
306
{
    return bindings()->globalNamespace();
}

307
308
309
LookupScope *LookupContext::lookupType(const Name *name, Scope *scope,
                                       LookupScope *enclosingBinding,
                                       QSet<const Declaration *> typedefsBeingResolved) const
310
{
311
    if (! scope || ! name) {
312
313
314
        return 0;
    } else if (Block *block = scope->asBlock()) {
        for (unsigned i = 0; i < block->memberCount(); ++i) {
315
316
            Symbol *m = block->memberAt(i);
            if (UsingNamespaceDirective *u = m->asUsingNamespaceDirective()) {
317
318
                if (LookupScope *uu = lookupType(u->name(), scope->enclosingNamespace())) {
                    if (LookupScope *r = uu->lookupType(name))
319
320
                        return r;
                }
321
            } else if (Declaration *d = m->asDeclaration()) {
322
                if (d->name() && d->name()->match(name->asNameId())) {
323
                    if (d->isTypedef() && d->type()) {
324
325
326
327
                        if (Q_UNLIKELY(debug)) {
                            Overview oo;
                            qDebug() << "Looks like" << oo(name) << "is a typedef for" << oo(d->type());
                        }
328
329
330
331
332
333
334
335
                        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);
                        }
336
337
                    }
                }
338
339
            } else if (UsingDeclaration *ud = m->asUsingDeclaration()) {
                if (name->isNameId()) {
340
341
                    if (const Name *usingDeclarationName = ud->name()) {
                        if (const QualifiedNameId *q = usingDeclarationName->asQualifiedNameId()) {
342
                            if (q->name() && q->name()->match(name))
343
                                return bindings()->globalNamespace()->lookupType(q);
344
345
346
                        }
                    }
                }
347
348
            }
        }
349
350
        // try to find it in block (rare case but has priority before enclosing scope)
        // e.g.: void foo() { struct S {};  S s; }
351
352
353
        if (LookupScope *b = bindings()->lookupType(scope, enclosingBinding)) {
            if (LookupScope *lookupScopeNestedInNestedBlock = b->lookupType(name, block))
                return lookupScopeNestedInNestedBlock;
354
355
356
        }

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

360
    } else if (LookupScope *b = bindings()->lookupType(scope, enclosingBinding)) {
361
        return b->lookupType(name);
362
363
    } else if (Class *scopeAsClass = scope->asClass()) {
        if (scopeAsClass->enclosingScope()->isBlock()) {
364
            if (LookupScope *b = lookupType(scopeAsClass->name(),
365
                                                 scopeAsClass->enclosingScope(),
366
                                                 enclosingBinding,
367
368
369
370
                                                 typedefsBeingResolved)) {
                return b->lookupType(name);
            }
        }
371
    }
372
373
374
375

    return 0;
}

376
LookupScope *LookupContext::lookupType(Symbol *symbol, LookupScope *enclosingBinding) const
377
{
378
    return bindings()->lookupType(symbol, enclosingBinding);
379
380
}

381
QList<LookupItem> LookupContext::lookup(const Name *name, Scope *scope) const
382
{
383
    QList<LookupItem> candidates;
384
385
386
387

    if (! name)
        return candidates;

388
    for (; scope; scope = scope->enclosingScope()) {
389
        if (name->identifier() != 0 && scope->isBlock()) {
390
            bindings()->lookupInScope(name, scope, &candidates);
391

392
393
394
395
396
397
398
399
            if (! candidates.isEmpty()) {
                // it's a local.
                //for qualified it can be outside of the local scope
                if (name->isQualifiedNameId())
                    continue;
                else
                    break;
            }
400

401
402
            for (unsigned i = 0; i < scope->memberCount(); ++i) {
                if (UsingNamespaceDirective *u = scope->memberAt(i)->asUsingNamespaceDirective()) {
403
                    if (LookupScope *uu = lookupType(u->name(), scope->enclosingNamespace())) {
404
                        candidates = uu->find(name);
405

406
407
                        if (! candidates.isEmpty())
                            return candidates;
408
409
410
411
                    }
                }
            }

412
413
            if (LookupScope *bindingScope = bindings()->lookupType(scope)) {
                if (LookupScope *bindingBlock = bindingScope->findBlock(scope->asBlock())) {
414
415
416
                    candidates = lookupByUsing(name, bindingBlock);
                    if (! candidates.isEmpty())
                        return candidates;
417

418
                    candidates = bindingBlock->find(name);
419
420
421
422
423
424

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

Roberto Raggi's avatar
Roberto Raggi committed
425
        } else if (Function *fun = scope->asFunction()) {
426
            bindings()->lookupInScope(name, fun, &candidates);
427

428
429
430
431
432
433
434
435
            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;
            }
436
437

            if (fun->name() && fun->name()->isQualifiedNameId()) {
438
                if (LookupScope *binding = bindings()->lookupType(fun)) {
Roberto Raggi's avatar
Roberto Raggi committed
439
                    candidates = binding->find(name);
440

441
442
443
444
                    // try find this name in parent class
                    while (candidates.isEmpty() && (binding = binding->parent()))
                        candidates = binding->find(name);

445
446
447
                    if (! candidates.isEmpty())
                        return candidates;
                }
448
449
            }

450
            // continue, and look at the enclosing scope.
451

Roberto Raggi's avatar
Roberto Raggi committed
452
        } else if (ObjCMethod *method = scope->asObjCMethod()) {
453
            bindings()->lookupInScope(name, method, &candidates);
454

455
456
457
            if (! candidates.isEmpty())
                break; // it's a formal argument.

458
        } else if (Template *templ = scope->asTemplate()) {
459
            bindings()->lookupInScope(name, templ, &candidates);
460

461
462
463
464
465
466
467
468
            if (! candidates.isEmpty()) {
                // it's a template parameter.
                //for qualified it can be outside of the local scope
                if (name->isQualifiedNameId())
                    continue;
                else
                    break;
            }
469

470
471
472
        } else if (scope->asNamespace()
                   || scope->asClass()
                   || (scope->asEnum() && scope->asEnum()->isScoped())) {
473

474
            if (LookupScope *bindingScope = bindings()->lookupType(scope)) {
475
                candidates = bindingScope->find(name);
476

477
478
479
480
481
482
483
                if (! candidates.isEmpty())
                    return candidates;

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

485
486
            // the scope can be defined inside a block, try to find it
            if (Block *block = scope->enclosingBlock()) {
487
488
489
                if (LookupScope *b = bindings()->lookupType(block)) {
                    if (LookupScope *lookupScopeNestedInNestedBlock = b->lookupType(scope->name(), block))
                        candidates = lookupScopeNestedInNestedBlock->find(name);
490
491
492
493
494
495
                }
            }

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

Roberto Raggi's avatar
Roberto Raggi committed
496
        } else if (scope->isObjCClass() || scope->isObjCProtocol()) {
497
            if (LookupScope *binding = bindings()->lookupType(scope))
Roberto Raggi's avatar
Roberto Raggi committed
498
499
500
501
                candidates = binding->find(name);

                if (! candidates.isEmpty())
                    return candidates;
502
503
504
505
506
507
        }
    }

    return candidates;
}

508
LookupScope *LookupContext::lookupParent(Symbol *symbol) const
509
{
510
    QList<const Name *> fqName = path(symbol);
511
    LookupScope *binding = globalNamespace();
512
513
514
515
516
517
518
519
520
    foreach (const Name *name, fqName) {
        binding = binding->findType(name);
        if (!binding)
            return 0;
    }

    return binding;
}

Orgad Shaneh's avatar
Orgad Shaneh committed
521
522
namespace Internal {

523
class LookupScopePrivate
Orgad Shaneh's avatar
Orgad Shaneh committed
524
525
{
public:
526
527
    LookupScopePrivate(LookupScope *q, CreateBindings *factory, LookupScope *parent);
    ~LookupScopePrivate();
Orgad Shaneh's avatar
Orgad Shaneh committed
528

529
    typedef std::map<const Name *, LookupScopePrivate *, Name::Compare> Table;
530
    typedef std::map<const Name *, Declaration *, Name::Compare> TypedefTable;
Orgad Shaneh's avatar
Orgad Shaneh committed
531
    typedef std::map<const TemplateNameId *,
532
                     LookupScopePrivate *,
Orgad Shaneh's avatar
Orgad Shaneh committed
533
                     TemplateNameId::Compare> TemplateNameIdTable;
534
    typedef QHash<const AnonymousNameId *, LookupScopePrivate *> Anonymouses;
Orgad Shaneh's avatar
Orgad Shaneh committed
535

536
    LookupScopePrivate *allocateChild(const Name *name);
Orgad Shaneh's avatar
Orgad Shaneh committed
537
538
539

    void flush();

540
    LookupScope *globalNamespace() const;
Orgad Shaneh's avatar
Orgad Shaneh committed
541
542
543

    Symbol *lookupInScope(const QList<const Name *> &fullName);

544
    LookupScope *findOrCreateType(const Name *name, LookupScopePrivate *origin = 0,
Orgad Shaneh's avatar
Orgad Shaneh committed
545
546
                                       Class *clazz = 0);

547
    LookupScopePrivate *findOrCreateNestedAnonymousType(const AnonymousNameId *anonymousNameId);
Orgad Shaneh's avatar
Orgad Shaneh committed
548
549
550
551

    void addTodo(Symbol *symbol);
    void addSymbol(Symbol *symbol);
    void addUnscopedEnum(Enum *e);
552
    void addTypedef(const Name *identifier, Declaration *d);
553
554
    void addUsing(LookupScope *u);
    void addNestedType(const Name *alias, LookupScope *e);
Orgad Shaneh's avatar
Orgad Shaneh committed
555
556
557

    QList<LookupItem> lookup_helper(const Name *name, bool searchInEnclosingScope);

558
    void lookup_helper(const Name *name, LookupScopePrivate *binding,
Orgad Shaneh's avatar
Orgad Shaneh committed
559
560
561
                       QList<LookupItem> *result,
                       ProcessedSet *processed);

562
563
    LookupScope *lookupType_helper(const Name *name, ProcessedSet *processed,
                                   bool searchInEnclosingScope, LookupScopePrivate *origin);
Orgad Shaneh's avatar
Orgad Shaneh committed
564

565
566
    LookupScope *findBlock_helper(Block *block, ProcessedSet *processed,
                                  bool searchInEnclosingScope);
Orgad Shaneh's avatar
Orgad Shaneh committed
567

568
569
570
private:
    LookupScopePrivate *findNestedType(const Name *name, LookupScopePrivate *origin);

571
    LookupScopePrivate *nestedType(const Name *name, LookupScopePrivate *origin);
Orgad Shaneh's avatar
Orgad Shaneh committed
572

573
    LookupScopePrivate *findSpecialization(const TemplateNameId *templId,
574
575
                                           const TemplateNameIdTable &specializations,
                                           LookupScopePrivate *origin);
Orgad Shaneh's avatar
Orgad Shaneh committed
576

577
public:
578
    LookupScope *q;
Orgad Shaneh's avatar
Orgad Shaneh committed
579
580

    CreateBindings *_factory;
581
    LookupScopePrivate *_parent;
Orgad Shaneh's avatar
Orgad Shaneh committed
582
    QList<Symbol *> _symbols;
583
584
    QList<LookupScope *> _usings;
    Table _nestedScopes;
585
    TypedefTable _typedefs;
586
    QHash<Block *, LookupScope *> _blocks;
Orgad Shaneh's avatar
Orgad Shaneh committed
587
588
589
590
    QList<Enum *> _enums;
    QList<Symbol *> _todo;
    QSharedPointer<Control> _control;
    TemplateNameIdTable _specializations;
591
    QMap<const TemplateNameId *, LookupScopePrivate *> _instantiations;
Orgad Shaneh's avatar
Orgad Shaneh committed
592
593
594
595
596
597
    Anonymouses _anonymouses;
    QSet<const AnonymousNameId *> _declaredOrTypedefedAnonymouses;

    QHash<Internal::FullyQualifiedName, Symbol *> *_scopeLookupCache;

    // it's an instantiation.
598
    LookupScopePrivate *_instantiationOrigin;
Orgad Shaneh's avatar
Orgad Shaneh committed
599
600
601

    AlreadyConsideredClassContainer<Class> _alreadyConsideredClasses;
    AlreadyConsideredClassContainer<TemplateNameId> _alreadyConsideredTemplates;
602
    QSet<const Declaration *> _alreadyConsideredTypedefs;
Orgad Shaneh's avatar
Orgad Shaneh committed
603
604

    Class *_rootClass;
605
    const Name *_name;
606
    bool _hasTypedefs;
Orgad Shaneh's avatar
Orgad Shaneh committed
607
608
609
};

class Instantiator
610
611
{
public:
Nikolai Kosjar's avatar
Nikolai Kosjar committed
612
613
    Instantiator(Clone &cloner, Subst &subst)
        : _cloner(cloner)
614
615
        , _subst(subst)
    {}
Orgad Shaneh's avatar
Orgad Shaneh committed
616
617
    void doInstantiate(LookupScopePrivate *lookupScope, LookupScopePrivate *instantiation);
    LookupScopePrivate *instantiate(LookupScopePrivate *lookupScope, LookupScopePrivate *origin);
618

Orgad Shaneh's avatar
Orgad Shaneh committed
619
private:
Orgad Shaneh's avatar
Orgad Shaneh committed
620
    ProcessedSet _alreadyConsideredInstantiations;
621
622
623
624
    Clone &_cloner;
    Subst &_subst;
};

625
LookupScopePrivate::LookupScopePrivate(LookupScope *q, CreateBindings *factory, LookupScope *parent)
Orgad Shaneh's avatar
Orgad Shaneh committed
626
627
628
    : q(q)
    , _factory(factory)
    , _parent(parent ? parent->d : 0)
629
630
    , _scopeLookupCache(0)
    , _instantiationOrigin(0)
631
    , _rootClass(0)
632
    , _name(0)
633
    , _hasTypedefs(false)
634
{
635
    Q_ASSERT(factory);
636
637
}

638
LookupScopePrivate::~LookupScopePrivate()
639
640
641
642
{
    delete _scopeLookupCache;
}

643
LookupScopePrivate *LookupScopePrivate::allocateChild(const Name *name)
Orgad Shaneh's avatar
Orgad Shaneh committed
644
{
645
    LookupScope *e = _factory->allocLookupScope(q, name);
Orgad Shaneh's avatar
Orgad Shaneh committed
646
647
648
649
650
    return e->d;
}

} // namespace Internal

651
652
LookupScope::LookupScope(CreateBindings *factory, LookupScope *parent)
    : d(new Internal::LookupScopePrivate(this, factory, parent))
Orgad Shaneh's avatar
Orgad Shaneh committed
653
654
655
{
}

656
LookupScope::~LookupScope()
Orgad Shaneh's avatar
Orgad Shaneh committed
657
658
659
660
{
    delete d;
}

661
LookupScope *LookupScope::instantiationOrigin() const
662
{
663
    if (Internal::LookupScopePrivate *i = d->_instantiationOrigin)
Orgad Shaneh's avatar
Orgad Shaneh committed
664
665
        return i->q;
    return 0;
666
667
}

668
LookupScope *LookupScope::parent() const
669
{
670
    if (Internal::LookupScopePrivate *p = d->_parent)
Orgad Shaneh's avatar
Orgad Shaneh committed
671
672
        return p->q;
    return 0;
673
674
}

675
QList<LookupScope *> LookupScope::usings() const
676
{
677
    const_cast<LookupScope *>(this)->d->flush();
Orgad Shaneh's avatar
Orgad Shaneh committed
678
    return d->_usings;
679
680
}

681
QList<Enum *> LookupScope::unscopedEnums() const
682
{
683
    const_cast<LookupScope *>(this)->d->flush();
Orgad Shaneh's avatar
Orgad Shaneh committed
684
    return d->_enums;
685
686
}

687
QList<Symbol *> LookupScope::symbols() const
688
{
689
    const_cast<LookupScope *>(this)->d->flush();
Orgad Shaneh's avatar
Orgad Shaneh committed
690
691
692
    return d->_symbols;
}

693
QList<LookupItem> LookupScope::find(const Name *name)
Orgad Shaneh's avatar
Orgad Shaneh committed
694
695
696
697
{
    return d->lookup_helper(name, false);
}

698
QList<LookupItem> LookupScope::lookup(const Name *name)
Orgad Shaneh's avatar
Orgad Shaneh committed
699
700
{
    return d->lookup_helper(name, true);
701
702
}

Orgad Shaneh's avatar
Orgad Shaneh committed
703
704
namespace Internal {

705
LookupScope *LookupScopePrivate::globalNamespace() const
706
{
707
    const LookupScopePrivate *e = this;
708
709
710
711
712
713
714
715

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

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

Orgad Shaneh's avatar
Orgad Shaneh committed
716
    return e ? e->q : 0;
717
718
}

719
QList<LookupItem> LookupScopePrivate::lookup_helper(const Name *name, bool searchInEnclosingScope)
720
{
721
    QList<LookupItem> result;
722

723
    if (name) {
724

Orgad Shaneh's avatar
Orgad Shaneh committed
725
726
727
        if (const QualifiedNameId *qName = name->asQualifiedNameId()) {
            if (! qName->base()) { // e.g. ::std::string
                result = globalNamespace()->find(qName->name());
728
            } else if (LookupScope *binding = q->lookupType(qName->base())) {
Orgad Shaneh's avatar
Orgad Shaneh committed
729
                result = binding->find(qName->name());
730

731
732
733
734
735
736
737
                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;
Orgad Shaneh's avatar
Orgad Shaneh committed
738
                ProcessedSet processed;
739
                for (LookupScopePrivate *parentBinding = binding->d->_parent;
740
                        parentBinding && !match;
Orgad Shaneh's avatar
Orgad Shaneh committed
741
                        parentBinding = parentBinding->_parent) {
Nikolai Kosjar's avatar
Nikolai Kosjar committed
742
743
744
                    if (processed.contains(parentBinding))
                        break;
                    processed.insert(parentBinding);
745
                    match = parentBinding->lookupInScope(fullName);
Nikolai Kosjar's avatar
Nikolai Kosjar committed
746
                }
747
748
749
750
751
752
753
754

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

756
757
            return result;
        }
758

Orgad Shaneh's avatar
Orgad Shaneh committed
759
760
        ProcessedSet processed;
        ProcessedSet processedOwnParents;
761
        LookupScopePrivate *binding = this;
762
        do {
Nikolai Kosjar's avatar
Nikolai Kosjar committed
763
764
765
            if (processedOwnParents.contains(binding))
                break;
            processedOwnParents.insert(binding);
766
            lookup_helper(name, binding, &result, &processed);
767
768
769
            binding = binding->_parent;
        } while (searchInEnclosingScope && binding);
    }
770
771
772
773

    return result;
}

774
775
void LookupScopePrivate::lookup_helper(
        const Name *name, LookupScopePrivate *binding, QList<LookupItem> *result,
Orgad Shaneh's avatar
Orgad Shaneh committed
776
        ProcessedSet *processed)
777
{
Orgad Shaneh's avatar
Orgad Shaneh committed
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
    if (!binding || processed->contains(binding))
        return;
    processed->insert(binding);

    binding->flush();
    const Identifier *nameId = name->identifier();

    foreach (Symbol *s, binding->_symbols) {
        if (s->isFriend())
            continue;
        else if (s->isUsingNamespaceDirective())
            continue;


        if (Scope *scope = s->asScope()) {
            if (Class *klass = scope->asClass()) {
                if (const Identifier *id = klass->identifier()) {
                    if (nameId && nameId->match(id)) {
                        LookupItem item;
                        item.setDeclaration(klass);
                        item.setBinding(binding->q);
                        result->append(item);
800
801
802
                    }
                }
            }
Orgad Shaneh's avatar
Orgad Shaneh committed
803
            _factory->lookupInScope(name, scope, result, binding->q);
804
        }
Orgad Shaneh's avatar
Orgad Shaneh committed
805
    }
806

Orgad Shaneh's avatar
Orgad Shaneh committed
807
808
    foreach (Enum *e, binding->_enums)
        _factory->lookupInScope(name, e, result, binding->q);
809

810
    foreach (LookupScope *u, binding->_usings)
Orgad Shaneh's avatar
Orgad Shaneh committed
811
        lookup_helper(name, u->d, result, processed);
812

Orgad Shaneh's avatar
Orgad Shaneh committed
813
814
815
816
    Anonymouses::const_iterator cit = binding->_anonymouses.constBegin();
    Anonymouses::const_iterator citEnd = binding->_anonymouses.constEnd();
    for (; cit != citEnd; ++cit) {
        const AnonymousNameId *anonymousNameId = cit.key();
817
        LookupScopePrivate *a = cit.value();
Orgad Shaneh's avatar
Orgad Shaneh committed
818
819
        if (!binding->_declaredOrTypedefedAnonymouses.contains(anonymousNameId))
            lookup_helper(name, a, result, processed);
820
821
822
    }
}

Orgad Shaneh's avatar
Orgad Shaneh committed
823
824
}

Roberto Raggi's avatar
Roberto Raggi committed
825
void CreateBindings::lookupInScope(const Name *name, Scope *scope,
826
                                   QList<LookupItem> *result,
827
                                   LookupScope *binding)
828
829
830
831
832
{
    if (! name) {
        return;

    } else if (const OperatorNameId *op = name->asOperatorNameId()) {
Roberto Raggi's avatar
Roberto Raggi committed
833
        for (Symbol *s = scope->find(op->kind()); s; s = s->next()) {
834
835
            if (! s->name())
                continue;
836
837
            else if (s->isFriend())
                continue;
838
            else if (! s->name()->match(op))
839
                continue;
840

841
842
843
844
            LookupItem item;
            item.setDeclaration(s);
            item.setBinding(binding);
            result->append(item);
845
846
847
        }

    } else if (const Identifier *id = name->identifier()) {
Roberto Raggi's avatar
Roberto Raggi committed
848
        for (Symbol *s = scope->find(id); s; s = s->next()) {
849
850
            if (s->isFriend())
                continue; // skip friends
851
852
            else if (s->isUsingNamespaceDirective())
                continue; // skip using namespace directives
853
            else if (! id->match(s->identifier()))
854
                continue;
855
            else if (s->name() && s->name()->isQualifiedNameId())
Roberto Raggi's avatar
Roberto Raggi committed
856
                continue; // skip qualified ids.
857

858
859
860
            if (Q_UNLIKELY(debug)) {
                Overview oo;
                qDebug() << "Found" << id->chars() << "in"
Orgad Shaneh's avatar
Orgad Shaneh committed
861
                         << (binding ? oo(binding->d->_name) : QString::fromLatin1("<null>"));
862
            }
863

864
865
866
            LookupItem item;
            item.setDeclaration(s);
            item.setBinding(binding);
867

868
            if (s->asNamespaceAlias() && binding) {
869
                LookupScope *targetNamespaceBinding = binding->lookupType(name);
870
871
                //there can be many namespace definitions
                if (targetNamespaceBinding && targetNamespaceBinding->symbols().size() > 0) {
872
873
874
875
876
                    Symbol *resolvedSymbol = targetNamespaceBinding->symbols().first();
                    item.setType(resolvedSymbol->type()); // override the type
                }
            }

877
            // instantiate function template
Orgad Shaneh's avatar
Orgad Shaneh committed
878
879