forked from qt-creator/qt-creator
QmlJS: Fix completion inside grouped propery bindings.
Task-number: QTCREATORBUG-3541 Change-Id: Ida8e59b65836c8515fbfbd2a9e4737d9ae04e76c Reviewed-on: http://codereview.qt.nokia.com/639 Reviewed-by: Fawzi Mohamed <fawzi.mohamed@nokia.com>
This commit is contained in:
@@ -308,17 +308,18 @@ bool Bind::visit(UiObjectDefinition *ast)
|
|||||||
{
|
{
|
||||||
// an UiObjectDefinition may be used to group property bindings
|
// an UiObjectDefinition may be used to group property bindings
|
||||||
// think anchors { ... }
|
// think anchors { ... }
|
||||||
bool isGroupedBinding = false;
|
bool isGroupedBinding = ast->qualifiedTypeNameId
|
||||||
for (UiQualifiedId *it = ast->qualifiedTypeNameId; it; it = it->next) {
|
&& ast->qualifiedTypeNameId->name
|
||||||
if (!it->next && it->name)
|
&& ast->qualifiedTypeNameId->name->asString().at(0).isLower();
|
||||||
isGroupedBinding = it->name->asString().at(0).isLower();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isGroupedBinding) {
|
if (!isGroupedBinding) {
|
||||||
ObjectValue *value = bindObject(ast->qualifiedTypeNameId, ast->initializer);
|
ObjectValue *value = bindObject(ast->qualifiedTypeNameId, ast->initializer);
|
||||||
_qmlObjects.insert(ast, value);
|
_qmlObjects.insert(ast, value);
|
||||||
} else {
|
} else {
|
||||||
_groupedPropertyBindings.insert(ast);
|
_groupedPropertyBindings.insert(ast);
|
||||||
|
Interpreter::ObjectValue *oldObjectValue = switchObjectValue(0);
|
||||||
|
accept(ast->initializer);
|
||||||
|
switchObjectValue(oldObjectValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@@ -337,7 +338,7 @@ bool Bind::visit(UiObjectBinding *ast)
|
|||||||
|
|
||||||
bool Bind::visit(UiScriptBinding *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 (ExpressionStatement *e = cast<ExpressionStatement*>(ast->statement))
|
||||||
if (IdentifierExpression *i = cast<IdentifierExpression*>(e->expression))
|
if (IdentifierExpression *i = cast<IdentifierExpression*>(e->expression))
|
||||||
if (i->name)
|
if (i->name)
|
||||||
@@ -369,7 +370,8 @@ bool Bind::visit(VariableDeclaration *ast)
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
ASTVariableReference *ref = new ASTVariableReference(ast, &_engine);
|
ASTVariableReference *ref = new ASTVariableReference(ast, &_engine);
|
||||||
_currentObjectValue->setMember(ast->name->asString(), ref);
|
if (_currentObjectValue)
|
||||||
|
_currentObjectValue->setMember(ast->name->asString(), ref);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -380,7 +382,7 @@ bool Bind::visit(FunctionExpression *ast)
|
|||||||
// return false;
|
// return false;
|
||||||
|
|
||||||
ASTFunctionValue *function = new ASTFunctionValue(ast, _doc, &_engine);
|
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);
|
_currentObjectValue->setMember(ast->name->asString(), function);
|
||||||
|
|
||||||
// build function scope
|
// build function scope
|
||||||
|
@@ -461,9 +461,9 @@ bool Check::visit(UiObjectBinding *ast)
|
|||||||
void Check::visitQmlObject(Node *ast, UiQualifiedId *typeId,
|
void Check::visitQmlObject(Node *ast, UiQualifiedId *typeId,
|
||||||
UiObjectInitializer *initializer)
|
UiObjectInitializer *initializer)
|
||||||
{
|
{
|
||||||
// If the 'typeId' starts with a lower-case letter, it doesn't define
|
// Don't do type checks if it's a grouped property binding.
|
||||||
// a new object instance. For instance: anchors { ... }
|
// For instance: anchors { ... }
|
||||||
if (typeId->name->asString().at(0).isLower() && ! typeId->next) {
|
if (_doc->bind()->isGroupedPropertyBinding(ast)) {
|
||||||
checkScopeObjectMember(typeId);
|
checkScopeObjectMember(typeId);
|
||||||
// ### don't give up!
|
// ### don't give up!
|
||||||
return;
|
return;
|
||||||
|
@@ -433,8 +433,10 @@ IAssistProposal *QmlJSCompletionAssistProcessor::perform(const IAssistInterface
|
|||||||
|
|
||||||
const Interpreter::ObjectValue *qmlScopeType = 0;
|
const Interpreter::ObjectValue *qmlScopeType = 0;
|
||||||
if (contextFinder.isInQmlContext()) {
|
if (contextFinder.isInQmlContext()) {
|
||||||
|
// find the enclosing qml object
|
||||||
// ### this should use semanticInfo.declaringMember instead, but that may also return functions
|
// ### 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];
|
AST::Node *node = path[i];
|
||||||
if (AST::cast<AST::UiObjectDefinition *>(node) || AST::cast<AST::UiObjectBinding *>(node)) {
|
if (AST::cast<AST::UiObjectDefinition *>(node) || AST::cast<AST::UiObjectBinding *>(node)) {
|
||||||
qmlScopeType = document->bind()->findQmlObject(node);
|
qmlScopeType = document->bind()->findQmlObject(node);
|
||||||
@@ -442,6 +444,25 @@ IAssistProposal *QmlJSCompletionAssistProcessor::perform(const IAssistInterface
|
|||||||
break;
|
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
|
// fallback to getting the base type object
|
||||||
if (!qmlScopeType)
|
if (!qmlScopeType)
|
||||||
qmlScopeType = context->lookupType(document.data(), contextFinder.qmlObjectTypeName());
|
qmlScopeType = context->lookupType(document.data(), contextFinder.qmlObjectTypeName());
|
||||||
|
Reference in New Issue
Block a user