diff options
author | Christian Kamm <christian.d.kamm@nokia.com> | 2011-10-10 12:53:28 +0200 |
---|---|---|
committer | Christian Kamm <christian.d.kamm@nokia.com> | 2011-10-18 13:16:18 +0200 |
commit | 89ff3cebe6d9ca8385d8d9300cfaa47cf07adb42 (patch) | |
tree | 690c6666c71a056a89bd35d5b59072e3ece7e36e | |
parent | 4cb8ec6a3271560753df4ebd679c027d9347d140 (diff) | |
download | qt-creator-89ff3cebe6d9ca8385d8d9300cfaa47cf07adb42.tar.gz |
QmlJS: Introduce UnknownValue.
To distinguish known-to-be-undefined from a genuinely unknown value.
Change-Id: I606b4ea4d726f94553400b8950d3c0a4e76564a8
Reviewed-by: Fawzi Mohamed <fawzi.mohamed@nokia.com>
-rw-r--r-- | src/libs/qmljs/qmljsbind.cpp | 2 | ||||
-rw-r--r-- | src/libs/qmljs/qmljscheck.cpp | 14 | ||||
-rw-r--r-- | src/libs/qmljs/qmljsevaluate.cpp | 3 | ||||
-rw-r--r-- | src/libs/qmljs/qmljsinterpreter.cpp | 66 | ||||
-rw-r--r-- | src/libs/qmljs/qmljsinterpreter.h | 19 | ||||
-rw-r--r-- | src/libs/qmljs/qmljslink.cpp | 2 | ||||
-rw-r--r-- | src/libs/qmljs/qmljsscopechain.cpp | 2 | ||||
-rw-r--r-- | src/libs/qmljs/qmljsvalueowner.cpp | 27 | ||||
-rw-r--r-- | src/libs/qmljs/qmljsvalueowner.h | 3 | ||||
-rw-r--r-- | tests/auto/qml/codemodel/check/equality-checks.qml | 43 |
10 files changed, 105 insertions, 76 deletions
diff --git a/src/libs/qmljs/qmljsbind.cpp b/src/libs/qmljs/qmljsbind.cpp index 99431b593b..abc219e791 100644 --- a/src/libs/qmljs/qmljsbind.cpp +++ b/src/libs/qmljs/qmljsbind.cpp @@ -325,7 +325,7 @@ bool Bind::visit(FunctionExpression *ast) // 1. Function formal arguments for (FormalParameterList *it = ast->formals; it; it = it->next) { if (!it->name.isEmpty()) - functionScope->setMember(it->name.toString(), _valueOwner.undefinedValue()); + functionScope->setMember(it->name.toString(), _valueOwner.unknownValue()); } // 2. Functions defined inside the function body diff --git a/src/libs/qmljs/qmljscheck.cpp b/src/libs/qmljs/qmljscheck.cpp index 88f6ffe55e..676bb5e11c 100644 --- a/src/libs/qmljs/qmljscheck.cpp +++ b/src/libs/qmljs/qmljscheck.cpp @@ -89,7 +89,7 @@ public: setMessage(ErrInvalidEnumValue); } } else if (! _rhsValue->asStringValue() && ! _rhsValue->asNumberValue() - && ! _rhsValue->asUndefinedValue()) { + && ! _rhsValue->asUnknownValue()) { setMessage(ErrEnumValueMustBeStringOrNumber); } } else { @@ -155,7 +155,7 @@ public: virtual void visit(const AnchorLineValue *) { - if (! (_rhsValue->asAnchorLineValue() || _rhsValue->asUndefinedValue())) + if (! (_rhsValue->asAnchorLineValue() || _rhsValue->asUnknownValue())) setMessage(ErrAnchorLineExpected); } @@ -842,9 +842,8 @@ bool Check::visit(FunctionExpression *ast) static bool shouldAvoidNonStrictEqualityCheck(const Value *lhs, const Value *rhs) { - // we currently use undefined as a "we don't know" value - if (lhs->asUndefinedValue() || rhs->asUndefinedValue()) - return true; + if (lhs->asUnknownValue() || rhs->asUnknownValue()) + return true; // may coerce or not if (lhs->asStringValue() && rhs->asNumberValue()) return true; // coerces string to number @@ -855,7 +854,8 @@ static bool shouldAvoidNonStrictEqualityCheck(const Value *lhs, const Value *rhs if (lhs->asObjectValue() && rhs->asStringValue()) return true; // coerces object to primitive - if (lhs->asBooleanValue() && !rhs->asBooleanValue()) + if (lhs->asBooleanValue() && (!rhs->asBooleanValue() + && !rhs->asUndefinedValue())) return true; // coerces bool to number return false; @@ -1156,7 +1156,7 @@ bool Check::visit(NewMemberExpression *ast) if (ast->arguments && ast->arguments->expression && !ast->arguments->next) { Evaluate evaluate(&_scopeChain); const Value *arg = evaluate(ast->arguments->expression); - if (arg->asNumberValue() || arg->asUndefinedValue()) + if (arg->asNumberValue() || arg->asUnknownValue()) ok = true; } if (!ok) diff --git a/src/libs/qmljs/qmljsevaluate.cpp b/src/libs/qmljs/qmljsevaluate.cpp index 501636e7e9..75e301344c 100644 --- a/src/libs/qmljs/qmljsevaluate.cpp +++ b/src/libs/qmljs/qmljsevaluate.cpp @@ -69,8 +69,9 @@ const Value *Evaluate::value(AST::Node *ast) result = _context->lookupReference(ref); } + // if evaluation fails, return an unknown value if (! result) - result = _valueOwner->undefinedValue(); + result = _valueOwner->unknownValue(); return result; } diff --git a/src/libs/qmljs/qmljsinterpreter.cpp b/src/libs/qmljs/qmljsinterpreter.cpp index f82c836645..b448212e3d 100644 --- a/src/libs/qmljs/qmljsinterpreter.cpp +++ b/src/libs/qmljs/qmljsinterpreter.cpp @@ -123,21 +123,11 @@ public: { } - virtual const Value *returnValue() const - { - return valueOwner()->undefinedValue(); - } - virtual int argumentCount() const { return _method.parameterNames().size(); } - virtual const Value *argument(int) const - { - return valueOwner()->undefinedValue(); - } - virtual QString argumentName(int index) const { if (index < _method.parameterNames().size()) @@ -153,7 +143,7 @@ public: virtual const Value *invoke(const Activation *) const { - return valueOwner()->undefinedValue(); + return valueOwner()->unknownValue(); } }; @@ -264,7 +254,7 @@ void CppComponentValue::processMembers(MemberProcessor *processor) const if (!explicitSignals.contains(signalName)) { // process the generated slot const QString &slotName = generatedSlotName(signalName); - processor->processGeneratedSlot(slotName, valueOwner()->undefinedValue()); + processor->processGeneratedSlot(slotName, valueOwner()->unknownValue()); } } @@ -337,7 +327,8 @@ const Value *CppComponentValue::valueForCppName(const QString &typeName) const return value; } - return valueOwner()->undefinedValue(); + // may still be a cpp based value + return valueOwner()->unknownValue(); } const CppComponentValue *CppComponentValue::prototype() const @@ -566,6 +557,10 @@ void ValueVisitor::visit(const UndefinedValue *) { } +void ValueVisitor::visit(const UnknownValue *) +{ +} + void ValueVisitor::visit(const NumberValue *) { } @@ -624,6 +619,11 @@ const UndefinedValue *Value::asUndefinedValue() const return 0; } +const UnknownValue *Value::asUnknownValue() const +{ + return 0; +} + const NumberValue *Value::asNumberValue() const { return 0; @@ -727,11 +727,20 @@ const UndefinedValue *UndefinedValue::asUndefinedValue() const return this; } -void UndefinedValue::accept(ValueVisitor *visitor) const +void UnknownValue::accept(ValueVisitor *visitor) const { visitor->visit(this); } +const UnknownValue *UnknownValue::asUnknownValue() const +{ + return this; +} + +void UndefinedValue::accept(ValueVisitor *visitor) const +{ + visitor->visit(this); +} const NumberValue *NumberValue::asNumberValue() const { return this; @@ -1168,7 +1177,7 @@ const Value *FunctionValue::call(const ObjectValue *thisObject, const ValueList const Value *FunctionValue::returnValue() const { - return valueOwner()->undefinedValue(); + return valueOwner()->unknownValue(); } int FunctionValue::argumentCount() const @@ -1178,7 +1187,7 @@ int FunctionValue::argumentCount() const const Value *FunctionValue::argument(int) const { - return valueOwner()->undefinedValue(); + return valueOwner()->unknownValue(); } QString FunctionValue::argumentName(int index) const @@ -1812,8 +1821,9 @@ ASTVariableReference::~ASTVariableReference() const Value *ASTVariableReference::value(ReferenceContext *referenceContext) const { + // may be assigned to later if (!_ast->expression) - return valueOwner()->undefinedValue(); + return valueOwner()->unknownValue(); Document::Ptr doc = _doc->ptr(); ScopeChain scopeChain(doc, referenceContext->context()); @@ -1850,21 +1860,11 @@ FunctionExpression *ASTFunctionValue::ast() const return _ast; } -const Value *ASTFunctionValue::returnValue() const -{ - return valueOwner()->undefinedValue(); -} - int ASTFunctionValue::argumentCount() const { return _argumentNames.size(); } -const Value *ASTFunctionValue::argument(int) const -{ - return valueOwner()->undefinedValue(); -} - QString ASTFunctionValue::argumentName(int index) const { if (index < _argumentNames.size()) { @@ -1876,11 +1876,6 @@ QString ASTFunctionValue::argumentName(int index) const return FunctionValue::argumentName(index); } -bool ASTFunctionValue::isVariadic() const -{ - return true; -} - bool ASTFunctionValue::getSourceLocation(QString *fileName, int *line, int *column) const { *fileName = _doc->fileName(); @@ -1963,10 +1958,7 @@ const Value *ASTPropertyReference::value(ReferenceContext *referenceContext) con return evaluator(_ast->statement); } - if (!_ast->memberType.isEmpty()) - return valueOwner()->defaultValueForBuiltinType(_ast->memberType.toString()); - - return valueOwner()->undefinedValue(); + return valueOwner()->defaultValueForBuiltinType(_ast->memberType.toString()); } ASTSignal::ASTSignal(UiPublicMember *ast, const Document *doc, ValueOwner *valueOwner) @@ -2006,7 +1998,7 @@ const Value *ASTSignal::argument(int index) const for (int i = 0; param && i < index; ++i) param = param->next; if (!param || param->type.isEmpty()) - return valueOwner()->undefinedValue(); + return valueOwner()->unknownValue(); return valueOwner()->defaultValueForBuiltinType(param->type.toString()); } diff --git a/src/libs/qmljs/qmljsinterpreter.h b/src/libs/qmljs/qmljsinterpreter.h index c550637ba1..c914d28d0f 100644 --- a/src/libs/qmljs/qmljsinterpreter.h +++ b/src/libs/qmljs/qmljsinterpreter.h @@ -58,6 +58,7 @@ class ValueOwner; class Value; class NullValue; class UndefinedValue; +class UnknownValue; class NumberValue; class IntValue; class RealValue; @@ -95,6 +96,7 @@ public: virtual void visit(const NullValue *); virtual void visit(const UndefinedValue *); + virtual void visit(const UnknownValue *); virtual void visit(const NumberValue *); virtual void visit(const BooleanValue *); virtual void visit(const StringValue *); @@ -119,6 +121,7 @@ public: virtual const NullValue *asNullValue() const; virtual const UndefinedValue *asUndefinedValue() const; + virtual const UnknownValue *asUnknownValue() const; virtual const NumberValue *asNumberValue() const; virtual const IntValue *asIntValue() const; virtual const RealValue *asRealValue() const; @@ -161,6 +164,12 @@ template <> Q_INLINE_TEMPLATE const UndefinedValue *value_cast(const Value *v) else return 0; } +template <> Q_INLINE_TEMPLATE const UnknownValue *value_cast(const Value *v) +{ + if (v) return v->asUnknownValue(); + else return 0; +} + template <> Q_INLINE_TEMPLATE const NumberValue *value_cast(const Value *v) { if (v) return v->asNumberValue(); @@ -280,6 +289,13 @@ public: virtual void accept(ValueVisitor *visitor) const; }; +class QMLJS_EXPORT UnknownValue: public Value +{ +public: + virtual const UnknownValue *asUnknownValue() const; + virtual void accept(ValueVisitor *) const; +}; + class QMLJS_EXPORT NumberValue: public Value { public: @@ -793,11 +809,8 @@ public: AST::FunctionExpression *ast() const; - virtual const Value *returnValue() const; virtual int argumentCount() const; - virtual const Value *argument(int) const; virtual QString argumentName(int index) const; - virtual bool isVariadic() const; virtual bool getSourceLocation(QString *fileName, int *line, int *column) const; }; diff --git a/src/libs/qmljs/qmljslink.cpp b/src/libs/qmljs/qmljslink.cpp index 7d693ec0c7..3e8cc72f14 100644 --- a/src/libs/qmljs/qmljslink.cpp +++ b/src/libs/qmljs/qmljslink.cpp @@ -165,7 +165,7 @@ Link::Link(const Snapshot &snapshot, const QStringList &importPaths, const Libra if (!cppTypeName.isEmpty()) value = d->valueOwner->cppQmlTypes().objectByCppName(cppTypeName); if (!value) - value = d->valueOwner->undefinedValue(); + value = d->valueOwner->unknownValue(); global->setMember(it.key(), value); } } diff --git a/src/libs/qmljs/qmljsscopechain.cpp b/src/libs/qmljs/qmljsscopechain.cpp index 17901321ea..378e2abbfa 100644 --- a/src/libs/qmljs/qmljsscopechain.cpp +++ b/src/libs/qmljs/qmljsscopechain.cpp @@ -112,6 +112,8 @@ const Value * ScopeChain::lookup(const QString &name, const ObjectValue **foundI if (foundInScope) *foundInScope = 0; + + // we're confident to implement global lookup correctly, so return 'undefined' return m_context->valueOwner()->undefinedValue(); } diff --git a/src/libs/qmljs/qmljsvalueowner.cpp b/src/libs/qmljs/qmljsvalueowner.cpp index a4b96bd40d..9182f03740 100644 --- a/src/libs/qmljs/qmljsvalueowner.cpp +++ b/src/libs/qmljs/qmljsvalueowner.cpp @@ -292,6 +292,11 @@ const UndefinedValue *ValueOwner::undefinedValue() const return &_undefinedValue; } +const UnknownValue *ValueOwner::unknownValue() const +{ + return &_unknownValue; +} + const NumberValue *ValueOwner::numberValue() const { return &_numberValue; @@ -488,7 +493,7 @@ Function *ValueOwner::addFunction(ObjectValue *object, const QString &name, cons Function *function = newFunction(); function->setReturnValue(result); for (int i = 0; i < argumentCount; ++i) - function->addArgument(undefinedValue()); // ### introduce unknownValue + function->addArgument(unknownValue()); object->setMember(name, function); return function; } @@ -497,7 +502,7 @@ Function *ValueOwner::addFunction(ObjectValue *object, const QString &name, int { Function *function = newFunction(); for (int i = 0; i < argumentCount; ++i) - function->addArgument(undefinedValue()); // ### introduce unknownValue + function->addArgument(unknownValue()); object->setMember(name, function); return function; } @@ -775,7 +780,7 @@ void ValueOwner::initializePrototypes() f->addArgument(stringValue(), "header"); f->addArgument(stringValue(), "value"); f = addFunction(xmlHttpRequest, "send"); - f->addArgument(undefinedValue(), "data"); + f->addArgument(unknownValue(), "data"); f = addFunction(xmlHttpRequest, "abort"); xmlHttpRequest->setMember("status", numberValue()); xmlHttpRequest->setMember("statusText", stringValue()); @@ -783,7 +788,7 @@ void ValueOwner::initializePrototypes() f->addArgument(stringValue(), "header"); f = addFunction(xmlHttpRequest, "getAllResponseHeaders"); xmlHttpRequest->setMember("responseText", stringValue()); - xmlHttpRequest->setMember("responseXML", undefinedValue()); + xmlHttpRequest->setMember("responseXML", unknownValue()); f = addFunction(_globalObject, "XMLHttpRequest", xmlHttpRequest); f->setMember("prototype", xmlHttpRequest); @@ -814,9 +819,9 @@ void ValueOwner::initializePrototypes() f->addArgument(stringValue(), "text"); f->addArgument(functionPrototype(), "reviver"); f = addFunction(json, "stringify", stringValue()); - f->addArgument(undefinedValue(), "value"); - f->addArgument(undefinedValue(), "replacer"); - f->addArgument(undefinedValue(), "space"); + f->addArgument(unknownValue(), "value"); + f->addArgument(unknownValue(), "replacer"); + f->addArgument(unknownValue(), "space"); _globalObject->setMember("JSON", json); // global Qt object, in alphabetic order @@ -864,8 +869,8 @@ void ValueOwner::initializePrototypes() _qmlFontObject = newObject(/*prototype =*/ 0); _qmlFontObject->setClassName(QLatin1String("Font")); _qmlFontObject->setMember("family", stringValue()); - _qmlFontObject->setMember("weight", undefinedValue()); // ### make me an object - _qmlFontObject->setMember("capitalization", undefinedValue()); // ### make me an object + _qmlFontObject->setMember("weight", unknownValue()); // ### make me an object + _qmlFontObject->setMember("capitalization", unknownValue()); // ### make me an object _qmlFontObject->setMember("bold", booleanValue()); _qmlFontObject->setMember("italic", booleanValue()); _qmlFontObject->setMember("underline", booleanValue()); @@ -948,7 +953,9 @@ const Value *ValueOwner::defaultValueForBuiltinType(const QString &name) const return colorValue(); } else if (name == QLatin1String("date")) { return datePrototype(); + } else if (name == QLatin1String("var") + || name == QLatin1String("variant")) { + return unknownValue(); } - // ### variant or var return undefinedValue(); } diff --git a/src/libs/qmljs/qmljsvalueowner.h b/src/libs/qmljs/qmljsvalueowner.h index 7e690578da..4b903f2512 100644 --- a/src/libs/qmljs/qmljsvalueowner.h +++ b/src/libs/qmljs/qmljsvalueowner.h @@ -46,6 +46,7 @@ namespace QmlJS { class Value; class NullValue; class UndefinedValue; +class UnknownValue; class NumberValue; class IntValue; class RealValue; @@ -72,6 +73,7 @@ public: const NullValue *nullValue() const; const UndefinedValue *undefinedValue() const; + const UnknownValue *unknownValue() const; const NumberValue *numberValue() const; const RealValue *realValue() const; const IntValue *intValue() const; @@ -174,6 +176,7 @@ private: NullValue _nullValue; UndefinedValue _undefinedValue; + UnknownValue _unknownValue; NumberValue _numberValue; RealValue _realValue; IntValue _intValue; diff --git a/tests/auto/qml/codemodel/check/equality-checks.qml b/tests/auto/qml/codemodel/check/equality-checks.qml index 700331780f..e92b1c4cc1 100644 --- a/tests/auto/qml/codemodel/check/equality-checks.qml +++ b/tests/auto/qml/codemodel/check/equality-checks.qml @@ -1,11 +1,8 @@ import Qt 4.7 Rectangle { - onXChanged: { - if (0 == undefined) {} // 126 15 16 - } - - function foo() { + function foo(k) { + // k is a unknown value var s = "" var n = 0 var N = null @@ -16,45 +13,59 @@ Rectangle { if (s == s) {} if (s == n) {} // 126 15 16 if (s == N) {} // ### should warn: always false - if (s == u) {} // 126 15 16 + if (s == u) {} // ### should warn: always false if (s == b) {} // 126 15 16 if (s == o) {} // 126 15 16 + if (s == k) {} // 126 15 16 if (n == s) {} // 126 15 16 if (n == n) {} if (n == N) {} // ### should warn: always false - if (n == u) {} // 126 15 16 + if (n == u) {} // ### should warn: always false if (n == b) {} // 126 15 16 if (n == o) {} // 126 15 16 + if (n == k) {} // 126 15 16 if (N == s) {} // ### should warn: always false if (N == n) {} // ### should warn: always false if (N == N) {} - if (N == u) {} // 126 15 16 + if (N == u) {} // ### should warn: always true // ### should warn: always false if (N == b) {} // 126 15 16 if (N == o) {} // ### should warn: always false + if (N == k) {} // 126 15 16 - if (u == s) {} // 126 15 16 - if (u == n) {} // 126 15 16 - if (u == N) {} // 126 15 16 - if (u == u) {} // 126 15 16 - if (u == b) {} // 126 15 16 - if (u == o) {} // 126 15 16 + if (u == s) {} // ### should warn: always false + if (u == n) {} // ### should warn: always false + if (u == N) {} // ### should warn: always true + if (u == u) {} // ### should warn: always true + if (u == b) {} // ### should warn: always false + if (u == o) {} // ### should warn: always false + if (u == k) {} // 126 15 16 if (b == s) {} // 126 15 16 if (b == n) {} // 126 15 16 // ### should warn: always false if (b == N) {} // 126 15 16 - if (b == u) {} // 126 15 16 + if (b == u) {} // ### should warn: always false if (b == b) {} if (b == o) {} // 126 15 16 + if (b == k) {} // 126 15 16 if (o == s) {} // 126 15 16 if (o == n) {} // 126 15 16 if (o == N) {} // ### should warn: always false - if (o == u) {} // 126 15 16 + if (o == u) {} // ### should warn: always false if (o == b) {} // 126 15 16 if (o == o) {} + if (o == k) {} // 126 15 16 + + if (k == s) {} // 126 15 16 + if (k == n) {} // 126 15 16 + if (k == N) {} // 126 15 16 + if (k == u) {} // 126 15 16 + if (k == b) {} // 126 15 16 + if (k == o) {} // 126 15 16 + if (k == k) {} // 126 15 16 } } |