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::AST;
|
||||||
using namespace QmlJS::Interpreter;
|
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)
|
Check::Check(Document::Ptr doc, const Snapshot &snapshot)
|
||||||
: _doc(doc)
|
: _doc(doc)
|
||||||
, _snapshot(snapshot)
|
, _snapshot(snapshot)
|
||||||
@@ -131,17 +233,6 @@ void Check::visitQmlObject(Node *ast, UiQualifiedId *typeId,
|
|||||||
_scopeBuilder.pop();
|
_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)
|
bool Check::visit(UiScriptBinding *ast)
|
||||||
{
|
{
|
||||||
// special case for id property
|
// special case for id property
|
||||||
@@ -181,7 +272,10 @@ bool Check::visit(UiScriptBinding *ast)
|
|||||||
|
|
||||||
const SourceLocation loc = locationFromRange(expStmt->firstSourceLocation(),
|
const SourceLocation loc = locationFromRange(expStmt->firstSourceLocation(),
|
||||||
expStmt->lastSourceLocation());
|
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;
|
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)
|
bool Check::visit(UiArrayBinding *ast)
|
||||||
{
|
{
|
||||||
checkScopeObjectMember(ast->qualifiedId);
|
checkScopeObjectMember(ast->qualifiedId);
|
||||||
|
|||||||
@@ -57,11 +57,6 @@ private:
|
|||||||
void visitQmlObject(AST::Node *ast, AST::UiQualifiedId *typeId,
|
void visitQmlObject(AST::Node *ast, AST::UiQualifiedId *typeId,
|
||||||
AST::UiObjectInitializer *initializer);
|
AST::UiObjectInitializer *initializer);
|
||||||
const Interpreter::Value *checkScopeObjectMember(const AST::UiQualifiedId *id);
|
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 warning(const AST::SourceLocation &loc, const QString &message);
|
||||||
void error(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();
|
const QString typeName = prop.typeName();
|
||||||
if (typeName == QLatin1String("QmlGraphicsAnchorLine")) {
|
if (typeName == QLatin1String("QmlGraphicsAnchorLine")) {
|
||||||
ObjectValue *object = engine()->newObject(/*prototype =*/ 0);
|
value = engine()->anchorLineValue();
|
||||||
object->setClassName(QLatin1String("AnchorLine"));
|
|
||||||
value = object;
|
|
||||||
}
|
}
|
||||||
if (value->asStringValue() && prop.name() == QLatin1String("easing")
|
if (value->asStringValue() && prop.name() == QLatin1String("easing")
|
||||||
&& isDerivedFrom(&QmlPropertyAnimation::staticMetaObject)) {
|
&& isDerivedFrom(&QmlPropertyAnimation::staticMetaObject)) {
|
||||||
@@ -618,6 +616,10 @@ void ValueVisitor::visit(const ColorValue *)
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ValueVisitor::visit(const AnchorLineValue *)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// Value
|
// Value
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
@@ -684,6 +686,11 @@ const ColorValue *Value::asColorValue() const
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const AnchorLineValue *Value::asAnchorLineValue() const
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// Values
|
// Values
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
@@ -1000,6 +1007,16 @@ const ColorValue *ColorValue::asColorValue() const
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AnchorLineValue::accept(ValueVisitor *visitor) const
|
||||||
|
{
|
||||||
|
visitor->visit(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
const AnchorLineValue *AnchorLineValue::asAnchorLineValue() const
|
||||||
|
{
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
MemberProcessor::MemberProcessor()
|
MemberProcessor::MemberProcessor()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -1577,6 +1594,21 @@ void TypeId::visit(const FunctionValue *object)
|
|||||||
_result = QLatin1String("Function");
|
_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()
|
Engine::Engine()
|
||||||
: _objectPrototype(0),
|
: _objectPrototype(0),
|
||||||
_functionPrototype(0),
|
_functionPrototype(0),
|
||||||
@@ -1649,6 +1681,11 @@ const ColorValue *Engine::colorValue() const
|
|||||||
return &_colorValue;
|
return &_colorValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const AnchorLineValue *Engine::anchorLineValue() const
|
||||||
|
{
|
||||||
|
return &_anchorLineValue;
|
||||||
|
}
|
||||||
|
|
||||||
const Value *Engine::newArray()
|
const Value *Engine::newArray()
|
||||||
{
|
{
|
||||||
return arrayCtor()->construct();
|
return arrayCtor()->construct();
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ class FunctionValue;
|
|||||||
class Reference;
|
class Reference;
|
||||||
class EasingCurveNameValue;
|
class EasingCurveNameValue;
|
||||||
class ColorValue;
|
class ColorValue;
|
||||||
|
class AnchorLineValue;
|
||||||
|
|
||||||
typedef QList<const Value *> ValueList;
|
typedef QList<const Value *> ValueList;
|
||||||
|
|
||||||
@@ -84,6 +85,7 @@ public:
|
|||||||
virtual void visit(const Reference *);
|
virtual void visit(const Reference *);
|
||||||
virtual void visit(const EasingCurveNameValue *);
|
virtual void visit(const EasingCurveNameValue *);
|
||||||
virtual void visit(const ColorValue *);
|
virtual void visit(const ColorValue *);
|
||||||
|
virtual void visit(const AnchorLineValue *);
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
@@ -108,6 +110,7 @@ public:
|
|||||||
virtual const Reference *asReference() const;
|
virtual const Reference *asReference() const;
|
||||||
virtual const EasingCurveNameValue *asEasingCurveNameValue() const;
|
virtual const EasingCurveNameValue *asEasingCurveNameValue() const;
|
||||||
virtual const ColorValue *asColorValue() const;
|
virtual const ColorValue *asColorValue() const;
|
||||||
|
virtual const AnchorLineValue *asAnchorLineValue() const;
|
||||||
|
|
||||||
virtual void accept(ValueVisitor *) const = 0;
|
virtual void accept(ValueVisitor *) const = 0;
|
||||||
|
|
||||||
@@ -176,6 +179,12 @@ template <> Q_INLINE_TEMPLATE const ColorValue *value_cast(const Value *v)
|
|||||||
else return 0;
|
else return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <> Q_INLINE_TEMPLATE const AnchorLineValue *value_cast(const Value *v)
|
||||||
|
{
|
||||||
|
if (v) return v->asAnchorLineValue();
|
||||||
|
else return 0;
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// Value nodes
|
// Value nodes
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
@@ -343,6 +352,14 @@ public:
|
|||||||
virtual void accept(ValueVisitor *) const;
|
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
|
class QMLJS_EXPORT ObjectValue: public Value
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -585,6 +602,9 @@ protected:
|
|||||||
virtual void visit(const StringValue *);
|
virtual void visit(const StringValue *);
|
||||||
virtual void visit(const ObjectValue *object);
|
virtual void visit(const ObjectValue *object);
|
||||||
virtual void visit(const FunctionValue *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
|
class QMLJS_EXPORT Engine
|
||||||
@@ -603,6 +623,7 @@ public:
|
|||||||
const StringValue *stringValue() const;
|
const StringValue *stringValue() const;
|
||||||
const EasingCurveNameValue *easingCurveNameValue() const;
|
const EasingCurveNameValue *easingCurveNameValue() const;
|
||||||
const ColorValue *colorValue() const;
|
const ColorValue *colorValue() const;
|
||||||
|
const AnchorLineValue *anchorLineValue() const;
|
||||||
|
|
||||||
ObjectValue *newObject(const ObjectValue *prototype);
|
ObjectValue *newObject(const ObjectValue *prototype);
|
||||||
ObjectValue *newObject();
|
ObjectValue *newObject();
|
||||||
@@ -693,6 +714,7 @@ private:
|
|||||||
StringValue _stringValue;
|
StringValue _stringValue;
|
||||||
EasingCurveNameValue _easingCurveNameValue;
|
EasingCurveNameValue _easingCurveNameValue;
|
||||||
ColorValue _colorValue;
|
ColorValue _colorValue;
|
||||||
|
AnchorLineValue _anchorLineValue;
|
||||||
QList<Value *> _registeredValues;
|
QList<Value *> _registeredValues;
|
||||||
|
|
||||||
ConvertToNumber _convertToNumber;
|
ConvertToNumber _convertToNumber;
|
||||||
|
|||||||
Reference in New Issue
Block a user