- Properly document and handle NULL callbacks for static properties. We
throw an exception in any case other than a ReadOnly property with a NULL
setProperty callback, because a NULL callback almost certainly indicates
a programming error. Also throw an exception if hasProperty returns true
for a property that getProperty can't get.
- If a static setProperty callback returns 'false', to indicate that the
property was not set, we no longer forward the set request up the class
chain, because that's almost certainly not what the programmer expected.
* API/JSCallbackObject.cpp:
(KJS::JSCallbackObject::getOwnPropertySlot):
(KJS::JSCallbackObject::put):
(KJS::JSCallbackObject::staticValueGetter):
(KJS::JSCallbackObject::staticFunctionGetter):
(KJS::JSCallbackObject::callbackGetter):
* API/JSObjectRef.h:
* API/minidom.js:
* API/testapi.c:
(MyObject_hasProperty):
* API/testapi.js:
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@15473
268f45cc-cd09-0410-ab3c-
d52691b4dbfc
}
if (__JSClass::StaticValuesTable* staticValues = jsClass->staticValues) {
- if (StaticValueEntry* entry = staticValues->get(propertyName.ustring().rep())) {
- if (entry->getProperty) {
- slot.setCustom(this, staticValueGetter);
- return true;
- }
+ if (staticValues->contains(propertyName.ustring().rep())) {
+ slot.setCustom(this, staticValueGetter);
+ return true;
}
}
if (StaticValueEntry* entry = staticValues->get(propertyName.ustring().rep())) {
if (entry->attributes & kJSPropertyAttributeReadOnly)
return;
- if (JSObjectSetPropertyCallback setProperty = entry->setProperty) {
- if (setProperty(context, thisRef, propertyNameRef, valueRef, toRef(exec->exceptionSlot())))
- return;
- }
+ if (JSObjectSetPropertyCallback setProperty = entry->setProperty)
+ setProperty(context, thisRef, propertyNameRef, valueRef, toRef(exec->exceptionSlot()));
+ else
+ throwError(exec, ReferenceError, "Writable static value property defined with NULL setProperty callback.");
}
}
if (JSValueRef value = getProperty(toRef(exec), thisRef, propertyNameRef, toRef(exec->exceptionSlot())))
return toJS(value);
- return jsUndefined();
+ return throwError(exec, ReferenceError, "Static value property defined with NULL getProperty callback.");
}
JSValue* JSCallbackObject::staticFunctionGetter(ExecState* exec, JSObject*, const Identifier& propertyName, const PropertySlot& slot)
for (JSClassRef jsClass = thisObj->m_class; jsClass; jsClass = jsClass->parentClass) {
if (__JSClass::StaticFunctionsTable* staticFunctions = jsClass->staticFunctions) {
if (StaticFunctionEntry* entry = staticFunctions->get(propertyName.ustring().rep())) {
- JSObject* o = new JSCallbackFunction(exec, entry->callAsFunction, propertyName);
- thisObj->putDirect(propertyName, o, entry->attributes);
- return o;
+ if (JSObjectCallAsFunctionCallback callAsFunction = entry->callAsFunction) {
+ JSObject* o = new JSCallbackFunction(exec, callAsFunction, propertyName);
+ thisObj->putDirect(propertyName, o, entry->attributes);
+ return o;
+ }
}
}
}
- return jsUndefined();
+ return throwError(exec, ReferenceError, "Static function property defined with NULL callAsFunction callback.");
}
JSValue* JSCallbackObject::callbackGetter(ExecState* exec, JSObject*, const Identifier& propertyName, const PropertySlot& slot)
if (JSValueRef value = getProperty(toRef(exec), thisRef, propertyNameRef, toRef(exec->exceptionSlot())))
return toJS(value);
- return jsUndefined();
+ return throwError(exec, ReferenceError, "hasProperty callback returned true for a property that doesn't exist.");
}
} // namespace KJS
@abstract This structure describes a statically declared value property.
@field name A null-terminated UTF8 string containing the property's name.
@field getProperty A JSObjectGetPropertyCallback to invoke when getting the property's value.
-@field setProperty A JSObjectSetPropertyCallback to invoke when setting the property's value.
+@field setProperty A JSObjectSetPropertyCallback to invoke when setting the property's value. May be NULL if the ReadOnly attribute is set.
@field attributes A logically ORed set of JSPropertyAttributes to give to the property.
*/
typedef struct {
}
}
+function shouldBe(a, b)
+{
+ var evalA;
+ try {
+ evalA = eval(a);
+ } catch(e) {
+ evalA = e;
+ }
+
+ if (evalA == b || isNaN(evalA) && typeof evalA == 'number' && isNaN(b) && typeof b == 'number')
+ print("PASS: " + a + " should be " + b + " and is.", "green");
+ else
+ print("__FAIL__: " + a + " should be " + b + " but instead is " + evalA + ".", "red");
+}
+
function test()
{
print("Node is " + Node);
} catch(e) {
print("caught: " + e);
}
+
+ oldNodeType = node.nodeType;
+ node.nodeType = 1;
+ shouldBe("node.nodeType", oldNodeType);
/*
var element, name, weapon;
if (JSStringIsEqualToUTF8CString(propertyName, "alwaysOne")
|| JSStringIsEqualToUTF8CString(propertyName, "cantFind")
- || JSStringIsEqualToUTF8CString(propertyName, "myPropertyName")) {
+ || JSStringIsEqualToUTF8CString(propertyName, "myPropertyName")
+ || JSStringIsEqualToUTF8CString(propertyName, "hasPropertyLie")) {
return true;
}
didFinalize = true;
}
+static JSStaticValue evilStaticValues[] = {
+ { "nullGetSet", 0, 0, kJSPropertyAttributeNone },
+ { 0, 0, 0, 0 }
+};
+
+static JSStaticFunction evilStaticFunctions[] = {
+ { "nullCall", 0, kJSPropertyAttributeNone },
+ { 0, 0, 0 }
+};
+
JSClassDefinition MyObject_definition = {
0,
"MyObject",
NULL,
- NULL,
- NULL,
+ evilStaticValues,
+ evilStaticFunctions,
MyObject_initialize,
MyObject_finalize,
print("__FAIL__: " + a + " should be " + b + " but instead is " + evalA + ".", "red");
}
+function shouldThrow(a)
+{
+ var result = "__FAIL__: " + a + " did not throw an exception.";
+
+ var evalA;
+ try {
+ eval(a);
+ } catch(e) {
+ result = "PASS: " + a + " threw: " + e;
+ }
+
+ print(result);
+}
+
shouldBe("typeof MyObject", "function"); // our object implements 'call'
MyObject.cantFind = 1;
shouldBe("MyObject.cantFind", undefined);
? "PASS: MyObject.regularType was enumerated"
: "__FAIL__: MyObject.regularType was not enumerated");
+myObject = new MyObject();
+
shouldBe("delete MyObject.regularType", true);
shouldBe("MyObject.regularType", undefined);
shouldBe("MyObject(0)", 1);
shouldBe("MyObject()", undefined);
-shouldBe("typeof new MyObject()", "object");
+shouldBe("typeof myObject", "object");
shouldBe("MyObject ? 1 : 0", true); // toBoolean
shouldBe("+MyObject", 1); // toNumber
shouldBe("(MyObject.toString())", "[object MyObject]"); // toString
constructedObject = new MyConstructor(1);
shouldBe("typeof constructedObject", "object");
shouldBe("constructedObject.value", 1);
-shouldBe("(new MyObject()) instanceof MyObject", true);
+shouldBe("myObject instanceof MyObject", true);
shouldBe("(new Object()) instanceof MyObject", false);
+
+shouldThrow("MyObject.nullGetSet = 1");
+shouldThrow("MyObject.nullGetSet");
+shouldThrow("MyObject.nullCall()");
+shouldThrow("MyObject.hasPropertyLie");
+2006-07-16 Geoffrey Garen <ggaren@apple.com>
+
+ Reviewed by Maciej.
+
+ - Properly document and handle NULL callbacks for static properties. We
+ throw an exception in any case other than a ReadOnly property with a NULL
+ setProperty callback, because a NULL callback almost certainly indicates
+ a programming error. Also throw an exception if hasProperty returns true
+ for a property that getProperty can't get.
+
+ - If a static setProperty callback returns 'false', to indicate that the
+ property was not set, we no longer forward the set request up the class
+ chain, because that's almost certainly not what the programmer expected.
+
+ * API/JSCallbackObject.cpp:
+ (KJS::JSCallbackObject::getOwnPropertySlot):
+ (KJS::JSCallbackObject::put):
+ (KJS::JSCallbackObject::staticValueGetter):
+ (KJS::JSCallbackObject::staticFunctionGetter):
+ (KJS::JSCallbackObject::callbackGetter):
+ * API/JSObjectRef.h:
+ * API/minidom.js:
+ * API/testapi.c:
+ (MyObject_hasProperty):
+ * API/testapi.js:
+
2006-07-16 Geoffrey Garen <ggaren@apple.com>
Reviewed by Maciej.