Commit 33a130e2 authored by Christian Kamm's avatar Christian Kamm
Browse files

QmlJS: Fix completion inside grouped propery bindings.

Task-number: QTCREATORBUG-3541
Change-Id: Ida8e59b65836c8515fbfbd2a9e4737d9ae04e76c
Reviewed-on: http://codereview.qt.nokia.com/639

Reviewed-by: default avatarFawzi Mohamed <fawzi.mohamed@nokia.com>
parent 87db498e
......@@ -308,17 +308,18 @@ bool Bind::visit(UiObjectDefinition *ast)
{
// an UiObjectDefinition may be used to group property bindings
// think anchors { ... }
bool isGroupedBinding = false;
for (UiQualifiedId *it = ast->qualifiedTypeNameId; it; it = it->next) {
if (!it->next && it->name)
isGroupedBinding = it->name->asString().at(0).isLower();
}
bool isGroupedBinding = ast->qualifiedTypeNameId
&& ast->qualifiedTypeNameId->name
&& ast->qualifiedTypeNameId->name->asString().at(0).isLower();
if (!isGroupedBinding) {
ObjectValue *value = bindObject(ast->qualifiedTypeNameId, ast->initializer);
_qmlObjects.insert(ast, value);
} else {
_groupedPropertyBindings.insert(ast);
Interpreter::ObjectValue *oldObjectValue = switchObjectValue(0);
accept(ast->initializer);
switchObjectValue(oldObjectValue);
}
return false;
......@@ -337,7 +338,7 @@ bool Bind::visit(UiObjectBinding *ast)
bool Bind::visit(UiScriptBinding *ast)
{
if (toString(ast->qualifiedId) == QLatin1String("id")) {
if (_currentObjectValue && toString(ast->qualifiedId) == QLatin1String("id")) {
if (ExpressionStatement *e = cast<ExpressionStatement*>(ast->statement))
if (IdentifierExpression *i = cast<IdentifierExpression*>(e->expression))
if (i->name)
......@@ -369,7 +370,8 @@ bool Bind::visit(VariableDeclaration *ast)
return false;
ASTVariableReference *ref = new ASTVariableReference(ast, &_engine);
_currentObjectValue->setMember(ast->name->asString(), ref);
if (_currentObjectValue)
_currentObjectValue->setMember(ast->name->asString(), ref);
return true;
}
......@@ -380,7 +382,7 @@ bool Bind::visit(FunctionExpression *ast)
// return false;
ASTFunctionValue *function = new ASTFunctionValue(ast, _doc, &_engine);
if (ast->name && cast<FunctionDeclaration *>(ast))
if (_currentObjectValue && ast->name && cast<FunctionDeclaration *>(ast))
_currentObjectValue->setMember(ast->name->asString(), function);
// build function scope
......
......@@ -461,9 +461,9 @@ bool Check::visit(UiObjectBinding *ast)
void Check::visitQmlObject(Node *ast, UiQualifiedId *typeId,
UiObjectInitializer *initializer)
{
// If the 'typeId' starts with a lower-case letter, it doesn't define
// a new object instance. For instance: anchors { ... }
if (typeId->name->asString().at(0).isLower() && ! typeId->next) {
// Don't do type checks if it's a grouped property binding.
// For instance: anchors { ... }
if (_doc->bind()->isGroupedPropertyBinding(ast)) {
checkScopeObjectMember(typeId);
// ### don't give up!
return;
......
......@@ -433,8 +433,10 @@ IAssistProposal *QmlJSCompletionAssistProcessor::perform(const IAssistInterface
const Interpreter::ObjectValue *qmlScopeType = 0;
if (contextFinder.isInQmlContext()) {
// find the enclosing qml object
// ### this should use semanticInfo.declaringMember instead, but that may also return functions
for (int i = path.size() - 1; i >= 0; --i) {
int i;
for (i = path.size() - 1; i >= 0; --i) {
AST::Node *node = path[i];
if (AST::cast<AST::UiObjectDefinition *>(node) || AST::cast<AST::UiObjectBinding *>(node)) {
qmlScopeType = document->bind()->findQmlObject(node);
......@@ -442,6 +444,25 @@ IAssistProposal *QmlJSCompletionAssistProcessor::perform(const IAssistInterface
break;
}
}
// grouped property bindings change the scope type
for (i++; i < path.size(); ++i) {
AST::UiObjectDefinition *objDef = AST::cast<AST::UiObjectDefinition *>(path[i]);
if (!objDef || !document->bind()->isGroupedPropertyBinding(objDef))
break;
const Interpreter::ObjectValue *newScopeType = qmlScopeType;
for (AST::UiQualifiedId *it = objDef->qualifiedTypeNameId; it; it = it->next) {
if (!newScopeType || !it->name) {
newScopeType = 0;
break;
}
const Interpreter::Value *v = newScopeType->lookupMember(it->name->asString(), context);
v = context->lookupReference(v);
newScopeType = Interpreter::value_cast<const Interpreter::ObjectValue *>(v);
}
if (!newScopeType)
break;
qmlScopeType = newScopeType;
}
// fallback to getting the base type object
if (!qmlScopeType)
qmlScopeType = context->lookupType(document.data(), contextFinder.qmlObjectTypeName());
......
Supports Markdown
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