diff --git a/src/libs/qmljs/qmljscheck.cpp b/src/libs/qmljs/qmljscheck.cpp
index 7a794cb03baa7e56a61e577e3793fb1b0c86846c..33392da27c454d075ccfb986f6e4aeacf1b530f0 100644
--- a/src/libs/qmljs/qmljscheck.cpp
+++ b/src/libs/qmljs/qmljscheck.cpp
@@ -61,7 +61,6 @@ Check::Check(Document::Ptr doc, const Snapshot &snapshot)
     , _snapshot(snapshot)
     , _context(&_engine)
     , _link(&_context, doc, snapshot)
-    , _extraScope(0)
     , _allowAnyProperty(false)
 {
 }
@@ -118,10 +117,12 @@ void Check::visitQmlObject(Node *ast, UiQualifiedId *typeId,
         _allowAnyProperty = true; // suppress subsequent "unknown property" errors
     }
 
-    const ObjectValue *oldScopeObject = _context.qmlScopeObject();
-    const ObjectValue *oldExtraScope = _extraScope;
+    QList<const ObjectValue *> oldScopeObjects = _context.scopeChain().qmlScopeObjects;
+
+    _context.scopeChain().qmlScopeObjects.clear();
     const ObjectValue *scopeObject = _doc->bind()->findQmlObject(ast);
-    _context.setQmlScopeObject(scopeObject);
+    _context.scopeChain().qmlScopeObjects += scopeObject;
+    _context.scopeChain().update();
 
 #ifndef NO_DECLARATIVE_BACKEND
     // check if the object has a Qt.ListElement ancestor
@@ -159,7 +160,7 @@ void Check::visitQmlObject(Node *ast, UiQualifiedId *typeId,
                         const Value *targetValue = evaluator(expStmt->expression);
 
                         if (const ObjectValue *target = value_cast<const ObjectValue *>(targetValue)) {
-                            _extraScope = target;
+                            _context.scopeChain().qmlScopeObjects.prepend(target);
                         } else {
                             _allowAnyProperty = true;
                         }
@@ -172,8 +173,7 @@ void Check::visitQmlObject(Node *ast, UiQualifiedId *typeId,
 
     Node::accept(initializer, this);
 
-    _context.setQmlScopeObject(oldScopeObject);
-    _extraScope = oldExtraScope;
+    _context.scopeChain().qmlScopeObjects = oldScopeObjects;
     _allowAnyProperty = oldAllowAnyProperty;
 }
 
@@ -235,7 +235,7 @@ const Value *Check::checkScopeObjectMember(const UiQualifiedId *id)
     if (_allowAnyProperty)
         return 0;
 
-    const ObjectValue *scopeObject = _context.qmlScopeObject();
+    QList<const ObjectValue *> scopeObjects = _context.scopeChain().qmlScopeObjects;
 
     if (! id)
         return 0; // ### error?
@@ -249,16 +249,19 @@ const Value *Check::checkScopeObjectMember(const UiQualifiedId *id)
     bool isAttachedProperty = false;
     if (! propertyName.isEmpty() && propertyName[0].isUpper()) {
         isAttachedProperty = true;
-        scopeObject = _context.typeEnvironment(_doc.data());
+        scopeObjects += _context.scopeChain().qmlTypes;
     }
 
-    if (! scopeObject)
+    if (scopeObjects.isEmpty())
         return 0;
 
     // global lookup for first part of id
-    const Value *value = scopeObject->lookupMember(propertyName, &_context);
-    if (_extraScope && !value)
-        value = _extraScope->lookupMember(propertyName, &_context);
+    const Value *value = 0;
+    for (int i = scopeObjects.size() - 1; i >= 0; --i) {
+        value = scopeObjects[i]->lookupMember(propertyName, &_context);
+        if (value)
+            break;
+    }
     if (!value) {
         error(id->identifierToken,
               tr(Messages::invalid_property_name).arg(propertyName));
diff --git a/src/libs/qmljs/qmljscheck.h b/src/libs/qmljs/qmljscheck.h
index 56ec5c0c83cae93e2abb6d0a83456f08e6355768..8810865f46ea4260f5f5a1ca359111135621e223 100644
--- a/src/libs/qmljs/qmljscheck.h
+++ b/src/libs/qmljs/qmljscheck.h
@@ -75,7 +75,6 @@ private:
 
     QList<DiagnosticMessage> _messages;
 
-    const Interpreter::ObjectValue *_extraScope;
     bool _allowAnyProperty;
 };
 
diff --git a/src/libs/qmljs/qmljsinterpreter.cpp b/src/libs/qmljs/qmljsinterpreter.cpp
index 20b1f47dbe7545e28318a317c7e0fd5816eb22a7..f7dc0c5393ddbcadaed2aa8aa6f584919f711ab4 100644
--- a/src/libs/qmljs/qmljsinterpreter.cpp
+++ b/src/libs/qmljs/qmljsinterpreter.cpp
@@ -725,6 +725,45 @@ void StringValue::accept(ValueVisitor *visitor) const
 }
 
 
+ScopeChain::ScopeChain()
+    : globalScope(0)
+    , qmlTypes(0)
+{
+}
+
+void ScopeChain::QmlComponentChain::add(QList<const ObjectValue *> *list) const
+{
+    foreach (QmlComponentChain *parent, instantiatingComponents)
+        parent->add(list);
+
+    if (rootObject)
+        list->append(rootObject);
+    list->append(functionScopes);
+    if (ids)
+        list->append(ids);
+}
+
+void ScopeChain::update()
+{
+    all.clear();
+
+    all += globalScope;
+
+    foreach (QmlComponentChain *parent, qmlComponentScope.instantiatingComponents)
+        parent->add(&all);
+
+    if (qmlComponentScope.rootObject)
+        all += qmlComponentScope.rootObject;
+    all += qmlScopeObjects;
+    all += qmlComponentScope.functionScopes;
+    if (qmlComponentScope.ids)
+        all += qmlComponentScope.ids;
+    if (qmlTypes)
+        all += qmlTypes;
+    all += jsScopes;
+}
+
+
 Context::Context(Engine *engine)
     : _engine(engine),
       _lookupMode(JSLookup),
@@ -748,7 +787,12 @@ Engine *Context::engine() const
     return _engine;
 }
 
-Context::ScopeChain Context::scopeChain() const
+const ScopeChain &Context::scopeChain() const
+{
+    return _scopeChain;
+}
+
+ScopeChain &Context::scopeChain()
 {
     return _scopeChain;
 }
@@ -773,54 +817,11 @@ void Context::setTypeEnvironment(const QmlJS::Document *doc, const ObjectValue *
     _typeEnvironments[doc] = typeEnvironment;
 }
 
-void Context::pushScope(const ObjectValue *object)
-{
-    if (object != 0)
-        _scopeChain.append(object);
-}
-
-void Context::popScope()
-{
-    _scopeChain.removeLast();
-    if (_scopeChain.length() <= _qmlScopeObjectIndex)
-        _qmlScopeObjectSet = false;
-}
-
-// Marks this to be the location where a scope object can be inserted.
-void Context::markQmlScopeObject()
-{
-    _qmlScopeObjectIndex = _scopeChain.length();
-}
-
-// Sets or inserts the scope object if scopeObject != 0, removes it otherwise.
-void Context::setQmlScopeObject(const ObjectValue *scopeObject)
-{
-    if (_qmlScopeObjectSet) {
-        if (scopeObject == 0) {
-            _scopeChain.removeAt(_qmlScopeObjectIndex);
-            _qmlScopeObjectSet = false;
-        } else {
-            _scopeChain[_qmlScopeObjectIndex] = scopeObject;
-        }
-    } else if (scopeObject != 0 && _scopeChain.length() >= _qmlScopeObjectIndex) {
-        _scopeChain.insert(_qmlScopeObjectIndex, scopeObject);
-        _qmlScopeObjectSet = true;
-    }
-}
-
-// Gets the scope object, if set. Returns 0 otherwise.
-const ObjectValue *Context::qmlScopeObject() const
-{
-    if (!_qmlScopeObjectSet)
-        return 0;
-    else
-        return _scopeChain[_qmlScopeObjectIndex];
-}
-
 const Value *Context::lookup(const QString &name)
 {
-    for (int index = _scopeChain.size() - 1; index != -1; --index) {
-        const ObjectValue *scope = _scopeChain.at(index);
+    QList<const ObjectValue *> scopes = _scopeChain.all;
+    for (int index = scopes.size() - 1; index != -1; --index) {
+        const ObjectValue *scope = scopes.at(index);
 
         if (const Value *member = scope->lookupMember(name, this)) {
             if (_lookupMode == JSLookup || ! dynamic_cast<const ASTVariableReference *>(member)) {
diff --git a/src/libs/qmljs/qmljsinterpreter.h b/src/libs/qmljs/qmljsinterpreter.h
index a1fac700ec85f2dcdc740948d51709b00687f88e..f91add8847e5c0bf5a50584b7b538cb6e926e65b 100644
--- a/src/libs/qmljs/qmljsinterpreter.h
+++ b/src/libs/qmljs/qmljsinterpreter.h
@@ -222,11 +222,39 @@ public:
     virtual bool processGeneratedSlot(const QString &name, const Value *value);
 };
 
-class QMLJS_EXPORT Context
+class QMLJS_EXPORT ScopeChain
 {
 public:
-    typedef QList<const ObjectValue *> ScopeChain;
+    ScopeChain();
+
+    struct QmlComponentChain
+    {
+        QmlComponentChain()
+            : rootObject(0), ids(0)
+        {}
 
+        QList<QmlComponentChain *> instantiatingComponents;
+        const ObjectValue *rootObject;
+        QList<const ObjectValue *> functionScopes;
+        const ObjectValue *ids;
+
+        void add(QList<const ObjectValue *> *list) const;
+    };
+
+    const ObjectValue *globalScope;
+    QmlComponentChain qmlComponentScope;
+    QList<const ObjectValue *> qmlScopeObjects;
+    const ObjectValue *qmlTypes;
+    QList<const ObjectValue *> jsScopes;
+
+    // rebuilds the flat list of all scopes
+    void update();
+    QList<const ObjectValue *> all;
+};
+
+class QMLJS_EXPORT Context
+{
+public:
     enum LookupMode {
         JSLookup,
         QmlLookup
@@ -239,7 +267,8 @@ public:
     void build(AST::Node *node, const Document::Ptr doc, const Snapshot &snapshot);
 
     Engine *engine() const;
-    ScopeChain scopeChain() const;
+    const ScopeChain &scopeChain() const;
+    ScopeChain &scopeChain();
 
     LookupMode lookupMode() const;
     void setLookupMode(LookupMode lookupMode);
@@ -247,13 +276,6 @@ public:
     const ObjectValue *typeEnvironment(const Document *doc) const;
     void setTypeEnvironment(const Document *doc, const ObjectValue *typeEnvironment);
 
-    void pushScope(const ObjectValue *object);
-    void popScope();
-
-    void markQmlScopeObject();
-    void setQmlScopeObject(const ObjectValue *scopeObject);
-    const ObjectValue *qmlScopeObject() const;
-
     const Value *lookup(const QString &name);
     const ObjectValue *lookupType(const Document *doc, AST::UiQualifiedId *qmlTypeName);
 
diff --git a/src/libs/qmljs/qmljslink.cpp b/src/libs/qmljs/qmljslink.cpp
index f67c428d37c9f739f7ca7688da59db01ec80cb01..6080ff1168c15aec681043c3d63705a79983ddc3 100644
--- a/src/libs/qmljs/qmljslink.cpp
+++ b/src/libs/qmljs/qmljslink.cpp
@@ -31,41 +31,50 @@ Interpreter::Engine *Link::engine()
 
 void Link::scopeChainAt(Document::Ptr doc, Node *currentObject)
 {
+    ScopeChain &scopeChain = _context->scopeChain();
+
     // ### TODO: This object ought to contain the global namespace additions by QML.
-    _context->pushScope(engine()->globalObject());
+    scopeChain.globalScope = engine()->globalObject();
 
     if (! doc)
         return;
 
     Bind *bind = doc->bind();
-    QStringList linkedDocs; // to prevent cycles
+    QHash<Document *, ScopeChain::QmlComponentChain *> componentScopes;
 
     if (doc->qmlProgram()) {
         _context->setLookupMode(Context::QmlLookup);
 
+        makeComponentChain(doc, &scopeChain.qmlComponentScope, &componentScopes);
+
         ObjectValue *scopeObject = 0;
         if (UiObjectDefinition *definition = cast<UiObjectDefinition *>(currentObject))
             scopeObject = bind->findQmlObject(definition);
         else if (UiObjectBinding *binding = cast<UiObjectBinding *>(currentObject))
             scopeObject = bind->findQmlObject(binding);
 
-        pushScopeChainForComponent(doc, &linkedDocs, scopeObject);
+        if (scopeObject && scopeObject != scopeChain.qmlComponentScope.rootObject)
+            scopeChain.qmlScopeObjects += scopeObject;
 
         if (const ObjectValue *typeEnvironment = _context->typeEnvironment(doc.data()))
-            _context->pushScope(typeEnvironment);
+            scopeChain.qmlTypes = typeEnvironment;
     } else {
         // the global scope of a js file does not see the instantiating component
         if (currentObject != 0) {
             // add scope chains for all components that source this document
             foreach (Document::Ptr otherDoc, _docs) {
-                if (otherDoc->bind()->includedScripts().contains(doc->fileName()))
-                    pushScopeChainForComponent(otherDoc, &linkedDocs);
+                if (otherDoc->bind()->includedScripts().contains(doc->fileName())) {
+                    ScopeChain::QmlComponentChain *component = new ScopeChain::QmlComponentChain;
+                    componentScopes.insert(otherDoc.data(), component);
+                    scopeChain.qmlComponentScope.instantiatingComponents += component;
+                    makeComponentChain(otherDoc, component, &componentScopes);
+                }
             }
 
             // ### TODO: Which type environment do scripts see?
         }
 
-        _context->pushScope(bind->rootObjectValue());
+        scopeChain.jsScopes += bind->rootObjectValue();
     }
 
     if (FunctionDeclaration *fun = cast<FunctionDeclaration *>(currentObject)) {
@@ -74,53 +83,55 @@ void Link::scopeChainAt(Document::Ptr doc, Node *currentObject)
             if (it->name)
                 activation->setProperty(it->name->asString(), engine()->undefinedValue());
         }
-        _context->pushScope(activation);
+        scopeChain.jsScopes += activation;
     }
+
+    scopeChain.update();
 }
 
-void Link::pushScopeChainForComponent(Document::Ptr doc, QStringList *linkedDocs,
-                                      ObjectValue *scopeObject)
+void Link::makeComponentChain(
+        Document::Ptr doc,
+        ScopeChain::QmlComponentChain *target,
+        QHash<Document *, ScopeChain::QmlComponentChain *> *components)
 {
     if (!doc->qmlProgram())
         return;
 
-    linkedDocs->append(doc->fileName());
-
     Bind *bind = doc->bind();
 
     // add scopes for all components instantiating this one
     foreach (Document::Ptr otherDoc, _docs) {
-        if (linkedDocs->contains(otherDoc->fileName()))
+        if (otherDoc == doc)
             continue;
-
         if (otherDoc->bind()->usesQmlPrototype(bind->rootObjectValue(), _context)) {
-            // ### TODO: Depth-first insertion doesn't give us correct name shadowing.
-            pushScopeChainForComponent(otherDoc, linkedDocs);
+            if (components->contains(otherDoc.data())) {
+                target->instantiatingComponents += components->value(otherDoc.data());
+            } else {
+                ScopeChain::QmlComponentChain *component = new ScopeChain::QmlComponentChain;
+                components->insert(otherDoc.data(), component);
+                target->instantiatingComponents += component;
+
+                makeComponentChain(otherDoc, component, components);
+            }
         }
     }
 
+    // build this component scope
     if (bind->rootObjectValue())
-        _context->pushScope(bind->rootObjectValue());
-
-    if (scopeObject) {
-        _context->markQmlScopeObject();
-        if (scopeObject != bind->rootObjectValue())
-            _context->setQmlScopeObject(scopeObject);
-    }
+        target->rootObject = bind->rootObjectValue();
 
     const QStringList &includedScripts = bind->includedScripts();
     for (int index = includedScripts.size() - 1; index != -1; --index) {
         const QString &scriptFile = includedScripts.at(index);
 
         if (Document::Ptr scriptDoc = _snapshot.document(scriptFile)) {
-            if (scriptDoc->jsProgram()) {
-                _context->pushScope(scriptDoc->bind()->rootObjectValue());
-            }
+            if (scriptDoc->jsProgram())
+                target->functionScopes += scriptDoc->bind()->rootObjectValue();
         }
     }
 
-    _context->pushScope(bind->functionEnvironment());
-    _context->pushScope(bind->idEnvironment());
+    target->functionScopes += bind->functionEnvironment();
+    target->ids = bind->idEnvironment();
 }
 
 void Link::linkImports()
diff --git a/src/libs/qmljs/qmljslink.h b/src/libs/qmljs/qmljslink.h
index 936851dac54c0274e84a76baa6eb66604edc7b3e..ba767523e20d734e67aaf201fdbc600e465bddcd 100644
--- a/src/libs/qmljs/qmljslink.h
+++ b/src/libs/qmljs/qmljslink.h
@@ -28,8 +28,10 @@ public:
 private:
     Interpreter::Engine *engine();
 
-    void pushScopeChainForComponent(Document::Ptr doc, QStringList *linkedDocs,
-                                    Interpreter::ObjectValue *scopeObject = 0);
+    void makeComponentChain(
+            Document::Ptr doc,
+            Interpreter::ScopeChain::QmlComponentChain *target,
+            QHash<Document *, Interpreter::ScopeChain::QmlComponentChain *> *components);
 
     static QList<Document::Ptr> reachableDocuments(Document::Ptr startDoc, const Snapshot &snapshot);
     static AST::UiQualifiedId *qualifiedTypeNameId(AST::Node *node);
diff --git a/src/plugins/qmljseditor/qmljscodecompletion.cpp b/src/plugins/qmljseditor/qmljscodecompletion.cpp
index f8905f689b1b6c507e704f71956d9c379c20f28b..5d00f7a65ac7bb7842059e8150c52a7026d164a8 100644
--- a/src/plugins/qmljseditor/qmljscodecompletion.cpp
+++ b/src/plugins/qmljseditor/qmljscodecompletion.cpp
@@ -189,7 +189,7 @@ public:
         _properties.clear();
         _currentObject = 0;
 
-        foreach (const Interpreter::ObjectValue *scope, _context->scopeChain())
+        foreach (const Interpreter::ObjectValue *scope, _context->scopeChain().all)
             enumerateProperties(scope);
 
         return _properties;