summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorChristian Kamm <christian.d.kamm@nokia.com>2011-07-12 14:55:27 +0200
committerChristian Kamm <christian.d.kamm@nokia.com>2011-08-08 12:05:03 +0200
commitf87dc6198609abdb58b430cf272a4e6ca7144865 (patch)
tree738d7024efedab5254676139ca456631e334c78a /src
parented1321a4f95d4ecbbd96794ec355cfc7984cfb2d (diff)
downloadqt-creator-f87dc6198609abdb58b430cf272a4e6ca7144865.tar.gz
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 <fawzi.mohamed@nokia.com>
Diffstat (limited to 'src')
-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
-rw-r--r--src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp17
-rw-r--r--src/plugins/qmljseditor/qmljscompletionassist.cpp26
-rw-r--r--src/plugins/qmljseditor/qmljseditor.cpp2
-rw-r--r--src/plugins/qmljseditor/qmljsfindreferences.cpp80
-rw-r--r--src/plugins/qmljseditor/qmljshoverhandler.cpp6
-rw-r--r--src/plugins/qmljseditor/quicktoolbar.cpp2
22 files changed, 670 insertions, 415 deletions
diff --git a/src/libs/qmljs/qmljs-lib.pri b/src/libs/qmljs/qmljs-lib.pri
index 47488948a0..7532a24eb2 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 1a4bafb350..149812bbbe 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 68849e1adc..8924bbaabb 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 5fb2c8bcce..84a0977c56 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 ab914cbfa9..2d659c0ccb 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 bd5c4cf03d..5d28c5872a 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 410d3d3a38..973144fbd5 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 b7fc24fabe..d7316449bd 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 1002f96162..d44c6065fd 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 85a49a5ee6..c88e7aaa79 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 04cc68938f..389a23fb86 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 ce4199e092..f71ae80284 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 10f18e6a80..90e97502df 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 c565a55e12..34982da9a8 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 0000000000..2b5cda90f8
--- /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 (info@qt.nokia.com)
+**
+**
+** 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 info@qt.nokia.com.
+**
+**************************************************************************/
+
+#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 0000000000..b937cc6809
--- /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 (info@qt.nokia.com)
+**
+**
+** 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 info@qt.nokia.com.
+**
+**************************************************************************/
+
+#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
diff --git a/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp b/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp
index 461745619f..5db49ed733 100644
--- a/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp
+++ b/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp
@@ -50,6 +50,7 @@
#include <qmljs/qmljscontext.h>
#include <qmljs/qmljslink.h>
#include <qmljs/qmljsscopebuilder.h>
+#include <qmljs/qmljsscopechain.h>
#include <qmljs/parser/qmljsast_p.h>
#include <qmljs/qmljscheck.h>
#include <qmljs/qmljsmodelmanagerinterface.h>
@@ -336,11 +337,10 @@ public:
, m_link(snapshot, importPaths,
QmlJS::ModelManagerInterface::instance()->builtins(doc))
, m_context(new Interpreter::Context(m_link(doc, &m_diagnosticLinkMessages)))
- , m_scopeBuilder(m_context, doc)
+ , m_scopeChain(doc, m_context)
+ , m_scopeBuilder(&m_scopeChain)
{
m_lookupContext = LookupContext::create(doc, *m_context, QList<AST::Node*>());
- // cheaper than calling m_scopeBuilder.initializeRootScope() again
- *m_context = *m_lookupContext->context();
}
~ReadingContext()
@@ -407,7 +407,7 @@ public:
/// ### Maybe put this into the context as a helper method.
bool lookupProperty(const QString &prefix, const UiQualifiedId *id, const Interpreter::Value **property = 0, const Interpreter::ObjectValue **parentObject = 0, QString *name = 0)
{
- QList<const Interpreter::ObjectValue *> scopeObjects = m_context->scopeChain().qmlScopeObjects;
+ QList<const Interpreter::ObjectValue *> scopeObjects = m_scopeChain.qmlScopeObjects();
if (scopeObjects.isEmpty())
return false;
@@ -433,7 +433,7 @@ public:
bool isAttachedProperty = false;
if (! propertyName.isEmpty() && propertyName[0].isUpper()) {
isAttachedProperty = true;
- if (const Interpreter::ObjectValue *qmlTypes = m_context->scopeChain().qmlTypes)
+ if (const Interpreter::ObjectValue *qmlTypes = m_scopeChain.qmlTypes())
scopeObjects += qmlTypes;
}
@@ -594,12 +594,12 @@ public:
const Interpreter::ObjectValue *rhsValueObject = 0;
QString rhsValueName;
if (IdentifierExpression *idExp = cast<IdentifierExpression *>(eStmt->expression)) {
- if (!m_context->scopeChain().qmlScopeObjects.isEmpty())
- rhsValueObject = m_context->scopeChain().qmlScopeObjects.last();
+ if (!m_scopeChain.qmlScopeObjects().isEmpty())
+ rhsValueObject = m_scopeChain.qmlScopeObjects().last();
if (idExp->name)
rhsValueName = idExp->name->asString();
} else if (FieldMemberExpression *memberExp = cast<FieldMemberExpression *>(eStmt->expression)) {
- Evaluate evaluate(m_context);
+ Evaluate evaluate(&m_scopeChain);
const Interpreter::Value *result = evaluate(memberExp->base);
rhsValueObject = result->asObjectValue();
@@ -634,6 +634,7 @@ private:
QList<DiagnosticMessage> m_diagnosticLinkMessages;
Interpreter::Context *m_context;
LookupContext::Ptr m_lookupContext;
+ Interpreter::ScopeChain m_scopeChain;
ScopeBuilder m_scopeBuilder;
};
diff --git a/src/plugins/qmljseditor/qmljscompletionassist.cpp b/src/plugins/qmljseditor/qmljscompletionassist.cpp
index 031447eb5f..a2079ccac5 100644
--- a/src/plugins/qmljseditor/qmljscompletionassist.cpp
+++ b/src/plugins/qmljseditor/qmljscompletionassist.cpp
@@ -48,6 +48,7 @@
#include <qmljs/parser/qmljsast_p.h>
#include <qmljs/qmljsinterpreter.h>
#include <qmljs/qmljscontext.h>
+#include <qmljs/qmljsscopechain.h>
#include <qmljs/qmljslookupcontext.h>
#include <qmljs/qmljsscanner.h>
#include <qmljs/qmljsbind.h>
@@ -86,15 +87,15 @@ class EnumerateProperties: private Interpreter::MemberProcessor
bool _globalCompletion;
bool _enumerateGeneratedSlots;
bool _enumerateSlots;
- const Interpreter::Context *_context;
+ const Interpreter::ScopeChain *_scopeChain;
const Interpreter::ObjectValue *_currentObject;
public:
- EnumerateProperties(const Interpreter::Context *context)
+ EnumerateProperties(const Interpreter::ScopeChain *scopeChain)
: _globalCompletion(false),
_enumerateGeneratedSlots(false),
_enumerateSlots(true),
- _context(context),
+ _scopeChain(scopeChain),
_currentObject(0)
{
}
@@ -131,7 +132,7 @@ public:
_properties.clear();
_currentObject = 0;
- foreach (const Interpreter::ObjectValue *scope, _context->scopeChain().all())
+ foreach (const Interpreter::ObjectValue *scope, _scopeChain->all())
enumerateProperties(scope);
return _properties;
@@ -192,7 +193,7 @@ private:
return;
_processed.insert(object);
- enumerateProperties(object->prototype(_context));
+ enumerateProperties(object->prototype(_scopeChain->context()));
object->processMembers(this);
}
@@ -422,6 +423,7 @@ IAssistProposal *QmlJSCompletionAssistProcessor::perform(const IAssistInterface
const QList<AST::Node *> path = semanticInfo.rangePath(m_interface->position());
LookupContext::Ptr lookupContext = semanticInfo.lookupContext(path);
const Interpreter::Context *context = lookupContext->context();
+ const Interpreter::ScopeChain &scopeChain = lookupContext->scopeChain();
// Search for the operator that triggered the completion.
QChar completionOperator;
@@ -521,7 +523,7 @@ IAssistProposal *QmlJSCompletionAssistProcessor::perform(const IAssistInterface
doJsKeywordCompletion = false;
doQmlTypeCompletion = true;
- EnumerateProperties enumerateProperties(context);
+ EnumerateProperties enumerateProperties(&scopeChain);
enumerateProperties.setGlobalCompletion(true);
enumerateProperties.setEnumerateGeneratedSlots(true);
enumerateProperties.setEnumerateSlots(false);
@@ -539,8 +541,8 @@ IAssistProposal *QmlJSCompletionAssistProcessor::perform(const IAssistInterface
contextFinder.isAfterOnInLhsOfBinding());
if (ScopeBuilder::isPropertyChangesObject(context, qmlScopeType)
- && context->scopeChain().qmlScopeObjects.size() == 2) {
- addCompletions(enumerateProperties(context->scopeChain().qmlScopeObjects.first()),
+ && scopeChain.qmlScopeObjects().size() == 2) {
+ addCompletions(enumerateProperties(scopeChain.qmlScopeObjects().first()),
m_interface->symbolIcon(),
SymbolOrder);
}
@@ -564,15 +566,15 @@ IAssistProposal *QmlJSCompletionAssistProcessor::perform(const IAssistInterface
doQmlTypeCompletion = true;
if (doQmlTypeCompletion) {
- if (const Interpreter::ObjectValue *qmlTypes = context->scopeChain().qmlTypes) {
- EnumerateProperties enumerateProperties(context);
+ if (const Interpreter::ObjectValue *qmlTypes = scopeChain.qmlTypes()) {
+ EnumerateProperties enumerateProperties(&scopeChain);
addCompletions(enumerateProperties(qmlTypes), m_interface->symbolIcon(), TypeOrder);
}
}
if (doGlobalCompletion) {
// It's a global completion.
- EnumerateProperties enumerateProperties(context);
+ EnumerateProperties enumerateProperties(&scopeChain);
enumerateProperties.setGlobalCompletion(true);
addCompletions(enumerateProperties(), m_interface->symbolIcon(), SymbolOrder);
}
@@ -619,7 +621,7 @@ IAssistProposal *QmlJSCompletionAssistProcessor::perform(const IAssistInterface
//qDebug() << "type:" << interp->typeId(value);
if (value && completionOperator == QLatin1Char('.')) { // member completion
- EnumerateProperties enumerateProperties(context);
+ EnumerateProperties enumerateProperties(&scopeChain);
if (contextFinder.isInLhsOfBinding() && qmlScopeType) {
enumerateProperties.setEnumerateGeneratedSlots(true);
addCompletionsPropertyLhs(enumerateProperties(value),
diff --git a/src/plugins/qmljseditor/qmljseditor.cpp b/src/plugins/qmljseditor/qmljseditor.cpp
index ebfdf17f0c..1e722884bb 100644
--- a/src/plugins/qmljseditor/qmljseditor.cpp
+++ b/src/plugins/qmljseditor/qmljseditor.cpp
@@ -1260,7 +1260,7 @@ TextEditor::BaseTextEditorWidget::Link QmlJSTextEditorWidget::findLinkAt(const Q
}
LookupContext::Ptr lookupContext = semanticInfo.lookupContext(semanticInfo.rangePath(cursorPosition));
- Evaluate evaluator(lookupContext->context());
+ Evaluate evaluator(&lookupContext->scopeChain());
const Interpreter::Value *value = evaluator.reference(node);
QString fileName;
diff --git a/src/plugins/qmljseditor/qmljsfindreferences.cpp b/src/plugins/qmljseditor/qmljsfindreferences.cpp
index 436af01a5f..1921ebc95d 100644
--- a/src/plugins/qmljseditor/qmljsfindreferences.cpp
+++ b/src/plugins/qmljseditor/qmljsfindreferences.cpp
@@ -80,10 +80,9 @@ public:
FindUsages(Document::Ptr doc, Context *context)
: _doc(doc)
- , _context(context)
- , _builder(context, doc)
+ , _scopeChain(doc, context)
+ , _builder(&_scopeChain)
{
- _builder.initializeRootScope();
}
Result operator()(const QString &name, const ObjectValue *scope)
@@ -106,7 +105,7 @@ protected:
{
if (node->name
&& node->name->asString() == _name
- && _context->scopeChain().qmlScopeObjects.contains(_scope)) {
+ && _scopeChain.qmlScopeObjects().contains(_scope)) {
_usages.append(node->identifierToken);
}
if (AST::cast<Block *>(node->statement)) {
@@ -176,7 +175,7 @@ protected:
return false;
const ObjectValue *scope;
- _context->lookup(_name, &scope);
+ _scopeChain.lookup(_name, &scope);
if (!scope)
return false;
if (check(scope)) {
@@ -188,14 +187,14 @@ protected:
// so it might still be a use - we just found a different value in a different scope first
// if scope is one of these, our match wasn't inside the instantiating components list
- const ScopeChain &chain = _context->scopeChain();
- if (chain.jsScopes.contains(scope)
- || chain.qmlScopeObjects.contains(scope)
- || chain.qmlTypes == scope
- || chain.globalScope == scope)
+ const ScopeChain &chain = _scopeChain;
+ if (chain.jsScopes().contains(scope)
+ || chain.qmlScopeObjects().contains(scope)
+ || chain.qmlTypes() == scope
+ || chain.globalScope() == scope)
return false;
- if (contains(chain.qmlComponentScope.data()))
+ if (contains(chain.qmlComponentChain().data()))
_usages.append(node->identifierToken);
return false;
@@ -206,7 +205,7 @@ protected:
if (!node->name || node->name->asString() != _name)
return true;
- Evaluate evaluate(_context);
+ Evaluate evaluate(&_scopeChain);
const Value *lhsValue = evaluate(node->base);
if (!lhsValue)
return true;
@@ -245,19 +244,19 @@ protected:
}
private:
- bool contains(const ScopeChain::QmlComponentChain *chain)
+ bool contains(const QmlComponentChain *chain)
{
- if (!chain || !chain->document)
+ if (!chain || !chain->document())
return false;
- if (chain->document->bind()->idEnvironment()->lookupMember(_name, _context))
- return chain->document->bind()->idEnvironment() == _scope;
- const ObjectValue *root = chain->document->bind()->rootObjectValue();
- if (root->lookupMember(_name, _context)) {
+ if (chain->document()->bind()->idEnvironment()->lookupMember(_name, _scopeChain.context()))
+ return chain->document()->bind()->idEnvironment() == _scope;
+ const ObjectValue *root = chain->document()->bind()->rootObjectValue();
+ if (root->lookupMember(_name, _scopeChain.context())) {
return check(root);
}
- foreach (const ScopeChain::QmlComponentChain *parent, chain->instantiatingComponents) {
+ foreach (const QmlComponentChain *parent, chain->instantiatingComponents()) {
if (contains(parent))
return true;
}
@@ -269,13 +268,13 @@ private:
if (!s)
return false;
const ObjectValue *definingObject;
- s->lookupMember(_name, _context, &definingObject);
+ s->lookupMember(_name, _scopeChain.context(), &definingObject);
return definingObject == _scope;
}
bool checkQmlScope()
{
- foreach (const ObjectValue *s, _context->scopeChain().qmlScopeObjects) {
+ foreach (const ObjectValue *s, _scopeChain.qmlScopeObjects()) {
if (check(s))
return true;
}
@@ -285,14 +284,14 @@ private:
bool checkLookup()
{
const ObjectValue *scope = 0;
- _context->lookup(_name, &scope);
+ _scopeChain.lookup(_name, &scope);
return check(scope);
}
Result _usages;
Document::Ptr _doc;
- Context *_context;
+ ScopeChain _scopeChain;
ScopeBuilder _builder;
QString _name;
@@ -307,9 +306,9 @@ public:
FindTypeUsages(Document::Ptr doc, Context *context)
: _doc(doc)
, _context(context)
- , _builder(context, doc)
+ , _scopeChain(doc, context)
+ , _builder(&_scopeChain)
{
- _builder.initializeRootScope();
}
Result operator()(const QString &name, const ObjectValue *typeValue)
@@ -380,7 +379,7 @@ protected:
return false;
const ObjectValue *scope;
- const Value *objV = _context->lookup(_name, &scope);
+ const Value *objV = _scopeChain.lookup(_name, &scope);
if (objV == _typeValue)
_usages.append(node->identifierToken);
return false;
@@ -390,7 +389,7 @@ protected:
{
if (!node->name || node->name->asString() != _name)
return true;
- Evaluate evaluate(_context);
+ Evaluate evaluate(&_scopeChain);
const Value *lhsValue = evaluate(node->base);
if (!lhsValue)
return true;
@@ -452,6 +451,7 @@ private:
Document::Ptr _doc;
Context *_context;
+ ScopeChain _scopeChain;
ScopeBuilder _builder;
QString _name;
@@ -466,8 +466,8 @@ public:
TypeKind
};
- FindTargetExpression(Document::Ptr doc, Context *context)
- : _doc(doc), _context(context)
+ FindTargetExpression(Document::Ptr doc, const ScopeChain *scopeChain)
+ : _doc(doc), _scopeChain(scopeChain)
{
}
@@ -488,7 +488,7 @@ public:
const ObjectValue *scope()
{
if (!_scope)
- _context->lookup(_name, &_scope);
+ _scopeChain->lookup(_name, &_scope);
return _scope;
}
@@ -524,7 +524,7 @@ protected:
_name = node->name->asString();
if ((!_name.isEmpty()) && _name.at(0).isUpper()) {
// a possible type
- _targetValue = _context->lookup(_name, &_scope);
+ _targetValue = _scopeChain->lookup(_name, &_scope);
if (value_cast<const ObjectValue*>(_targetValue))
_typeKind = TypeKind;
}
@@ -539,14 +539,14 @@ protected:
_name = node->name->asString();
if ((!_name.isEmpty()) && _name.at(0).isUpper()) {
// a possible type
- Evaluate evaluate(_context);
+ Evaluate evaluate(_scopeChain);
const Value *lhsValue = evaluate(node->base);
if (!lhsValue)
return true;
const ObjectValue *lhsObj = lhsValue->asObjectValue();
if (lhsObj) {
_scope = lhsObj;
- _targetValue = lhsObj->lookupMember(_name, _context);
+ _targetValue = lhsObj->lookupMember(_name, _scopeChain->context());
_typeKind = TypeKind;
}
}
@@ -593,7 +593,7 @@ protected:
if (containsOffset(node->typeToken)){
if (node->memberType){
_name = node->memberType->asString();
- _targetValue = _context->lookupType(_doc.data(), QStringList(_name));
+ _targetValue = _scopeChain->context()->lookupType(_doc.data(), QStringList(_name));
_scope = 0;
_typeKind = TypeKind;
}
@@ -654,7 +654,7 @@ private:
{
for (UiQualifiedId *att = id; att; att = att->next) {
if (att->name && containsOffset(att->identifierToken)) {
- _targetValue = _context->lookupType(_doc.data(), id, att->next);
+ _targetValue = _scopeChain->context()->lookupType(_doc.data(), id, att->next);
_scope = 0;
_name = att->name->asString();
_typeKind = TypeKind;
@@ -666,7 +666,7 @@ private:
void setScope(Node *node)
{
- Evaluate evaluate(_context);
+ Evaluate evaluate(_scopeChain);
const Value *v = evaluate(node);
if (v)
_scope = v->asObjectValue();
@@ -677,7 +677,7 @@ private:
const Value *_targetValue;
Node *_objectNode;
Document::Ptr _doc;
- Context *_context;
+ const ScopeChain *_scopeChain;
quint32 _offset;
Kind _typeKind;
};
@@ -823,12 +823,12 @@ static void find_helper(QFutureInterface<FindReferences::Usage> &future,
Link link(snapshot, modelManager->importPaths(), modelManager->builtins(doc));
Context context = link();
- ScopeBuilder builder(&context, doc);
- builder.initializeRootScope();
+ ScopeChain scopeChain(doc, &context);
+ ScopeBuilder builder(&scopeChain);
ScopeAstPath astPath(doc);
builder.push(astPath(offset));
- FindTargetExpression findTarget(doc, &context);
+ FindTargetExpression findTarget(doc, &scopeChain);
findTarget(offset);
const QString &name = findTarget.name();
if (name.isEmpty())
diff --git a/src/plugins/qmljseditor/qmljshoverhandler.cpp b/src/plugins/qmljseditor/qmljshoverhandler.cpp
index ee7a17deb1..57f1921f4b 100644
--- a/src/plugins/qmljseditor/qmljshoverhandler.cpp
+++ b/src/plugins/qmljseditor/qmljshoverhandler.cpp
@@ -186,7 +186,7 @@ bool HoverHandler::matchColorItem(const LookupContext::Ptr &lookupContext,
} else if (const AST::UiPublicMember *publicMember =
AST::cast<const AST::UiPublicMember *>(member)) {
if (publicMember->name && posIsInSource(pos, publicMember->statement)) {
- value = lookupContext->context()->lookup(publicMember->name->asString());
+ value = lookupContext->scopeChain().lookup(publicMember->name->asString());
if (const Interpreter::Reference *ref = value->asReference())
value = lookupContext->context()->lookupReference(ref);
color = textAt(qmlDocument,
@@ -306,7 +306,7 @@ static const Interpreter::ObjectValue *isMember(const LookupContext::Ptr &lookup
if (!identExp->name)
return 0;
*name = identExp->name->asString();
- lookupContext->context()->lookup(*name, &owningObject);
+ lookupContext->scopeChain().lookup(*name, &owningObject);
} else if (AST::FieldMemberExpression *fme = AST::cast<AST::FieldMemberExpression *>(node)) {
if (!fme->base || !fme->name)
return 0;
@@ -321,7 +321,7 @@ static const Interpreter::ObjectValue *isMember(const LookupContext::Ptr &lookup
if (!qid->name)
return 0;
*name = qid->name->asString();
- const Interpreter::Value *value = lookupContext->context()->lookup(*name, &owningObject);
+ const Interpreter::Value *value = lookupContext->scopeChain().lookup(*name, &owningObject);
for (AST::UiQualifiedId *it = qid->next; it; it = it->next) {
if (!value)
return 0;
diff --git a/src/plugins/qmljseditor/quicktoolbar.cpp b/src/plugins/qmljseditor/quicktoolbar.cpp
index 4d86052feb..9c4fe1a372 100644
--- a/src/plugins/qmljseditor/quicktoolbar.cpp
+++ b/src/plugins/qmljseditor/quicktoolbar.cpp
@@ -78,7 +78,7 @@ static inline const Interpreter::ObjectValue * getPropertyChangesTarget(Node *no
if (scriptBinding->qualifiedId
&& scriptBinding->qualifiedId->name->asString() == QLatin1String("target")
&& ! scriptBinding->qualifiedId->next) {
- Evaluate evaluator(lookupContext->context());
+ Evaluate evaluator(&lookupContext->scopeChain());
const Interpreter::Value *targetValue = evaluator(scriptBinding->statement);
if (const Interpreter::ObjectValue *targetObject = Interpreter::value_cast<const Interpreter::ObjectValue *>(targetValue)) {
return targetObject;