Bind each QML document after parsing. Link them before use.

Reviewed-by: Roberto Raggi <roberto.raggi@nokia.com>
This commit is contained in:
Christian Kamm
2010-02-02 15:55:17 +01:00
parent e7a330f92a
commit 03fa188b41
8 changed files with 321 additions and 315 deletions

View File

@@ -121,76 +121,27 @@ public:
}
};
class ProcessSourceElements: protected AST::Visitor
{
Interpreter::Engine *_interp;
public:
ProcessSourceElements(Interpreter::Engine *interp)
: _interp(interp),
typeOfExpression(interp)
{
}
void operator()(AST::Node *node)
{
if (node)
node->accept(this);
}
protected:
using AST::Visitor::visit;
virtual bool visit(FunctionDeclaration *ast)
{
if (ast->name)
_interp->globalObject()->setProperty(ast->name->asString(), new ASTFunctionValue(ast, _interp));
return false;
}
virtual bool visit(VariableDeclaration *ast)
{
if (ast->name) {
const Value *value = _interp->undefinedValue();
if (ast->expression)
value = typeOfExpression(ast->expression, _interp->globalObject());
_interp->globalObject()->setProperty(ast->name->asString(), value);
}
return false;
}
Check typeOfExpression;
};
} // end of anonymous namespace
Bind::Bind(Document::Ptr doc, Interpreter::Engine *interp)
Bind::Bind(Document *doc)
: _doc(doc),
_interp(interp),
_currentObjectValue(0),
_typeEnvironment(0),
_idEnvironment(0),
_functionEnvironment(0),
_rootObjectValue(0)
{
if (_doc && _doc->qmlProgram() != 0) {
UiProgram *program = _doc->qmlProgram();
if (!_doc)
return;
_currentObjectValue = 0;
_typeEnvironment = _interp->newObject(/*prototype =*/ 0);
_idEnvironment = _interp->newObject(/*prototype =*/ 0);
_functionEnvironment = _interp->newObject(/*prototype =*/ 0);
_rootObjectValue = 0;
_qmlObjectDefinitions.clear();
_qmlObjectBindings.clear();
accept(program);
if (_doc->qmlProgram()) {
_idEnvironment = _interp.newObject(/*prototype =*/ 0);
_functionEnvironment = _interp.newObject(/*prototype =*/ 0);
} else if (_doc->jsProgram()) {
_currentObjectValue = _interp.globalObject();
_rootObjectValue = _interp.globalObject();
}
accept(_doc->ast());
}
Bind::~Bind()
@@ -214,77 +165,6 @@ ObjectValue *Bind::switchObjectValue(ObjectValue *newObjectValue)
return oldObjectValue;
}
ObjectValue *Bind::scopeChainAt(Document::Ptr currentDocument, const Snapshot &snapshot,
Interpreter::Engine *interp, AST::UiObjectMember *currentObject)
{
Bind *currentBind = 0;
QList<Bind *> binds;
QSet<QString> processed;
QStringList todo;
QMultiHash<QString, Document::Ptr> documentByPath;
foreach (Document::Ptr doc, snapshot)
documentByPath.insert(doc->path(), doc);
todo.append(currentDocument->path());
// Bind the reachable documents.
while (! todo.isEmpty()) {
const QString path = todo.takeFirst();
if (processed.contains(path))
continue;
processed.insert(path);
QStringList localImports;
foreach (Document::Ptr doc, documentByPath.values(path)) {
Bind *newBind = new Bind(doc, interp);
binds += newBind;
localImports += newBind->localImports();
if (doc == currentDocument)
currentBind = newBind;
}
localImports.removeDuplicates();
todo += localImports;
}
LinkImports linkImports;
Link link;
// link the import directives
linkImports(binds);
// link the scripts
QStringList includedScriptFiles;
foreach (Bind *bind, binds)
includedScriptFiles += bind->includedScripts();
includedScriptFiles.removeDuplicates();
ProcessSourceElements processSourceElements(interp);
foreach (const QString &scriptFile, includedScriptFiles) {
if (Document::Ptr scriptDoc = snapshot.document(scriptFile)) {
if (AST::Program *program = scriptDoc->jsProgram()) {
processSourceElements(program);
}
}
}
ObjectValue *scope = interp->globalObject();
if (currentBind)
scope = link(binds, currentBind, currentObject);
qDeleteAll(binds);
return scope;
}
QString Bind::toString(UiQualifiedId *qualifiedId, QChar delimiter)
{
QString result;
@@ -350,7 +230,7 @@ ObjectValue *Bind::bindObject(UiQualifiedId *qualifiedTypeNameId, UiObjectInitia
}
// normal component instance
ASTObjectValue *objectValue = new ASTObjectValue(qualifiedTypeNameId, initializer, _interp);
ASTObjectValue *objectValue = new ASTObjectValue(qualifiedTypeNameId, initializer, &_interp);
parentObjectValue = switchObjectValue(objectValue);
if (parentObjectValue)
@@ -368,64 +248,9 @@ void Bind::accept(Node *node)
Node::accept(node, this);
}
/*
import Qt 4.6
import Qt 4.6 as Xxx
(import com.nokia.qt is the same as the ones above)
import "content"
import "content" as Xxx
import "content" 4.6
import "content" 4.6 as Xxx
import "http://www.ovi.com/" as Ovi
*/
// ### TODO: Move to LinkImports
bool Bind::visit(UiImport *ast)
{
if (! (ast->importUri || ast->fileName))
return false; // nothing to do.
ObjectValue *namespaceObject = 0;
if (ast->asToken.isValid()) { // with namespace we insert an object in the type env. to hold the imported types
if (!ast->importId)
return false; // this should never happen, but better be safe than sorry
namespaceObject = _interp->newObject(/*prototype */ 0);
_typeEnvironment->setProperty(ast->importId->asString(), namespaceObject);
} else { // without namespace we insert all types directly into the type env.
namespaceObject = _typeEnvironment;
}
// look at files first
// else try the metaobject system
if (ast->importUri) {
const QString package = toString(ast->importUri, '/');
int majorVersion = -1; // ### TODO: Check these magic version numbers
int minorVersion = -1; // ### TODO: Check these magic version numbers
if (ast->versionToken.isValid()) {
const QString versionString = _doc->source().mid(ast->versionToken.offset, ast->versionToken.length);
const int dotIdx = versionString.indexOf(QLatin1Char('.'));
if (dotIdx == -1) {
// only major (which is probably invalid, but let's handle it anyway)
majorVersion = versionString.toInt();
minorVersion = 0; // ### TODO: Check with magic version numbers above
} else {
majorVersion = versionString.left(dotIdx).toInt();
minorVersion = versionString.mid(dotIdx + 1).toInt();
}
}
#ifndef NO_DECLARATIVE_BACKEND
foreach (QmlObjectValue *object, _interp->metaTypeSystem().staticTypesForImport(package, majorVersion, minorVersion)) {
namespaceObject->setProperty(object->qmlTypeName(), object);
}
#endif // NO_DECLARATIVE_BACKEND
} else if (ast->fileName) {
if (ast->fileName) {
QString path = _doc->path();
path += QLatin1Char('/');
path += ast->fileName->asString();
@@ -488,7 +313,7 @@ bool Bind::visit(FunctionDeclaration *ast)
if (_currentObjectValue->property(ast->name->asString()))
return false;
ASTFunctionValue *function = new ASTFunctionValue(ast, _interp);
ASTFunctionValue *function = new ASTFunctionValue(ast, &_interp);
_currentObjectValue->setProperty(ast->name->asString(), function);
return false; // ### eventually want to visit function bodies
}

View File

@@ -31,11 +31,12 @@
#define QMLBIND_H
#include <qmljs/parser/qmljsastvisitor_p.h>
#include <qmljs/qmljsdocument.h>
#include <qmljs/qmljsinterpreter.h>
#include <qmljs/qmljsdocument.h>
#include <QtCore/QHash>
#include <QtCore/QStringList>
#include <QtCore/QSharedPointer>
namespace QmlJS {
@@ -44,21 +45,13 @@ class Link;
class QMLJS_EXPORT Bind: protected AST::Visitor
{
protected:
Bind(Document::Ptr doc, Interpreter::Engine *interp);
public:
Bind(Document *doc);
virtual ~Bind();
QStringList includedScripts() const;
QStringList localImports() const;
// ### TODO: This methods should go. Bind each document after parsing, link later.
static Interpreter::ObjectValue *scopeChainAt(Document::Ptr currentDocument,
const Snapshot &snapshot,
Interpreter::Engine *interp,
AST::UiObjectMember *currentObject);
protected:
using AST::Visitor::visit;
@@ -83,11 +76,10 @@ protected:
Interpreter::ObjectValue *bindObject(AST::UiQualifiedId *qualifiedTypeNameId, AST::UiObjectInitializer *initializer);
private:
Document::Ptr _doc;
Interpreter::Engine *_interp;
Document *_doc;
Interpreter::Engine _interp;
Interpreter::ObjectValue *_currentObjectValue;
Interpreter::ObjectValue *_typeEnvironment;
Interpreter::ObjectValue *_idEnvironment;
Interpreter::ObjectValue *_functionEnvironment;
Interpreter::ObjectValue *_rootObjectValue;
@@ -100,6 +92,7 @@ private:
friend class LinkImports;
friend class Link;
};
typedef QSharedPointer<Bind> BindPtr;
} // end of namespace Qml

View File

@@ -28,6 +28,7 @@
**************************************************************************/
#include "qmljsdocument.h"
#include "qmljsbind.h"
#include <qmljs/parser/qmljsast_p.h>
#include <qmljs/parser/qmljslexer_p.h>
#include <qmljs/parser/qmljsparser_p.h>
@@ -143,6 +144,8 @@ bool Document::parseQml()
_ast = parser.ast();
_diagnosticMessages = parser.diagnosticMessages();
_bind = BindPtr(new Bind(this));
return _parsedCorrectly;
}
@@ -164,6 +167,8 @@ bool Document::parseJavaScript()
_ast = cast<Program*>(parser.rootNode());
_diagnosticMessages = parser.diagnosticMessages();
_bind = BindPtr(new Bind(this));
return _parsedCorrectly;
}
@@ -190,6 +195,11 @@ bool Document::parseExpression()
return _parsedCorrectly;
}
BindPtr Document::bind() const
{
return _bind;
}
Snapshot::Snapshot()
{
}

View File

@@ -40,6 +40,9 @@
namespace QmlJS {
class Bind;
typedef QSharedPointer<Bind> BindPtr;
class QMLJS_EXPORT Document
{
public:
@@ -71,6 +74,8 @@ public:
bool isParsedCorrectly() const
{ return _parsedCorrectly; }
BindPtr bind() const;
int documentRevision() const;
void setDocumentRevision(int documentRevision);
@@ -89,6 +94,7 @@ private:
QString _path;
QString _componentName;
QString _source;
BindPtr _bind;
};
class QMLJS_EXPORT Snapshot

View File

@@ -12,6 +12,124 @@ using namespace QmlJS;
using namespace QmlJS::Interpreter;
using namespace QmlJS::AST;
Link::Link(Document::Ptr currentDoc, const Snapshot &snapshot, Interpreter::Engine *interp)
: _snapshot(snapshot)
, _interp(interp)
{
_docs = reachableDocuments(currentDoc, snapshot);
linkImports();
}
Link::~Link()
{
// unset all prototypes and scopes
foreach (Document::Ptr doc, _docs) {
BindPtr bind = doc->bind();
if (doc->qmlProgram()) {
bind->_idEnvironment->setScope(0);
bind->_functionEnvironment->setScope(0);
foreach (ObjectValue *object, bind->_qmlObjectBindings) {
object->setPrototype(0);
object->setScope(0);
}
foreach (ObjectValue *object, bind->_qmlObjectDefinitions) {
object->setPrototype(0);
object->setScope(0);
}
} else if (doc->jsProgram()) {
bind->_rootObjectValue->setScope(0);
}
}
}
static ObjectValue *pushScope(ObjectValue *next, ObjectValue *onto)
{
onto->setScope(next);
return next;
}
ObjectValue *Link::scopeChainAt(Document::Ptr doc, UiObjectMember *currentObject)
{
BindPtr bind = doc->bind();
ObjectValue *scopeObject;
if (UiObjectDefinition *definition = cast<UiObjectDefinition *>(currentObject))
scopeObject = bind->_qmlObjectDefinitions.value(definition);
else if (UiObjectBinding *binding = cast<UiObjectBinding *>(currentObject))
scopeObject = bind->_qmlObjectBindings.value(binding);
else
return bind->_interp.globalObject();
if (!scopeObject)
return bind->_interp.globalObject();
// Build the scope chain.
ObjectValue *scopeStart = _typeEnvironments.value(doc.data());
ObjectValue *scope = scopeStart;
scope = pushScope(bind->_idEnvironment, scope);
scope = pushScope(bind->_functionEnvironment, scope);
foreach (const QString &scriptFile, doc->bind()->includedScripts()) {
if (Document::Ptr scriptDoc = _snapshot.document(scriptFile)) {
if (scriptDoc->jsProgram()) {
scope = pushScope(scriptDoc->bind()->_rootObjectValue, scope);
}
}
}
scope = pushScope(scopeObject, scope);
if (scopeObject != bind->_rootObjectValue)
scope = pushScope(bind->_rootObjectValue, scope);
scope = pushScope(bind->_interp.globalObject(), scope);
// May want to link to instantiating components from here.
return scopeStart;
}
void Link::linkImports()
{
foreach (Document::Ptr doc, _docs) {
BindPtr bind = doc->bind();
ObjectValue *typeEnv = _interp->newObject(/*prototype =*/0);
_typeEnvironments.insert(doc.data(), typeEnv);
// Populate the _typeEnvironment with imports.
populateImportedTypes(typeEnv, doc);
// Set the prototypes.
{
QHash<UiObjectDefinition *, ObjectValue *>::iterator it = bind->_qmlObjectDefinitions.begin();
QHash<UiObjectDefinition *, ObjectValue *>::iterator end = bind->_qmlObjectDefinitions.end();
for (; it != end; ++it) {
UiObjectDefinition *key = it.key();
ObjectValue *value = it.value();
if (!key->qualifiedTypeNameId)
continue;
value->setPrototype(lookupType(typeEnv, key->qualifiedTypeNameId));
}
}
{
QHash<UiObjectBinding *, ObjectValue *>::iterator it = bind->_qmlObjectBindings.begin();
QHash<UiObjectBinding *, ObjectValue *>::iterator end = bind->_qmlObjectBindings.end();
for (; it != end; ++it) {
UiObjectBinding *key = it.key();
ObjectValue *value = it.value();
if (!key->qualifiedTypeNameId)
continue;
value->setPrototype(lookupType(typeEnv, key->qualifiedTypeNameId));
}
}
}
}
static QString componentName(const QString &fileName)
{
QString componentName = fileName;
@@ -22,11 +140,8 @@ static QString componentName(const QString &fileName)
return componentName;
}
void LinkImports::linkImports(Bind *bind, const QList<Bind *> &binds)
void Link::populateImportedTypes(Interpreter::ObjectValue *typeEnv, Document::Ptr doc)
{
// ### TODO: remove all properties from _typeEnv
Document::Ptr doc = bind->_doc;
if (! (doc->qmlProgram() && doc->qmlProgram()->imports))
return;
@@ -35,35 +150,55 @@ void LinkImports::linkImports(Bind *bind, const QList<Bind *> &binds)
// implicit imports:
// qml files in the same directory are available without explicit imports
foreach (Bind *otherBind, binds) {
if (otherBind == bind)
foreach (Document::Ptr otherDoc, _docs) {
if (otherDoc == doc)
continue;
Document::Ptr otherDoc = otherBind->_doc;
QFileInfo otherFileInfo(otherDoc->fileName());
const QString otherAbsolutePath = otherFileInfo.absolutePath();
if (otherAbsolutePath != absolutePath)
continue;
bind->_typeEnvironment->setProperty(componentName(otherFileInfo.fileName()),
otherBind->_rootObjectValue);
typeEnv->setProperty(componentName(otherFileInfo.fileName()),
otherDoc->bind()->_rootObjectValue);
}
// explicit imports, whether directories or files
for (UiImportList *it = doc->qmlProgram()->imports; it; it = it->next) {
if (! (it->import && it->import->fileName))
if (! it->import)
continue;
QString path = absolutePath;
if (it->import->fileName) {
importFile(typeEnv, doc, it->import, absolutePath);
} else if (it->import->importUri) {
importNonFile(typeEnv, doc, it->import);
}
}
}
/*
import "content"
import "content" as Xxx
import "content" 4.6
import "content" 4.6 as Xxx
import "http://www.ovi.com/" as Ovi
*/
void Link::importFile(Interpreter::ObjectValue *typeEnv, Document::Ptr doc,
AST::UiImport *import, const QString &startPath)
{
if (!import->fileName)
return;
QString path = startPath;
path += QLatin1Char('/');
path += it->import->fileName->asString();
path += import->fileName->asString();
path = QDir::cleanPath(path);
ObjectValue *importNamespace = 0;
foreach (Bind *otherBind, binds) {
Document::Ptr otherDoc = otherBind->_doc;
foreach (Document::Ptr otherDoc, _docs) {
QFileInfo otherFileInfo(otherDoc->fileName());
const QString otherAbsolutePath = otherFileInfo.absolutePath();
@@ -72,28 +207,70 @@ void LinkImports::linkImports(Bind *bind, const QList<Bind *> &binds)
if (!directoryImport && !fileImport)
continue;
if (directoryImport && it->import->importId && !importNamespace) {
importNamespace = bind->_interp->newObject(/*prototype =*/0);
bind->_typeEnvironment->setProperty(it->import->importId->asString(), importNamespace);
if (directoryImport && import->importId && !importNamespace) {
importNamespace = _interp->newObject(/*prototype =*/0);
typeEnv->setProperty(import->importId->asString(), importNamespace);
}
QString targetName;
if (fileImport && it->import->importId) {
targetName = it->import->importId->asString();
if (fileImport && import->importId) {
targetName = import->importId->asString();
} else {
targetName = componentName(otherFileInfo.fileName());
}
ObjectValue *importInto = bind->_typeEnvironment;
ObjectValue *importInto = typeEnv;
if (importNamespace)
importInto = importNamespace;
importInto->setProperty(targetName, otherBind->_rootObjectValue);
}
importInto->setProperty(targetName, otherDoc->bind()->_rootObjectValue);
}
}
static const ObjectValue *lookupType(ObjectValue *env, UiQualifiedId *id)
/*
import Qt 4.6
import Qt 4.6 as Xxx
(import com.nokia.qt is the same as the ones above)
*/
void Link::importNonFile(Interpreter::ObjectValue *typeEnv, Document::Ptr doc, AST::UiImport *import)
{
ObjectValue *namespaceObject = 0;
if (import->importId) { // with namespace we insert an object in the type env. to hold the imported types
namespaceObject = _interp->newObject(/*prototype */ 0);
typeEnv->setProperty(import->importId->asString(), namespaceObject);
} else { // without namespace we insert all types directly into the type env.
namespaceObject = typeEnv;
}
// try the metaobject system
if (import->importUri) {
const QString package = Bind::toString(import->importUri, '/');
int majorVersion = -1; // ### TODO: Check these magic version numbers
int minorVersion = -1; // ### TODO: Check these magic version numbers
if (import->versionToken.isValid()) {
const QString versionString = doc->source().mid(import->versionToken.offset, import->versionToken.length);
const int dotIdx = versionString.indexOf(QLatin1Char('.'));
if (dotIdx == -1) {
// only major (which is probably invalid, but let's handle it anyway)
majorVersion = versionString.toInt();
minorVersion = 0; // ### TODO: Check with magic version numbers above
} else {
majorVersion = versionString.left(dotIdx).toInt();
minorVersion = versionString.mid(dotIdx + 1).toInt();
}
}
#ifndef NO_DECLARATIVE_BACKEND
foreach (QmlObjectValue *object, _interp->metaTypeSystem().staticTypesForImport(package, majorVersion, minorVersion)) {
namespaceObject->setProperty(object->qmlTypeName(), object);
}
#endif // NO_DECLARATIVE_BACKEND
}
}
const ObjectValue *Link::lookupType(ObjectValue *env, UiQualifiedId *id)
{
const ObjectValue *objectValue = env;
@@ -111,65 +288,37 @@ static const ObjectValue *lookupType(ObjectValue *env, UiQualifiedId *id)
return objectValue;
}
void LinkImports::operator()(const QList<Bind *> &binds)
QList<Document::Ptr> Link::reachableDocuments(Document::Ptr startDoc, const Snapshot &snapshot)
{
foreach (Bind *bind, binds) {
// Populate the _typeEnvironment with imports.
linkImports(bind, binds);
QList<Document::Ptr> docs;
// Set the prototypes.
{
QHash<UiObjectDefinition *, ObjectValue *>::iterator it = bind->_qmlObjectDefinitions.begin();
QHash<UiObjectDefinition *, ObjectValue *>::iterator end = bind->_qmlObjectDefinitions.end();
for (; it != end; ++it) {
UiObjectDefinition *key = it.key();
ObjectValue *value = it.value();
if (!key->qualifiedTypeNameId)
QSet<QString> processed;
QStringList todo;
QMultiHash<QString, Document::Ptr> documentByPath;
foreach (Document::Ptr doc, snapshot)
documentByPath.insert(doc->path(), doc);
todo.append(startDoc->path());
// Find the reachable documents.
while (! todo.isEmpty()) {
const QString path = todo.takeFirst();
if (processed.contains(path))
continue;
value->setPrototype(lookupType(bind->_typeEnvironment, key->qualifiedTypeNameId));
}
}
{
QHash<UiObjectBinding *, ObjectValue *>::iterator it = bind->_qmlObjectBindings.begin();
QHash<UiObjectBinding *, ObjectValue *>::iterator end = bind->_qmlObjectBindings.end();
for (; it != end; ++it) {
UiObjectBinding *key = it.key();
ObjectValue *value = it.value();
if (!key->qualifiedTypeNameId)
continue;
processed.insert(path);
value->setPrototype(lookupType(bind->_typeEnvironment, key->qualifiedTypeNameId));
}
QStringList localImports;
foreach (Document::Ptr doc, documentByPath.values(path)) {
docs += doc;
localImports += doc->bind()->localImports();
}
localImports.removeDuplicates();
todo += localImports;
}
}
ObjectValue *Link::operator()(const QList<Bind *> &binds, Bind *currentBind, UiObjectMember *currentObject)
{
Q_UNUSED(binds);
ObjectValue *scopeObject;
if (UiObjectDefinition *definition = cast<UiObjectDefinition *>(currentObject))
scopeObject = currentBind->_qmlObjectDefinitions.value(definition);
else if (UiObjectBinding *binding = cast<UiObjectBinding *>(currentObject))
scopeObject = currentBind->_qmlObjectBindings.value(binding);
else
return currentBind->_interp->globalObject();
if (!scopeObject)
return currentBind->_interp->globalObject();
// Build the scope chain.
currentBind->_typeEnvironment->setScope(currentBind->_idEnvironment);
currentBind->_idEnvironment->setScope(currentBind->_functionEnvironment);
currentBind->_functionEnvironment->setScope(scopeObject);
if (scopeObject != currentBind->_rootObjectValue) {
scopeObject->setScope(currentBind->_rootObjectValue);
currentBind->_rootObjectValue->setScope(currentBind->_interp->globalObject());
} else {
scopeObject->setScope(currentBind->_interp->globalObject());
}
// May want to link to instantiating components from here.
return currentBind->_typeEnvironment;
return docs;
}

View File

@@ -1,29 +1,49 @@
#ifndef QMLJSLINK_H
#define QMLJSLINK_H
#include <qmljs/qmljsdocument.h>
#include <qmljs/qmljsbind.h>
#include <qmljs/qmljsinterpreter.h>
#include <qmljs/parser/qmljsastfwd_p.h>
#include <qmljs/parser/qmljsengine_p.h>
#include <QtCore/QList>
#include <QtCore/QHash>
namespace QmlJS {
class Bind;
class LinkImports
/*
Temporarily links a set of bound documents together to allow resolving cross-document
dependencies. The link is undone when this object is destoyed.
*/
class QMLJS_EXPORT Link
{
public:
void operator()(const QList<Bind *> &binds);
// Link all documents in snapshot reachable from doc.
Link(Document::Ptr doc, const Snapshot &snapshot, Interpreter::Engine *interp);
~Link();
// Get the scope chain for the currentObject inside doc.
Interpreter::ObjectValue *scopeChainAt(Document::Ptr doc, AST::UiObjectMember *currentObject);
private:
void importObject(Bind *bind, const QString &name, Interpreter::ObjectValue *object, NameId* targetNamespace);
void linkImports(Bind *bind, const QList<Bind *> &binds);
};
static QList<Document::Ptr> reachableDocuments(Document::Ptr startDoc, const Snapshot &snapshot);
static const Interpreter::ObjectValue *lookupType(Interpreter::ObjectValue *env, AST::UiQualifiedId *id);
class Link
{
public:
Interpreter::ObjectValue *operator()(const QList<Bind *> &binds, Bind *currentBind, AST::UiObjectMember *currentObject);
void linkImports();
void populateImportedTypes(Interpreter::ObjectValue *typeEnv, Document::Ptr doc);
void importFile(Interpreter::ObjectValue *typeEnv, Document::Ptr doc,
AST::UiImport *import, const QString &startPath);
void importNonFile(Interpreter::ObjectValue *typeEnv, Document::Ptr doc,
AST::UiImport *import);
void importObject(BindPtr bind, const QString &name, Interpreter::ObjectValue *object, NameId* targetNamespace);
private:
Snapshot _snapshot;
Interpreter::Engine *_interp;
QList<Document::Ptr> _docs;
QHash<Document *, Interpreter::ObjectValue *> _typeEnvironments;
};
} // namespace QmlJS

View File

@@ -632,10 +632,11 @@ int QmlCodeCompletion::startCompletion(TextEditor::ITextEditable *editor)
// Set up the current scope chain.
Interpreter::ObjectValue *scope = interp.globalObject();
Link link(qmlDocument, snapshot, &interp);
if (isQmlFile && qmlDocument) {
AST::UiObjectMember *declaringMember = semanticInfo.declaringMember(editor->position());
scope = Bind::scopeChainAt(qmlDocument, snapshot, &interp, declaringMember);
scope = link.scopeChainAt(qmlDocument, declaringMember);
}
// Search for the operator that triggered the completion.

View File

@@ -37,6 +37,7 @@
#include <debugger/debuggerconstants.h>
#include <extensionsystem/pluginmanager.h>
#include <qmljs/qmljsbind.h>
#include <qmljs/qmljslink.h>
#include <qmljs/qmljscheck.h>
#include <qmljs/qmljsinterpreter.h>
#include <qmljs/parser/qmljsast_p.h>
@@ -171,7 +172,8 @@ void QmlHoverHandler::updateHelpIdAndTooltip(TextEditor::ITextEditor *editor, in
AST::UiObjectMember *declaringMember = semanticInfo.declaringMember(pos);
Interpreter::Engine interp;
const Interpreter::ObjectValue *scope = Bind::scopeChainAt(qmlDocument, snapshot, &interp, declaringMember);
Link link(qmlDocument, snapshot, &interp);
const Interpreter::ObjectValue *scope = link.scopeChainAt(qmlDocument, declaringMember);
Check check(&interp);
const Interpreter::Value *value = check(node, scope);