summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Kamm <christian.d.kamm@nokia.com>2011-10-10 12:53:28 +0200
committerChristian Kamm <christian.d.kamm@nokia.com>2011-10-18 13:16:18 +0200
commit89ff3cebe6d9ca8385d8d9300cfaa47cf07adb42 (patch)
tree690c6666c71a056a89bd35d5b59072e3ece7e36e
parent4cb8ec6a3271560753df4ebd679c027d9347d140 (diff)
downloadqt-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.cpp2
-rw-r--r--src/libs/qmljs/qmljscheck.cpp14
-rw-r--r--src/libs/qmljs/qmljsevaluate.cpp3
-rw-r--r--src/libs/qmljs/qmljsinterpreter.cpp66
-rw-r--r--src/libs/qmljs/qmljsinterpreter.h19
-rw-r--r--src/libs/qmljs/qmljslink.cpp2
-rw-r--r--src/libs/qmljs/qmljsscopechain.cpp2
-rw-r--r--src/libs/qmljs/qmljsvalueowner.cpp27
-rw-r--r--src/libs/qmljs/qmljsvalueowner.h3
-rw-r--r--tests/auto/qml/codemodel/check/equality-checks.qml43
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
}
}