From 1f0b717ad2c6cd6bd4f7d70efa0bb6cc6f8f14be Mon Sep 17 00:00:00 2001 From: Roberto Raggi <roberto.raggi@nokia.com> Date: Wed, 3 Feb 2010 14:31:03 +0100 Subject: [PATCH] Completion for global variables in JS. * Support for lookup JS vs Qml * Bind global variables. Done-with: ckamm --- src/libs/qmljs/qmljsbind.cpp | 120 +++---------- src/libs/qmljs/qmljsbind.h | 6 + src/libs/qmljs/qmljscheck.cpp | 12 +- src/libs/qmljs/qmljscheck.h | 4 +- src/libs/qmljs/qmljsinterpreter.cpp | 159 +++++++++++++++++- src/libs/qmljs/qmljsinterpreter.h | 84 ++++++++- src/libs/qmljs/qmljslink.cpp | 77 ++++----- src/libs/qmljs/qmljslink.h | 8 - src/plugins/qmljseditor/qmlcodecompletion.cpp | 30 ++-- src/plugins/qmljseditor/qmlhoverhandler.cpp | 2 +- 10 files changed, 324 insertions(+), 178 deletions(-) diff --git a/src/libs/qmljs/qmljsbind.cpp b/src/libs/qmljs/qmljsbind.cpp index a7da7492439..c7e387bd9a1 100644 --- a/src/libs/qmljs/qmljsbind.cpp +++ b/src/libs/qmljs/qmljsbind.cpp @@ -41,88 +41,6 @@ using namespace QmlJS; using namespace QmlJS::AST; using namespace QmlJS::Interpreter; -namespace { - -class ASTObjectValue: public ObjectValue -{ - UiQualifiedId *_typeName; - UiObjectInitializer *_initializer; - -public: - ASTObjectValue(UiQualifiedId *typeName, UiObjectInitializer *initializer, Interpreter::Engine *engine) - : ObjectValue(engine), _typeName(typeName), _initializer(initializer) - { - } - - virtual void processMembers(MemberProcessor *processor) const - { - if (_initializer) { - for (UiObjectMemberList *it = _initializer->members; it; it = it->next) { - UiObjectMember *member = it->member; - if (UiPublicMember *def = cast<UiPublicMember *>(member)) { - if (def->name && def->memberType) { - const QString propName = def->name->asString(); - const QString propType = def->memberType->asString(); - - processor->processProperty(propName, engine()->defaultValueForBuiltinType(propType)); - } - } - } - } - ObjectValue::processMembers(processor); - } -}; - -class ASTFunctionValue: public FunctionValue -{ - FunctionDeclaration *_ast; - QList<NameId *> _argumentNames; - -public: - ASTFunctionValue(FunctionDeclaration *ast, Interpreter::Engine *engine) - : FunctionValue(engine), _ast(ast) - { - setPrototype(engine->functionPrototype()); - - for (FormalParameterList *it = ast->formals; it; it = it->next) - _argumentNames.append(it->name); - } - - FunctionDeclaration *ast() const { return _ast; } - - virtual const Value *returnValue() const - { - return engine()->undefinedValue(); - } - - virtual int argumentCount() const - { - return _argumentNames.size(); - } - - virtual const Value *argument(int) const - { - return engine()->undefinedValue(); - } - - virtual QString argumentName(int index) const - { - if (index < _argumentNames.size()) { - if (NameId *nameId = _argumentNames.at(index)) - return nameId->asString(); - } - - return FunctionValue::argumentName(index); - } - - virtual bool isVariadic() const - { - return true; - } -}; - -} // end of anonymous namespace - Bind::Bind(Document *doc) : _doc(doc), _currentObjectValue(0), @@ -130,18 +48,8 @@ Bind::Bind(Document *doc) _functionEnvironment(0), _rootObjectValue(0) { - if (!_doc) - return; - - 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()); + if (_doc) + accept(_doc->ast()); } Bind::~Bind() @@ -248,6 +156,20 @@ void Bind::accept(Node *node) Node::accept(node, this); } +bool Bind::visit(AST::UiProgram *) +{ + _idEnvironment = _interp.newObject(/*prototype =*/ 0); + _functionEnvironment = _interp.newObject(/*prototype =*/ 0); + return true; +} + +bool Bind::visit(AST::Program *) +{ + _currentObjectValue = _interp.globalObject(); + _rootObjectValue = _interp.globalObject(); + return true; +} + bool Bind::visit(UiImport *ast) { if (ast->fileName) { @@ -305,6 +227,16 @@ bool Bind::visit(UiArrayBinding *) return true; } +bool Bind::visit(VariableDeclaration *ast) +{ + if (! ast->name) + return false; + + ASTVariableReference *ref = new ASTVariableReference(ast, &_interp); + _currentObjectValue->setProperty(ast->name->asString(), ref); + return false; +} + bool Bind::visit(FunctionDeclaration *ast) { if (!ast->name) diff --git a/src/libs/qmljs/qmljsbind.h b/src/libs/qmljs/qmljsbind.h index d24075e2905..bb64a8685bc 100644 --- a/src/libs/qmljs/qmljsbind.h +++ b/src/libs/qmljs/qmljsbind.h @@ -61,6 +61,9 @@ protected: void accept(AST::Node *node); + virtual bool visit(AST::UiProgram *ast); + virtual bool visit(AST::Program *ast); + // Ui virtual bool visit(AST::UiImport *ast); virtual bool visit(AST::UiPublicMember *ast); @@ -68,7 +71,10 @@ protected: virtual bool visit(AST::UiObjectBinding *ast); virtual bool visit(AST::UiScriptBinding *ast); virtual bool visit(AST::UiArrayBinding *ast); + + // QML/JS virtual bool visit(AST::FunctionDeclaration *ast); + virtual bool visit(AST::VariableDeclaration *ast); protected: Interpreter::ObjectValue *switchObjectValue(Interpreter::ObjectValue *newObjectValue); diff --git a/src/libs/qmljs/qmljscheck.cpp b/src/libs/qmljs/qmljscheck.cpp index 3d24f79054d..31b4567af3e 100644 --- a/src/libs/qmljs/qmljscheck.cpp +++ b/src/libs/qmljs/qmljscheck.cpp @@ -37,9 +37,9 @@ using namespace QmlJS; using namespace QmlJS::Interpreter; -Check::Check(Link *link) - : _engine(link->engine()), - _link(link), +Check::Check(Context *context) + : _engine(context->engine()), + _context(context), _scope(_engine->globalObject()), _result(0) { @@ -66,7 +66,7 @@ const Interpreter::Value *Check::check(AST::Node *ast) const Value *result = switchResult(previousResult); if (const Reference *ref = value_cast<const Reference *>(result)) - result = ref->value(_link->context()); + result = ref->value(_context); if (! result) result = _engine->undefinedValue(); @@ -165,7 +165,7 @@ bool Check::visit(AST::UiQualifiedId *ast) if (! ast->name) return false; - const Value *value = _link->lookup(ast->name->asString()); + const Value *value = _context->lookup(ast->name->asString()); if (! ast->next) { _result = value; @@ -213,7 +213,7 @@ bool Check::visit(AST::IdentifierExpression *ast) if (! ast->name) return false; - _result = _link->lookup(ast->name->asString()); + _result = _context->lookup(ast->name->asString()); return false; } diff --git a/src/libs/qmljs/qmljscheck.h b/src/libs/qmljs/qmljscheck.h index 95fef91b3ff..14a56f8507d 100644 --- a/src/libs/qmljs/qmljscheck.h +++ b/src/libs/qmljs/qmljscheck.h @@ -48,7 +48,7 @@ namespace Interpreter { class QMLJS_EXPORT Check: protected AST::Visitor { public: - Check(Link *link); + Check(Interpreter::Context *context); virtual ~Check(); const Interpreter::Value *operator()(AST::Node *ast); @@ -158,7 +158,7 @@ protected: private: QmlJS::Document::Ptr _doc; Interpreter::Engine *_engine; - Link *_link; + Interpreter::Context *_context; const Interpreter::ObjectValue *_scope; const Interpreter::Value *_result; }; diff --git a/src/libs/qmljs/qmljsinterpreter.cpp b/src/libs/qmljs/qmljsinterpreter.cpp index 6d293ac5e37..0a650c98177 100644 --- a/src/libs/qmljs/qmljsinterpreter.cpp +++ b/src/libs/qmljs/qmljsinterpreter.cpp @@ -28,7 +28,8 @@ **************************************************************************/ #include "qmljsinterpreter.h" - +#include "qmljscheck.h" +#include "parser/qmljsast_p.h" #include <QtCore/QMetaObject> #include <QtCore/QMetaProperty> #include <QtCore/QDebug> @@ -42,6 +43,7 @@ #endif using namespace QmlJS::Interpreter; +using namespace QmlJS::AST; namespace { @@ -677,7 +679,8 @@ void StringValue::accept(ValueVisitor *visitor) const Context::Context(Engine *engine) - : _engine(engine) + : _engine(engine), + _lookupMode(JSLookup) { } @@ -690,6 +693,46 @@ Engine *Context::engine() const return _engine; } +Context::ScopeChain Context::scopeChain() const +{ + return _scopeChain; +} + +Context::LookupMode Context::lookupMode() const +{ + return _lookupMode; +} + +void Context::setLookupMode(LookupMode lookupMode) +{ + _lookupMode = lookupMode; +} + +void Context::pushScope(const ObjectValue *object) +{ + _scopeChain.append(object); +} + +void Context::popScope() +{ + _scopeChain.removeLast(); +} + +const Value *Context::lookup(const QString &name) const +{ + for (int index = _scopeChain.size() - 1; index != -1; --index) { + const ObjectValue *scope = _scopeChain.at(index); + + if (const Value *member = scope->lookupMember(name)) { + if (_lookupMode == JSLookup || ! dynamic_cast<const ASTVariableReference *>(member)) { + return member; + } + } + } + + return _engine->undefinedValue(); +} + const Value *Context::property(const ObjectValue *object, const QString &name) const { const Properties properties = _properties.value(object); @@ -701,14 +744,21 @@ void Context::setProperty(const ObjectValue *object, const QString &name, const _properties[object].insert(name, value); } -Reference::Reference() +Reference::Reference(Engine *engine) + : _engine(engine) { + _engine->registerValue(this); } Reference::~Reference() { } +Engine *Reference::engine() const +{ + return _engine; +} + const Reference *Reference::asReference() const { return this; @@ -719,6 +769,10 @@ void Reference::accept(ValueVisitor *visitor) const visitor->visit(this); } +const Value *Reference::value(Context *) const +{ + return _engine->undefinedValue(); +} MemberProcessor::MemberProcessor() { @@ -757,7 +811,7 @@ ObjectValue::ObjectValue(Engine *engine) : _engine(engine), _prototype(0) { - engine->registerObject(this); + engine->registerValue(this); } ObjectValue::~ObjectValue() @@ -1314,7 +1368,7 @@ Engine::Engine() Engine::~Engine() { - qDeleteAll(_registeredObjects); + qDeleteAll(_registeredValues); } const NullValue *Engine::nullValue() const @@ -1456,9 +1510,9 @@ const ObjectValue *Engine::mathObject() const return _mathObject; } -void Engine::registerObject(ObjectValue *object) +void Engine::registerValue(Value *value) { - _registeredObjects.append(object); + _registeredValues.append(value); } const Value *Engine::convertToBoolean(const Value *value) @@ -1802,3 +1856,94 @@ QmlObjectValue *Engine::newQmlObject(const QString &name, const QString &prefix, } #endif + + +ASTObjectValue::ASTObjectValue(UiQualifiedId *typeName, UiObjectInitializer *initializer, Engine *engine) + : ObjectValue(engine), _typeName(typeName), _initializer(initializer) +{ +} + +ASTObjectValue::~ASTObjectValue() +{ +} + +void ASTObjectValue::processMembers(MemberProcessor *processor) const +{ + if (_initializer) { + for (UiObjectMemberList *it = _initializer->members; it; it = it->next) { + UiObjectMember *member = it->member; + if (UiPublicMember *def = cast<UiPublicMember *>(member)) { + if (def->name && def->memberType) { + const QString propName = def->name->asString(); + const QString propType = def->memberType->asString(); + + processor->processProperty(propName, engine()->defaultValueForBuiltinType(propType)); + } + } + } + } + ObjectValue::processMembers(processor); +} + +ASTVariableReference::ASTVariableReference(VariableDeclaration *ast, Engine *engine) + : Reference(engine), _ast(ast) +{ +} + +ASTVariableReference::~ASTVariableReference() +{ +} + +const Value *ASTVariableReference::value(Context *context) const +{ + Check check(context); + return check(_ast->expression); +} + +ASTFunctionValue::ASTFunctionValue(FunctionDeclaration *ast, Engine *engine) + : FunctionValue(engine), _ast(ast) +{ + setPrototype(engine->functionPrototype()); + + for (FormalParameterList *it = ast->formals; it; it = it->next) + _argumentNames.append(it->name); +} + +ASTFunctionValue::~ASTFunctionValue() +{ +} + +FunctionDeclaration *ASTFunctionValue::ast() const +{ + return _ast; +} + +const Value *ASTFunctionValue::returnValue() const +{ + return engine()->undefinedValue(); +} + +int ASTFunctionValue::argumentCount() const +{ + return _argumentNames.size(); +} + +const Value *ASTFunctionValue::argument(int) const +{ + return engine()->undefinedValue(); +} + +QString ASTFunctionValue::argumentName(int index) const +{ + if (index < _argumentNames.size()) { + if (NameId *nameId = _argumentNames.at(index)) + return nameId->asString(); + } + + return FunctionValue::argumentName(index); +} + +bool ASTFunctionValue::isVariadic() const +{ + return true; +} diff --git a/src/libs/qmljs/qmljsinterpreter.h b/src/libs/qmljs/qmljsinterpreter.h index f6cc9dc5201..1d3e261e883 100644 --- a/src/libs/qmljs/qmljsinterpreter.h +++ b/src/libs/qmljs/qmljsinterpreter.h @@ -32,6 +32,7 @@ #include <qmljs/qmljs_global.h> #include <qmljs/qmljsmetatypesystem.h> +#include <qmljs/parser/qmljsastfwd_p.h> #include <QtCore/QList> #include <QtCore/QString> @@ -39,6 +40,9 @@ #include <QtCore/QSet> namespace QmlJS { + +class NameId; + namespace Interpreter { //////////////////////////////////////////////////////////////////////////////// @@ -207,11 +211,28 @@ public: class QMLJS_EXPORT Context { +public: + typedef QList<const ObjectValue *> ScopeChain; + + enum LookupMode { + JSLookup, + QmlLookup + }; + public: Context(Engine *engine); - virtual ~Context(); + ~Context(); Engine *engine() const; + ScopeChain scopeChain() const; + + LookupMode lookupMode() const; + void setLookupMode(LookupMode lookupMode); + + void pushScope(const ObjectValue *object); + void popScope(); + + const Value *lookup(const QString &name) const; const Value *property(const ObjectValue *object, const QString &name) const; void setProperty(const ObjectValue *object, const QString &name, const Value *value); @@ -220,20 +241,26 @@ private: typedef QHash<QString, const Value *> Properties; Engine *_engine; + LookupMode _lookupMode; QHash<const ObjectValue *, Properties> _properties; + ScopeChain _scopeChain; }; class QMLJS_EXPORT Reference: public Value { public: - Reference(); + Reference(Engine *engine); virtual ~Reference(); - virtual const Value *value(const Context *context) const = 0; + Engine *engine() const; + virtual const Value *value(Context *context) const; // Value interface virtual const Reference *asReference() const; virtual void accept(ValueVisitor *) const; + +private: + Engine *_engine; }; class QMLJS_EXPORT ObjectValue: public Value @@ -506,8 +533,6 @@ public: ObjectValue *globalObject() const; const ObjectValue *mathObject() const; - void registerObject(ObjectValue *object); - // prototypes ObjectValue *objectPrototype() const; ObjectValue *functionPrototype() const; @@ -539,6 +564,8 @@ public: const MetaTypeSystem &metaTypeSystem() const { return _metaTypeSystem; } + void registerValue(Value *value); // internal + private: void initializePrototypes(); @@ -575,7 +602,7 @@ private: NumberValue _numberValue; BooleanValue _booleanValue; StringValue _stringValue; - QList<ObjectValue *> _registeredObjects; + QList<Value *> _registeredValues; ConvertToNumber _convertToNumber; ConvertToString _convertToString; @@ -585,6 +612,51 @@ private: MetaTypeSystem _metaTypeSystem; }; + +// internal +class QMLJS_EXPORT ASTObjectValue: public ObjectValue +{ + AST::UiQualifiedId *_typeName; + AST::UiObjectInitializer *_initializer; + +public: + ASTObjectValue(AST::UiQualifiedId *typeName, AST::UiObjectInitializer *initializer, Engine *engine); + virtual ~ASTObjectValue(); + + virtual void processMembers(MemberProcessor *processor) const; +}; + +class QMLJS_EXPORT ASTVariableReference: public Reference +{ + AST::VariableDeclaration *_ast; + +public: + ASTVariableReference(AST::VariableDeclaration *ast, Engine *engine); + virtual ~ASTVariableReference(); + + virtual const Value *value(Context *context) const; +}; + +class QMLJS_EXPORT ASTFunctionValue: public FunctionValue +{ + AST::FunctionDeclaration *_ast; + QList<NameId *> _argumentNames; + +public: + ASTFunctionValue(AST::FunctionDeclaration *ast, Engine *engine); + virtual ~ASTFunctionValue(); + + AST::FunctionDeclaration *ast() const; + + virtual const Value *returnValue() const; + virtual int argumentCount() const; + virtual const Value *argument(int) const; + virtual QString argumentName(int index) const; + virtual bool isVariadic() const; +}; + + + } } // end of namespace QmlJS::Interpreter #endif // QMLJS_INTERPRETER_H diff --git a/src/libs/qmljs/qmljslink.cpp b/src/libs/qmljs/qmljslink.cpp index 5af7edf8308..6ce97d04f62 100644 --- a/src/libs/qmljs/qmljslink.cpp +++ b/src/libs/qmljs/qmljslink.cpp @@ -14,7 +14,6 @@ using namespace QmlJS::AST; Link::Link(Document::Ptr currentDoc, const Snapshot &snapshot, Interpreter::Engine *interp) : _snapshot(snapshot) - , _interp(interp) , _context(interp) { _docs = reachableDocuments(currentDoc, snapshot); @@ -41,64 +40,58 @@ Context *Link::context() return &_context; } -Link::ScopeChain Link::scopeChain() const -{ - return _scopeChain; -} - Interpreter::Engine *Link::engine() { - return _interp; + return _context.engine(); } void Link::scopeChainAt(Document::Ptr doc, Node *currentObject) { - _scopeChain.clear(); + _context.pushScope(engine()->globalObject()); - if (! doc) { - _scopeChain.append(_interp->globalObject()); + if (! doc) return; - } + + if (doc->qmlProgram() != 0) + _context.setLookupMode(Context::QmlLookup); BindPtr bind = doc->bind(); // Build the scope chain. - _scopeChain.append(_typeEnvironments.value(doc.data())); - _scopeChain.append(bind->_idEnvironment); - _scopeChain.append(bind->_functionEnvironment); - foreach (const QString &scriptFile, doc->bind()->includedScripts()) { - if (Document::Ptr scriptDoc = _snapshot.document(scriptFile)) { - if (scriptDoc->jsProgram()) { - _scopeChain.append(scriptDoc->bind()->_rootObjectValue); - } - } - } + // ### FIXME: May want to link to instantiating components from here. + if (bind->_rootObjectValue) + _context.pushScope(bind->_rootObjectValue); - if (UiObjectDefinition *definition = cast<UiObjectDefinition *>(currentObject)) { - ObjectValue *scopeObject = bind->_qmlObjects.value(definition); - _scopeChain.append(scopeObject); + ObjectValue *scopeObject = 0; + if (UiObjectDefinition *definition = cast<UiObjectDefinition *>(currentObject)) + scopeObject = bind->_qmlObjects.value(definition); + else if (UiObjectBinding *binding = cast<UiObjectBinding *>(currentObject)) + scopeObject = bind->_qmlObjects.value(binding); - // ### FIXME: should add the root regardless - if (scopeObject != bind->_rootObjectValue) - _scopeChain.append(bind->_rootObjectValue); - } - - _scopeChain.append(bind->_interp.globalObject()); + if (scopeObject && scopeObject != bind->_rootObjectValue) + _context.pushScope(scopeObject); - // May want to link to instantiating components from here. -} + const QStringList &includedScripts = bind->includedScripts(); + for (int index = includedScripts.size() - 1; index != -1; --index) { + const QString &scriptFile = includedScripts.at(index); -const Value *Link::lookup(const QString &name) const -{ - foreach (const ObjectValue *scope, _scopeChain) { - if (const Value *member = scope->lookupMember(name)) { - return member; + if (Document::Ptr scriptDoc = _snapshot.document(scriptFile)) { + if (scriptDoc->jsProgram()) { + _context.pushScope(scriptDoc->bind()->_rootObjectValue); + } } } - return _interp->undefinedValue(); + if (bind->_functionEnvironment) + _context.pushScope(bind->_functionEnvironment); + + if (bind->_idEnvironment) + _context.pushScope(bind->_idEnvironment); + + if (const ObjectValue *typeEnvironment = _typeEnvironments.value(doc.data())) + _context.pushScope(typeEnvironment); } void Link::linkImports() @@ -106,7 +99,7 @@ void Link::linkImports() foreach (Document::Ptr doc, _docs) { BindPtr bind = doc->bind(); - ObjectValue *typeEnv = _interp->newObject(/*prototype =*/0); + ObjectValue *typeEnv = engine()->newObject(/*prototype =*/0); // ### FIXME _typeEnvironments.insert(doc.data(), typeEnv); // Populate the _typeEnvironment with imports. @@ -205,7 +198,7 @@ void Link::importFile(Interpreter::ObjectValue *typeEnv, Document::Ptr doc, continue; if (directoryImport && import->importId && !importNamespace) { - importNamespace = _interp->newObject(/*prototype =*/0); + importNamespace = engine()->newObject(/*prototype =*/0); typeEnv->setProperty(import->importId->asString(), importNamespace); } @@ -234,7 +227,7 @@ void Link::importNonFile(Interpreter::ObjectValue *typeEnv, Document::Ptr doc, A 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); + namespaceObject = engine()->newObject(/*prototype */ 0); typeEnv->setProperty(import->importId->asString(), namespaceObject); } else { // without namespace we insert all types directly into the type env. @@ -260,7 +253,7 @@ void Link::importNonFile(Interpreter::ObjectValue *typeEnv, Document::Ptr doc, A } } #ifndef NO_DECLARATIVE_BACKEND - foreach (QmlObjectValue *object, _interp->metaTypeSystem().staticTypesForImport(package, majorVersion, minorVersion)) { + foreach (QmlObjectValue *object, engine()->metaTypeSystem().staticTypesForImport(package, majorVersion, minorVersion)) { namespaceObject->setProperty(object->qmlTypeName(), object); } #endif // NO_DECLARATIVE_BACKEND diff --git a/src/libs/qmljs/qmljslink.h b/src/libs/qmljs/qmljslink.h index 8b622140ed0..8c346ac62be 100644 --- a/src/libs/qmljs/qmljslink.h +++ b/src/libs/qmljs/qmljslink.h @@ -18,23 +18,17 @@ namespace QmlJS { */ class QMLJS_EXPORT Link { -public: - typedef QList<const Interpreter::ObjectValue *> ScopeChain; - public: // Link all documents in snapshot reachable from doc. Link(Document::Ptr doc, const Snapshot &snapshot, Interpreter::Engine *interp); ~Link(); Interpreter::Context *context(); - ScopeChain scopeChain() const; Interpreter::Engine *engine(); // Get the scope chain for the currentObject inside doc. void scopeChainAt(Document::Ptr doc, AST::Node *currentObject); - const Interpreter::Value *lookup(const QString &name) const; - private: static QList<Document::Ptr> reachableDocuments(Document::Ptr startDoc, const Snapshot &snapshot); static const Interpreter::ObjectValue *lookupType(Interpreter::ObjectValue *env, AST::UiQualifiedId *id); @@ -51,11 +45,9 @@ private: private: Snapshot _snapshot; - Interpreter::Engine *_interp; Interpreter::Context _context; QList<Document::Ptr> _docs; QHash<Document *, Interpreter::ObjectValue *> _typeEnvironments; - ScopeChain _scopeChain; }; } // namespace QmlJS diff --git a/src/plugins/qmljseditor/qmlcodecompletion.cpp b/src/plugins/qmljseditor/qmlcodecompletion.cpp index 6346b372aae..fed3ee48e2c 100644 --- a/src/plugins/qmljseditor/qmlcodecompletion.cpp +++ b/src/plugins/qmljseditor/qmlcodecompletion.cpp @@ -129,12 +129,12 @@ class EnumerateProperties: private Interpreter::MemberProcessor QSet<const Interpreter::ObjectValue *> _processed; QHash<QString, const Interpreter::Value *> _properties; bool _globalCompletion; - Link *_link; + Interpreter::Context *_context; public: - EnumerateProperties(Link *link) + EnumerateProperties(Interpreter::Context *context) : _globalCompletion(false), - _link(link) + _context(context) { } @@ -158,23 +158,30 @@ public: _processed.clear(); _properties.clear(); - foreach (const Interpreter::ObjectValue *scope, _link->scopeChain()) + foreach (const Interpreter::ObjectValue *scope, _context->scopeChain()) enumerateProperties(scope); return _properties; } private: + void insertProperty(const QString &name, const Interpreter::Value *value) + { + if (_context->lookupMode() == Interpreter::Context::JSLookup || + ! dynamic_cast<const Interpreter::ASTVariableReference *>(value)) + _properties.insert(name, value); + } + virtual bool processProperty(const QString &name, const Interpreter::Value *value) { - _properties.insert(name, value); + insertProperty(name, value); return true; } virtual bool processEnumerator(const QString &name, const Interpreter::Value *value) { if (! _globalCompletion) - _properties.insert(name, value); + insertProperty(name, value); return true; } @@ -186,14 +193,14 @@ private: virtual bool processSlot(const QString &name, const Interpreter::Value *value) { if (! _globalCompletion) - _properties.insert(name, value); + insertProperty(name, value); return true; } virtual bool processGeneratedSlot(const QString &name, const Interpreter::Value *value) { if (_globalCompletion) - _properties.insert(name, value); + insertProperty(name, value); return true; } @@ -646,7 +653,6 @@ int QmlCodeCompletion::startCompletion(TextEditor::ITextEditable *editor) AST::Node *declaringMember = semanticInfo.declaringMember(editor->position()); link.scopeChainAt(document, declaringMember); - Link::ScopeChain scope = link.scopeChain(); // Search for the operator that triggered the completion. QChar completionOperator; @@ -656,7 +662,7 @@ int QmlCodeCompletion::startCompletion(TextEditor::ITextEditable *editor) if (completionOperator.isSpace() || completionOperator.isNull() || isDelimiter(completionOperator) || (completionOperator == QLatin1Char('(') && m_startPosition != editor->position())) { // It's a global completion. - EnumerateProperties enumerateProperties(&link); + EnumerateProperties enumerateProperties(link.context()); enumerateProperties.setGlobalCompletion(true); QHashIterator<QString, const Interpreter::Value *> it(enumerateProperties()); while (it.hasNext()) { @@ -679,14 +685,14 @@ int QmlCodeCompletion::startCompletion(TextEditor::ITextEditable *editor) //qDebug() << "expression:" << expression; if (expression != 0) { - Check evaluate(&link); + Check evaluate(link.context()); // Evaluate the expression under cursor. const Interpreter::Value *value = interp.convertToObject(evaluate(expression)); //qDebug() << "type:" << interp.typeId(value); if (value && completionOperator == QLatin1Char('.')) { // member completion - EnumerateProperties enumerateProperties(&link); + EnumerateProperties enumerateProperties(link.context()); QHashIterator<QString, const Interpreter::Value *> it(enumerateProperties(value)); while (it.hasNext()) { it.next(); diff --git a/src/plugins/qmljseditor/qmlhoverhandler.cpp b/src/plugins/qmljseditor/qmlhoverhandler.cpp index 167a7c887d0..8b94716a170 100644 --- a/src/plugins/qmljseditor/qmlhoverhandler.cpp +++ b/src/plugins/qmljseditor/qmlhoverhandler.cpp @@ -175,7 +175,7 @@ void QmlHoverHandler::updateHelpIdAndTooltip(TextEditor::ITextEditor *editor, in Link link(qmlDocument, snapshot, &interp); link.scopeChainAt(qmlDocument, declaringMember); - Check check(&link); + Check check(link.context()); const Interpreter::Value *value = check(node); QStringList baseClasses; -- GitLab