Commit fe564852 authored by Fawzi Mohamed's avatar Fawzi Mohamed
Browse files

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: default avatarChristian Kamm <christian.d.kamm@nokia.com>
parent c54575e6
......@@ -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"
......
......@@ -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;
......
......@@ -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;
......
......@@ -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);
......
......@@ -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);
......
......@@ -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
......
......@@ -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;
}
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment