forked from qt-creator/qt-creator
		
	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>
			
			
This commit is contained in:
		@@ -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);
 | 
			
		||||
 
 | 
			
		||||
@@ -133,6 +133,7 @@ private:
 | 
			
		||||
    QList<AST::Node *> _chain;
 | 
			
		||||
    QStack<StringSet> m_idStack;
 | 
			
		||||
    QStack<StringSet> m_propertyStack;
 | 
			
		||||
    QStack<QString> m_typeStack;
 | 
			
		||||
 | 
			
		||||
    class MessageTypeAndSuppression
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -215,6 +215,17 @@ StaticAnalysisMessages::StaticAnalysisMessages()
 | 
			
		||||
           tr("maximum string value length is %1"), 1);
 | 
			
		||||
    newMsg(ErrInvalidArrayValueLength, Error,
 | 
			
		||||
           tr("%1 elements expected in array value"), 1);
 | 
			
		||||
    newMsg(WarnImperativeCodeNotEditableInVisualDesigner, Warning,
 | 
			
		||||
            tr("Imperative code is not supported in the Qt Quick Designer"));
 | 
			
		||||
    newMsg(WarnUnsupportedTypeInVisualDesigner, Warning,
 | 
			
		||||
            tr("This type is not supported in the Qt Quick Designer"));
 | 
			
		||||
    newMsg(WarnReferenceToParentItemNotSupportedByVisualDesigner, Warning,
 | 
			
		||||
            tr("Reference to parent item cannot be resolved correctly by the Qt Quick Designer"));
 | 
			
		||||
    newMsg(WarnUndefinedValueForVisualDesigner, Warning,
 | 
			
		||||
            tr("This visual property binding cannot be evaluted in the local context "
 | 
			
		||||
               "and might not show up in Qt Quick Designer as expected"));
 | 
			
		||||
    newMsg(WarnStatesOnlyInRootItemForVisualDesigner, Warning,
 | 
			
		||||
            tr("Qt Quick Designer only supports states in the root item "));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // anonymous namespace
 | 
			
		||||
 
 | 
			
		||||
@@ -101,6 +101,11 @@ enum Type
 | 
			
		||||
    WarnConfusingExpressionStatement = 127,
 | 
			
		||||
    HintDeclarationsShouldBeAtStartOfFunction = 201,
 | 
			
		||||
    HintOneStatementPerLine = 202,
 | 
			
		||||
    WarnImperativeCodeNotEditableInVisualDesigner = 203,
 | 
			
		||||
    WarnUnsupportedTypeInVisualDesigner = 204,
 | 
			
		||||
    WarnReferenceToParentItemNotSupportedByVisualDesigner = 205,
 | 
			
		||||
    WarnUndefinedValueForVisualDesigner = 206,
 | 
			
		||||
    WarnStatesOnlyInRootItemForVisualDesigner = 207,
 | 
			
		||||
    ErrUnknownComponent = 300,
 | 
			
		||||
    ErrCouldNotResolvePrototypeOf = 301,
 | 
			
		||||
    ErrCouldNotResolvePrototype = 302,
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user