aboutsummaryrefslogtreecommitdiffstats
path: root/src/libs
diff options
context:
space:
mode:
authorRoberto Raggi <[email protected]>2010-05-05 10:28:32 +0200
committerRoberto Raggi <[email protected]>2010-05-05 16:36:45 +0200
commit9eea78d7f1df329c25df6fd4cbc113b93d905e36 (patch)
tree80aca290a496390eb15c77cf6b7570bedb2fb775 /src/libs
parentc35bb4226bd809a3da3487a9db3f61ba34cce70d (diff)
Initial work on the new LookupContext.
Diffstat (limited to 'src/libs')
-rw-r--r--src/libs/cplusplus/LookupContext.cpp815
-rw-r--r--src/libs/cplusplus/LookupContext.h210
-rw-r--r--src/libs/cplusplus/cplusplus-lib.pri2
3 files changed, 1027 insertions, 0 deletions
diff --git a/src/libs/cplusplus/LookupContext.cpp b/src/libs/cplusplus/LookupContext.cpp
new file mode 100644
index 00000000000..ccb36e9cbb9
--- /dev/null
+++ b/src/libs/cplusplus/LookupContext.cpp
@@ -0,0 +1,815 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation ([email protected])
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "LookupContext.h"
+#include "ResolveExpression.h"
+#include "Overview.h"
+#include "CppBindings.h"
+
+#include <CoreTypes.h>
+#include <Symbols.h>
+#include <Literals.h>
+#include <Names.h>
+#include <Scope.h>
+#include <Control.h>
+
+#include <QtDebug>
+
+#define CPLUSPLUS_NO_LAZY_LOOKUP
+
+using namespace CPlusPlus;
+
+/////////////////////////////////////////////////////////////////////
+// LookupContext
+/////////////////////////////////////////////////////////////////////
+LookupContext::LookupContext()
+ : _control(0)
+{ }
+
+LookupContext::LookupContext(Document::Ptr thisDocument,
+ const Snapshot &snapshot)
+ : _expressionDocument(Document::create("<LookupContext>")),
+ _thisDocument(thisDocument),
+ _snapshot(snapshot)
+{
+ _control = _expressionDocument->control();
+}
+
+LookupContext::LookupContext(Document::Ptr expressionDocument,
+ Document::Ptr thisDocument,
+ const Snapshot &snapshot)
+ : _expressionDocument(expressionDocument),
+ _thisDocument(thisDocument),
+ _snapshot(snapshot)
+{
+ _control = _expressionDocument->control();
+}
+
+LookupContext::LookupContext(const LookupContext &other)
+ : _control(other._control),
+ _expressionDocument(other._expressionDocument),
+ _thisDocument(other._thisDocument),
+ _snapshot(other._snapshot),
+ _bindings(other._bindings)
+{ }
+
+LookupContext &LookupContext::operator = (const LookupContext &other)
+{
+ _control = other._control;
+ _expressionDocument = other._expressionDocument;
+ _thisDocument = other._thisDocument;
+ _snapshot = other._snapshot;
+ _bindings = other._bindings;
+ return *this;
+}
+
+QSharedPointer<CreateBindings> LookupContext::bindings() const
+{
+ if (! _bindings)
+ _bindings = QSharedPointer<CreateBindings>(new CreateBindings(_thisDocument, _snapshot));
+
+ return _bindings;
+}
+
+void LookupContext::setBindings(QSharedPointer<CreateBindings> bindings)
+{
+ _bindings = bindings;
+}
+
+bool LookupContext::isValid() const
+{ return _control != 0; }
+
+Control *LookupContext::control() const
+{ return _control; }
+
+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();
+}
+
+ClassOrNamespace *LookupContext::classOrNamespace(const Name *name, Scope *scope) const
+{
+ if (ClassOrNamespace *b = bindings()->findClassOrNamespace(scope->owner()))
+ return b->lookupClassOrNamespace(name);
+
+ return 0;
+}
+
+ClassOrNamespace *LookupContext::classOrNamespace(Symbol *symbol) const
+{
+ return bindings()->findClassOrNamespace(symbol);
+}
+
+QList<Symbol *> LookupContext::lookup(const Name *name, Scope *scope) const
+{
+ QList<Symbol *> candidates;
+
+ if (! name)
+ return candidates;
+
+ const Identifier *id = name->identifier();
+
+ for (; scope; scope = scope->enclosingScope()) {
+ if (id && scope->isBlockScope()) {
+ ClassOrNamespace::lookup_helper(name, scope, &candidates);
+
+ if (! candidates.isEmpty())
+ break; // it's a local.
+
+ for (unsigned index = 0; index < scope->symbolCount(); ++index) {
+ Symbol *member = scope->symbolAt(index);
+
+ if (UsingNamespaceDirective *u = member->asUsingNamespaceDirective()) {
+ Namespace *enclosingNamespace = u->enclosingNamespaceScope()->owner()->asNamespace();
+ //qDebug() << "*** enclosing namespace:" << enclosingNamespace;
+ Q_ASSERT(enclosingNamespace != 0);
+
+ ClassOrNamespace *b = bindings()->findClassOrNamespace(enclosingNamespace);
+ //qDebug() << "**** binding:" << b;
+ Q_ASSERT(b != 0);
+
+ if (ClassOrNamespace *uu = b->lookupClassOrNamespace(u->name())) {
+ candidates = uu->lookup(name);
+
+ if (! candidates.isEmpty())
+ return candidates;
+ }
+ }
+ }
+
+ } else if (scope->isFunctionScope()) {
+ Function *fun = scope->owner()->asFunction();
+ ClassOrNamespace::lookup_helper(name, fun->arguments(), &candidates);
+ if (! candidates.isEmpty())
+ break; // it's a formal argument.
+
+ if (fun->name() && fun->name()->isQualifiedNameId()) {
+ const QualifiedNameId *q = fun->name()->asQualifiedNameId();
+ QList<QByteArray> path;
+
+ for (unsigned index = 0; index < q->nameCount() - 1; ++index) {
+ if (const Identifier *id = q->nameAt(index)->identifier())
+ path.append(QByteArray::fromRawData(id->chars(), id->size()));
+ }
+
+ if (ClassOrNamespace *binding = bindings()->findClassOrNamespace(path))
+ return binding->lookup(name);
+ }
+
+ } else if (scope->isObjCMethodScope()) {
+ ObjCMethod *method = scope->owner()->asObjCMethod();
+ ClassOrNamespace::lookup_helper(name, method->arguments(), &candidates);
+ if (! candidates.isEmpty())
+ break; // it's a formal argument.
+
+ } else if (scope->isClassScope() || scope->isNamespaceScope()
+ || scope->isObjCClassScope() || scope->isObjCProtocolScope()) {
+ if (ClassOrNamespace *binding = bindings()->findClassOrNamespace(scope->owner()))
+ return binding->lookup(name);
+
+ break;
+ }
+ }
+
+ return candidates;
+}
+
+ClassOrNamespace::ClassOrNamespace(CreateBindings *factory, ClassOrNamespace *parent)
+ : _factory(factory), _parent(parent), _flushing(false)
+{
+}
+
+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;
+}
+
+QList<Symbol *> ClassOrNamespace::lookup(const Name *name)
+{
+ QList<Symbol *> result;
+ if (! name)
+ return result;
+
+ if (const QualifiedNameId *q = name->asQualifiedNameId()) {
+ ClassOrNamespace *binding = this;
+
+ if (q->isGlobal())
+ binding = globalNamespace();
+
+ binding = binding->lookupClassOrNamespace(q->nameAt(0));
+
+ for (unsigned index = 1; binding && index < q->nameCount() - 1; ++index)
+ binding = binding->findClassOrNamespace(q->nameAt(index));
+
+ if (binding)
+ result = binding->lookup(q->unqualifiedNameId());
+
+ return result;
+ }
+
+ QSet<ClassOrNamespace *> processed;
+ ClassOrNamespace *binding = this;
+ do {
+ lookup_helper(name, binding, &result, &processed);
+ binding = binding->_parent;
+ } while (binding);
+
+ return result;
+}
+
+void ClassOrNamespace::lookup_helper(const Name *name, ClassOrNamespace *binding,
+ QList<Symbol *> *result,
+ QSet<ClassOrNamespace *> *processed)
+{
+ if (! binding)
+ return;
+
+ else if (! processed->contains(binding)) {
+ processed->insert(binding);
+
+ foreach (Symbol *s, binding->symbols()) {
+ if (ScopedSymbol *scoped = s->asScopedSymbol())
+ lookup_helper(name, scoped->members(), result);
+ }
+
+ foreach (Enum *e, binding->enums())
+ lookup_helper(name, e->members(), result);
+
+ foreach (ClassOrNamespace *u, binding->usings())
+ lookup_helper(name, u, result, processed);
+ }
+}
+
+void ClassOrNamespace::lookup_helper(const Name *name, Scope *scope, QList<Symbol *> *result)
+{
+ if (! name) {
+ return;
+
+ } else if (const OperatorNameId *op = name->asOperatorNameId()) {
+ for (Symbol *s = scope->lookat(op->kind()); s; s = s->next()) {
+ if (! s->name())
+ continue;
+ else if (! s->name()->isEqualTo(op))
+ continue;
+ result->append(s);
+ }
+
+ } else if (const Identifier *id = name->identifier()) {
+ for (Symbol *s = scope->lookat(id); s; s = s->next()) {
+ if (! s->name())
+ continue;
+ else if (! id->isEqualTo(s->identifier()))
+ continue;
+ else if (s->name()->isQualifiedNameId()) {
+#if 0
+ Overview oo;
+ oo.setShowReturnTypes(true);
+ oo.setShowFunctionSignatures(true);
+ qDebug() << "SKIP:" << oo(s->type(), s->name()) << s->fileName() << s->line() << s->column();
+#endif
+ continue;
+ }
+ result->append(s);
+ }
+
+ }
+}
+
+ClassOrNamespace *ClassOrNamespace::lookupClassOrNamespace(const Name *name)
+{
+ if (! name)
+ return 0;
+
+ QSet<ClassOrNamespace *> processed;
+ return lookupClassOrNamespace_helper(name, &processed);
+}
+
+ClassOrNamespace *ClassOrNamespace::findClassOrNamespace(const Name *name)
+{
+ QSet<ClassOrNamespace *> processed;
+ return findClassOrNamespace_helper(name, &processed);
+}
+
+ClassOrNamespace *ClassOrNamespace::findClassOrNamespace(const QList<QByteArray> &path)
+{
+ if (path.isEmpty())
+ return globalNamespace();
+
+ ClassOrNamespace *e = this;
+
+ for (int i = 0; e && i < path.size(); ++i) {
+ QSet<ClassOrNamespace *> processed;
+ e = e->findClassOrNamespace_helper(path.at(i), &processed);
+ }
+
+ return e;
+}
+
+ClassOrNamespace *ClassOrNamespace::lookupClassOrNamespace_helper(const Name *name,
+ QSet<ClassOrNamespace *> *processed)
+{
+ Q_ASSERT(name != 0);
+
+ if (! processed->contains(this)) {
+ processed->insert(this);
+
+ if (const QualifiedNameId *q = name->asQualifiedNameId()) {
+ ClassOrNamespace *e = this;
+
+ if (q->isGlobal())
+ e = globalNamespace();
+
+ e = e->lookupClassOrNamespace(q->nameAt(0));
+
+ for (unsigned index = 1; e && index < q->nameCount(); ++index) {
+ QSet<ClassOrNamespace *> processed;
+ e = e->findClassOrNamespace_helper(q->nameAt(index), &processed);
+ }
+
+ return e;
+
+ } else if (const Identifier *id = name->identifier()) {
+ const QByteArray classOrNamespaceName = QByteArray::fromRawData(id->chars(), id->size());
+
+ if (ClassOrNamespace *e = nestedClassOrNamespace(classOrNamespaceName))
+ return e;
+
+ foreach (ClassOrNamespace *u, usings()) {
+ if (ClassOrNamespace *r = u->lookupClassOrNamespace_helper(name, processed))
+ return r;
+ }
+ }
+
+ if (_parent)
+ return _parent->lookupClassOrNamespace_helper(name, processed);
+ }
+
+ return 0;
+}
+
+ClassOrNamespace *ClassOrNamespace::findClassOrNamespace_helper(const Name *name,
+ QSet<ClassOrNamespace *> *processed)
+{
+ if (! name) {
+ return 0;
+
+ } else if (const QualifiedNameId *q = name->asQualifiedNameId()) {
+ ClassOrNamespace *e = this;
+
+ if (q->isGlobal())
+ e = globalNamespace();
+
+ for (unsigned i = 0; e && i < q->nameCount(); ++i) {
+ QSet<ClassOrNamespace *> processed;
+ e = e->findClassOrNamespace_helper(q->nameAt(i), &processed);
+ }
+
+ return e;
+
+ } else if (const Identifier *id = name->identifier()) {
+ const QByteArray classOrNamespaceName = QByteArray::fromRawData(id->chars(), id->size());
+ return findClassOrNamespace_helper(classOrNamespaceName, processed);
+
+ }
+
+ return 0;
+}
+
+ClassOrNamespace *ClassOrNamespace::findClassOrNamespace_helper(const QByteArray &name,
+ QSet<ClassOrNamespace *> *processed)
+{
+ if (ClassOrNamespace *e = nestedClassOrNamespace(name))
+ return e;
+
+ else if (! processed->contains(this)) {
+ processed->insert(this);
+
+ foreach (ClassOrNamespace *u, usings()) {
+ if (ClassOrNamespace *e = u->findClassOrNamespace_helper(name, processed))
+ return e;
+ }
+ }
+
+ return 0;
+}
+
+ClassOrNamespace *ClassOrNamespace::nestedClassOrNamespace(const QByteArray &name) const
+{
+ const_cast<ClassOrNamespace *>(this)->flush();
+ return _classOrNamespaces.value(name);
+}
+
+void ClassOrNamespace::flush()
+{
+#ifndef CPLUSPLUS_NO_LAZY_LOOKUP
+ if (! _flushing) {
+ _flushing = true;
+
+ while (! _todo.isEmpty()) {
+ Symbol *member = _todo.takeFirst();
+ _factory->process(member, this);
+ }
+ }
+#endif
+}
+
+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);
+}
+
+void ClassOrNamespace::addNestedClassOrNamespace(const QByteArray &alias, ClassOrNamespace *e)
+{
+ _classOrNamespaces.insert(alias, e);
+}
+
+ClassOrNamespace *ClassOrNamespace::findOrCreate(const Name *name)
+{
+ if (! name)
+ return this;
+
+ if (const QualifiedNameId *q = name->asQualifiedNameId()) {
+ ClassOrNamespace *e = this;
+
+ for (unsigned i = 0; e && i < q->nameCount(); ++i)
+ e = e->findOrCreate(q->nameAt(i));
+
+ return e;
+
+ } else if (const Identifier *id = name->identifier()) {
+ const QByteArray name = QByteArray::fromRawData(id->chars(), id->size());
+ ClassOrNamespace *e = nestedClassOrNamespace(name);
+
+ if (! e) {
+ e = _factory->allocClassOrNamespace(this);
+ _classOrNamespaces.insert(name, e);
+ }
+
+ return e;
+ }
+
+ return 0;
+}
+
+CreateBindings::CreateBindings(Document::Ptr thisDocument, const Snapshot &snapshot)
+ : _snapshot(snapshot)
+{
+ _globalNamespace = allocClassOrNamespace(/*parent = */ 0);
+ _currentClassOrNamespace = _globalNamespace;
+
+ process(thisDocument);
+}
+
+CreateBindings::~CreateBindings()
+{
+ qDeleteAll(_entities);
+}
+
+ClassOrNamespace *CreateBindings::switchCurrentEntity(ClassOrNamespace *classOrNamespace)
+{
+ ClassOrNamespace *previous = _currentClassOrNamespace;
+ _currentClassOrNamespace = classOrNamespace;
+ return previous;
+}
+
+ClassOrNamespace *CreateBindings::globalNamespace() const
+{
+ return _globalNamespace;
+}
+
+ClassOrNamespace *CreateBindings::findClassOrNamespace(Symbol *s)
+{
+ // jump to the enclosing class or namespace.
+ for (; s; s = s->enclosingSymbol()) {
+ if (s->isClass() || s->isNamespace())
+ break;
+ }
+
+ QList<QByteArray> path;
+ for (; s; s = s->enclosingSymbol()) {
+ if (const Identifier *id = s->identifier())
+ path.prepend(QByteArray::fromRawData(id->chars(), id->size()));
+ }
+
+ ClassOrNamespace *e = _globalNamespace->findClassOrNamespace(path);
+ return e;
+}
+
+ClassOrNamespace *CreateBindings::findClassOrNamespace(const QList<QByteArray> &path)
+{
+ ClassOrNamespace *e = _globalNamespace->findClassOrNamespace(path);
+ return e;
+}
+
+void CreateBindings::process(Symbol *s, ClassOrNamespace *classOrNamespace)
+{
+ ClassOrNamespace *previous = switchCurrentEntity(classOrNamespace);
+ accept(s);
+ (void) switchCurrentEntity(previous);
+}
+
+void CreateBindings::process(Symbol *symbol)
+{
+#ifndef CPLUSPLUS_NO_LAZY_LOOKUP
+ _currentClassOrNamespace->addTodo(symbol);
+#else
+ accept(symbol);
+#endif
+}
+
+ClassOrNamespace *CreateBindings::allocClassOrNamespace(ClassOrNamespace *parent)
+{
+ ClassOrNamespace *e = new ClassOrNamespace(this, parent);
+ _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);
+ }
+ }
+}
+
+ClassOrNamespace *CreateBindings::enterEntity(Symbol *symbol)
+{
+ ClassOrNamespace *entity = _currentClassOrNamespace->findOrCreate(symbol->name());
+ entity->addSymbol(symbol);
+
+ return switchCurrentEntity(entity);
+}
+
+ClassOrNamespace *CreateBindings::enterGlobalEntity(Symbol *symbol)
+{
+ ClassOrNamespace *entity = _globalNamespace->findOrCreate(symbol->name());
+ entity->addSymbol(symbol);
+
+ return switchCurrentEntity(entity);
+}
+
+bool CreateBindings::visit(Namespace *ns)
+{
+ ClassOrNamespace *previous = enterEntity(ns);
+
+ for (unsigned i = 0; i < ns->memberCount(); ++i)
+ process(ns->memberAt(i));
+
+ _currentClassOrNamespace = previous;
+ return false;
+}
+
+bool CreateBindings::visit(Class *klass)
+{
+ ClassOrNamespace *previous = enterEntity(klass);
+
+ for (unsigned i = 0; i < klass->baseClassCount(); ++i)
+ process(klass->baseClassAt(i));
+
+ for (unsigned i = 0; i < klass->memberCount(); ++i)
+ process(klass->memberAt(i));
+
+ _currentClassOrNamespace = previous;
+ return false;
+}
+
+bool CreateBindings::visit(ForwardClassDeclaration *klass)
+{
+ ClassOrNamespace *previous = enterEntity(klass);
+ _currentClassOrNamespace = previous;
+ return false;
+}
+
+bool CreateBindings::visit(Enum *e)
+{
+ _currentClassOrNamespace->addEnum(e);
+ return false;
+}
+
+bool CreateBindings::visit(Declaration *decl)
+{
+ if (decl->isTypedef()) {
+ const FullySpecifiedType ty = decl->type();
+ const Identifier *typedefId = decl->identifier();
+
+ if (typedefId && ! (ty.isConst() || ty.isVolatile())) {
+ if (const NamedType *namedTy = ty->asNamedType()) {
+ if (ClassOrNamespace *e = _currentClassOrNamespace->lookupClassOrNamespace(namedTy->name())) {
+ const QByteArray alias = QByteArray::fromRawData(typedefId->chars(), typedefId->size());
+ _currentClassOrNamespace->addNestedClassOrNamespace(alias, e);
+ } else if (false) {
+ Overview oo;
+ qDebug() << "found entity not found for" << oo(namedTy->name());
+ }
+ }
+ }
+ }
+
+ return false;
+}
+
+bool CreateBindings::visit(Function *)
+{
+ return false;
+}
+
+bool CreateBindings::visit(BaseClass *b)
+{
+ if (ClassOrNamespace *base = _currentClassOrNamespace->lookupClassOrNamespace(b->name())) {
+ _currentClassOrNamespace->addUsing(base);
+ } else if (false) {
+ Overview oo;
+ qDebug() << "no entity for:" << oo(b->name());
+ }
+ return false;
+}
+
+bool CreateBindings::visit(UsingNamespaceDirective *u)
+{
+ if (ClassOrNamespace *e = _currentClassOrNamespace->lookupClassOrNamespace(u->name())) {
+ _currentClassOrNamespace->addUsing(e);
+ } else if (false) {
+ Overview oo;
+ qDebug() << "no entity for namespace:" << oo(u->name());
+ }
+ return false;
+}
+
+bool CreateBindings::visit(NamespaceAlias *a)
+{
+ if (! a->identifier()) {
+ return false;
+
+ } else if (ClassOrNamespace *e = _currentClassOrNamespace->lookupClassOrNamespace(a->namespaceName())) {
+ const QByteArray name = QByteArray::fromRawData(a->identifier()->chars(), a->identifier()->size());
+ _currentClassOrNamespace->addNestedClassOrNamespace(name, e);
+
+ } else if (false) {
+ Overview oo;
+ qDebug() << "no entity for namespace:" << oo(a->namespaceName());
+ }
+
+ return false;
+}
+
+bool CreateBindings::visit(ObjCClass *klass)
+{
+ ClassOrNamespace *previous = enterGlobalEntity(klass);
+
+ process(klass->baseClass());
+
+ for (unsigned i = 0; i < klass->protocolCount(); ++i)
+ process(klass->protocolAt(i));
+
+ for (unsigned i = 0; i < klass->memberCount(); ++i)
+ process(klass->memberAt(i));
+
+ _currentClassOrNamespace = previous;
+ return false;
+}
+
+bool CreateBindings::visit(ObjCBaseClass *b)
+{
+ if (ClassOrNamespace *base = _globalNamespace->lookupClassOrNamespace(b->name())) {
+ _currentClassOrNamespace->addUsing(base);
+ } else if (false) {
+ Overview oo;
+ qDebug() << "no entity for:" << oo(b->name());
+ }
+ return false;
+}
+
+bool CreateBindings::visit(ObjCForwardClassDeclaration *klass)
+{
+ ClassOrNamespace *previous = enterGlobalEntity(klass);
+ _currentClassOrNamespace = previous;
+ return false;
+}
+
+bool CreateBindings::visit(ObjCProtocol *proto)
+{
+ ClassOrNamespace *previous = enterGlobalEntity(proto);
+
+ for (unsigned i = 0; i < proto->protocolCount(); ++i)
+ process(proto->protocolAt(i));
+
+ for (unsigned i = 0; i < proto->memberCount(); ++i)
+ process(proto->memberAt(i));
+
+ _currentClassOrNamespace = previous;
+ return false;
+}
+
+bool CreateBindings::visit(ObjCBaseProtocol *b)
+{
+ if (ClassOrNamespace *base = _globalNamespace->lookupClassOrNamespace(b->name())) {
+ _currentClassOrNamespace->addUsing(base);
+ } else if (false) {
+ Overview oo;
+ qDebug() << "no entity for:" << oo(b->name());
+ }
+ return false;
+}
+
+bool CreateBindings::visit(ObjCForwardProtocolDeclaration *proto)
+{
+ ClassOrNamespace *previous = enterGlobalEntity(proto);
+ _currentClassOrNamespace = previous;
+ return false;
+}
+
+bool CreateBindings::visit(ObjCMethod *)
+{
+ return false;
+}
diff --git a/src/libs/cplusplus/LookupContext.h b/src/libs/cplusplus/LookupContext.h
new file mode 100644
index 00000000000..a39e7bb7371
--- /dev/null
+++ b/src/libs/cplusplus/LookupContext.h
@@ -0,0 +1,210 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation ([email protected])
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef CPLUSPLUS_LOOKUPCONTEXT_H
+#define CPLUSPLUS_LOOKUPCONTEXT_H
+
+#include "CppDocument.h"
+#include "LookupItem.h"
+#include <FullySpecifiedType.h>
+#include <Type.h>
+#include <SymbolVisitor.h>
+#include <QtCore/QSet>
+
+namespace CPlusPlus {
+
+class CreateBindings;
+
+class CPLUSPLUS_EXPORT ClassOrNamespace
+{
+public:
+ ClassOrNamespace(CreateBindings *factory, ClassOrNamespace *parent);
+
+ QList<ClassOrNamespace *> usings() const;
+ QList<Enum *> enums() const;
+ QList<Symbol *> symbols() const;
+
+ ClassOrNamespace *globalNamespace() const;
+
+ QList<Symbol *> lookup(const Name *name);
+
+ ClassOrNamespace *lookupClassOrNamespace(const Name *name);
+ ClassOrNamespace *findClassOrNamespace(const Name *name);
+ ClassOrNamespace *findClassOrNamespace(const QList<QByteArray> &path);
+
+ /// \internal
+ static void lookup_helper(const Name *name, Scope *scope, QList<Symbol *> *result);
+
+private:
+ /// \internal
+ void flush();
+
+ /// \internal
+ ClassOrNamespace *findOrCreate(const Name *name);
+
+ void addTodo(Symbol *symbol);
+ void addSymbol(Symbol *symbol);
+ void addEnum(Enum *e);
+ void addUsing(ClassOrNamespace *u);
+ void addNestedClassOrNamespace(const QByteArray &alias, ClassOrNamespace *e);
+
+ void lookup_helper(const Name *name, ClassOrNamespace *binding,
+ QList<Symbol *> *result,
+ QSet<ClassOrNamespace *> *processed);
+
+ ClassOrNamespace *lookupClassOrNamespace_helper(const Name *name, QSet<ClassOrNamespace *> *processed);
+ ClassOrNamespace *findClassOrNamespace_helper(const Name *name, QSet<ClassOrNamespace *> *processed);
+ ClassOrNamespace *findClassOrNamespace_helper(const QByteArray &name, QSet<ClassOrNamespace *> *processed);
+
+ ClassOrNamespace *nestedClassOrNamespace(const QByteArray &name) const;
+
+private:
+ CreateBindings *_factory;
+ ClassOrNamespace *_parent;
+ QList<Symbol *> _symbols;
+ QList<ClassOrNamespace *> _usings;
+ QHash<QByteArray, ClassOrNamespace *> _classOrNamespaces;
+ QList<Enum *> _enums;
+ QList<Symbol *> _todo;
+ bool _flushing;
+
+ friend class CreateBindings;
+};
+
+class CPLUSPLUS_EXPORT CreateBindings: protected SymbolVisitor
+{
+ Q_DISABLE_COPY(CreateBindings)
+
+public:
+ CreateBindings(Document::Ptr thisDocument, const Snapshot &snapshot);
+ virtual ~CreateBindings();
+
+ ClassOrNamespace *globalNamespace() const;
+
+ ClassOrNamespace *findClassOrNamespace(Symbol *s); // ### rename
+ ClassOrNamespace *findClassOrNamespace(const QList<QByteArray> &path);
+
+ /// \internal
+ void process(Symbol *s, ClassOrNamespace *classOrNamespace);
+
+ /// \internal
+ ClassOrNamespace *allocClassOrNamespace(ClassOrNamespace *parent);
+
+protected:
+ using SymbolVisitor::visit;
+
+ ClassOrNamespace *switchCurrentEntity(ClassOrNamespace *classOrNamespace);
+ ClassOrNamespace *enterEntity(Symbol *symbol);
+ ClassOrNamespace *enterGlobalEntity(Symbol *symbol);
+
+ void process(Document::Ptr doc);
+ void process(Symbol *symbol);
+
+ virtual bool visit(Namespace *ns);
+ virtual bool visit(Class *klass);
+ virtual bool visit(ForwardClassDeclaration *klass);
+ virtual bool visit(Enum *e);
+ virtual bool visit(Declaration *decl);
+ virtual bool visit(Function *);
+ virtual bool visit(BaseClass *b);
+ virtual bool visit(UsingNamespaceDirective *u);
+ virtual bool visit(NamespaceAlias *a);
+
+ virtual bool visit(ObjCClass *klass);
+ virtual bool visit(ObjCBaseClass *b);
+ virtual bool visit(ObjCForwardClassDeclaration *klass);
+ virtual bool visit(ObjCProtocol *proto);
+ virtual bool visit(ObjCBaseProtocol *b);
+ virtual bool visit(ObjCForwardProtocolDeclaration *proto);
+ virtual bool visit(ObjCMethod *);
+
+private:
+ Snapshot _snapshot;
+ QSet<Namespace *> _processed;
+ QList<ClassOrNamespace *> _entities;
+ ClassOrNamespace *_globalNamespace;
+ ClassOrNamespace *_currentClassOrNamespace;
+};
+
+class CPLUSPLUS_EXPORT LookupContext
+{
+public:
+ LookupContext();
+
+ LookupContext(Document::Ptr thisDocument,
+ const Snapshot &snapshot);
+
+ LookupContext(Document::Ptr expressionDocument,
+ Document::Ptr thisDocument,
+ const Snapshot &snapshot);
+
+ LookupContext(const LookupContext &other);
+ LookupContext &operator = (const LookupContext &other);
+
+ bool isValid() const;
+
+ Document::Ptr expressionDocument() const;
+ Document::Ptr thisDocument() const;
+ Document::Ptr document(const QString &fileName) const;
+ Snapshot snapshot() const;
+
+ QList<Symbol *> lookup(const Name *name, Scope *scope) const;
+
+ ClassOrNamespace *globalNamespace() const;
+
+ ClassOrNamespace *classOrNamespace(const Name *name, Scope *scope) const;
+ ClassOrNamespace *classOrNamespace(Symbol *symbol) const;
+
+ /// \internal
+ QSharedPointer<CreateBindings> bindings() const;
+
+ /// \internal
+ void setBindings(QSharedPointer<CreateBindings> bindings);
+
+ Q_DECL_DEPRECATED Control *control() const;
+
+private:
+ Control *_control;
+
+ // The current expression.
+ Document::Ptr _expressionDocument;
+
+ // The current document.
+ Document::Ptr _thisDocument;
+
+ // All documents.
+ Snapshot _snapshot;
+
+ // Bindings
+ mutable QSharedPointer<CreateBindings> _bindings;
+};
+
+} // end of namespace CPlusPlus
+
+#endif // CPLUSPLUS_LOOKUPCONTEXT_H
diff --git a/src/libs/cplusplus/cplusplus-lib.pri b/src/libs/cplusplus/cplusplus-lib.pri
index 3904b690ad3..cdd03b7b4f0 100644
--- a/src/libs/cplusplus/cplusplus-lib.pri
+++ b/src/libs/cplusplus/cplusplus-lib.pri
@@ -35,6 +35,7 @@ HEADERS += \
$$PWD/TypePrettyPrinter.h \
$$PWD/ResolveExpression.h \
$$PWD/LookupItem.h \
+ $$PWD/LookupContext.h \
$$PWD/DeprecatedLookupContext.h \
$$PWD/CppBindings.h \
$$PWD/ASTParent.h \
@@ -61,6 +62,7 @@ SOURCES += \
$$PWD/TypePrettyPrinter.cpp \
$$PWD/ResolveExpression.cpp \
$$PWD/LookupItem.cpp \
+ $$PWD/LookupContext.cpp \
$$PWD/DeprecatedLookupContext.cpp \
$$PWD/CppBindings.cpp \
$$PWD/ASTParent.cpp \