From f0674aa7e9853cf5d3d48e3832a67de1b4033ad9 Mon Sep 17 00:00:00 2001 From: Christian Kamm <christian.d.kamm@nokia.com> Date: Tue, 23 Feb 2010 17:02:50 +0100 Subject: [PATCH] Add check for anchor line, changed value assignment checks into visitor. Done-with: Erik Verbruggen --- src/libs/qmljs/qmljscheck.cpp | 174 +++++++++++++++++----------- src/libs/qmljs/qmljscheck.h | 5 - src/libs/qmljs/qmljsinterpreter.cpp | 43 ++++++- src/libs/qmljs/qmljsinterpreter.h | 22 ++++ 4 files changed, 168 insertions(+), 76 deletions(-) diff --git a/src/libs/qmljs/qmljscheck.cpp b/src/libs/qmljs/qmljscheck.cpp index 8269f92c893..8a7592dfc0e 100644 --- a/src/libs/qmljs/qmljscheck.cpp +++ b/src/libs/qmljs/qmljscheck.cpp @@ -62,6 +62,108 @@ using namespace QmlJS; using namespace QmlJS::AST; using namespace QmlJS::Interpreter; + +namespace { + +class AssignmentCheck : public ValueVisitor +{ +public: + DiagnosticMessage operator()( + const SourceLocation &location, + const Interpreter::Value *lhsValue, + const Interpreter::Value *rhsValue, + ExpressionNode *ast) + { + _message = DiagnosticMessage(DiagnosticMessage::Error, location, QString()); + _rhsValue = rhsValue; + _ast = ast; + + if (lhsValue) + lhsValue->accept(this); + + return _message; + } + + virtual void visit(const NumberValue *) + { + // ### Consider enums: elide: "ElideLeft" is valid, but currently elide is a NumberValue. + if (/*cast<StringLiteral *>(_ast) + ||*/ _ast->kind == Node::Kind_TrueLiteral + || _ast->kind == Node::Kind_FalseLiteral) { + _message.message = QCoreApplication::translate("QmlJS::Check", "numerical value expected"); + } + } + + virtual void visit(const BooleanValue *) + { + UnaryMinusExpression *unaryMinus = cast<UnaryMinusExpression *>(_ast); + + if (cast<StringLiteral *>(_ast) + || cast<NumericLiteral *>(_ast) + || (unaryMinus && cast<NumericLiteral *>(unaryMinus->expression))) { + _message.message = QCoreApplication::translate("QmlJS::Check", "boolean value expected"); + } + } + + virtual void visit(const StringValue *) + { + UnaryMinusExpression *unaryMinus = cast<UnaryMinusExpression *>(_ast); + + if (cast<NumericLiteral *>(_ast) + || (unaryMinus && cast<NumericLiteral *>(unaryMinus->expression)) + || _ast->kind == Node::Kind_TrueLiteral + || _ast->kind == Node::Kind_FalseLiteral) { + _message.message = QCoreApplication::translate("QmlJS::Check", "string value expected"); + } + } + + virtual void visit(const EasingCurveNameValue *) + { + if (StringLiteral *stringLiteral = cast<StringLiteral *>(_ast)) { + const QString curveName = stringLiteral->value->asString(); + + // ### update when easing changes hit master + if (!EasingCurveNameValue::curveNames().contains(curveName)) { + _message.message = tr(Messages::unknown_easing_curve_name); + } + } else if (_rhsValue->asUndefinedValue()) { + _message.kind = DiagnosticMessage::Warning; + _message.message = tr(Messages::value_might_be_undefined); + } else if (! _rhsValue->asStringValue()) { + _message.message = tr(Messages::easing_curve_not_a_string); + } + } + + virtual void visit(const ColorValue *) + { + if (StringLiteral *stringLiteral = cast<StringLiteral *>(_ast)) { + const QString colorString = stringLiteral->value->asString(); + +#ifndef NO_DECLARATIVE_BACKEND + bool ok = false; + QmlStringConverters::colorFromString(colorString, &ok); + if (!ok) + _message.message = QCoreApplication::translate("QmlJS::Check", "not a valid color"); +#endif + } else { + visit((StringValue *)0); + } + } + + virtual void visit(const AnchorLineValue *) + { + if (! (_rhsValue->asAnchorLineValue() || _rhsValue->asUndefinedValue())) + _message.message = QCoreApplication::translate("QmlJS::Check", "expected anchor line"); + } + + DiagnosticMessage _message; + const Value *_rhsValue; + ExpressionNode *_ast; +}; + +} // end of anonymous namespace + + Check::Check(Document::Ptr doc, const Snapshot &snapshot) : _doc(doc) , _snapshot(snapshot) @@ -131,17 +233,6 @@ void Check::visitQmlObject(Node *ast, UiQualifiedId *typeId, _scopeBuilder.pop(); } -void Check::errorOnWrongRhs(const SourceLocation &loc, const Value *lhsValue) -{ - if (lhsValue->asBooleanValue()) { - error(loc, QCoreApplication::translate("QmlJS::Check", "boolean value expected")); - } else if (lhsValue->asNumberValue()) { - error(loc, QCoreApplication::translate("QmlJS::Check", "numerical value expected")); - } else if (lhsValue->asStringValue()) { - error(loc, QCoreApplication::translate("QmlJS::Check", "string value expected")); - } -} - bool Check::visit(UiScriptBinding *ast) { // special case for id property @@ -181,7 +272,10 @@ bool Check::visit(UiScriptBinding *ast) const SourceLocation loc = locationFromRange(expStmt->firstSourceLocation(), expStmt->lastSourceLocation()); - checkPropertyAssignment(loc, lhsValue, rhsValue, expr); + AssignmentCheck assignmentCheck; + DiagnosticMessage message = assignmentCheck(loc, lhsValue, rhsValue, expr); + if (! message.message.isEmpty()) + _messages += message; } } @@ -189,62 +283,6 @@ bool Check::visit(UiScriptBinding *ast) return true; } -void Check::checkPropertyAssignment(const SourceLocation &location, - const Interpreter::Value *lhsValue, - const Interpreter::Value *rhsValue, - ExpressionNode *ast) -{ - UnaryMinusExpression *unaryMinus = cast<UnaryMinusExpression *>(ast); - - // Qml is particularly strict with literals - if (StringLiteral *stringLiteral = cast<StringLiteral *>(ast)) { - const QString string = stringLiteral->value->asString(); - - if (lhsValue->asStringValue()) { - // okay - } else if (lhsValue->asColorValue()) { -#ifndef NO_DECLARATIVE_BACKEND - bool ok = false; - QmlStringConverters::colorFromString(string, &ok); - if (!ok) - error(location, QCoreApplication::translate("QmlJS::Check", "not a valid color")); -#endif - } else if (lhsValue->asEasingCurveNameValue()) { - // ### do something with easing-curve attributes. - // ### Incomplete documentation at: http://qt.nokia.com/doc/4.7-snapshot/qml-propertyanimation.html#easing-prop - // ### The implementation is at: src/declarative/util/qmlanimation.cpp - const QString curveName = string.left(string.indexOf(QLatin1Char('('))); - if (!EasingCurveNameValue::curveNames().contains(curveName)) { - error(location, tr(Messages::unknown_easing_curve_name)); - } - } else { - errorOnWrongRhs(location, lhsValue); - } - } else if ((ast->kind == Node::Kind_TrueLiteral - || ast->kind == Node::Kind_FalseLiteral) - && ! lhsValue->asBooleanValue()) { - errorOnWrongRhs(location, lhsValue); - } else if (cast<NumericLiteral *>(ast) - && ! lhsValue->asNumberValue()) { - errorOnWrongRhs(location, lhsValue); - } else if (unaryMinus && cast<NumericLiteral *>(unaryMinus->expression) - && ! lhsValue->asNumberValue()) { - errorOnWrongRhs(location, lhsValue); - } else { - // rhs is not a literal - if (lhsValue->asEasingCurveNameValue()) { - const StringValue *rhsStringValue = rhsValue->asStringValue(); - if (!rhsStringValue) { - if (rhsValue->asUndefinedValue()) - warning(location, tr(Messages::value_might_be_undefined)); - else - error(location, tr(Messages::easing_curve_not_a_string)); - return; - } - } - } -} - bool Check::visit(UiArrayBinding *ast) { checkScopeObjectMember(ast->qualifiedId); diff --git a/src/libs/qmljs/qmljscheck.h b/src/libs/qmljs/qmljscheck.h index a50953e15fa..d49057841c8 100644 --- a/src/libs/qmljs/qmljscheck.h +++ b/src/libs/qmljs/qmljscheck.h @@ -57,11 +57,6 @@ private: void visitQmlObject(AST::Node *ast, AST::UiQualifiedId *typeId, AST::UiObjectInitializer *initializer); const Interpreter::Value *checkScopeObjectMember(const AST::UiQualifiedId *id); - void checkPropertyAssignment(const AST::SourceLocation &location, - const Interpreter::Value *lhsValue, - const Interpreter::Value *rhsValue, - QmlJS::AST::ExpressionNode *ast); - void errorOnWrongRhs(const AST::SourceLocation &loc, const Interpreter::Value *lhsValue); void warning(const AST::SourceLocation &loc, const QString &message); void error(const AST::SourceLocation &loc, const QString &message); diff --git a/src/libs/qmljs/qmljsinterpreter.cpp b/src/libs/qmljs/qmljsinterpreter.cpp index 9d4461749f3..9975afdacb6 100644 --- a/src/libs/qmljs/qmljsinterpreter.cpp +++ b/src/libs/qmljs/qmljsinterpreter.cpp @@ -336,9 +336,7 @@ const Value *QmlObjectValue::propertyValue(const QMetaProperty &prop) const const QString typeName = prop.typeName(); if (typeName == QLatin1String("QmlGraphicsAnchorLine")) { - ObjectValue *object = engine()->newObject(/*prototype =*/ 0); - object->setClassName(QLatin1String("AnchorLine")); - value = object; + value = engine()->anchorLineValue(); } if (value->asStringValue() && prop.name() == QLatin1String("easing") && isDerivedFrom(&QmlPropertyAnimation::staticMetaObject)) { @@ -618,6 +616,10 @@ void ValueVisitor::visit(const ColorValue *) { } +void ValueVisitor::visit(const AnchorLineValue *) +{ +} + //////////////////////////////////////////////////////////////////////////////// // Value //////////////////////////////////////////////////////////////////////////////// @@ -684,6 +686,11 @@ const ColorValue *Value::asColorValue() const return 0; } +const AnchorLineValue *Value::asAnchorLineValue() const +{ + return 0; +} + //////////////////////////////////////////////////////////////////////////////// // Values //////////////////////////////////////////////////////////////////////////////// @@ -1000,6 +1007,16 @@ const ColorValue *ColorValue::asColorValue() const return this; } +void AnchorLineValue::accept(ValueVisitor *visitor) const +{ + visitor->visit(this); +} + +const AnchorLineValue *AnchorLineValue::asAnchorLineValue() const +{ + return this; +} + MemberProcessor::MemberProcessor() { } @@ -1577,6 +1594,21 @@ void TypeId::visit(const FunctionValue *object) _result = QLatin1String("Function"); } +void TypeId::visit(const EasingCurveNameValue *) +{ + _result = QLatin1String("string"); +} + +void TypeId::visit(const ColorValue *) +{ + _result = QLatin1String("string"); +} + +void TypeId::visit(const AnchorLineValue *) +{ + _result = QLatin1String("AnchorLine"); +} + Engine::Engine() : _objectPrototype(0), _functionPrototype(0), @@ -1649,6 +1681,11 @@ const ColorValue *Engine::colorValue() const return &_colorValue; } +const AnchorLineValue *Engine::anchorLineValue() const +{ + return &_anchorLineValue; +} + const Value *Engine::newArray() { return arrayCtor()->construct(); diff --git a/src/libs/qmljs/qmljsinterpreter.h b/src/libs/qmljs/qmljsinterpreter.h index 35137579e7a..164e6094026 100644 --- a/src/libs/qmljs/qmljsinterpreter.h +++ b/src/libs/qmljs/qmljsinterpreter.h @@ -62,6 +62,7 @@ class FunctionValue; class Reference; class EasingCurveNameValue; class ColorValue; +class AnchorLineValue; typedef QList<const Value *> ValueList; @@ -84,6 +85,7 @@ public: virtual void visit(const Reference *); virtual void visit(const EasingCurveNameValue *); virtual void visit(const ColorValue *); + virtual void visit(const AnchorLineValue *); }; //////////////////////////////////////////////////////////////////////////////// @@ -108,6 +110,7 @@ public: virtual const Reference *asReference() const; virtual const EasingCurveNameValue *asEasingCurveNameValue() const; virtual const ColorValue *asColorValue() const; + virtual const AnchorLineValue *asAnchorLineValue() const; virtual void accept(ValueVisitor *) const = 0; @@ -176,6 +179,12 @@ template <> Q_INLINE_TEMPLATE const ColorValue *value_cast(const Value *v) else return 0; } +template <> Q_INLINE_TEMPLATE const AnchorLineValue *value_cast(const Value *v) +{ + if (v) return v->asAnchorLineValue(); + else return 0; +} + //////////////////////////////////////////////////////////////////////////////// // Value nodes //////////////////////////////////////////////////////////////////////////////// @@ -343,6 +352,14 @@ public: virtual void accept(ValueVisitor *) const; }; +class QMLJS_EXPORT AnchorLineValue: public Value +{ +public: + // Value interface + virtual const AnchorLineValue *asAnchorLineValue() const; + virtual void accept(ValueVisitor *) const; +}; + class QMLJS_EXPORT ObjectValue: public Value { public: @@ -585,6 +602,9 @@ protected: virtual void visit(const StringValue *); virtual void visit(const ObjectValue *object); virtual void visit(const FunctionValue *object); + virtual void visit(const EasingCurveNameValue *); + virtual void visit(const ColorValue *); + virtual void visit(const AnchorLineValue *); }; class QMLJS_EXPORT Engine @@ -603,6 +623,7 @@ public: const StringValue *stringValue() const; const EasingCurveNameValue *easingCurveNameValue() const; const ColorValue *colorValue() const; + const AnchorLineValue *anchorLineValue() const; ObjectValue *newObject(const ObjectValue *prototype); ObjectValue *newObject(); @@ -693,6 +714,7 @@ private: StringValue _stringValue; EasingCurveNameValue _easingCurveNameValue; ColorValue _colorValue; + AnchorLineValue _anchorLineValue; QList<Value *> _registeredValues; ConvertToNumber _convertToNumber; -- GitLab