diff --git a/src/libs/qmljs/qmljsbind.cpp b/src/libs/qmljs/qmljsbind.cpp index acf87e5f8dd78806b25bdb185d820e96639b14af..fb4291cd6953e255c79408a5d0a26930021bdbac 100644 --- a/src/libs/qmljs/qmljsbind.cpp +++ b/src/libs/qmljs/qmljsbind.cpp @@ -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 diff --git a/src/libs/qmljs/qmljscheck.cpp b/src/libs/qmljs/qmljscheck.cpp index be1ce15c1c396d2a16f0e7beff56cf2ce8e7ff7f..1639c5dcd0f084c6227e7e72bc72c88546ee111f 100644 --- a/src/libs/qmljs/qmljscheck.cpp +++ b/src/libs/qmljs/qmljscheck.cpp @@ -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; diff --git a/src/plugins/qmljseditor/qmljscompletionassist.cpp b/src/plugins/qmljseditor/qmljscompletionassist.cpp index 2e09bfc4d6c2382cff95c5d7c0792c5551e5c467..017fffeeda77aba2d4be554266b081544acd7483 100644 --- a/src/plugins/qmljseditor/qmljscompletionassist.cpp +++ b/src/plugins/qmljseditor/qmljscompletionassist.cpp @@ -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());