diff --git a/src/libs/qmljs/qmljsbind.cpp b/src/libs/qmljs/qmljsbind.cpp index 93580d6fda9b5523b7ecc07f914d11d6792808a7..acf87e5f8dd78806b25bdb185d820e96639b14af 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 e875be82f9361fbeffb27a9350458cd74b338dd6..c86a27d1cd74efc50d2cee272d9c080c5d93cb5d 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 5ceafdb62f51c99a294e32cc766a3d71ffa1e1b1..be1ce15c1c396d2a16f0e7beff56cf2ce8e7ff7f 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 06e786c0d604b5df3edaa20531caef0edea8cf0a..2672b56a9bc367ee5968930ae8ccce8a8431a490 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 905a1f87d5b004df3601feb7eeebb7d16986de7d..33e5024c5588759dc3bd93e953c8836111175973 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 5fb853aa0a2e57ad60d1cc437f492803db67d94d..cd41f3ed8068b3b19d1d7015100610e11c6c9e29 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 26e9bbc27e68770f73b84e65c17b62aa28123dcb..e3e0d51d847af332eb84a9b59f1e1273c9a71370 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; } }