summaryrefslogtreecommitdiff
path: root/src/libs/qmljs/qmljscheck.cpp
diff options
context:
space:
mode:
authorThomas Hartmann <Thomas.Hartmann@nokia.com>2012-09-17 14:06:03 +0200
committerThomas Hartmann <Thomas.Hartmann@nokia.com>2012-09-17 14:45:56 +0200
commite5699c09255ec5b85def92bac4f7746bb3f8d3b2 (patch)
treee1d16c026e47f5eb3dc73e49757d005690e45d47 /src/libs/qmljs/qmljscheck.cpp
parent484d4dc26e00b2511ed1f09524803121e2374f60 (diff)
downloadqt-creator-e5699c09255ec5b85def92bac4f7746bb3f8d3b2.tar.gz
QmlJS.Check: Warnings for qml code not supported by Qt Quick Designer
This patch adds several warnings for qml code not supported by Qt Quick Designer. * WarnImperativeCodeNotEditableInVisualDesigner: This warns about imperative code affecting a visual property. e.g.: "x = 10;" * WarnUnsupportedTypeInVisualDesigner: This warns about types which are currently not supported. * WarnReferenceToParentItemNotSupportedByDesigner: This warns about things like: "width: parent.width" in the root item. * WarnUndefinedValueForDesigner: This warns about visual properties that cannot be evaluated in the local context. e.g.: "x: somethingNotDefinedInTheLocalContext.x" * WarnStatesOnlyInRootItemForDesigner: This warns about states not defined in the root item. All the Qt Quick designer related warnings are disabled by default in Check. Change-Id: If31a8199fb95dc8bf6ac613634a2e442e436e267 Reviewed-by: Christian Kamm <kamm@incasoftware.de>
Diffstat (limited to 'src/libs/qmljs/qmljscheck.cpp')
-rw-r--r--src/libs/qmljs/qmljscheck.cpp138
1 files changed, 131 insertions, 7 deletions
diff --git a/src/libs/qmljs/qmljscheck.cpp b/src/libs/qmljs/qmljscheck.cpp
index fbd0c5f083..11a64daf53 100644
--- a/src/libs/qmljs/qmljscheck.cpp
+++ b/src/libs/qmljs/qmljscheck.cpp
@@ -503,8 +503,44 @@ private:
bool _seenNonDeclarationStatement;
};
+class VisualAspectsPropertyBlackList : public QStringList
+{
+public:
+ VisualAspectsPropertyBlackList()
+ {
+ (*this) << QLatin1String("x") << QLatin1String("y") << QLatin1String("z")
+ << QLatin1String("width") << QLatin1String("height") << QLatin1String("color")
+ << QLatin1String("opacity") << QLatin1String("scale")
+ << QLatin1String("rotation") << QLatin1String("margins")
+ << QLatin1String("verticalCenterOffset") << QLatin1String("horizontalCenterOffset")
+ << QLatin1String("baselineOffset") << QLatin1String("bottomMargin")
+ << QLatin1String("topMargin") << QLatin1String("leftMargin")
+ << QLatin1String("rightMargin") << QLatin1String("baseline")
+ << QLatin1String("centerIn") << QLatin1String("fill")
+ << QLatin1String("left") << QLatin1String("right")
+ << QLatin1String("mirrored") << QLatin1String("verticalCenter")
+ << QLatin1String("horizontalCenter");
+
+ }
+};
+
+class UnsupportedTypesByVisualDesigner : public QStringList
+{
+public:
+ UnsupportedTypesByVisualDesigner()
+ {
+ (*this) << QLatin1String("Transform") << QLatin1String("Timer")
+ << QLatin1String("Rotation") << QLatin1String("Scale")
+ << QLatin1String("Translate") << QLatin1String("Package")
+ << QLatin1String("Particles");
+ }
+
+};
} // end of anonymous namespace
+Q_GLOBAL_STATIC(VisualAspectsPropertyBlackList, visualAspectsPropertyBlackList)
+Q_GLOBAL_STATIC(UnsupportedTypesByVisualDesigner, unsupportedTypesByVisualDesigner)
+
Check::Check(Document::Ptr doc, const ContextPtr &context)
: _doc(doc)
, _context(context)
@@ -524,6 +560,11 @@ Check::Check(Document::Ptr doc, const ContextPtr &context)
disableMessage(HintBinaryOperatorSpacing);
disableMessage(HintOneStatementPerLine);
disableMessage(HintExtraParentheses);
+ disableMessage(WarnImperativeCodeNotEditableInVisualDesigner);
+ disableMessage(WarnUnsupportedTypeInVisualDesigner);
+ disableMessage(WarnReferenceToParentItemNotSupportedByVisualDesigner);
+ disableMessage(WarnUndefinedValueForVisualDesigner);
+ disableMessage(WarnStatesOnlyInRootItemForVisualDesigner);
}
Check::~Check()
@@ -569,21 +610,28 @@ bool Check::visit(UiProgram *)
bool Check::visit(UiObjectInitializer *)
{
+ QString typeName;
m_propertyStack.push(StringSet());
- UiObjectDefinition *objectDefinition = cast<UiObjectDefinition *>(parent());
- if (objectDefinition && objectDefinition->qualifiedTypeNameId->name == "Component")
- m_idStack.push(StringSet());
- UiObjectBinding *objectBinding = cast<UiObjectBinding *>(parent());
- if (objectBinding && objectBinding->qualifiedTypeNameId->name == "Component")
- m_idStack.push(StringSet());
+ UiQualifiedId *qualifiedTypeId = qualifiedTypeNameId(parent());
+ if (qualifiedTypeId) {
+ typeName = qualifiedTypeId->name.toString();
+ if (typeName == QLatin1String("Component"))
+ m_idStack.push(StringSet());
+ }
+
+ if (!typeName.isEmpty() && typeName.at(0).isUpper())
+ m_typeStack.push(typeName);
+
if (m_idStack.isEmpty())
m_idStack.push(StringSet());
+
return true;
}
void Check::endVisit(UiObjectInitializer *)
{
m_propertyStack.pop();
+ m_typeStack.pop();
UiObjectDefinition *objectDenition = cast<UiObjectDefinition *>(parent());
if (objectDenition && objectDenition->qualifiedTypeNameId->name == "Component")
m_idStack.pop();
@@ -619,6 +667,57 @@ bool Check::visit(UiObjectBinding *ast)
return false;
}
+static bool expressionAffectsVisualAspects(BinaryExpression *expression)
+{
+ if (expression->op == QSOperator::Assign
+ || expression->op == QSOperator::InplaceSub
+ || expression->op == QSOperator::InplaceAdd
+ || expression->op == QSOperator::InplaceDiv
+ || expression->op == QSOperator::InplaceMul
+ || expression->op == QSOperator::InplaceOr
+ || expression->op == QSOperator::InplaceXor
+ || expression->op == QSOperator::InplaceAnd) {
+
+ const ExpressionNode *lhsValue = expression->left;
+
+ if (const IdentifierExpression* identifierExpression = cast<const IdentifierExpression *>(lhsValue)) {
+ if (visualAspectsPropertyBlackList()->contains(identifierExpression->name.toString()))
+ return true;
+ } else if (const FieldMemberExpression* fieldMemberExpression = cast<const FieldMemberExpression *>(lhsValue)) {
+ if (visualAspectsPropertyBlackList()->contains(fieldMemberExpression->name.toString()))
+ return true;
+ }
+ }
+ return false;
+}
+
+static UiQualifiedId *getRightMostIdentifier(UiQualifiedId *typeId)
+{
+ if (typeId->next)
+ return getRightMostIdentifier(typeId->next);
+
+ return typeId;
+}
+
+static bool checkTypeForDesignerSupport(UiQualifiedId *typeId)
+{
+ return unsupportedTypesByVisualDesigner()->contains(getRightMostIdentifier(typeId)->name.toString());
+}
+
+static bool checkTopLevelBindingForParentReference(ExpressionStatement *expStmt, const QString &source)
+{
+ if (!expStmt)
+ return false;
+
+ SourceLocation location = locationFromRange(expStmt->firstSourceLocation(), expStmt->lastSourceLocation());
+ QString stmtSource = source.mid(location.begin(), location.length);
+
+ if (stmtSource.contains(QRegExp("(^|\\W)parent\\.")))
+ return true;
+
+ return false;
+}
+
void Check::visitQmlObject(Node *ast, UiQualifiedId *typeId,
UiObjectInitializer *initializer)
{
@@ -630,9 +729,16 @@ void Check::visitQmlObject(Node *ast, UiQualifiedId *typeId,
return;
}
+ const SourceLocation typeErrorLocation = fullLocationForQualifiedId(typeId);
+
+ if (checkTypeForDesignerSupport(typeId))
+ addMessage(WarnUnsupportedTypeInVisualDesigner, typeErrorLocation);
+
+ if (m_typeStack.count() > 1 && getRightMostIdentifier(typeId)->name.toString() == QLatin1String("State"))
+ addMessage(WarnStatesOnlyInRootItemForVisualDesigner, typeErrorLocation);
+
bool typeError = false;
if (_importsOk) {
- const SourceLocation typeErrorLocation = fullLocationForQualifiedId(typeId);
const ObjectValue *prototype = _context->lookupType(_doc.data(), typeId);
if (!prototype) {
typeError = true;
@@ -712,6 +818,13 @@ bool Check::visit(UiScriptBinding *ast)
m_idStack.top().insert(id);
}
+ if (m_typeStack.count() == 1
+ && visualAspectsPropertyBlackList()->contains(ast->qualifiedId->name.toString())
+ && checkTopLevelBindingForParentReference(cast<ExpressionStatement *>(ast->statement), _doc->source())) {
+ addMessage(WarnReferenceToParentItemNotSupportedByVisualDesigner,
+ locationFromRange(ast->firstSourceLocation(), ast->lastSourceLocation()));
+ }
+
checkProperty(ast->qualifiedId);
if (!ast->statement)
@@ -722,6 +835,12 @@ bool Check::visit(UiScriptBinding *ast)
Evaluate evaluator(&_scopeChain);
const Value *rhsValue = evaluator(ast->statement);
+ if (visualAspectsPropertyBlackList()->contains(ast->qualifiedId->name.toString()) &&
+ rhsValue->asUndefinedValue()) {
+ addMessage(WarnUndefinedValueForVisualDesigner,
+ locationFromRange(ast->firstSourceLocation(), ast->lastSourceLocation()));
+ }
+
const SourceLocation loc = locationFromRange(ast->statement->firstSourceLocation(),
ast->statement->lastSourceLocation());
AssignmentCheck assignmentCheck;
@@ -911,6 +1030,11 @@ bool Check::visit(BinaryExpression *ast)
addMessage(HintBinaryOperatorSpacing, op);
}
+ SourceLocation expressionSourceLocation = locationFromRange(ast->firstSourceLocation(),
+ ast->lastSourceLocation());
+ if (expressionAffectsVisualAspects(ast))
+ addMessage(WarnImperativeCodeNotEditableInVisualDesigner, expressionSourceLocation);
+
// check ==, !=
if (ast->op == QSOperator::Equal || ast->op == QSOperator::NotEqual) {
Evaluate eval(&_scopeChain);