aboutsummaryrefslogtreecommitdiffstats
path: root/src/libs
diff options
context:
space:
mode:
authorChristian Kamm <[email protected]>2011-07-12 14:55:27 +0200
committerChristian Kamm <[email protected]>2011-08-08 12:05:03 +0200
commitf87dc6198609abdb58b430cf272a4e6ca7144865 (patch)
tree738d7024efedab5254676139ca456631e334c78a /src/libs
parented1321a4f95d4ecbbd96794ec355cfc7984cfb2d (diff)
QmlJS: Split Context and ScopeChain.
Context is created by Link and has information about imports for all Documents in a Snapshot. ScopeChain represents how lookup is done at a specific place in a Document. Change-Id: I874102d57bbaf1a497fa3f27633bed6ee75dcf10 Reviewed-on: http://codereview.qt.nokia.com/1694 Reviewed-by: Fawzi Mohamed <[email protected]>
Diffstat (limited to 'src/libs')
-rw-r--r--src/libs/qmljs/qmljs-lib.pri6
-rw-r--r--src/libs/qmljs/qmljsbind.cpp2
-rw-r--r--src/libs/qmljs/qmljscheck.cpp21
-rw-r--r--src/libs/qmljs/qmljscheck.h5
-rw-r--r--src/libs/qmljs/qmljscontext.cpp76
-rw-r--r--src/libs/qmljs/qmljscontext.h31
-rw-r--r--src/libs/qmljs/qmljsevaluate.cpp12
-rw-r--r--src/libs/qmljs/qmljsevaluate.h4
-rw-r--r--src/libs/qmljs/qmljsinterpreter.cpp118
-rw-r--r--src/libs/qmljs/qmljsinterpreter.h50
-rw-r--r--src/libs/qmljs/qmljslookupcontext.cpp30
-rw-r--r--src/libs/qmljs/qmljslookupcontext.h6
-rw-r--r--src/libs/qmljs/qmljsscopebuilder.cpp153
-rw-r--r--src/libs/qmljs/qmljsscopebuilder.h20
-rw-r--r--src/libs/qmljs/qmljsscopechain.cpp291
-rw-r--r--src/libs/qmljs/qmljsscopechain.h127
16 files changed, 602 insertions, 350 deletions
diff --git a/src/libs/qmljs/qmljs-lib.pri b/src/libs/qmljs/qmljs-lib.pri
index 47488948a0b..7532a24eb28 100644
--- a/src/libs/qmljs/qmljs-lib.pri
+++ b/src/libs/qmljs/qmljs-lib.pri
@@ -30,7 +30,8 @@ HEADERS += \
$$PWD/qmljstypedescriptionreader.h \
$$PWD/qmljsscopeastpath.h \
$$PWD/qmljsvalueowner.h \
- $$PWD/qmljscontext.h
+ $$PWD/qmljscontext.h \
+ $$PWD/qmljsscopechain.h
SOURCES += \
$$PWD/qmljsbind.cpp \
@@ -52,7 +53,8 @@ SOURCES += \
$$PWD/qmljstypedescriptionreader.cpp \
$$PWD/qmljsscopeastpath.cpp \
$$PWD/qmljsvalueowner.cpp \
- $$PWD/qmljscontext.cpp
+ $$PWD/qmljscontext.cpp \
+ $$PWD/qmljsscopechain.cpp
RESOURCES += \
$$PWD/qmljs.qrc
diff --git a/src/libs/qmljs/qmljsbind.cpp b/src/libs/qmljs/qmljsbind.cpp
index 1a4bafb3505..149812bbbe8 100644
--- a/src/libs/qmljs/qmljsbind.cpp
+++ b/src/libs/qmljs/qmljsbind.cpp
@@ -369,7 +369,7 @@ bool Bind::visit(VariableDeclaration *ast)
if (! ast->name)
return false;
- ASTVariableReference *ref = new ASTVariableReference(ast, &_valueOwner);
+ ASTVariableReference *ref = new ASTVariableReference(ast, _doc, &_valueOwner);
if (_currentObjectValue)
_currentObjectValue->setMember(ast->name->asString(), ref);
return true;
diff --git a/src/libs/qmljs/qmljscheck.cpp b/src/libs/qmljs/qmljscheck.cpp
index 68849e1adc4..8924bbaabb2 100644
--- a/src/libs/qmljs/qmljscheck.cpp
+++ b/src/libs/qmljs/qmljscheck.cpp
@@ -365,17 +365,17 @@ private:
} // end of anonymous namespace
-Check::Check(Document::Ptr doc, const Context *linkedContextNoScope)
+Check::Check(Document::Ptr doc, const Context *context)
: _doc(doc)
- , _context(*linkedContextNoScope)
- , _scopeBuilder(&_context, doc)
+ , _context(*context)
+ , _scopeChain(doc, &_context)
+ , _scopeBuilder(&_scopeChain)
, _options(WarnDangerousNonStrictEqualityChecks | WarnBlocks | WarnWith
| WarnVoid | WarnCommaExpression | WarnExpressionStatement
| WarnAssignInCondition | WarnUseBeforeDeclaration | WarnDuplicateDeclaration
| WarnCaseWithoutFlowControlEnd | ErrCheckTypeErrors)
, _lastValue(0)
{
- _scopeBuilder.initializeRootScope();
}
Check::~Check()
@@ -509,8 +509,7 @@ void Check::visitQmlObject(Node *ast, UiQualifiedId *typeId,
// suppress subsequent errors about scope object lookup by clearing
// the scope object list
// ### todo: better way?
- _context.scopeChain().qmlScopeObjects.clear();
- _context.scopeChain().update();
+ _scopeChain.setQmlScopeObjects(QList<const ObjectValue *>());
}
Node::accept(initializer, this);
@@ -565,7 +564,7 @@ bool Check::visit(UiScriptBinding *ast)
if (ExpressionStatement *expStmt = cast<ExpressionStatement *>(ast->statement)) {
ExpressionNode *expr = expStmt->expression;
- Evaluate evaluator(&_context);
+ Evaluate evaluator(&_scopeChain);
const Value *rhsValue = evaluator(expr);
const SourceLocation loc = locationFromRange(expStmt->firstSourceLocation(),
@@ -606,7 +605,7 @@ bool Check::visit(IdentifierExpression *ast)
_lastValue = 0;
if (ast->name) {
- Evaluate evaluator(&_context);
+ Evaluate evaluator(&_scopeChain);
_lastValue = evaluator.reference(ast);
if (!_lastValue)
error(ast->identifierToken, tr("unknown identifier"));
@@ -683,7 +682,7 @@ bool Check::visit(BinaryExpression *ast)
if (ast->op == QSOperator::Equal || ast->op == QSOperator::NotEqual) {
bool warn = _options & WarnAllNonStrictEqualityChecks;
if (!warn && _options & WarnDangerousNonStrictEqualityChecks) {
- Evaluate eval(&_context);
+ Evaluate eval(&_scopeChain);
const Value *lhs = eval(ast->left);
const Value *rhs = eval(ast->right);
warn = shouldAvoidNonStrictEqualityCheck(ast->left, rhs)
@@ -850,7 +849,7 @@ bool Check::visit(DefaultClause *ast)
/// ### Maybe put this into the context as a helper method.
const Value *Check::checkScopeObjectMember(const UiQualifiedId *id)
{
- QList<const ObjectValue *> scopeObjects = _context.scopeChain().qmlScopeObjects;
+ QList<const ObjectValue *> scopeObjects = _scopeChain.qmlScopeObjects();
if (scopeObjects.isEmpty())
return 0;
@@ -869,7 +868,7 @@ const Value *Check::checkScopeObjectMember(const UiQualifiedId *id)
bool isAttachedProperty = false;
if (! propertyName.isEmpty() && propertyName[0].isUpper()) {
isAttachedProperty = true;
- if (const ObjectValue *qmlTypes = _context.scopeChain().qmlTypes)
+ if (const ObjectValue *qmlTypes = _scopeChain.qmlTypes())
scopeObjects += qmlTypes;
}
diff --git a/src/libs/qmljs/qmljscheck.h b/src/libs/qmljs/qmljscheck.h
index 5fb2c8bcce2..84a0977c566 100644
--- a/src/libs/qmljs/qmljscheck.h
+++ b/src/libs/qmljs/qmljscheck.h
@@ -36,6 +36,7 @@
#include <qmljs/qmljsdocument.h>
#include <qmljs/qmljscontext.h>
#include <qmljs/qmljsscopebuilder.h>
+#include <qmljs/qmljsscopechain.h>
#include <qmljs/parser/qmljsastvisitor_p.h>
#include <QtCore/QCoreApplication>
@@ -52,7 +53,8 @@ class QMLJS_EXPORT Check: protected AST::Visitor
typedef QSet<QString> StringSet;
public:
- Check(Document::Ptr doc, const Interpreter::Context *linkedContextNoScope);
+ // prefer taking root scope chain?
+ Check(Document::Ptr doc, const Interpreter::Context *context);
virtual ~Check();
QList<DiagnosticMessage> operator()();
@@ -127,6 +129,7 @@ private:
Document::Ptr _doc;
Interpreter::Context _context;
+ Interpreter::ScopeChain _scopeChain;
ScopeBuilder _scopeBuilder;
QList<DiagnosticMessage> _messages;
diff --git a/src/libs/qmljs/qmljscontext.cpp b/src/libs/qmljs/qmljscontext.cpp
index ab914cbfa9e..2d659c0ccbd 100644
--- a/src/libs/qmljs/qmljscontext.cpp
+++ b/src/libs/qmljs/qmljscontext.cpp
@@ -41,9 +41,7 @@ using namespace QmlJS::Interpreter;
Context::Context(const QmlJS::Snapshot &snapshot, ValueOwner *valueOwner, const ImportsPerDocument &imports)
: _snapshot(snapshot),
_valueOwner(valueOwner),
- _imports(imports),
- _qmlScopeObjectIndex(-1),
- _qmlScopeObjectSet(false)
+ _imports(imports)
{
}
@@ -62,16 +60,6 @@ QmlJS::Snapshot Context::snapshot() const
return _snapshot;
}
-const ScopeChain &Context::scopeChain() const
-{
- return _scopeChain;
-}
-
-ScopeChain &Context::scopeChain()
-{
- return _scopeChain;
-}
-
const Imports *Context::imports(const QmlJS::Document *doc) const
{
if (!doc)
@@ -79,24 +67,6 @@ const Imports *Context::imports(const QmlJS::Document *doc) const
return _imports.value(doc).data();
}
-const Value *Context::lookup(const QString &name, const ObjectValue **foundInScope) const
-{
- 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 (foundInScope)
- *foundInScope = scope;
- return member;
- }
- }
-
- if (foundInScope)
- *foundInScope = 0;
- return _valueOwner->undefinedValue();
-}
-
const ObjectValue *Context::lookupType(const QmlJS::Document *doc, UiQualifiedId *qmlTypeName,
UiQualifiedId *qmlTypeNameEnd) const
{
@@ -147,18 +117,8 @@ const ObjectValue *Context::lookupType(const QmlJS::Document *doc, const QString
const Value *Context::lookupReference(const Value *value) const
{
- const Reference *reference = value_cast<const Reference *>(value);
- if (!reference)
- return value;
-
- if (_referenceStack.contains(reference))
- return 0;
-
- _referenceStack.append(reference);
- const Value *v = reference->value(this);
- _referenceStack.removeLast();
-
- return v;
+ ReferenceContext refContext(this);
+ return refContext.lookupReference(value);
}
QString Context::defaultPropertyName(const ObjectValue *object) const
@@ -176,3 +136,33 @@ QString Context::defaultPropertyName(const ObjectValue *object) const
}
return QString();
}
+
+ReferenceContext::ReferenceContext(const Context *context)
+ : m_context(context)
+{}
+
+const Value *ReferenceContext::lookupReference(const Value *value)
+{
+ const Reference *reference = value_cast<const Reference *>(value);
+ if (!reference)
+ return value;
+
+ if (m_references.contains(reference))
+ return reference; // ### error
+
+ m_references.append(reference);
+ const Value *v = reference->value(this);
+ m_references.removeLast();
+
+ return v;
+}
+
+const Context *ReferenceContext::context() const
+{
+ return m_context;
+}
+
+ReferenceContext::operator const Context *() const
+{
+ return m_context;
+}
diff --git a/src/libs/qmljs/qmljscontext.h b/src/libs/qmljs/qmljscontext.h
index bd5c4cf03d5..5d28c5872a9 100644
--- a/src/libs/qmljs/qmljscontext.h
+++ b/src/libs/qmljs/qmljscontext.h
@@ -45,9 +45,12 @@ class Snapshot;
namespace Interpreter {
+// shared among threads, completely threadsafe
+// currently also safe to copy, but will be deprecated
class QMLJS_EXPORT Context
{
public:
+ typedef QSharedPointer<Context> Ptr;
typedef QHash<const Document *, QSharedPointer<const Imports> > ImportsPerDocument;
// Context takes ownership of valueOwner
@@ -57,12 +60,8 @@ public:
ValueOwner *valueOwner() const;
Snapshot snapshot() const;
- const ScopeChain &scopeChain() const;
- ScopeChain &scopeChain();
-
const Imports *imports(const Document *doc) const;
- const Value *lookup(const QString &name, const ObjectValue **foundInScope = 0) const;
const ObjectValue *lookupType(const Document *doc, AST::UiQualifiedId *qmlTypeName,
AST::UiQualifiedId *qmlTypeNameEnd = 0) const;
const ObjectValue *lookupType(const Document *doc, const QStringList &qmlTypeName) const;
@@ -71,19 +70,29 @@ public:
QString defaultPropertyName(const ObjectValue *object) const;
private:
- typedef QHash<QString, const Value *> Properties;
-
Snapshot _snapshot;
QSharedPointer<ValueOwner> _valueOwner;
ImportsPerDocument _imports;
- ScopeChain _scopeChain;
- int _qmlScopeObjectIndex;
- bool _qmlScopeObjectSet;
+};
+
+// for looking up references
+class QMLJS_EXPORT ReferenceContext
+{
+public:
+ // implicit conversion ok
+ ReferenceContext(const Context *context);
+
+ const Value *lookupReference(const Value *value);
+
+ const Context *context() const;
+ operator const Context *() const;
- // for avoiding reference cycles during lookup
- mutable QList<const Reference *> _referenceStack;
+private:
+ const Context *m_context;
+ QList<const Reference *> m_references;
};
+
} // namespace Interpreter
} // namespace QmlJS
diff --git a/src/libs/qmljs/qmljsevaluate.cpp b/src/libs/qmljs/qmljsevaluate.cpp
index 410d3d3a383..973144fbd5e 100644
--- a/src/libs/qmljs/qmljsevaluate.cpp
+++ b/src/libs/qmljs/qmljsevaluate.cpp
@@ -33,15 +33,17 @@
#include "qmljsevaluate.h"
#include "qmljscontext.h"
#include "qmljsvalueowner.h"
+#include "qmljsscopechain.h"
#include "parser/qmljsast_p.h"
#include <QtCore/QDebug>
using namespace QmlJS;
using namespace QmlJS::Interpreter;
-Evaluate::Evaluate(const Context *context)
- : _valueOwner(context->valueOwner()),
- _context(context),
+Evaluate::Evaluate(const ScopeChain *scopeChain)
+ : _valueOwner(scopeChain->context()->valueOwner()),
+ _context(scopeChain->context()),
+ _scopeChain(scopeChain),
_scope(_valueOwner->globalObject()),
_result(0)
{
@@ -165,7 +167,7 @@ bool Evaluate::visit(AST::UiQualifiedId *ast)
if (! ast->name)
return false;
- const Value *value = _context->lookup(ast->name->asString());
+ const Value *value = _scopeChain->lookup(ast->name->asString());
if (! ast->next) {
_result = value;
@@ -213,7 +215,7 @@ bool Evaluate::visit(AST::IdentifierExpression *ast)
if (! ast->name)
return false;
- _result = _context->lookup(ast->name->asString());
+ _result = _scopeChain->lookup(ast->name->asString());
return false;
}
diff --git a/src/libs/qmljs/qmljsevaluate.h b/src/libs/qmljs/qmljsevaluate.h
index b7fc24fabe3..d7316449bde 100644
--- a/src/libs/qmljs/qmljsevaluate.h
+++ b/src/libs/qmljs/qmljsevaluate.h
@@ -35,6 +35,7 @@
#include "parser/qmljsastvisitor_p.h"
#include "qmljsdocument.h"
+#include "qmljsscopechain.h"
namespace QmlJS {
@@ -49,7 +50,7 @@ namespace Interpreter {
class QMLJS_EXPORT Evaluate: protected AST::Visitor
{
public:
- Evaluate(const Interpreter::Context *context);
+ Evaluate(const Interpreter::ScopeChain *scopeChain);
virtual ~Evaluate();
// same as value()
@@ -165,6 +166,7 @@ private:
QmlJS::Document::Ptr _doc;
Interpreter::ValueOwner *_valueOwner;
const Interpreter::Context *_context;
+ const Interpreter::ScopeChain *_scopeChain;
const Interpreter::ObjectValue *_scope;
const Interpreter::Value *_result;
};
diff --git a/src/libs/qmljs/qmljsinterpreter.cpp b/src/libs/qmljs/qmljsinterpreter.cpp
index 1002f96162e..d44c6065fd3 100644
--- a/src/libs/qmljs/qmljsinterpreter.cpp
+++ b/src/libs/qmljs/qmljsinterpreter.cpp
@@ -35,8 +35,9 @@
#include "qmljslink.h"
#include "qmljsbind.h"
#include "qmljsscopebuilder.h"
-#include "qmljstypedescriptionreader.h"
+#include "qmljsscopechain.h"
#include "qmljsscopeastpath.h"
+#include "qmljstypedescriptionreader.h"
#include "qmljsvalueowner.h"
#include "qmljscontext.h"
#include "parser/qmljsast_p.h"
@@ -688,82 +689,6 @@ void StringValue::accept(ValueVisitor *visitor) const
visitor->visit(this);
}
-
-ScopeChain::ScopeChain()
- : globalScope(0)
- , qmlTypes(0)
- , jsImports(0)
-{
-}
-
-ScopeChain::QmlComponentChain::QmlComponentChain()
-{
-}
-
-ScopeChain::QmlComponentChain::~QmlComponentChain()
-{
- qDeleteAll(instantiatingComponents);
-}
-
-void ScopeChain::QmlComponentChain::clear()
-{
- qDeleteAll(instantiatingComponents);
- instantiatingComponents.clear();
- document = Document::Ptr(0);
-}
-
-void ScopeChain::QmlComponentChain::collect(QList<const ObjectValue *> *list) const
-{
- foreach (const QmlComponentChain *parent, instantiatingComponents)
- parent->collect(list);
-
- if (!document)
- return;
-
- if (ObjectValue *root = document->bind()->rootObjectValue())
- list->append(root);
- if (ObjectValue *ids = document->bind()->idEnvironment())
- list->append(ids);
-}
-
-void ScopeChain::update()
-{
- _all.clear();
-
- _all += globalScope;
-
- // the root scope in js files doesn't see instantiating components
- if (jsScopes.count() != 1 || !qmlScopeObjects.isEmpty()) {
- if (qmlComponentScope) {
- foreach (const QmlComponentChain *parent, qmlComponentScope->instantiatingComponents)
- parent->collect(&_all);
- }
- }
-
- ObjectValue *root = 0;
- ObjectValue *ids = 0;
- if (qmlComponentScope && qmlComponentScope->document) {
- root = qmlComponentScope->document->bind()->rootObjectValue();
- ids = qmlComponentScope->document->bind()->idEnvironment();
- }
-
- if (root && !qmlScopeObjects.contains(root))
- _all += root;
- _all += qmlScopeObjects;
- if (ids)
- _all += ids;
- if (qmlTypes)
- _all += qmlTypes;
- if (jsImports)
- _all += jsImports;
- _all += jsScopes;
-}
-
-QList<const ObjectValue *> ScopeChain::all() const
-{
- return _all;
-}
-
Reference::Reference(ValueOwner *valueOwner)
: _valueOwner(valueOwner)
{
@@ -789,7 +714,7 @@ void Reference::accept(ValueVisitor *visitor) const
visitor->visit(this);
}
-const Value *Reference::value(const Context *) const
+const Value *Reference::value(const ReferenceContext *) const
{
return _valueOwner->undefinedValue();
}
@@ -1771,8 +1696,10 @@ const QmlJS::Document *ASTObjectValue::document() const
return _doc;
}
-ASTVariableReference::ASTVariableReference(VariableDeclaration *ast, ValueOwner *valueOwner)
- : Reference(valueOwner), _ast(ast)
+ASTVariableReference::ASTVariableReference(VariableDeclaration *ast, const QmlJS::Document *doc, ValueOwner *valueOwner)
+ : Reference(valueOwner)
+ , _ast(ast)
+ , _doc(doc)
{
}
@@ -1780,10 +1707,18 @@ ASTVariableReference::~ASTVariableReference()
{
}
-const Value *ASTVariableReference::value(const Context *context) const
+const Value *ASTVariableReference::value(const ReferenceContext *referenceContext) const
{
- Evaluate check(context);
- return check(_ast->expression);
+ if (!_ast->expression)
+ return valueOwner()->undefinedValue();
+
+ Document::Ptr doc = _doc->ptr();
+ ScopeChain scopeChain(doc, referenceContext->context());
+ QmlJS::ScopeBuilder builder(&scopeChain);
+ builder.push(QmlJS::ScopeAstPath(doc)(_ast->expression->firstSourceLocation().begin()));
+
+ QmlJS::Evaluate evaluator(&scopeChain);
+ return evaluator(_ast->expression);
}
ASTFunctionValue::ASTFunctionValue(FunctionExpression *ast, const QmlJS::Document *doc, ValueOwner *valueOwner)
@@ -1859,9 +1794,9 @@ UiQualifiedId *QmlPrototypeReference::qmlTypeName() const
return _qmlTypeName;
}
-const Value *QmlPrototypeReference::value(const Context *context) const
+const Value *QmlPrototypeReference::value(const ReferenceContext *referenceContext) const
{
- return context->lookupType(_doc, _qmlTypeName);
+ return referenceContext->context()->lookupType(_doc, _qmlTypeName);
}
ASTPropertyReference::ASTPropertyReference(UiPublicMember *ast, const QmlJS::Document *doc, ValueOwner *valueOwner)
@@ -1886,7 +1821,7 @@ bool ASTPropertyReference::getSourceLocation(QString *fileName, int *line, int *
return true;
}
-const Value *ASTPropertyReference::value(const Context *context) const
+const Value *ASTPropertyReference::value(const ReferenceContext *referenceContext) const
{
if (_ast->statement
&& (!_ast->memberType || _ast->memberType->asString() == QLatin1String("variant")
@@ -1896,15 +1831,14 @@ const Value *ASTPropertyReference::value(const Context *context) const
// ### Improve efficiency by caching the 'use chain' constructed in ScopeBuilder.
QmlJS::Document::Ptr doc = _doc->ptr();
- Context localContext(*context);
- QmlJS::ScopeBuilder builder(&localContext, doc);
- builder.initializeRootScope();
+ ScopeChain scopeChain(doc, referenceContext->context());
+ QmlJS::ScopeBuilder builder(&scopeChain);
int offset = _ast->statement->firstSourceLocation().begin();
builder.push(ScopeAstPath(doc)(offset));
- Evaluate check(&localContext);
- return check(_ast->statement);
+ QmlJS::Evaluate evaluator(&scopeChain);
+ return evaluator(_ast->statement);
}
if (_ast->memberType)
@@ -1934,7 +1868,7 @@ bool ASTSignalReference::getSourceLocation(QString *fileName, int *line, int *co
return true;
}
-const Value *ASTSignalReference::value(const Context *) const
+const Value *ASTSignalReference::value(const ReferenceContext *) const
{
return valueOwner()->undefinedValue();
}
diff --git a/src/libs/qmljs/qmljsinterpreter.h b/src/libs/qmljs/qmljsinterpreter.h
index 85a49a5ee6a..c88e7aaa793 100644
--- a/src/libs/qmljs/qmljsinterpreter.h
+++ b/src/libs/qmljs/qmljsinterpreter.h
@@ -75,6 +75,7 @@ class Imports;
class TypeScope;
class JSImportScope;
class Context;
+class ReferenceContext;
typedef QList<const Value *> ValueList;
@@ -283,40 +284,6 @@ public:
virtual bool processGeneratedSlot(const QString &name, const Value *value);
};
-class QMLJS_EXPORT ScopeChain
-{
-public:
- ScopeChain();
-
- class QMLJS_EXPORT QmlComponentChain
- {
- Q_DISABLE_COPY(QmlComponentChain)
- public:
- QmlComponentChain();
- ~QmlComponentChain();
-
- QList<const QmlComponentChain *> instantiatingComponents;
- Document::Ptr document;
-
- void collect(QList<const ObjectValue *> *list) const;
- void clear();
- };
-
- const ObjectValue *globalScope;
- QSharedPointer<const QmlComponentChain> qmlComponentScope;
- QList<const ObjectValue *> qmlScopeObjects;
- const TypeScope *qmlTypes;
- const JSImportScope *jsImports;
- QList<const ObjectValue *> jsScopes;
-
- // rebuilds the flat list of all scopes
- void update();
- QList<const ObjectValue *> all() const;
-
-private:
- QList<const ObjectValue *> _all;
-};
-
class QMLJS_EXPORT Reference: public Value
{
public:
@@ -330,10 +297,10 @@ public:
virtual void accept(ValueVisitor *) const;
private:
- virtual const Value *value(const Context *context) const;
+ virtual const Value *value(const ReferenceContext *referenceContext) const;
ValueOwner *_valueOwner;
- friend class Context;
+ friend class ReferenceContext;
};
class QMLJS_EXPORT ColorValue: public Value
@@ -724,7 +691,7 @@ public:
AST::UiQualifiedId *qmlTypeName() const;
private:
- virtual const Value *value(const Context *context) const;
+ virtual const Value *value(const ReferenceContext *referenceContext) const;
AST::UiQualifiedId *_qmlTypeName;
const Document *_doc;
@@ -733,13 +700,14 @@ private:
class QMLJS_EXPORT ASTVariableReference: public Reference
{
AST::VariableDeclaration *_ast;
+ const Document *_doc;
public:
- ASTVariableReference(AST::VariableDeclaration *ast, ValueOwner *valueOwner);
+ ASTVariableReference(AST::VariableDeclaration *ast, const Document *doc, ValueOwner *valueOwner);
virtual ~ASTVariableReference();
private:
- virtual const Value *value(const Context *context) const;
+ virtual const Value *value(const ReferenceContext *referenceContext) const;
};
class QMLJS_EXPORT ASTFunctionValue: public FunctionValue
@@ -779,7 +747,7 @@ public:
virtual bool getSourceLocation(QString *fileName, int *line, int *column) const;
private:
- virtual const Value *value(const Context *context) const;
+ virtual const Value *value(const ReferenceContext *referenceContext) const;
};
class QMLJS_EXPORT ASTSignalReference: public Reference
@@ -798,7 +766,7 @@ public:
virtual bool getSourceLocation(QString *fileName, int *line, int *column) const;
private:
- virtual const Value *value(const Context *context) const;
+ virtual const Value *value(const ReferenceContext *referenceContext) const;
};
class QMLJS_EXPORT ASTObjectValue: public ObjectValue
diff --git a/src/libs/qmljs/qmljslookupcontext.cpp b/src/libs/qmljs/qmljslookupcontext.cpp
index 04cc68938f7..389a23fb86c 100644
--- a/src/libs/qmljs/qmljslookupcontext.cpp
+++ b/src/libs/qmljs/qmljslookupcontext.cpp
@@ -36,6 +36,7 @@
#include "qmljsscopebuilder.h"
#include "qmljsmodelmanagerinterface.h"
#include "qmljsevaluate.h"
+#include "qmljsscopechain.h"
using namespace QmlJS;
@@ -47,26 +48,26 @@ public:
, context(Link(snapshot,
ModelManagerInterface::instance()->importPaths(),
ModelManagerInterface::instance()->builtins(doc))())
+ , scopeChain(doc, &context)
{
- ScopeBuilder scopeBuilder(&context, doc);
- scopeBuilder.initializeRootScope();
+ ScopeBuilder scopeBuilder(&scopeChain);
scopeBuilder.push(path);
}
LookupContextData(Document::Ptr doc,
- const Interpreter::Context &contextWithoutScope,
+ const Interpreter::Context &context,
const QList<AST::Node *> &path)
: doc(doc)
- , context(contextWithoutScope)
+ , context(context)
+ , scopeChain(doc, &context)
{
- ScopeBuilder scopeBuilder(&context, doc);
- scopeBuilder.initializeRootScope();
+ ScopeBuilder scopeBuilder(&scopeChain);
scopeBuilder.push(path);
}
Document::Ptr doc;
Interpreter::Context context;
- // snapshot is in context
+ Interpreter::ScopeChain scopeChain;
};
LookupContext::LookupContext(Document::Ptr doc, const Snapshot &snapshot, const QList<AST::Node *> &path)
@@ -75,9 +76,9 @@ LookupContext::LookupContext(Document::Ptr doc, const Snapshot &snapshot, const
}
LookupContext::LookupContext(const Document::Ptr doc,
- const Interpreter::Context &contextWithoutScope,
+ const Interpreter::Context &context,
const QList<AST::Node *> &path)
- : d(new LookupContextData(doc, contextWithoutScope, path))
+ : d(new LookupContextData(doc, context, path))
{
}
@@ -92,16 +93,16 @@ LookupContext::Ptr LookupContext::create(Document::Ptr doc, const Snapshot &snap
}
LookupContext::Ptr LookupContext::create(const Document::Ptr doc,
- const Interpreter::Context &linkedContextWithoutScope,
+ const Interpreter::Context &context,
const QList<AST::Node *> &path)
{
- Ptr ptr(new LookupContext(doc, linkedContextWithoutScope, path));
+ Ptr ptr(new LookupContext(doc, context, path));
return ptr;
}
const Interpreter::Value *LookupContext::evaluate(AST::Node *node) const
{
- Evaluate check(&d->context);
+ Evaluate check(&d->scopeChain);
return check(node);
}
@@ -126,3 +127,8 @@ const Interpreter::Context *LookupContext::context() const
{
return &d->context;
}
+
+const Interpreter::ScopeChain &LookupContext::scopeChain() const
+{
+ return d->scopeChain;
+}
diff --git a/src/libs/qmljs/qmljslookupcontext.h b/src/libs/qmljs/qmljslookupcontext.h
index ce4199e0921..f71ae802847 100644
--- a/src/libs/qmljs/qmljslookupcontext.h
+++ b/src/libs/qmljs/qmljslookupcontext.h
@@ -47,6 +47,7 @@ class LookupContextData;
namespace Interpreter {
class Value;
class Context;
+class ScopeChain;
}
class QMLJS_EXPORT LookupContext
@@ -55,7 +56,7 @@ class QMLJS_EXPORT LookupContext
LookupContext(const Document::Ptr doc, const Snapshot &snapshot, const QList<AST::Node *> &path);
LookupContext(const Document::Ptr doc,
- const Interpreter::Context &linkedContextWithoutScope,
+ const Interpreter::Context &context,
const QList<AST::Node *> &path);
public:
@@ -67,7 +68,7 @@ public:
static Ptr create(const Document::Ptr doc, const Snapshot &snapshot,
const QList<AST::Node *> &path);
static Ptr create(const Document::Ptr doc,
- const Interpreter::Context &linkedContextWithoutScope,
+ const Interpreter::Context &context,
const QList<AST::Node *> &path);
const Interpreter::Value *evaluate(AST::Node *node) const;
@@ -76,6 +77,7 @@ public:
Snapshot snapshot() const;
Interpreter::ValueOwner *valueOwner() const;
const Interpreter::Context *context() const;
+ const Interpreter::ScopeChain &scopeChain() const;
private:
QScopedPointer<LookupContextData> d;
diff --git a/src/libs/qmljs/qmljsscopebuilder.cpp b/src/libs/qmljs/qmljsscopebuilder.cpp
index 10f18e6a803..90e97502df3 100644
--- a/src/libs/qmljs/qmljsscopebuilder.cpp
+++ b/src/libs/qmljs/qmljsscopebuilder.cpp
@@ -35,15 +35,15 @@
#include "qmljsbind.h"
#include "qmljscontext.h"
#include "qmljsevaluate.h"
+#include "qmljsscopechain.h"
#include "parser/qmljsast_p.h"
using namespace QmlJS;
using namespace QmlJS::Interpreter;
using namespace QmlJS::AST;
-ScopeBuilder::ScopeBuilder(Context *context, Document::Ptr doc)
- : _doc(doc)
- , _context(context)
+ScopeBuilder::ScopeBuilder(ScopeChain *scopeChain)
+ : _scopeChain(scopeChain)
{
}
@@ -69,16 +69,17 @@ void ScopeBuilder::push(AST::Node *node)
case Node::Kind_FunctionExpression:
case Node::Kind_UiPublicMember:
{
- ObjectValue *scope = _doc->bind()->findAttachedJSScope(node);
- if (scope)
- _context->scopeChain().jsScopes += scope;
+ ObjectValue *scope = _scopeChain->document()->bind()->findAttachedJSScope(node);
+ if (scope) {
+ QList<const ObjectValue *> jsScopes = _scopeChain->jsScopes();
+ jsScopes += scope;
+ _scopeChain->setJsScopes(jsScopes);
+ }
break;
}
default:
break;
}
-
- _context->scopeChain().update();
}
void ScopeBuilder::push(const QList<AST::Node *> &nodes)
@@ -99,9 +100,14 @@ void ScopeBuilder::pop()
case Node::Kind_FunctionExpression:
case Node::Kind_UiPublicMember:
{
- ObjectValue *scope = _doc->bind()->findAttachedJSScope(toRemove);
- if (scope)
- _context->scopeChain().jsScopes.removeLast();
+ ObjectValue *scope = _scopeChain->document()->bind()->findAttachedJSScope(toRemove);
+ if (scope) {
+ QList<const ObjectValue *> jsScopes = _scopeChain->jsScopes();
+ if (!jsScopes.isEmpty()) {
+ jsScopes.removeLast();
+ _scopeChain->setJsScopes(jsScopes);
+ }
+ }
break;
}
default:
@@ -112,103 +118,12 @@ void ScopeBuilder::pop()
if (! _nodes.isEmpty()
&& (cast<UiObjectDefinition *>(toRemove) || cast<UiObjectBinding *>(toRemove)))
setQmlScopeObject(_nodes.last());
-
- _context->scopeChain().update();
-}
-
-void ScopeBuilder::initializeRootScope()
-{
- ScopeChain &scopeChain = _context->scopeChain();
- if (scopeChain.qmlComponentScope
- && scopeChain.qmlComponentScope->document == _doc) {
- return;
- }
-
- scopeChain = ScopeChain(); // reset
-
- Interpreter::ValueOwner *valueOwner = _context->valueOwner();
-
- // ### TODO: This object ought to contain the global namespace additions by QML.
- scopeChain.globalScope = valueOwner->globalObject();
-
- if (! _doc) {
- scopeChain.update();
- return;
- }
-
- Bind *bind = _doc->bind();
- QHash<Document *, ScopeChain::QmlComponentChain *> componentScopes;
- const Snapshot &snapshot = _context->snapshot();
-
- ScopeChain::QmlComponentChain *chain = new ScopeChain::QmlComponentChain;
- scopeChain.qmlComponentScope = QSharedPointer<const ScopeChain::QmlComponentChain>(chain);
- if (_doc->qmlProgram()) {
- componentScopes.insert(_doc.data(), chain);
- makeComponentChain(_doc, snapshot, chain, &componentScopes);
-
- if (const Imports *imports = _context->imports(_doc.data())) {
- scopeChain.qmlTypes = imports->typeScope();
- scopeChain.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 && _doc->fileName() == import.name()) {
- ScopeChain::QmlComponentChain *component = new ScopeChain::QmlComponentChain;
- componentScopes.insert(otherDoc.data(), component);
- chain->instantiatingComponents += component;
- makeComponentChain(otherDoc, snapshot, component, &componentScopes);
- }
- }
- }
-
- // ### TODO: Which type environment do scripts see?
-
- if (bind->rootObjectValue())
- scopeChain.jsScopes += bind->rootObjectValue();
- }
-
- scopeChain.update();
-}
-
-void ScopeBuilder::makeComponentChain(
- Document::Ptr doc,
- const Snapshot &snapshot,
- ScopeChain::QmlComponentChain *target,
- QHash<Document *, ScopeChain::QmlComponentChain *> *components)
-{
- if (!doc->qmlProgram())
- return;
-
- 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(), _context)) {
- 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, snapshot, component, components);
- }
- }
- }
-
- // build this component scope
- target->document = doc;
}
void ScopeBuilder::setQmlScopeObject(Node *node)
{
- ScopeChain &scopeChain = _context->scopeChain();
-
- if (_doc->bind()->isGroupedPropertyBinding(node)) {
+ QList<const ObjectValue *> qmlScopeObjects;
+ if (_scopeChain->document()->bind()->isGroupedPropertyBinding(node)) {
UiObjectDefinition *definition = cast<UiObjectDefinition *>(node);
if (!definition)
return;
@@ -219,21 +134,21 @@ void ScopeBuilder::setQmlScopeObject(Node *node)
if (!object)
return;
- scopeChain.qmlScopeObjects.clear();
- scopeChain.qmlScopeObjects += object;
+ qmlScopeObjects += object;
+ _scopeChain->setQmlScopeObjects(qmlScopeObjects);
+ return;
}
- const ObjectValue *scopeObject = _doc->bind()->findQmlObject(node);
+ const ObjectValue *scopeObject = _scopeChain->document()->bind()->findQmlObject(node);
if (scopeObject) {
- scopeChain.qmlScopeObjects.clear();
- scopeChain.qmlScopeObjects += scopeObject;
+ qmlScopeObjects += scopeObject;
} else {
return; // Probably syntax errors, where we're working with a "recovered" AST.
}
// check if the object has a Qt.ListElement or Qt.Connections ancestor
// ### allow only signal bindings for Connections
- PrototypeIterator iter(scopeObject, _context);
+ PrototypeIterator iter(scopeObject, _scopeChain->context());
iter.next();
while (iter.hasNext()) {
const ObjectValue *prototype = iter.next();
@@ -242,15 +157,15 @@ void ScopeBuilder::setQmlScopeObject(Node *node)
|| qmlMetaObject->className() == QLatin1String("Connections")
) && (qmlMetaObject->packageName() == QLatin1String("Qt")
|| qmlMetaObject->packageName() == QLatin1String("QtQuick"))) {
- scopeChain.qmlScopeObjects.clear();
+ qmlScopeObjects.clear();
break;
}
}
}
// check if the object has a Qt.PropertyChanges ancestor
- const ObjectValue *prototype = scopeObject->prototype(_context);
- prototype = isPropertyChangesObject(_context, prototype);
+ const ObjectValue *prototype = scopeObject->prototype(_scopeChain->context());
+ prototype = isPropertyChangesObject(_scopeChain->context(), prototype);
// find the target script binding
if (prototype) {
UiObjectInitializer *initializer = 0;
@@ -264,31 +179,33 @@ void ScopeBuilder::setQmlScopeObject(Node *node)
if (scriptBinding->qualifiedId && scriptBinding->qualifiedId->name
&& scriptBinding->qualifiedId->name->asString() == QLatin1String("target")
&& ! scriptBinding->qualifiedId->next) {
- Evaluate evaluator(_context);
+ Evaluate evaluator(_scopeChain);
const Value *targetValue = evaluator(scriptBinding->statement);
if (const ObjectValue *target = value_cast<const ObjectValue *>(targetValue)) {
- scopeChain.qmlScopeObjects.prepend(target);
+ qmlScopeObjects.prepend(target);
} else {
- scopeChain.qmlScopeObjects.clear();
+ qmlScopeObjects.clear();
}
}
}
}
}
}
+
+ _scopeChain->setQmlScopeObjects(qmlScopeObjects);
}
const Value *ScopeBuilder::scopeObjectLookup(AST::UiQualifiedId *id)
{
// do a name lookup on the scope objects
const Value *result = 0;
- foreach (const ObjectValue *scopeObject, _context->scopeChain().qmlScopeObjects) {
+ foreach (const ObjectValue *scopeObject, _scopeChain->qmlScopeObjects()) {
const ObjectValue *object = scopeObject;
for (UiQualifiedId *it = id; it; it = it->next) {
if (!it->name)
return 0;
- result = object->lookupMember(it->name->asString(), _context);
+ result = object->lookupMember(it->name->asString(), _scopeChain->context());
if (!result)
break;
if (it->next) {
diff --git a/src/libs/qmljs/qmljsscopebuilder.h b/src/libs/qmljs/qmljsscopebuilder.h
index c565a55e129..34982da9a8e 100644
--- a/src/libs/qmljs/qmljsscopebuilder.h
+++ b/src/libs/qmljs/qmljsscopebuilder.h
@@ -34,12 +34,19 @@
#define QMLJSSCOPEBUILDER_H
#include <qmljs/qmljsdocument.h>
-#include <qmljs/qmljsinterpreter.h>
#include <QtCore/QList>
namespace QmlJS {
+namespace Interpreter {
+class QmlComponentChain;
+class Context;
+class ObjectValue;
+class Value;
+class ScopeChain;
+}
+
namespace AST {
class Node;
}
@@ -47,11 +54,9 @@ namespace AST {
class QMLJS_EXPORT ScopeBuilder
{
public:
- ScopeBuilder(Interpreter::Context *context, Document::Ptr doc);
+ ScopeBuilder(Interpreter::ScopeChain *scopeChain);
~ScopeBuilder();
- void initializeRootScope();
-
void push(AST::Node *node);
void push(const QList<AST::Node *> &nodes);
void pop();
@@ -59,15 +64,10 @@ public:
static const Interpreter::ObjectValue *isPropertyChangesObject(const Interpreter::Context *context, const Interpreter::ObjectValue *object);
private:
- void makeComponentChain(Document::Ptr doc, const Snapshot &snapshot,
- Interpreter::ScopeChain::QmlComponentChain *target,
- QHash<Document *, Interpreter::ScopeChain::QmlComponentChain *> *components);
-
void setQmlScopeObject(AST::Node *node);
const Interpreter::Value *scopeObjectLookup(AST::UiQualifiedId *id);
- Document::Ptr _doc;
- Interpreter::Context *_context;
+ Interpreter::ScopeChain *_scopeChain;
QList<AST::Node *> _nodes;
};
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);
+ }
+ }
+ }
+}
+
diff --git a/src/libs/qmljs/qmljsscopechain.h b/src/libs/qmljs/qmljsscopechain.h
new file mode 100644
index 00000000000..b937cc6809a
--- /dev/null
+++ b/src/libs/qmljs/qmljsscopechain.h
@@ -0,0 +1,127 @@
+/**************************************************************************
+**
+** 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].
+**
+**************************************************************************/
+
+#ifndef QMLJS_SCOPECHAIN_H
+#define QMLJS_SCOPECHAIN_H
+
+#include "qmljs_global.h"
+#include "qmljsdocument.h"
+#include "qmljscontext.h"
+
+#include <QtCore/QList>
+#include <QtCore/QSharedPointer>
+
+namespace QmlJS {
+namespace Interpreter {
+
+class ObjectValue;
+class TypeScope;
+class JSImportScope;
+class Context;
+class Value;
+
+class QMLJS_EXPORT QmlComponentChain
+{
+ Q_DISABLE_COPY(QmlComponentChain)
+public:
+ QmlComponentChain(const Document::Ptr &document);
+ ~QmlComponentChain();
+
+ Document::Ptr document() const;
+ QList<const QmlComponentChain *> instantiatingComponents() const;
+
+ // takes ownership
+ void addInstantiatingComponent(const QmlComponentChain *component);
+
+private:
+ QList<const QmlComponentChain *> m_instantiatingComponents;
+ Document::Ptr m_document;
+};
+
+// scope chains are copyable
+// constructing a new scope chain is currently too expensive:
+// building the instantiating component chain needs to be sped up
+class QMLJS_EXPORT ScopeChain
+{
+public:
+ explicit ScopeChain(const Document::Ptr &document, const Context *context);
+
+ Document::Ptr document() const;
+ const Context *context() const;
+
+ const Value *lookup(const QString &name, const ObjectValue **foundInScope = 0) const;
+
+ const ObjectValue *globalScope() const;
+ void setGlobalScope(const ObjectValue *globalScope);
+
+ QSharedPointer<const QmlComponentChain> qmlComponentChain() const;
+ void setQmlComponentChain(const QSharedPointer<const QmlComponentChain> &qmlComponentChain);
+
+ QList<const ObjectValue *> qmlScopeObjects() const;
+ void setQmlScopeObjects(const QList<const ObjectValue *> &qmlScopeObjects);
+
+ const TypeScope *qmlTypes() const;
+ void setQmlTypes(const TypeScope *qmlTypes);
+
+ const JSImportScope *jsImports() const;
+ void setJsImports(const JSImportScope *jsImports);
+
+ QList<const ObjectValue *> jsScopes() const;
+ void setJsScopes(const QList<const ObjectValue *> &jsScopes);
+
+ QList<const ObjectValue *> all() const;
+
+private:
+ void update() const;
+ void initializeRootScope();
+ void makeComponentChain(QmlComponentChain *target, const Snapshot &snapshot,
+ QHash<Document *, QmlComponentChain *> *components);
+
+
+ Document::Ptr m_document;
+ const Context *m_context;
+
+ const ObjectValue *m_globalScope;
+ QSharedPointer<const QmlComponentChain> m_qmlComponentScope;
+ QList<const ObjectValue *> m_qmlScopeObjects;
+ const TypeScope *m_qmlTypes;
+ const JSImportScope *m_jsImports;
+ QList<const ObjectValue *> m_jsScopes;
+
+ bool m_modified;
+ mutable QList<const ObjectValue *> m_all;
+};
+
+} // namespace Interpreter
+} // namespace QmlJS
+
+#endif // QMLJS_SCOPECHAIN_H