diff --git a/src/libs/qmljs/qmljsbind.cpp b/src/libs/qmljs/qmljsbind.cpp
index c699508463b8970ca659edf29bf445b4a4e445fb..a0b42b0c0205069be15c2a6aacbfe6e1cfd0766e 100644
--- a/src/libs/qmljs/qmljsbind.cpp
+++ b/src/libs/qmljs/qmljsbind.cpp
@@ -92,6 +92,19 @@ Interpreter::ObjectValue *Bind::findQmlObject(AST::Node *node) const
     return _qmlObjects.value(node);
 }
 
+bool Bind::usesQmlPrototype(ObjectValue *prototype,
+                            Context *context) const
+{
+    foreach (ObjectValue *object, _qmlObjects.values()) {
+        const ObjectValue *resolvedPrototype = object->prototype(context);
+
+        if (resolvedPrototype == prototype)
+            return true;
+    }
+
+    return false;
+}
+
 ObjectValue *Bind::switchObjectValue(ObjectValue *newObjectValue)
 {
     ObjectValue *oldObjectValue = _currentObjectValue;
@@ -195,8 +208,8 @@ bool Bind::visit(AST::UiProgram *)
 
 bool Bind::visit(AST::Program *)
 {
-    _currentObjectValue = _engine.globalObject();
-    _rootObjectValue = _engine.globalObject();
+    _currentObjectValue = _engine.newObject(/*prototype =*/ 0);
+    _rootObjectValue = _currentObjectValue;
     return true;
 }
 
diff --git a/src/libs/qmljs/qmljsbind.h b/src/libs/qmljs/qmljsbind.h
index eacc943cf13d5ae41627b328c556a375f5512101..eaaababa97ed7495db293842d62a5d1d0c95b5ad 100644
--- a/src/libs/qmljs/qmljsbind.h
+++ b/src/libs/qmljs/qmljsbind.h
@@ -59,6 +59,8 @@ public:
     Interpreter::ObjectValue *rootObjectValue() const;
 
     Interpreter::ObjectValue *findQmlObject(AST::Node *node) const;
+    bool usesQmlPrototype(Interpreter::ObjectValue *prototype,
+                          Interpreter::Context *context) const;
 
     static QString toString(AST::UiQualifiedId *qualifiedId, QChar delimiter = QChar('.'));
 
diff --git a/src/libs/qmljs/qmljslink.cpp b/src/libs/qmljs/qmljslink.cpp
index 5e9c645ae943b9812a5a5a223a05d5e012987548..5b9d38fa291a35de424bb02ff0288a498cf81d13 100644
--- a/src/libs/qmljs/qmljslink.cpp
+++ b/src/libs/qmljs/qmljslink.cpp
@@ -31,28 +31,41 @@ Interpreter::Engine *Link::engine()
 
 void Link::scopeChainAt(Document::Ptr doc, Node *currentObject)
 {
+    // ### TODO: This object ought to contain the global namespace additions by QML.
     _context->pushScope(engine()->globalObject());
 
     if (! doc)
         return;
 
-    if (doc->qmlProgram() != 0)
-        _context->setLookupMode(Context::QmlLookup);
-
     Bind *bind = doc->bind();
+    QStringList linkedDocs; // to prevent cycles
 
-    // Build the scope chain.
+    if (doc->qmlProgram()) {
+        _context->setLookupMode(Context::QmlLookup);
+
+        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 (const ObjectValue *typeEnvironment = _context->typeEnvironment(doc.data()))
+            _context->pushScope(typeEnvironment);
+    } else {
+        // 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);
+        }
 
-    // ### FIXME: May want to link to instantiating components from here.
+        // ### TODO: Which type environment do scripts see?
 
-    ObjectValue *scopeObject = 0;
-    if (UiObjectDefinition *definition = cast<UiObjectDefinition *>(currentObject))
-        scopeObject = bind->findQmlObject(definition);
-    else if (UiObjectBinding *binding = cast<UiObjectBinding *>(currentObject))
-        scopeObject = bind->findQmlObject(binding);
-    else if (FunctionDeclaration *fun = cast<FunctionDeclaration *>(currentObject)) {
         _context->pushScope(bind->rootObjectValue());
+    }
 
+    if (FunctionDeclaration *fun = cast<FunctionDeclaration *>(currentObject)) {
         ObjectValue *activation = engine()->newObject(/*prototype = */ 0);
         for (FormalParameterList *it = fun->formals; it; it = it->next) {
             if (it->name)
@@ -60,15 +73,35 @@ void Link::scopeChainAt(Document::Ptr doc, Node *currentObject)
         }
         _context->pushScope(activation);
     }
+}
+
+void Link::pushScopeChainForComponent(Document::Ptr doc, QStringList *linkedDocs,
+                                      ObjectValue *scopeObject)
+{
+    if (!doc->qmlProgram())
+        return;
 
-    if (scopeObject) {
-        if (bind->rootObjectValue())
-            _context->pushScope(bind->rootObjectValue());
+    linkedDocs->append(doc->fileName());
 
-        if (scopeObject != bind->rootObjectValue())
-            _context->pushScope(scopeObject);
+    Bind *bind = doc->bind();
+
+    // add scopes for all components instantiating this one
+    foreach (Document::Ptr otherDoc, _docs) {
+        if (linkedDocs->contains(otherDoc->fileName()))
+            continue;
+
+        if (otherDoc->bind()->usesQmlPrototype(bind->rootObjectValue(), _context)) {
+            // ### TODO: Depth-first insertion doesn't give us correct name shadowing.
+            pushScopeChainForComponent(otherDoc, linkedDocs);
+        }
     }
 
+    if (bind->rootObjectValue())
+        _context->pushScope(bind->rootObjectValue());
+
+    if (scopeObject && scopeObject != bind->rootObjectValue())
+        _context->pushScope(scopeObject);
+
     const QStringList &includedScripts = bind->includedScripts();
     for (int index = includedScripts.size() - 1; index != -1; --index) {
         const QString &scriptFile = includedScripts.at(index);
@@ -82,9 +115,6 @@ void Link::scopeChainAt(Document::Ptr doc, Node *currentObject)
 
     _context->pushScope(bind->functionEnvironment());
     _context->pushScope(bind->idEnvironment());
-
-    if (const ObjectValue *typeEnvironment = _context->typeEnvironment(doc.data()))
-        _context->pushScope(typeEnvironment);
 }
 
 void Link::linkImports()
@@ -251,40 +281,85 @@ UiQualifiedId *Link::qualifiedTypeNameId(Node *node)
         return 0;
 }
 
+static uint qHash(Document::Ptr doc) {
+    return qHash(doc.data());
+}
+
 QList<Document::Ptr> Link::reachableDocuments(Document::Ptr startDoc, const Snapshot &snapshot)
 {
-    QList<Document::Ptr> docs;
+    QSet<Document::Ptr> docs;
 
     if (! startDoc)
-        return docs;
-
-    QSet<QString> processed;
-    QStringList todo;
+        return docs.values();
 
     QMultiHash<QString, Document::Ptr> documentByPath;
     foreach (Document::Ptr doc, snapshot)
         documentByPath.insert(doc->path(), doc);
 
-    todo.append(startDoc->path());
-
-    // Find the reachable documents.
-    while (! todo.isEmpty()) {
-        const QString path = todo.takeFirst();
+    // ### TODO: This doesn't scale well. Maybe just use the whole snapshot?
+    // Find all documents that (indirectly) include startDoc
+    {
+        QList<Document::Ptr> todo;
+        todo += startDoc;
 
-        if (processed.contains(path))
-            continue;
-
-        processed.insert(path);
+        while (! todo.isEmpty()) {
+            Document::Ptr doc = todo.takeFirst();
 
-        QStringList localImports;
-        foreach (Document::Ptr doc, documentByPath.values(path)) {
             docs += doc;
-            localImports += doc->bind()->localImports();
+
+            Snapshot::const_iterator it, end = snapshot.end();
+            for (it = snapshot.begin(); it != end; ++it) {
+                Document::Ptr otherDoc = *it;
+                if (docs.contains(otherDoc))
+                    continue;
+
+                QStringList localImports = otherDoc->bind()->localImports();
+                if (localImports.contains(doc->fileName())
+                    || localImports.contains(doc->path())
+                    || otherDoc->bind()->includedScripts().contains(doc->fileName())
+                ) {
+                    todo += otherDoc;
+                }
+            }
         }
+    }
 
-        localImports.removeDuplicates();
-        todo += localImports;
+    // Find all documents that are included by these (even if indirectly).
+    {
+        QSet<QString> processed;
+        QStringList todo;
+        foreach (Document::Ptr doc, docs)
+            todo.append(doc->fileName());
+
+        while (! todo.isEmpty()) {
+            QString path = todo.takeFirst();
+
+            if (processed.contains(path))
+                continue;
+            processed.insert(path);
+
+            if (Document::Ptr doc = snapshot.document(path)) {
+                docs += doc;
+
+                if (doc->qmlProgram())
+                    path = doc->path();
+                else
+                    continue;
+            }
+
+            QStringList localImports;
+            foreach (Document::Ptr doc, documentByPath.values(path)) {
+                if (doc->qmlProgram()) {
+                    docs += doc;
+                    localImports += doc->bind()->localImports();
+                    localImports += doc->bind()->includedScripts();
+                }
+            }
+
+            localImports.removeDuplicates();
+            todo += localImports;
+        }
     }
 
-    return docs;
+    return docs.values();
 }
diff --git a/src/libs/qmljs/qmljslink.h b/src/libs/qmljs/qmljslink.h
index c6329fef324c0f24c78cb8dfe81cd429aacbd2df..936851dac54c0274e84a76baa6eb66604edc7b3e 100644
--- a/src/libs/qmljs/qmljslink.h
+++ b/src/libs/qmljs/qmljslink.h
@@ -28,6 +28,9 @@ public:
 private:
     Interpreter::Engine *engine();
 
+    void pushScopeChainForComponent(Document::Ptr doc, QStringList *linkedDocs,
+                                    Interpreter::ObjectValue *scopeObject = 0);
+
     static QList<Document::Ptr> reachableDocuments(Document::Ptr startDoc, const Snapshot &snapshot);
     static AST::UiQualifiedId *qualifiedTypeNameId(AST::Node *node);