From fe564852ade33f160be846d823b76b65bad53fd8 Mon Sep 17 00:00:00 2001 From: Fawzi Mohamed <fawzi.mohamed@nokia.com> Date: Mon, 6 Jun 2011 14:13:50 +0200 Subject: [PATCH] Qmljs: added scope for blocks in UiScriptBindings and UiPublicMember correctly insert the scope for code blocks in UiScriptBindings and UiPublicMember, and improve find usages for types (correctly detecting variables in the same scope) Change-Id: Iaaf1a59f041f3831fbe04243b220fb85fde76479 Reviewed-on: http://codereview.qt.nokia.com/335 Reviewed-by: Christian Kamm <christian.d.kamm@nokia.com> --- src/libs/qmljs/qmljsbind.cpp | 30 +++++++++++--- src/libs/qmljs/qmljsbind.h | 4 +- src/libs/qmljs/qmljscheck.cpp | 5 +++ src/libs/qmljs/qmljsscopeastpath.cpp | 25 ++++++++++++ src/libs/qmljs/qmljsscopeastpath.h | 2 + src/libs/qmljs/qmljsscopebuilder.cpp | 33 +++++++++++---- .../qmljseditor/qmljsfindreferences.cpp | 40 ++++++++++++++++--- 7 files changed, 119 insertions(+), 20 deletions(-) diff --git a/src/libs/qmljs/qmljsbind.cpp b/src/libs/qmljs/qmljsbind.cpp index 93580d6fda9..acf87e5f8dd 100644 --- a/src/libs/qmljs/qmljsbind.cpp +++ b/src/libs/qmljs/qmljsbind.cpp @@ -171,9 +171,9 @@ bool Bind::usesQmlPrototype(ObjectValue *prototype, return false; } -Interpreter::ObjectValue *Bind::findFunctionScope(AST::FunctionExpression *node) const +Interpreter::ObjectValue *Bind::findAttachedJSScope(AST::Node *node) const { - return _functionScopes.value(node); + return _attachedJSScopes.value(node); } bool Bind::isGroupedPropertyBinding(AST::Node *node) const @@ -289,9 +289,18 @@ bool Bind::visit(UiImport *ast) return false; } -bool Bind::visit(UiPublicMember *) +bool Bind::visit(UiPublicMember *ast) { - // nothing to do. + const Block *block = AST::cast<const Block*>(ast->statement); + if (block) { + // build block scope + ObjectValue *blockScope = _engine.newObject(/*prototype=*/0); + _attachedJSScopes.insert(ast, blockScope); // associated with the UiPublicMember, not with the block + ObjectValue *parent = switchObjectValue(blockScope); + accept(ast->statement); + switchObjectValue(parent); + return false; + } return true; } @@ -334,7 +343,16 @@ bool Bind::visit(UiScriptBinding *ast) if (i->name) _idEnvironment->setMember(i->name->asString(), _currentObjectValue); } - + const Block *block = AST::cast<const Block*>(ast->statement); + if (block) { + // build block scope + ObjectValue *blockScope = _engine.newObject(/*prototype=*/0); + _attachedJSScopes.insert(ast, blockScope); // associated with the UiScriptBinding, not with the block + ObjectValue *parent = switchObjectValue(blockScope); + accept(ast->statement); + switchObjectValue(parent); + return false; + } return true; } @@ -367,7 +385,7 @@ bool Bind::visit(FunctionExpression *ast) // build function scope ObjectValue *functionScope = _engine.newObject(/*prototype=*/0); - _functionScopes.insert(ast, functionScope); + _attachedJSScopes.insert(ast, functionScope); ObjectValue *parent = switchObjectValue(functionScope); // The order of the following is important. Example: A function with name "arguments" diff --git a/src/libs/qmljs/qmljsbind.h b/src/libs/qmljs/qmljsbind.h index e875be82f93..c86a27d1cd7 100644 --- a/src/libs/qmljs/qmljsbind.h +++ b/src/libs/qmljs/qmljsbind.h @@ -63,7 +63,7 @@ public: bool usesQmlPrototype(Interpreter::ObjectValue *prototype, const Interpreter::Context *context) const; - Interpreter::ObjectValue *findFunctionScope(AST::FunctionExpression *node) const; + Interpreter::ObjectValue *findAttachedJSScope(AST::Node *node) const; bool isGroupedPropertyBinding(AST::Node *node) const; static QString toString(AST::UiQualifiedId *qualifiedId, QChar delimiter = QChar('.')); @@ -102,7 +102,7 @@ private: QHash<AST::Node *, Interpreter::ObjectValue *> _qmlObjects; QSet<AST::Node *> _groupedPropertyBindings; - QHash<AST::FunctionExpression *, Interpreter::ObjectValue *> _functionScopes; + QHash<AST::Node *, Interpreter::ObjectValue *> _attachedJSScopes; QStringList _includedScripts; QList<Interpreter::ImportInfo> _imports; diff --git a/src/libs/qmljs/qmljscheck.cpp b/src/libs/qmljs/qmljscheck.cpp index 5ceafdb62f5..be1ce15c1c3 100644 --- a/src/libs/qmljs/qmljscheck.cpp +++ b/src/libs/qmljs/qmljscheck.cpp @@ -580,6 +580,11 @@ bool Check::visit(UiScriptBinding *ast) if (Block *block = cast<Block *>(ast->statement)) { FunctionBodyCheck bodyCheck; _messages.append(bodyCheck(block->statements, _options)); + Node::accept(ast->qualifiedId, this); + _scopeBuilder.push(ast); + Node::accept(block->statements, this); + _scopeBuilder.pop(); + return false; } return true; diff --git a/src/libs/qmljs/qmljsscopeastpath.cpp b/src/libs/qmljs/qmljsscopeastpath.cpp index 06e786c0d60..2672b56a9bc 100644 --- a/src/libs/qmljs/qmljsscopeastpath.cpp +++ b/src/libs/qmljs/qmljsscopeastpath.cpp @@ -66,6 +66,31 @@ bool ScopeAstPath::preVisit(Node *node) return true; } +bool ScopeAstPath::visit(UiPublicMember *node) +{ + if (node && node->statement && node->statement->kind == node->Kind_Block + && containsOffset(node->statement->firstSourceLocation(), + node->statement->lastSourceLocation())) { + _result.append(node); + Node::accept(node->statement, this); + return false; + } + return true; +} + +bool ScopeAstPath::visit(UiScriptBinding *node) +{ + if (node && node->statement && node->statement->kind == node->Kind_Block + && containsOffset(node->statement->firstSourceLocation(), + node->statement->lastSourceLocation())) + { + _result.append(node); + Node::accept(node->statement, this); + return false; + } + return true; +} + bool ScopeAstPath::visit(UiObjectDefinition *node) { _result.append(node); diff --git a/src/libs/qmljs/qmljsscopeastpath.h b/src/libs/qmljs/qmljsscopeastpath.h index 905a1f87d5b..33e5024c558 100644 --- a/src/libs/qmljs/qmljsscopeastpath.h +++ b/src/libs/qmljs/qmljsscopeastpath.h @@ -52,6 +52,8 @@ protected: using Visitor::visit; virtual bool preVisit(AST::Node *node); + virtual bool visit(AST::UiPublicMember *node); + virtual bool visit(AST::UiScriptBinding *node); virtual bool visit(AST::UiObjectDefinition *node); virtual bool visit(AST::UiObjectBinding *node); virtual bool visit(AST::FunctionDeclaration *node); diff --git a/src/libs/qmljs/qmljsscopebuilder.cpp b/src/libs/qmljs/qmljsscopebuilder.cpp index 5fb853aa0a2..cd41f3ed806 100644 --- a/src/libs/qmljs/qmljsscopebuilder.cpp +++ b/src/libs/qmljs/qmljsscopebuilder.cpp @@ -62,11 +62,20 @@ void ScopeBuilder::push(AST::Node *node) if (qmlObject) setQmlScopeObject(qmlObject); - // JS scopes (catch both, FunctionExpression and FunctionDeclaration) - if (FunctionExpression *fun = dynamic_cast<FunctionExpression *>(node)) { - ObjectValue *functionScope = _doc->bind()->findFunctionScope(fun); - if (functionScope) - _context->scopeChain().jsScopes += functionScope; + // JS scopes + switch (node->kind) { + case Node::Kind_UiScriptBinding: + case Node::Kind_FunctionDeclaration: + case Node::Kind_FunctionExpression: + case Node::Kind_UiPublicMember: + { + ObjectValue *scope = _doc->bind()->findAttachedJSScope(node); + if (scope) + _context->scopeChain().jsScopes += scope; + break; + } + default: + break; } _context->scopeChain().update(); @@ -84,9 +93,19 @@ void ScopeBuilder::pop() _nodes.removeLast(); // JS scopes - if (FunctionExpression *fun = dynamic_cast<FunctionExpression *>(toRemove)) { - if (_doc->bind()->findFunctionScope(fun)) + switch (toRemove->kind) { + case Node::Kind_UiScriptBinding: + case Node::Kind_FunctionDeclaration: + case Node::Kind_FunctionExpression: + case Node::Kind_UiPublicMember: + { + ObjectValue *scope = _doc->bind()->findAttachedJSScope(toRemove); + if (scope) _context->scopeChain().jsScopes.removeLast(); + break; + } + default: + break; } // QML scope object diff --git a/src/plugins/qmljseditor/qmljsfindreferences.cpp b/src/plugins/qmljseditor/qmljsfindreferences.cpp index 26e9bbc27e6..e3e0d51d847 100644 --- a/src/plugins/qmljseditor/qmljsfindreferences.cpp +++ b/src/plugins/qmljseditor/qmljsfindreferences.cpp @@ -109,7 +109,12 @@ protected: && _context->scopeChain().qmlScopeObjects.contains(_scope)) { _usages.append(node->identifierToken); } - + if (AST::cast<Block *>(node->statement)) { + _builder.push(node); + Node::accept(node->statement, this); + _builder.pop(); + return false; + } return true; } @@ -144,6 +149,13 @@ protected: && checkQmlScope()) { _usages.append(node->qualifiedId->identifierToken); } + if (AST::cast<Block *>(node->statement)) { + Node::accept(node->qualifiedId, this); + _builder.push(node); + Node::accept(node->statement, this); + _builder.pop(); + return false; + } return true; } @@ -324,6 +336,12 @@ protected: if (tVal == _typeValue) _usages.append(node->typeToken); } + if (AST::cast<Block *>(node->statement)) { + _builder.push(node); + Node::accept(node->statement, this); + _builder.pop(); + return false; + } return true; } @@ -345,6 +363,18 @@ protected: return false; } + virtual bool visit(AST::UiScriptBinding *node) + { + if (AST::cast<Block *>(node->statement)) { + Node::accept(node->qualifiedId, this); + _builder.push(node); + Node::accept(node->statement, this); + _builder.pop(); + return false; + } + return true; + } + virtual bool visit(AST::IdentifierExpression *node) { if (!node->name || node->name->asString() != _name) @@ -495,9 +525,9 @@ protected: _name = node->name->asString(); if ((!_name.isEmpty()) && _name.at(0).isUpper()) { // a possible type - _targetValue = _context->lookupType(_doc.data(), QStringList(_name)); - _scope = 0; - _typeKind = TypeKind; + _targetValue = _context->lookup(_name, &_scope); + if (value_cast<const ObjectValue*>(_targetValue)) + _typeKind = TypeKind; } } return true; @@ -517,7 +547,7 @@ protected: const ObjectValue *lhsObj = lhsValue->asObjectValue(); if (lhsObj) { _scope = lhsObj; - _targetValue = value_cast<const ObjectValue*>(lhsObj->lookupMember(_name, _context)); + _targetValue = lhsObj->lookupMember(_name, _context); _typeKind = TypeKind; } } -- GitLab