LookupContext.cpp 57.8 KB
Newer Older
hjk's avatar
hjk committed
1
/****************************************************************************
2
**
3
** Copyright (C) 2013 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

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

55

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

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

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

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

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

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

94 95
namespace CPlusPlus {

96
static inline bool compareName(const Name *name, const Name *other)
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 123 124 125 126
{
    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;
}

}

127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
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;
}
}
}

151 152 153 154
/////////////////////////////////////////////////////////////////////
// LookupContext
/////////////////////////////////////////////////////////////////////
LookupContext::LookupContext()
155
    : m_expandTemplates(false)
156 157 158 159
{ }

LookupContext::LookupContext(Document::Ptr thisDocument,
                             const Snapshot &snapshot)
160 161 162 163
    : _expressionDocument(Document::create(QLatin1String("<LookupContext>")))
    , _thisDocument(thisDocument)
    , _snapshot(snapshot)
    , m_expandTemplates(false)
164 165 166 167 168 169
{
}

LookupContext::LookupContext(Document::Ptr expressionDocument,
                             Document::Ptr thisDocument,
                             const Snapshot &snapshot)
170 171 172 173
    : _expressionDocument(expressionDocument)
    , _thisDocument(thisDocument)
    , _snapshot(snapshot)
    , m_expandTemplates(false)
174 175 176 177
{
}

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

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

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

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

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

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

242
    return n;
243 244
}

245 246 247 248 249 250 251
QList<LookupItem> LookupContext::lookupByUsing(const Name *name, Scope *scope) const
{
    QList<LookupItem> candidates;
    // if it is a nameId there can be a using declaration for it
    if (name->isNameId()) {
        for (unsigned i = 0, count = scope->memberCount(); i < count; ++i) {
            if (UsingDeclaration *u = scope->memberAt(i)->asUsingDeclaration()) {
252 253 254 255 256 257 258 259 260 261 262 263 264
                if (const Name *usingDeclarationName = u->name()) {
                    if (const QualifiedNameId *q = usingDeclarationName->asQualifiedNameId()) {
                        if (q->name() && q->name()->isEqualTo(name)) {
                            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->scope()) {
                                LookupItem item;
                                item.setDeclaration(u);
                                item.setScope(scope);
                                candidates.append(item);
                            }
265 266 267 268 269 270 271 272 273
                        }
                    }
                }
            }
        }
    }
    return candidates;
}

274

275 276
QSharedPointer<CreateBindings> LookupContext::bindings() const
{
277
    if (! _bindings) {
278
        _bindings = QSharedPointer<CreateBindings>(new CreateBindings(_thisDocument, _snapshot));
279 280
        _bindings->setExpandTemplates(m_expandTemplates);
    }
281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306

    return _bindings;
}

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

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

307
ClassOrNamespace *LookupContext::lookupType(const Name *name, Scope *scope,
308 309
                                            ClassOrNamespace* enclosingTemplateInstantiation,
                                            QSet<const Declaration *> typedefsBeingResolved) const
310
{
311 312 313 314
    if (! scope) {
        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 319 320
                if (ClassOrNamespace *uu = lookupType(u->name(), scope->enclosingNamespace())) {
                    if (ClassOrNamespace *r = uu->lookupType(name))
                        return r;
                }
321 322 323 324 325 326 327
            } else if (Declaration *d = m->asDeclaration()) {
                if (d->name() && d->name()->isEqualTo(name->asNameId())) {
                    if (d->isTypedef() && d->type()) {
#ifdef DEBUG_LOOKUP
                        Overview oo;
                        qDebug() << "Looks like" << oo(name) << "is a typedef for" << oo(d->type());
#endif // DEBUG_LOOKUP
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 342 343 344
                    if (const Name *usingDeclarationName = ud->name()) {
                        if (const QualifiedNameId *q = usingDeclarationName->asQualifiedNameId()) {
                            if (q->name() && q->name()->isEqualTo(name)) {
                                return bindings()->globalNamespace()->lookupType(q);
                            }
345 346 347 348
                        }
                    }

                }
349 350 351
            }
        }
        return lookupType(name, scope->enclosingScope());
352
    } else if (ClassOrNamespace *b = bindings()->lookupType(scope, enclosingTemplateInstantiation)) {
353
        return b->lookupType(name);
354
    }
355 356 357 358

    return 0;
}

359 360
ClassOrNamespace *LookupContext::lookupType(Symbol *symbol,
                                            ClassOrNamespace* enclosingTemplateInstantiation) const
361
{
362
    return bindings()->lookupType(symbol, enclosingTemplateInstantiation);
363 364
}

365
QList<LookupItem> LookupContext::lookup(const Name *name, Scope *scope) const
366
{
367
    QList<LookupItem> candidates;
368 369 370 371

    if (! name)
        return candidates;

372
    for (; scope; scope = scope->enclosingScope()) {
373
        if (name->identifier() != 0 && scope->isBlock()) {
374
            bindings()->lookupInScope(name, scope, &candidates, /*templateId = */ 0, /*binding=*/ 0);
375

376 377 378 379 380 381 382 383
            if (! candidates.isEmpty()) {
                // it's a local.
                //for qualified it can be outside of the local scope
                if (name->isQualifiedNameId())
                    continue;
                else
                    break;
            }
384

385 386 387 388
            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);
389

390 391
                        if (! candidates.isEmpty())
                            return candidates;
392 393 394 395
                    }
                }
            }

396 397 398 399
            candidates = lookupByUsing(name, scope);
            if (! candidates.isEmpty())
                return candidates;

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

403 404 405 406 407 408 409 410
            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;
            }
411 412

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

416 417 418 419
                    // try find this name in parent class
                    while (candidates.isEmpty() && (binding = binding->parent()))
                        candidates = binding->find(name);

420 421 422
                    if (! candidates.isEmpty())
                        return candidates;
                }
423 424
            }

425
            // continue, and look at the enclosing scope.
426

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

430 431 432
            if (! candidates.isEmpty())
                break; // it's a formal argument.

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

436 437 438 439 440 441 442 443
            if (! candidates.isEmpty()) {
                // it's a template parameter.
                //for qualified it can be outside of the local scope
                if (name->isQualifiedNameId())
                    continue;
                else
                    break;
            }
444

445 446 447 448
        } else if (scope->asNamespace()
                   || scope->asClass()
                   || (scope->asEnum() && scope->asEnum()->isScoped())) {
            if (ClassOrNamespace *binding = bindings()->lookupType(scope))
Roberto Raggi's avatar
Roberto Raggi committed
449
                candidates = binding->find(name);
450

451 452 453 454 455 456
            if (! candidates.isEmpty())
                return candidates;

            candidates = lookupByUsing(name, scope);
            if (! candidates.isEmpty())
                return candidates;
Roberto Raggi's avatar
Roberto Raggi committed
457

Roberto Raggi's avatar
Roberto Raggi committed
458 459
        } else if (scope->isObjCClass() || scope->isObjCProtocol()) {
            if (ClassOrNamespace *binding = bindings()->lookupType(scope))
Roberto Raggi's avatar
Roberto Raggi committed
460 461 462 463
                candidates = binding->find(name);

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

    return candidates;
}

470 471
ClassOrNamespace *LookupContext::lookupParent(Symbol *symbol) const
{
472
    QList<const Name *> fqName = path(symbol);
473 474 475 476 477 478 479 480 481 482
    ClassOrNamespace *binding = globalNamespace();
    foreach (const Name *name, fqName) {
        binding = binding->findType(name);
        if (!binding)
            return 0;
    }

    return binding;
}

483
ClassOrNamespace::ClassOrNamespace(CreateBindings *factory, ClassOrNamespace *parent)
484 485 486 487 488
    : _factory(factory)
    , _parent(parent)
    , _scopeLookupCache(0)
    , _templateId(0)
    , _instantiationOrigin(0)
489 490 491
#ifdef DEBUG_LOOKUP
    , _name(0)
#endif // DEBUG_LOOKUP
492 493 494
{
}

495 496 497 498 499
ClassOrNamespace::~ClassOrNamespace()
{
    delete _scopeLookupCache;
}

500 501 502 503 504
const TemplateNameId *ClassOrNamespace::templateId() const
{
    return _templateId;
}

505 506 507 508 509
ClassOrNamespace *ClassOrNamespace::instantiationOrigin() const
{
    return _instantiationOrigin;
}

510 511 512 513 514
ClassOrNamespace *ClassOrNamespace::parent() const
{
    return _parent;
}

515 516 517 518 519 520
QList<ClassOrNamespace *> ClassOrNamespace::usings() const
{
    const_cast<ClassOrNamespace *>(this)->flush();
    return _usings;
}

521
QList<Enum *> ClassOrNamespace::unscopedEnums() const
522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546
{
    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;
}

547
QList<LookupItem> ClassOrNamespace::find(const Name *name)
548 549 550 551
{
    return lookup_helper(name, false);
}

552
QList<LookupItem> ClassOrNamespace::lookup(const Name *name)
553 554 555 556
{
    return lookup_helper(name, true);
}

557
QList<LookupItem> ClassOrNamespace::lookup_helper(const Name *name, bool searchInEnclosingScope)
558
{
559
    QList<LookupItem> result;
560

561
    if (name) {
562

563
        if (const QualifiedNameId *q = name->asQualifiedNameId()) {
564
            if (! q->base()) // e.g. ::std::string
565
                result = globalNamespace()->find(q->name());
566

567
            else if (ClassOrNamespace *binding = lookupType(q->base())) {
568
                result = binding->find(q->name());
569

570 571 572 573 574 575 576
                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;
577 578 579 580
                for (ClassOrNamespace *parentBinding = binding->parent();
                        parentBinding && !match;
                        parentBinding = parentBinding->parent())
                    match = parentBinding->lookupInScope(fullName);
581 582 583 584 585 586 587 588

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

590 591
            return result;
        }
592

593
        QSet<ClassOrNamespace *> processed;
594 595 596 597 598 599
        ClassOrNamespace *binding = this;
        do {
            lookup_helper(name, binding, &result, &processed, /*templateId = */ 0);
            binding = binding->_parent;
        } while (searchInEnclosingScope && binding);
    }
600 601 602 603 604

    return result;
}

void ClassOrNamespace::lookup_helper(const Name *name, ClassOrNamespace *binding,
605 606 607
                                          QList<LookupItem> *result,
                                          QSet<ClassOrNamespace *> *processed,
                                          const TemplateNameId *templateId)
608
{
Roberto Raggi's avatar
Roberto Raggi committed
609
    if (binding && ! processed->contains(binding)) {
610 611
        processed->insert(binding);

612 613
        const Identifier *nameId = name->identifier();

614
        foreach (Symbol *s, binding->symbols()) {
615 616
            if (s->isFriend())
                continue;
617 618
            else if (s->isUsingNamespaceDirective())
                continue;
619

620

Roberto Raggi's avatar
Roberto Raggi committed
621 622
            if (Scope *scope = s->asScope()) {
                if (Class *klass = scope->asClass()) {
623
                    if (const Identifier *id = klass->identifier()) {
624 625 626 627 628 629
                        if (nameId && nameId->isEqualTo(id)) {
                            LookupItem item;
                            item.setDeclaration(klass);
                            item.setBinding(binding);
                            result->append(item);
                        }
630 631
                    }
                }
Roberto Raggi's avatar
Roberto Raggi committed
632
                _factory->lookupInScope(name, scope, result, templateId, binding);
633
            }
634 635
        }

636
        foreach (Enum *e, binding->unscopedEnums())
Roberto Raggi's avatar
Roberto Raggi committed
637
            _factory->lookupInScope(name, e, result, templateId, binding);
638 639

        foreach (ClassOrNamespace *u, binding->usings())
640
            lookup_helper(name, u, result, processed, binding->_templateId);
641 642 643
    }
}

Roberto Raggi's avatar
Roberto Raggi committed
644
void CreateBindings::lookupInScope(const Name *name, Scope *scope,
645 646 647
                                   QList<LookupItem> *result,
                                   const TemplateNameId *templateId,
                                   ClassOrNamespace *binding)
648 649 650 651 652
{
    if (! name) {
        return;

    } else if (const OperatorNameId *op = name->asOperatorNameId()) {
Roberto Raggi's avatar
Roberto Raggi committed
653
        for (Symbol *s = scope->find(op->kind()); s; s = s->next()) {
654 655
            if (! s->name())
                continue;
656 657
            else if (s->isFriend())
                continue;
658 659
            else if (! s->name()->isEqualTo(op))
                continue;
660

661 662 663 664
            LookupItem item;
            item.setDeclaration(s);
            item.setBinding(binding);
            result->append(item);
665 666 667
        }

    } else if (const Identifier *id = name->identifier()) {
Roberto Raggi's avatar
Roberto Raggi committed
668
        for (Symbol *s = scope->find(id); s; s = s->next()) {
669 670
            if (s->isFriend())
                continue; // skip friends
671 672
            else if (s->isUsingNamespaceDirective())
                continue; // skip using namespace directives
673
            else if (! id->isEqualTo(s->identifier()))
674
                continue;
Roberto Raggi's avatar
Roberto Raggi committed
675 676
            else if (s->name()->isQualifiedNameId())
                continue; // skip qualified ids.
677

678 679
#ifdef DEBUG_LOOKUP
            Overview oo;
680
            qDebug() << "Found" << id->chars() << "in"
681
                     << (binding ? oo(binding->_name) : QString::fromLatin1("<null>"));
682 683
#endif // DEBUG_LOOKUP

684 685 686
            LookupItem item;
            item.setDeclaration(s);
            item.setBinding(binding);
687

688 689
            if (s->asNamespaceAlias() && binding) {
                ClassOrNamespace *targetNamespaceBinding = binding->lookupType(name);
690 691
                //there can be many namespace definitions
                if (targetNamespaceBinding && targetNamespaceBinding->symbols().size() > 0) {
692 693 694 695 696
                    Symbol *resolvedSymbol = targetNamespaceBinding->symbols().first();
                    item.setType(resolvedSymbol->type()); // override the type
                }
            }

697
            if (templateId && (s->isDeclaration() || s->isFunction())) {
698
                FullySpecifiedType ty = DeprecatedGenTemplateInstance::instantiate(templateId, s, control());
699
                item.setType(ty); // override the type.
700 701
            }

702 703 704 705 706 707 708 709 710 711
            // 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.
            }

712
            result->append(item);
713 714 715 716
        }
    }
}

717
ClassOrNamespace *ClassOrNamespace::lookupType(const Name *name)
718 719 720 721 722
{
    if (! name)
        return 0;

    QSet<ClassOrNamespace *> processed;
723
    return lookupType_helper(name, &processed, /*searchInEnclosingScope =*/ true, this);
724 725
}

726
ClassOrNamespace *ClassOrNamespace::findType(const Name *name)
727 728
{
    QSet<ClassOrNamespace *> processed;
729
    return lookupType_helper(name, &processed, /*searchInEnclosingScope =*/ false, this);
730 731
}

732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749
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
750
ClassOrNamespace *ClassOrNamespace::lookupType_helper(const Name *name,
751
                                                      QSet<ClassOrNamespace *> *processed,
752 753
                                                      bool searchInEnclosingScope,
                                                      ClassOrNamespace *origin)
754
{
755 756 757 758 759
#ifdef DEBUG_LOOKUP
    Overview oo;
    qDebug() << "Looking up" << oo(name) << "in" << oo(_name);
#endif // DEBUG_LOOKUP

760
    if (const QualifiedNameId *q = name->asQualifiedNameId()) {
761

762
        QSet<ClassOrNamespace *> innerProcessed;
763
        if (! q->base())
764
            return globalNamespace()->lookupType_helper(q->name(), &innerProcessed, true, origin);
765

766
        if (ClassOrNamespace *binding = lookupType_helper(q->base(), processed, true, origin))
767
            return binding->lookupType_helper(q->name(), &innerProcessed, false, origin);
768

769
        return 0;
770

771 772
    } else if (! processed->contains(this)) {
        processed->insert(this);
773

774
        if (name->isNameId() || name->isTemplateNameId() || name->isAnonymousNameId()) {
775
            flush();
776

777 778 779 780 781 782 783
            foreach (Symbol *s, symbols()) {
                if (Class *klass = s->asClass()) {
                    if (klass->identifier() && klass->identifier()->isEqualTo(name->identifier()))
                        return this;
                }
            }

784
            if (ClassOrNamespace *e = nestedType(name, origin))
785 786
                return e;

787
            else if (_templateId) {
788 789 790
                if (_usings.size() == 1) {
                    ClassOrNamespace *delegate = _usings.first();

791 792 793 794
                    if (ClassOrNamespace *r = delegate->lookupType_helper(name,
                                                                          processed,
                                                                          /*searchInEnclosingScope = */ true,
                                                                          origin))
795 796 797
                        return r;
                } else {
                    if (debug)
798 799
                        qWarning() << "expected one using declaration. Number of using declarations is:"
                                   << _usings.size();
800
                }
801 802
            }

803
            foreach (ClassOrNamespace *u, usings()) {
804 805 806 807
                if (ClassOrNamespace *r = u->lookupType_helper(name,
                                                               processed,
                                                               /*searchInEnclosingScope =*/ false,
                                                               origin))
808 809 810 811
                    return r;
            }
        }

812 813
        if (_parent && searchInEnclosingScope)
            return _parent->lookupType_helper(name, processed, searchInEnclosingScope, origin);
814 815 816 817 818
    }

    return 0;
}

819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852
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;
}

853
ClassOrNamespace *ClassOrNamespace::nestedType(const Name *name, ClassOrNamespace *origin)
854
{
855
    Q_ASSERT(name != 0);
856
    Q_ASSERT(name->isNameId() || name->isTemplateNameId() || name->isAnonymousNameId());
857

858
    const_cast<ClassOrNamespace *>(this)->flush();
859

860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875
    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);
#ifdef DEBUG_LOOKUP
            newAnonymous->_name = anonymousNameId;
#endif // DEBUG_LOOKUP
            _anonymouses[anonymousNameId] = newAnonymous;
            return newAnonymous;
        }
    }

876 877 878
    Table::const_iterator it = _classOrNamespaces.find(name);
    if (it == _classOrNamespaces.end())
        return 0;
879

880
    ClassOrNamespace *reference = it->second;
881
    ClassOrNamespace *baseTemplateClassReference = reference;
882

883 884
    const TemplateNameId *templId = name->asTemplateNameId();
    if (templId) {
885 886 887 888 889 890
        // 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];

891 892 893 894 895 896
        // 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)
897 898
            TemplateNameIdTable::const_iterator cit
                    = reference->_specializations.find(templId);
899 900 901 902 903 904 905 906 907 908 909
            if (cit != reference->_specializations.end()) {
                return cit->second;
            } else {
                ClassOrNamespace *newSpecialization = _factory->allocClassOrNamespace(reference);
#ifdef DEBUG_LOOKUP
                newSpecialization->_name = templId;
#endif // DEBUG_LOOKUP
                reference->_specializations[templId] = newSpecialization;
                return newSpecialization;
            }
        } else {
910 911 912 913
            QMap<const TemplateNameId *, ClassOrNamespace *>::const_iterator citInstantiation
                    = reference->_instantiations.find(templId);
            if (citInstantiation != reference->_instantiations.end())
                return citInstantiation.value();
914 915 916 917
            TemplateNameId *nonConstTemplId = const_cast<TemplateNameId *>(templId);
            // make this instantiation looks like specialization which help to find
            // full specialization for this instantiation
            nonConstTemplId->setIsSpecialization(true);
918 919 920
            const TemplateNameIdTable &specializations = reference->_specializations;
            TemplateNameIdTable::const_iterator cit = specializations.find(templId);
            if (cit != specializations.end()) {
921 922 923
                // we found full specialization
                reference = cit->second;
            } else {
924 925 926 927
                ClassOrNamespace *specializationWithPointer
                        = findSpecializationWithPointer(templId, specializations);
                if (specializationWithPointer)
                    reference = specializationWithPointer;
928 929 930 931 932 933 934
                // TODO: find the best specialization(probably partial) for this instantiation
            }
            // let's instantiation be instantiation
            nonConstTemplId->setIsSpecialization(false);
        }
    }

935 936 937 938 939
    // 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;
940
    QList<const Name *> allBases;
941 942 943 944
    foreach (Symbol *s, reference->symbols()) {
        if (Class *clazz = s->asClass()) {
            for (unsigned i = 0; i < clazz->baseClassCount(); ++i) {
                BaseClass *baseClass = clazz->baseClassAt(i);
945 946
                if (baseClass->name())
                    allBases.append(baseClass->name());
947 948 949 950 951 952 953 954 955
            }
            referenceClass = clazz;
            break;
        }
    }

    if (!referenceClass)
        return reference;

956
    if ((! templId && _alreadyConsideredClasses.contains(referenceClass)) ||
957 958 959 960 961 962 963 964
            (templId &&
            _alreadyConsideredTemplates.contains(templId))) {
            return reference;
    }

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

965 966
    QSet<ClassOrNamespace *> knownUsings = reference->usings().toSet();

967 968
    // If we are dealling with a template type, more work is required, since we need to
    // construct all instantiation data.
969 970
    if (templId) {
        _alreadyConsideredTemplates.insert(templId);
971
        ClassOrNamespace *instantiation = _factory->allocClassOrNamespace(baseTemplateClassReference);
972 973 974
#ifdef DEBUG_LOOKUP
        instantiation->_name = templId;
#endif // DEBUG_LOOKUP
975 976 977 978
        instantiation->_templateId = templId;
        instantiation->_instantiationOrigin = origin;

        // The instantiation should have all symbols, enums, and usings from the reference.
979
        instantiation->_enums.append(reference->unscopedEnums());
980 981 982 983
        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.
984 985 986 987
        if (Template *templateSpecialization = referenceClass->enclosingTemplate()) {
            const unsigned argumentCountOfInitialization = templId->templateArgumentCount();
            const unsigned argumentCountOfSpecialization
                    = templateSpecialization->templateParameterCount();
988 989

            if (_factory->expandTemplates()) {
990
                Clone cloner(_control.data());
991
                Subst subst(_control.data());
992 993 994
                for (unsigned i = 0; i < argumentCountOfSpecialization; ++i) {
                    const TypenameArgument *tParam
                            = templateSpecialization->templateParameterAt(i)->asTypenameArgument();
995 996 997 998 999
                    if (!tParam)
                        continue;
                    const Name *name = tParam->name();
                    if (!name)
                        continue;
1000 1001 1002 1003 1004

                    FullySpecifiedType ty = (i < argumentCountOfInitialization) ?
                                templId->templateArgumentAt(i):
                                cloner.type(tParam->type(), &subst);

1005
                    subst.bind(cloner.name(name, &subst), ty);
1006 1007 1008
                }

                foreach (Symbol *s, reference->symbols()) {
1009
                    Symbol *clone = cloner.symbol(s, &subst);
1010
                    clone->setScope(s->scope());
1011 1012
                    instantiation->_symbols.append(clone);
#ifdef DEBUG_LOOKUP
1013 1014 1015
                    Overview oo;oo.showFunctionSignatures = true;
                    oo.showReturnTypes = true;
                    oo.showTemplateParameters = true;
1016
                    qDebug()<<"cloned"<<oo(clone->type());
1017
                    if (Class *klass = s->asClass()) {
1018 1019 1020 1021 1022 1023 1024 1025 1026 1027
                        const unsigned klassMemberCount = klass->memberCount();
                        for (unsigned i = 0; i < klassMemberCount; ++i){
                            Symbol *klassMemberAsSymbol = klass->memberAt(i);
                            if (klassMemberAsSymbol->isTypedef()) {
                                if (Declaration *declaration = klassMemberAsSymbol->asDeclaration()) {
                                    qDebug() << "Member: " << oo(declaration->type(), declaration->name());
                                }
                            }
                        }
                    }
1028
#endif // DEBUG_LOOKUP
1029
                }
1030
                instantiateNestedClasses(reference, cloner, subst, instantiation);
1031 1032 1033 1034
            } else {
                instantiation->_symbols.append(reference->symbols());
            }

1035
            QHash<const Name*, unsigned> templParams;
1036 1037
            for (unsigned i = 0; i < argumentCountOfSpecialization; ++i)
                templParams.insert(templateSpecialization->templateParameterAt(i)->name(), i);
1038

1039