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(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(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 _qmlObjects; QSet _groupedPropertyBindings; - QHash _functionScopes; + QHash _attachedJSScopes; QStringList _includedScripts; QList _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(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(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(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(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(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(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(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(_targetValue)) + _typeKind = TypeKind; } } return true; @@ -517,7 +547,7 @@ protected: const ObjectValue *lhsObj = lhsValue->asObjectValue(); if (lhsObj) { _scope = lhsObj; - _targetValue = value_cast(lhsObj->lookupMember(_name, _context)); + _targetValue = lhsObj->lookupMember(_name, _context); _typeKind = TypeKind; } }