aboutsummaryrefslogtreecommitdiffstats
path: root/src/libs/qmljs/qmljsscopechain.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs/qmljs/qmljsscopechain.cpp')
-rw-r--r--src/libs/qmljs/qmljsscopechain.cpp291
1 files changed, 291 insertions, 0 deletions
diff --git a/src/libs/qmljs/qmljsscopechain.cpp b/src/libs/qmljs/qmljsscopechain.cpp
new file mode 100644
index 00000000000..2b5cda90f83
--- /dev/null
+++ b/src/libs/qmljs/qmljsscopechain.cpp
@@ -0,0 +1,291 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation ([email protected])
+**
+**
+** GNU Lesser General Public License Usage
+**
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** Other Usage
+**
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at [email protected].
+**
+**************************************************************************/
+
+#include "qmljsscopechain.h"
+#include "qmljsbind.h"
+
+using namespace QmlJS;
+using namespace QmlJS::Interpreter;
+
+QmlComponentChain::QmlComponentChain(const Document::Ptr &document)
+ : m_document(document)
+{
+}
+
+QmlComponentChain::~QmlComponentChain()
+{
+ qDeleteAll(m_instantiatingComponents);
+}
+
+Document::Ptr QmlComponentChain::document() const
+{
+ return m_document;
+}
+
+QList<const QmlComponentChain *> QmlComponentChain::instantiatingComponents() const
+{
+ return m_instantiatingComponents;
+}
+
+void QmlComponentChain::addInstantiatingComponent(const QmlComponentChain *component)
+{
+ m_instantiatingComponents.append(component);
+}
+
+
+ScopeChain::ScopeChain(const Document::Ptr &document, const Context *context)
+ : m_document(document)
+ , m_context(context)
+ , m_globalScope(0)
+ , m_qmlTypes(0)
+ , m_jsImports(0)
+ , m_modified(false)
+{
+ initializeRootScope();
+}
+
+Document::Ptr ScopeChain::document() const
+{
+ return m_document;
+}
+
+const Context *ScopeChain::context() const
+{
+ return m_context;
+}
+
+const Value * ScopeChain::lookup(const QString &name, const ObjectValue **foundInScope) const
+{
+ QList<const ObjectValue *> scopes = all();
+ for (int index = scopes.size() - 1; index != -1; --index) {
+ const ObjectValue *scope = scopes.at(index);
+
+ if (const Value *member = scope->lookupMember(name, m_context)) {
+ if (foundInScope)
+ *foundInScope = scope;
+ return member;
+ }
+ }
+
+ if (foundInScope)
+ *foundInScope = 0;
+ return m_context->valueOwner()->undefinedValue();
+}
+
+const ObjectValue *ScopeChain::globalScope() const
+{
+ return m_globalScope;
+}
+
+void ScopeChain::setGlobalScope(const ObjectValue *globalScope)
+{
+ m_modified = true;
+ m_globalScope = globalScope;
+}
+
+QSharedPointer<const QmlComponentChain> ScopeChain::qmlComponentChain() const
+{
+ return m_qmlComponentScope;
+}
+
+void ScopeChain::setQmlComponentChain(const QSharedPointer<const QmlComponentChain> &qmlComponentChain)
+{
+ m_modified = true;
+ m_qmlComponentScope = qmlComponentChain;
+}
+
+QList<const ObjectValue *> ScopeChain::qmlScopeObjects() const
+{
+ return m_qmlScopeObjects;
+}
+
+void ScopeChain::setQmlScopeObjects(const QList<const ObjectValue *> &qmlScopeObjects)
+{
+ m_modified = true;
+ m_qmlScopeObjects = qmlScopeObjects;
+}
+
+const TypeScope *ScopeChain::qmlTypes() const
+{
+ return m_qmlTypes;
+}
+
+void ScopeChain::setQmlTypes(const TypeScope *qmlTypes)
+{
+ m_modified = true;
+ m_qmlTypes = qmlTypes;
+}
+
+const JSImportScope *ScopeChain::jsImports() const
+{
+ return m_jsImports;
+}
+
+void ScopeChain::setJsImports(const JSImportScope *jsImports)
+{
+ m_modified = true;
+ m_jsImports = jsImports;
+}
+
+QList<const ObjectValue *> ScopeChain::jsScopes() const
+{
+ return m_jsScopes;
+}
+
+void ScopeChain::setJsScopes(const QList<const ObjectValue *> &jsScopes)
+{
+ m_modified = true;
+ m_jsScopes = jsScopes;
+}
+
+QList<const ObjectValue *> ScopeChain::all() const
+{
+ if (m_modified)
+ update();
+ return m_all;
+}
+
+static void collectScopes(const QmlComponentChain *chain, QList<const ObjectValue *> *target)
+{
+ foreach (const QmlComponentChain *parent, chain->instantiatingComponents())
+ collectScopes(parent, target);
+
+ if (!chain->document())
+ return;
+
+ if (ObjectValue *root = chain->document()->bind()->rootObjectValue())
+ target->append(root);
+ if (ObjectValue *ids = chain->document()->bind()->idEnvironment())
+ target->append(ids);
+}
+
+void ScopeChain::update() const
+{
+ m_all.clear();
+
+ m_all += m_globalScope;
+
+ // the root scope in js files doesn't see instantiating components
+ if (m_jsScopes.count() != 1 || !m_qmlScopeObjects.isEmpty()) {
+ if (m_qmlComponentScope) {
+ foreach (const QmlComponentChain *parent, m_qmlComponentScope->instantiatingComponents())
+ collectScopes(parent, &m_all);
+ }
+ }
+
+ ObjectValue *root = 0;
+ ObjectValue *ids = 0;
+ if (m_qmlComponentScope && m_qmlComponentScope->document()) {
+ const Bind *bind = m_qmlComponentScope->document()->bind();
+ root = bind->rootObjectValue();
+ ids = bind->idEnvironment();
+ }
+
+ if (root && !m_qmlScopeObjects.contains(root))
+ m_all += root;
+ m_all += m_qmlScopeObjects;
+ if (ids)
+ m_all += ids;
+ if (m_qmlTypes)
+ m_all += m_qmlTypes;
+ if (m_jsImports)
+ m_all += m_jsImports;
+ m_all += m_jsScopes;
+}
+
+void ScopeChain::initializeRootScope()
+{
+ ValueOwner *valueOwner = m_context->valueOwner();
+ const Snapshot &snapshot = m_context->snapshot();
+ Bind *bind = m_document->bind();
+
+ m_globalScope = valueOwner->globalObject();
+
+ QHash<Document *, QmlComponentChain *> componentScopes;
+ QmlComponentChain *chain = new QmlComponentChain(m_document);
+ m_qmlComponentScope = QSharedPointer<const QmlComponentChain>(chain);
+
+ if (m_document->qmlProgram()) {
+ componentScopes.insert(m_document.data(), chain);
+ makeComponentChain(chain, snapshot, &componentScopes);
+
+ if (const Imports *imports = m_context->imports(m_document.data())) {
+ m_qmlTypes = imports->typeScope();
+ m_jsImports = imports->jsImportScope();
+ }
+ } else {
+ // add scope chains for all components that import this file
+ foreach (Document::Ptr otherDoc, snapshot) {
+ foreach (const ImportInfo &import, otherDoc->bind()->imports()) {
+ if (import.type() == ImportInfo::FileImport && m_document->fileName() == import.name()) {
+ QmlComponentChain *component = new QmlComponentChain(otherDoc);
+ componentScopes.insert(otherDoc.data(), component);
+ chain->addInstantiatingComponent(component);
+ makeComponentChain(component, snapshot, &componentScopes);
+ }
+ }
+ }
+
+ // ### TODO: Which type environment do scripts see?
+
+ if (bind->rootObjectValue())
+ m_jsScopes += bind->rootObjectValue();
+ }
+}
+
+void ScopeChain::makeComponentChain(
+ QmlComponentChain *target,
+ const Snapshot &snapshot,
+ QHash<Document *, QmlComponentChain *> *components)
+{
+ Document::Ptr doc = target->document();
+ if (!doc->qmlProgram())
+ return;
+
+ const Bind *bind = doc->bind();
+
+ // add scopes for all components instantiating this one
+ foreach (Document::Ptr otherDoc, snapshot) {
+ if (otherDoc == doc)
+ continue;
+ if (otherDoc->bind()->usesQmlPrototype(bind->rootObjectValue(), m_context)) {
+ if (!components->contains(otherDoc.data())) {
+ QmlComponentChain *component = new QmlComponentChain(otherDoc);
+ components->insert(otherDoc.data(), component);
+ target->addInstantiatingComponent(component);
+
+ makeComponentChain(component, snapshot, components);
+ }
+ }
+ }
+}
+