forked from qt-creator/qt-creator
Add check for anchor line, changed value assignment checks into visitor.
Done-with: Erik Verbruggen
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user