LookupContext.cpp 39.6 KB
Newer Older
hjk's avatar
hjk committed
1
/****************************************************************************
2
**
hjk's avatar
hjk committed
3 4
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
** 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 31 32

#include "LookupContext.h"
#include "ResolveExpression.h"
#include "Overview.h"
33
#include "DeprecatedGenTemplateInstance.h"
34
#include "CppRewriter.h"
35 36 37 38 39 40 41 42

#include <CoreTypes.h>
#include <Symbols.h>
#include <Literals.h>
#include <Names.h>
#include <Scope.h>
#include <Control.h>

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

using namespace CPlusPlus;
49

Roberto Raggi's avatar
Roberto Raggi committed
50
namespace {
51 52
const bool debug = ! qgetenv("CPLUSPLUS_LOOKUPCONTEXT_DEBUG").isEmpty();
} // end of anonymous namespace
Roberto Raggi's avatar
Roberto Raggi committed
53

54

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

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

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

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

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

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

90 91 92
namespace CPlusPlus {

bool compareName(const Name *name, const Name *other)
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
{
    if (name == other)
        return true;

    else if (name && other) {
        const Identifier *id = name->identifier();
        const Identifier *otherId = other->identifier();

        if (id == otherId || (id && id->isEqualTo(otherId)))
            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;
}

}

123 124 125 126
/////////////////////////////////////////////////////////////////////
// LookupContext
/////////////////////////////////////////////////////////////////////
LookupContext::LookupContext()
127
    : _control(new Control())
128
    , m_expandTemplates(false)
129 130 131 132 133 134
{ }

LookupContext::LookupContext(Document::Ptr thisDocument,
                             const Snapshot &snapshot)
    : _expressionDocument(Document::create("<LookupContext>")),
      _thisDocument(thisDocument),
135
      _snapshot(snapshot),
136 137
      _control(new Control()),
      m_expandTemplates(false)
138 139 140 141 142 143 144 145
{
}

LookupContext::LookupContext(Document::Ptr expressionDocument,
                             Document::Ptr thisDocument,
                             const Snapshot &snapshot)
    : _expressionDocument(expressionDocument),
      _thisDocument(thisDocument),
146
      _snapshot(snapshot),
147 148
      _control(new Control()),
      m_expandTemplates(false)
149 150 151 152
{
}

LookupContext::LookupContext(const LookupContext &other)
153
    : _expressionDocument(other._expressionDocument),
154 155
      _thisDocument(other._thisDocument),
      _snapshot(other._snapshot),
156
      _bindings(other._bindings),
157 158
      _control(other._control),
      m_expandTemplates(other.m_expandTemplates)
159 160 161 162 163 164 165 166
{ }

LookupContext &LookupContext::operator = (const LookupContext &other)
{
    _expressionDocument = other._expressionDocument;
    _thisDocument = other._thisDocument;
    _snapshot = other._snapshot;
    _bindings = other._bindings;
167
    _control = other._control;
168
    m_expandTemplates = other.m_expandTemplates;
169 170 171
    return *this;
}

172
QList<const Name *> LookupContext::fullyQualifiedName(Symbol *symbol)
173
{
174
    QList<const Name *> qualifiedName = path(symbol->enclosingScope());
175 176 177 178 179
    addNames(symbol->name(), &qualifiedName, /*add all names*/ true);
    return qualifiedName;
}

QList<const Name *> LookupContext::path(Symbol *symbol)
180 181
{
    QList<const Name *> names;
182
    path_helper(symbol, &names);
183 184 185
    return names;
}

186 187 188 189 190 191 192 193 194 195 196
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());
}
197

198
const Name *LookupContext::minimalName(Symbol *symbol, ClassOrNamespace *target, Control *control)
199
{
200 201 202 203 204 205
    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);
206
        else
207 208 209 210 211 212 213 214 215 216
            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;
            }
        }
217 218
    }

219
    return n;
220 221 222
}


223 224
QSharedPointer<CreateBindings> LookupContext::bindings() const
{
225
    if (! _bindings) {
226
        _bindings = QSharedPointer<CreateBindings>(new CreateBindings(_thisDocument, _snapshot, control()));
227 228
        _bindings->setExpandTemplates(m_expandTemplates);
    }
229 230 231 232 233 234 235 236 237

    return _bindings;
}

void LookupContext::setBindings(QSharedPointer<CreateBindings> bindings)
{
    _bindings = bindings;
}

238 239 240 241
QSharedPointer<Control> LookupContext::control() const
{
    return _control;
}
242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259

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();
}

260
ClassOrNamespace *LookupContext::lookupType(const Name *name, Scope *scope) const
261
{
262 263 264 265 266 267 268 269 270 271 272 273 274
    if (! scope) {
        return 0;
    } else if (Block *block = scope->asBlock()) {
        for (unsigned i = 0; i < block->memberCount(); ++i) {
            if (UsingNamespaceDirective *u = block->memberAt(i)->asUsingNamespaceDirective()) {
                if (ClassOrNamespace *uu = lookupType(u->name(), scope->enclosingNamespace())) {
                    if (ClassOrNamespace *r = uu->lookupType(name))
                        return r;
                }
            }
        }
        return lookupType(name, scope->enclosingScope());
    } else if (ClassOrNamespace *b = bindings()->lookupType(scope)) {
275
        return b->lookupType(name);
276
    }
277 278 279 280

    return 0;
}

281
ClassOrNamespace *LookupContext::lookupType(Symbol *symbol) const
282
{
Roberto Raggi's avatar
Roberto Raggi committed
283
    return bindings()->lookupType(symbol);
284 285
}

286
QList<LookupItem> LookupContext::lookup(const Name *name, Scope *scope) const
287
{
288
    QList<LookupItem> candidates;
289 290 291 292

    if (! name)
        return candidates;

293
    for (; scope; scope = scope->enclosingScope()) {
294
        if (name->identifier() != 0 && scope->isBlock()) {
295
            bindings()->lookupInScope(name, scope, &candidates, /*templateId = */ 0, /*binding=*/ 0);
296 297 298 299

            if (! candidates.isEmpty())
                break; // it's a local.

300 301 302 303
            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);
304

305 306
                        if (! candidates.isEmpty())
                            return candidates;
307 308 309 310
                    }
                }
            }

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

314
            if (! candidates.isEmpty())
315
                break; // it's an argument or a template parameter.
316 317

            if (fun->name() && fun->name()->isQualifiedNameId()) {
318
                if (ClassOrNamespace *binding = bindings()->lookupType(fun)) {
Roberto Raggi's avatar
Roberto Raggi committed
319
                    candidates = binding->find(name);
320 321 322 323

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

326 327
            // contunue, and look at the enclosing scope.

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

331 332 333
            if (! candidates.isEmpty())
                break; // it's a formal argument.

334 335
        } else if (Template *templ = scope->asTemplate()) {
            bindings()->lookupInScope(name, templ, &candidates, /*templateId = */ 0, /*binding=*/ 0);
336 337

            if (! candidates.isEmpty())
338 339 340
                return candidates;  // it's a template parameter.

        } else if (Class *klass = scope->asClass()) {
341 342

            if (ClassOrNamespace *binding = bindings()->lookupType(klass)) {
Roberto Raggi's avatar
Roberto Raggi committed
343
                candidates = binding->find(name);
344 345 346 347 348

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

Roberto Raggi's avatar
Roberto Raggi committed
349 350
        } else if (Namespace *ns = scope->asNamespace()) {
            if (ClassOrNamespace *binding = bindings()->lookupType(ns))
Roberto Raggi's avatar
Roberto Raggi committed
351
                candidates = binding->find(name);
352

Roberto Raggi's avatar
Roberto Raggi committed
353 354 355
                if (! candidates.isEmpty())
                    return candidates;

Roberto Raggi's avatar
Roberto Raggi committed
356 357
        } else if (scope->isObjCClass() || scope->isObjCProtocol()) {
            if (ClassOrNamespace *binding = bindings()->lookupType(scope))
Roberto Raggi's avatar
Roberto Raggi committed
358 359 360 361
                candidates = binding->find(name);

                if (! candidates.isEmpty())
                    return candidates;
362 363 364 365 366 367
        }
    }

    return candidates;
}

368 369
ClassOrNamespace *LookupContext::lookupParent(Symbol *symbol) const
{
370
    QList<const Name *> fqName = path(symbol);
371 372 373 374 375 376 377 378 379 380
    ClassOrNamespace *binding = globalNamespace();
    foreach (const Name *name, fqName) {
        binding = binding->findType(name);
        if (!binding)
            return 0;
    }

    return binding;
}

381
ClassOrNamespace::ClassOrNamespace(CreateBindings *factory, ClassOrNamespace *parent)
382
    : _factory(factory), _parent(parent), _templateId(0), _instantiationOrigin(0)
383 384 385
{
}

386 387 388 389 390
const TemplateNameId *ClassOrNamespace::templateId() const
{
    return _templateId;
}

391 392 393 394 395
ClassOrNamespace *ClassOrNamespace::instantiationOrigin() const
{
    return _instantiationOrigin;
}

396 397 398 399 400
ClassOrNamespace *ClassOrNamespace::parent() const
{
    return _parent;
}

401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432
QList<ClassOrNamespace *> ClassOrNamespace::usings() const
{
    const_cast<ClassOrNamespace *>(this)->flush();
    return _usings;
}

QList<Enum *> ClassOrNamespace::enums() const
{
    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;
}

433
QList<LookupItem> ClassOrNamespace::find(const Name *name)
434 435 436 437
{
    return lookup_helper(name, false);
}

438
QList<LookupItem> ClassOrNamespace::lookup(const Name *name)
439 440 441 442
{
    return lookup_helper(name, true);
}

443
QList<LookupItem> ClassOrNamespace::lookup_helper(const Name *name, bool searchInEnclosingScope)
444
{
445
    QList<LookupItem> result;
446

447
    if (name) {
448

449
        if (const QualifiedNameId *q = name->asQualifiedNameId()) {
450 451
            if (! q->base())
                result = globalNamespace()->find(q->name());
452

453
            else if (ClassOrNamespace *binding = lookupType(q->base())) {
454
                result = binding->find(q->name());
455

456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487
                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;
                ClassOrNamespace *parentBinding = binding->parent();
                while (parentBinding && !match) {
                    for (int j = 0; j < parentBinding->symbols().size() && !match; ++j) {
                        if (Scope *scope = parentBinding->symbols().at(j)->asScope()) {
                            for (unsigned i = 0; i < scope->memberCount(); ++i) {
                                Symbol *candidate = scope->memberAt(i);
                                if (compareFullyQualifiedName(
                                            fullName,
                                            LookupContext::fullyQualifiedName(candidate))) {
                                    match = candidate;
                                    break;
                                }
                            }
                        }
                    }
                    parentBinding = parentBinding->parent();
                }

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

489 490
            return result;
        }
491

492
        QSet<ClassOrNamespace *> processed;
493 494 495 496 497 498
        ClassOrNamespace *binding = this;
        do {
            lookup_helper(name, binding, &result, &processed, /*templateId = */ 0);
            binding = binding->_parent;
        } while (searchInEnclosingScope && binding);
    }
499 500 501 502 503

    return result;
}

void ClassOrNamespace::lookup_helper(const Name *name, ClassOrNamespace *binding,
504 505 506
                                          QList<LookupItem> *result,
                                          QSet<ClassOrNamespace *> *processed,
                                          const TemplateNameId *templateId)
507
{
Roberto Raggi's avatar
Roberto Raggi committed
508
    if (binding && ! processed->contains(binding)) {
509 510
        processed->insert(binding);

511 512
        const Identifier *nameId = name->identifier();

513
        foreach (Symbol *s, binding->symbols()) {
514 515
            if (s->isFriend())
                continue;
516 517
            else if (s->isUsingNamespaceDirective())
                continue;
518

519

Roberto Raggi's avatar
Roberto Raggi committed
520 521
            if (Scope *scope = s->asScope()) {
                if (Class *klass = scope->asClass()) {
522
                    if (const Identifier *id = klass->identifier()) {
523 524 525 526 527 528
                        if (nameId && nameId->isEqualTo(id)) {
                            LookupItem item;
                            item.setDeclaration(klass);
                            item.setBinding(binding);
                            result->append(item);
                        }
529 530
                    }
                }
Roberto Raggi's avatar
Roberto Raggi committed
531
                _factory->lookupInScope(name, scope, result, templateId, binding);
532
            }
533 534 535
        }

        foreach (Enum *e, binding->enums())
Roberto Raggi's avatar
Roberto Raggi committed
536
            _factory->lookupInScope(name, e, result, templateId, binding);
537 538

        foreach (ClassOrNamespace *u, binding->usings())
539
            lookup_helper(name, u, result, processed, binding->_templateId);
540 541 542
    }
}

Roberto Raggi's avatar
Roberto Raggi committed
543
void CreateBindings::lookupInScope(const Name *name, Scope *scope,
544 545 546
                                   QList<LookupItem> *result,
                                   const TemplateNameId *templateId,
                                   ClassOrNamespace *binding)
547 548 549 550 551
{
    if (! name) {
        return;

    } else if (const OperatorNameId *op = name->asOperatorNameId()) {
Roberto Raggi's avatar
Roberto Raggi committed
552
        for (Symbol *s = scope->find(op->kind()); s; s = s->next()) {
553 554
            if (! s->name())
                continue;
555 556
            else if (s->isFriend())
                continue;
557 558
            else if (! s->name()->isEqualTo(op))
                continue;
559

560 561 562 563
            LookupItem item;
            item.setDeclaration(s);
            item.setBinding(binding);
            result->append(item);
564 565 566
        }

    } else if (const Identifier *id = name->identifier()) {
Roberto Raggi's avatar
Roberto Raggi committed
567
        for (Symbol *s = scope->find(id); s; s = s->next()) {
568 569
            if (s->isFriend())
                continue; // skip friends
570 571
            else if (s->isUsingNamespaceDirective())
                continue; // skip using namespace directives
572
            else if (! id->isEqualTo(s->identifier()))
573
                continue;
Roberto Raggi's avatar
Roberto Raggi committed
574 575
            else if (s->name()->isQualifiedNameId())
                continue; // skip qualified ids.
576

577 578 579
            LookupItem item;
            item.setDeclaration(s);
            item.setBinding(binding);
580

581 582 583 584 585 586 587 588
            if (s->asNamespaceAlias() && binding) {
                ClassOrNamespace *targetNamespaceBinding = binding->lookupType(name);
                if (targetNamespaceBinding && targetNamespaceBinding->symbols().size() == 1) {
                    Symbol *resolvedSymbol = targetNamespaceBinding->symbols().first();
                    item.setType(resolvedSymbol->type()); // override the type
                }
            }

589
            if (templateId && (s->isDeclaration() || s->isFunction())) {
Roberto Raggi's avatar
Roberto Raggi committed
590
                FullySpecifiedType ty = DeprecatedGenTemplateInstance::instantiate(templateId, s, _control);
591
                item.setType(ty); // override the type.
592 593
            }

594
            result->append(item);
595 596 597 598
        }
    }
}

599
ClassOrNamespace *ClassOrNamespace::lookupType(const Name *name)
600 601 602 603 604
{
    if (! name)
        return 0;

    QSet<ClassOrNamespace *> processed;
605
    return lookupType_helper(name, &processed, /*searchInEnclosingScope =*/ true, this);
606 607
}

608
ClassOrNamespace *ClassOrNamespace::findType(const Name *name)
609 610
{
    QSet<ClassOrNamespace *> processed;
611
    return lookupType_helper(name, &processed, /*searchInEnclosingScope =*/ false, this);
612 613
}

Roberto Raggi's avatar
Roberto Raggi committed
614
ClassOrNamespace *ClassOrNamespace::lookupType_helper(const Name *name,
615
                                                      QSet<ClassOrNamespace *> *processed,
616 617
                                                      bool searchInEnclosingScope,
                                                      ClassOrNamespace *origin)
618
{
619
    if (const QualifiedNameId *q = name->asQualifiedNameId()) {
620

621 622 623 624
        QSet<ClassOrNamespace *> innerProcessed;
        if (! q->base()) {
            return globalNamespace()->lookupType_helper(q->name(), &innerProcessed, true, origin);
        }
625

626 627 628
        if (ClassOrNamespace *binding = lookupType_helper(q->base(), processed, true, origin)) {
            return binding->lookupType_helper(q->name(), &innerProcessed, false, origin);
        }
629

630
        return 0;
631

632 633
    } else if (! processed->contains(this)) {
        processed->insert(this);
634

635 636
        if (name->isNameId() || name->isTemplateNameId()) {
            flush();
637

638 639 640 641 642 643 644
            foreach (Symbol *s, symbols()) {
                if (Class *klass = s->asClass()) {
                    if (klass->identifier() && klass->identifier()->isEqualTo(name->identifier()))
                        return this;
                }
            }

645
            if (ClassOrNamespace *e = nestedType(name, origin))
646 647
                return e;

648
            else if (_templateId) {
649 650 651
                if (_usings.size() == 1) {
                    ClassOrNamespace *delegate = _usings.first();

652
                    if (ClassOrNamespace *r = delegate->lookupType_helper(name, processed, /*searchInEnclosingScope = */ true, origin))
653 654 655 656 657
                        return r;
                } else {
                    if (debug)
                        qWarning() << "expected one using declaration. Number of using declarations is:" << _usings.size();
                }
658 659
            }

660
            foreach (ClassOrNamespace *u, usings()) {
661
                if (ClassOrNamespace *r = u->lookupType_helper(name, processed, /*searchInEnclosingScope =*/ false, origin))
662 663 664 665
                    return r;
            }
        }

666
        if (_parent && searchInEnclosingScope)
667
            return _parent->lookupType_helper(name, processed, searchInEnclosingScope, origin);
668 669 670 671 672
    }

    return 0;
}

673
ClassOrNamespace *ClassOrNamespace::nestedType(const Name *name, ClassOrNamespace *origin)
674
{
675 676
    Q_ASSERT(name != 0);
    Q_ASSERT(name->isNameId() || name->isTemplateNameId());
677

678
    const_cast<ClassOrNamespace *>(this)->flush();
679

680 681 682
    Table::const_iterator it = _classOrNamespaces.find(name);
    if (it == _classOrNamespaces.end())
        return 0;
683

684 685 686 687 688 689 690
    ClassOrNamespace *reference = it->second;

    // 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;
691
    QList<const Name *> allBases;
692 693 694 695
    foreach (Symbol *s, reference->symbols()) {
        if (Class *clazz = s->asClass()) {
            for (unsigned i = 0; i < clazz->baseClassCount(); ++i) {
                BaseClass *baseClass = clazz->baseClassAt(i);
696 697
                if (baseClass->name())
                    allBases.append(baseClass->name());
698 699 700 701 702 703 704 705 706
            }
            referenceClass = clazz;
            break;
        }
    }

    if (!referenceClass)
        return reference;

707 708 709 710 711 712 713 714 715 716
    const TemplateNameId *templId = name->asTemplateNameId();
    if (_alreadyConsideredClasses.contains(referenceClass) ||
            (templId &&
            _alreadyConsideredTemplates.contains(templId))) {
            return reference;
    }

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

717 718
    QSet<ClassOrNamespace *> knownUsings = reference->usings().toSet();

719 720
    // If we are dealling with a template type, more work is required, since we need to
    // construct all instantiation data.
721 722
    if (templId) {
        _alreadyConsideredTemplates.insert(templId);
723 724 725 726 727 728 729 730 731 732 733
        ClassOrNamespace *instantiation = _factory->allocClassOrNamespace(reference);
        instantiation->_templateId = templId;
        instantiation->_instantiationOrigin = origin;

        // The instantiation should have all symbols, enums, and usings from the reference.
        instantiation->_enums.append(reference->enums());
        instantiation->_usings.append(reference->usings());

        // It gets a bit complicated if the reference is actually a class template because we
        // now must worry about dependent names in base classes.
        if (Template *templ = referenceClass->enclosingTemplate()) {
734
            const unsigned argumentCount = templId->templateArgumentCount();
735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756

            if (_factory->expandTemplates()) {
                Subst subst(_control.data());
                for (unsigned i = 0, ei = std::min(argumentCount, templ->templateParameterCount()); i < ei; ++i) {
                    const TypenameArgument *tParam = templ->templateParameterAt(i)->asTypenameArgument();
                    if (!tParam)
                        continue;
                    const Name *name = tParam->name();
                    if (!name)
                        continue;
                    const FullySpecifiedType &ty = templId->templateArgumentAt(i);
                    subst.bind(name, ty);
                }

                Clone cloner(_control.data());
                foreach (Symbol *s, reference->symbols()) {
                    instantiation->_symbols.append(cloner.symbol(s, &subst));
                }
            } else {
                instantiation->_symbols.append(reference->symbols());
            }

757 758 759 760
            QHash<const Name*, unsigned> templParams;
            for (unsigned i = 0; i < templ->templateParameterCount(); ++i)
                templParams.insert(templ->templateParameterAt(i)->name(), i);

761
            foreach (const Name *baseName, allBases) {
762 763 764 765 766 767
                ClassOrNamespace *baseBinding = 0;

                if (const Identifier *nameId = baseName->asNameId()) {
                    // This is the simple case in which a template parameter is itself a base.
                    // Ex.: template <class T> class A : public T {};
                    if (templParams.contains(nameId)) {
768 769 770 771 772 773 774 775 776
                        const unsigned parameterIndex = templParams.value(nameId);
                        if (parameterIndex < argumentCount) {
                            const FullySpecifiedType &fullType =
                                    templId->templateArgumentAt(parameterIndex);
                            if (fullType.isValid()) {
                                if (NamedType *namedType = fullType.type()->asNamedType())
                                    baseBinding = lookupType(namedType->name());
                            }
                        }
777 778 779 780
                    }
                } else {
                    SubstitutionMap map;
                    for (unsigned i = 0;
781
                         i < templ->templateParameterCount() && i < argumentCount;
782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799
                         ++i) {
                        map.bind(templ->templateParameterAt(i)->name(),
                                 templId->templateArgumentAt(i));
                    }
                    SubstitutionEnvironment env;
                    env.enter(&map);

                    baseName = rewriteName(baseName, &env, _control.data());

                    if (const TemplateNameId *baseTemplId = baseName->asTemplateNameId()) {
                        // Another template that uses the dependent name.
                        // Ex.: template <class T> class A : public B<T> {};
                        if (baseTemplId->identifier() != templId->identifier())
                            baseBinding = nestedType(baseName, origin);
                    } else if (const QualifiedNameId *qBaseName = baseName->asQualifiedNameId()) {
                        // Qualified names in general.
                        // Ex.: template <class T> class A : public B<T>::Type {};
                        ClassOrNamespace *binding = this;
800 801 802 803 804
                        if (const Name *qualification = qBaseName->base()) {
                            const TemplateNameId *baseTemplName = qualification->asTemplateNameId();
                            if (!baseTemplName || !compareName(baseTemplName, templ->name()))
                                binding = lookupType(qualification);
                        }
805 806 807 808 809 810 811
                        baseName = qBaseName->name();

                        if (binding)
                            baseBinding = binding->lookupType(baseName);
                    }
                }

812
                if (baseBinding && !knownUsings.contains(baseBinding))
813 814
                    instantiation->addUsing(baseBinding);
            }
815 816
        } else {
            instantiation->_symbols.append(reference->symbols());
817 818
        }

819
        _alreadyConsideredTemplates.clear(templId);
820
        return instantiation;
821 822
    }

823 824 825 826 827
    if (allBases.isEmpty() || allBases.size() == knownUsings.size())
        return reference;

    QList<const Name *> fullyQualifiedNameForReferenceClass =
            LookupContext::fullyQualifiedName(referenceClass);
828 829
    // Find the missing bases for regular (non-template) types.
    // Ex.: class A : public B<Some>::Type {};
830
    foreach (const Name *baseName, allBases) {
831 832
        ClassOrNamespace *binding = this;
        if (const QualifiedNameId *qBaseName = baseName->asQualifiedNameId()) {
833 834 835 836 837 838 839
            QList<const Name *> fullyQualifiedNameForBaseClass;
            addNames(baseName, &fullyQualifiedNameForBaseClass);
            if (compareFullyQualifiedName(fullyQualifiedNameForReferenceClass,
                                          fullyQualifiedNameForBaseClass)) {
                continue;
            }

840 841
            if (const Name *qualification = qBaseName->base())
                binding = lookupType(qualification);
842 843 844 845 846 847 848
            else if (binding->parent() != 0)
                //if this is global identifier we take global namespace
                //Ex: class A{}; namespace NS { class A: public ::A{}; }
                binding = binding->globalNamespace();
            else
                //if we are in the global scope
                continue;
849 850
            baseName = qBaseName->name();
        }
851 852 853
        else if (compareName(name, baseName)) {
            continue;
        }
854 855 856

        if (binding) {
            ClassOrNamespace * baseBinding = binding->lookupType(baseName);
857
            if (baseBinding && !knownUsings.contains(baseBinding))
858 859 860 861
                reference->addUsing(baseBinding);
        }
    }

862
    _alreadyConsideredClasses.clear(referenceClass);
863
    return reference;
864 865 866 867
}

void ClassOrNamespace::flush()
{
Roberto Raggi's avatar
Roberto Raggi committed
868 869 870
    if (! _todo.isEmpty()) {
        const QList<Symbol *> todo = _todo;
        _todo.clear();
871

Roberto Raggi's avatar
Roberto Raggi committed
872
        foreach (Symbol *member, todo)
873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896
            _factory->process(member, this);
    }
}

void ClassOrNamespace::addSymbol(Symbol *symbol)
{
    _symbols.append(symbol);
}

void ClassOrNamespace::addTodo(Symbol *symbol)
{
    _todo.append(symbol);
}

void ClassOrNamespace::addEnum(Enum *e)
{
    _enums.append(e);
}

void ClassOrNamespace::addUsing(ClassOrNamespace *u)
{
    _usings.append(u);
}

Roberto Raggi's avatar
Roberto Raggi committed
897
void ClassOrNamespace::addNestedType(const Name *alias, ClassOrNamespace *e)
898
{
899
    _classOrNamespaces[alias] = e;
900 901
}

902
ClassOrNamespace *ClassOrNamespace::findOrCreateType(const Name *name, ClassOrNamespace *origin)
903 904 905
{
    if (! name)
        return this;
906 907
    if (! origin)
        origin = this;
908 909

    if (const QualifiedNameId *q = name->asQualifiedNameId()) {
910
        if (! q->base())
911
            return globalNamespace()->findOrCreateType(q->name(), origin);
912

913
        return findOrCreateType(q->base(), origin)->findOrCreateType(q->name(), origin);
914

915
    } else if (name->isNameId() || name->isTemplateNameId()) {
916
        ClassOrNamespace *e = nestedType(name, origin);
917 918 919

        if (! e) {
            e = _factory->allocClassOrNamespace(this);
920
            _classOrNamespaces[name] = e;
921 922 923 924 925 926 927 928
        }

        return e;
    }

    return 0;
}

929
CreateBindings::CreateBindings(Document::Ptr thisDocument, const Snapshot &snapshot, QSharedPointer<Control> control)
930
    : _snapshot(snapshot), _control(control), _expandTemplates(false)
931 932 933 934 935 936 937 938 939 940 941 942
{
    _globalNamespace = allocClassOrNamespace(/*parent = */ 0);
    _currentClassOrNamespace = _globalNamespace;

    process(thisDocument);
}

CreateBindings::~CreateBindings()
{
    qDeleteAll(_entities);
}

Roberto Raggi's avatar
Roberto Raggi committed
943
ClassOrNamespace *CreateBindings::switchCurrentClassOrNamespace(ClassOrNamespace *classOrNamespace)
944 945 946 947 948 949 950 951 952 953 954
{
    ClassOrNamespace *previous = _currentClassOrNamespace;
    _currentClassOrNamespace = classOrNamespace;
    return previous;
}

ClassOrNamespace *CreateBindings::globalNamespace() const
{
    return _globalNamespace;
}

Roberto Raggi's avatar
Roberto Raggi committed
955
ClassOrNamespace *CreateBindings::lookupType(Symbol *symbol)
956
{
957 958 959
    const QList<const Name *> path = LookupContext::path(symbol);
    return lookupType(path);
}
960

961 962 963
ClassOrNamespace *CreateBindings::lookupType(const QList<const Name *> &path)
{
    if (path.isEmpty())
964
        return _globalNamespace;
965

966
    ClassOrNamespace *b = _globalNamespace->lookupType(path.at(0));
967

968 969
    for (int i = 1; b && i < path.size(); ++i)
        b = b->findType(path.at(i));
970 971

    return b;
972 973 974 975
}

void CreateBindings::process(Symbol *s, ClassOrNamespace *classOrNamespace)
{
Roberto Raggi's avatar
Roberto Raggi committed
976
    ClassOrNamespace *previous = switchCurrentClassOrNamespace(classOrNamespace);
977
    accept(s);
Roberto Raggi's avatar
Roberto Raggi committed
978
    (void) switchCurrentClassOrNamespace(previous);
979 980 981 982 983 984 985
}

void CreateBindings::process(Symbol *symbol)
{
    _currentClassOrNamespace->addTodo(symbol);
}

986
QSharedPointer<Control> CreateBindings::control() const
987 988 989 990
{
    return _control;
}

991 992 993
ClassOrNamespace *CreateBindings::allocClassOrNamespace(ClassOrNamespace *parent)
{
    ClassOrNamespace *e = new ClassOrNamespace(this, parent);
994
    e->_control = control();
995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017
    _entities.append(e);
    return e;
}

void CreateBindings::process(Document::Ptr doc)
{
    if (! doc)
        return;

    else if (Namespace *globalNamespace = doc->globalNamespace()) {
        if (! _processed.contains(globalNamespace)) {
            _processed.insert(globalNamespace);

            foreach (const Document::Include &i, doc->includes()) {
                if (Document::Ptr incl = _snapshot.document(i.fileName()))
                    process(incl);
            }

            accept(globalNamespace);
        }
    }
}

1018
ClassOrNamespace *CreateBindings::enterClassOrNamespaceBinding(Symbol *symbol)
1019
{
1020
    ClassOrNamespace *entity = _currentClassOrNamespace->findOrCreateType(symbol->name());
1021 1022
    entity->addSymbol(symbol);

Roberto Raggi's avatar
Roberto Raggi committed
1023
    return switchCurrentClassOrNamespace(entity);
1024 1025
}

1026
ClassOrNamespace *CreateBindings::enterGlobalClassOrNamespace(Symbol *symbol)
1027
{
1028
    ClassOrNamespace *entity = _globalNamespace->findOrCreateType(symbol->name());
1029 1030
    entity->addSymbol(symbol);

Roberto Raggi's avatar
Roberto Raggi committed
1031
    return switchCurrentClassOrNamespace(entity);
1032 1033
}

1034 1035
bool CreateBindings::visit(Template *templ)
{
Roberto Raggi's avatar
Roberto Raggi committed
1036 1037 1038
    if (Symbol *d = templ->declaration())
        accept(d);