Skip to content

Commit d63044a

Browse files
committed
src: enable type cast checks in tests
1 parent 82e881c commit d63044a

22 files changed

+140
-102
lines changed

doc/value.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,19 @@ In order to enforce expected type, use `Napi::Value::Is*()` methods to check
8686
the type before calling `Napi::Value::As()`, or compile with definition
8787
`NODE_ADDON_API_ENABLE_TYPE_CHECK_ON_AS` to enforce type checks.
8888

89+
### UnsafeAs
90+
91+
```cpp
92+
template <typename T> T Napi::Value::UnsafeAs() const;
93+
```
94+
95+
Casts to another type of `Napi::Value`, when the actual type is known or
96+
assumed.
97+
98+
This conversion does not coerce the type. This does not check the type even if
99+
`NODE_ADDON_API_ENABLE_TYPE_CHECK_ON_AS` is defined. This indicates intentional
100+
unsafe type cast. Use `Napi::Value::As()` if possible.
101+
89102
### Env
90103

91104
```cpp

napi-inl.h

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -896,6 +896,16 @@ inline T Value::As() const {
896896
return T(_env, _value);
897897
}
898898

899+
template <typename T>
900+
inline T Value::UnsafeAs() const {
901+
return T(_env, _value);
902+
}
903+
904+
// static
905+
inline void Value::CheckCast(napi_env env, napi_value value) {
906+
NAPI_CHECK(value != nullptr, "Value::CheckCast", "empty value");
907+
}
908+
899909
inline MaybeOrValue<Boolean> Value::ToBoolean() const {
900910
napi_value result;
901911
napi_status status = napi_coerce_to_bool(_env, _value, &result);
@@ -1303,12 +1313,15 @@ inline Symbol Symbol::New(napi_env env, napi_value description) {
13031313

13041314
inline MaybeOrValue<Symbol> Symbol::WellKnown(napi_env env,
13051315
const std::string& name) {
1316+
// No need to check if the return value is a symbol or undefined.
1317+
// Well known symbols are definite and it is an develop time error
1318+
// if the symbol does not exist.
13061319
#if defined(NODE_ADDON_API_ENABLE_MAYBE)
13071320
Value symbol_obj;
13081321
Value symbol_value;
13091322
if (Napi::Env(env).Global().Get("Symbol").UnwrapTo(&symbol_obj) &&
13101323
symbol_obj.As<Object>().Get(name).UnwrapTo(&symbol_value)) {
1311-
return Just<Symbol>(symbol_value.As<Symbol>());
1324+
return Just<Symbol>(symbol_value.UnsafeAs<Symbol>());
13121325
}
13131326
return Nothing<Symbol>();
13141327
#else
@@ -1317,7 +1330,7 @@ inline MaybeOrValue<Symbol> Symbol::WellKnown(napi_env env,
13171330
.Get("Symbol")
13181331
.As<Object>()
13191332
.Get(name)
1320-
.As<Symbol>();
1333+
.UnsafeAs<Symbol>();
13211334
#endif
13221335
}
13231336

@@ -1535,7 +1548,10 @@ inline void Object::CheckCast(napi_env env, napi_value value) {
15351548
napi_valuetype type;
15361549
napi_status status = napi_typeof(env, value, &type);
15371550
NAPI_CHECK(status == napi_ok, "Object::CheckCast", "napi_typeof failed");
1538-
NAPI_INTERNAL_CHECK_EQ(type, napi_object, "%d", "Object::CheckCast");
1551+
NAPI_INTERNAL_CHECK(type == napi_object || type == napi_function,
1552+
"Object::CheckCast",
1553+
"Expect napi_object or napi_function, but got %d.",
1554+
type);
15391555
}
15401556

15411557
inline Object::Object() : TypeTaggable() {}

napi.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -461,6 +461,8 @@ class Value {
461461
template <typename T>
462462
static Value From(napi_env env, const T& value);
463463

464+
static void CheckCast(napi_env env, napi_value value);
465+
464466
/// Converts to a Node-API value primitive.
465467
///
466468
/// If the instance is _empty_, this returns `nullptr`.
@@ -527,6 +529,10 @@ class Value {
527529
template <typename T>
528530
T As() const;
529531

532+
// Unsafe Value::As(), should be avoided.
533+
template <typename T>
534+
T UnsafeAs() const;
535+
530536
MaybeOrValue<Boolean> ToBoolean()
531537
const; ///< Coerces a value to a JavaScript boolean.
532538
MaybeOrValue<Number> ToNumber()

test/async_worker.cc

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,14 @@ class TestWorkerWithUserDefRecv : public AsyncWorker {
2020
static void DoWorkWithAsyncRes(const CallbackInfo& info) {
2121
Object recv = info[0].As<Object>();
2222
Function cb = info[1].As<Function>();
23-
Object resource = info[2].As<Object>();
23+
Value resource = info[2];
2424

2525
TestWorkerWithUserDefRecv* worker = nullptr;
2626
if (resource == info.Env().Null()) {
2727
worker = new TestWorkerWithUserDefRecv(recv, cb, "TestResource");
2828
} else {
29-
worker =
30-
new TestWorkerWithUserDefRecv(recv, cb, "TestResource", resource);
29+
worker = new TestWorkerWithUserDefRecv(
30+
recv, cb, "TestResource", resource.As<Object>());
3131
}
3232

3333
worker->Queue();

test/binding.gyp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,8 @@
106106
{
107107
'target_name': 'binding',
108108
'dependencies': ['../node_addon_api.gyp:node_addon_api_except'],
109-
'sources': ['>@(build_sources)']
109+
'sources': ['>@(build_sources)'],
110+
'defines': ['NODE_ADDON_API_ENABLE_TYPE_CHECK_ON_AS']
110111
},
111112
{
112113
'target_name': 'binding_noexcept',

test/function.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ function test (binding) {
8989
assert.deepStrictEqual(args, [7, 8, 9]);
9090

9191
assert.throws(() => {
92-
binding.callWithInvalidReceiver();
92+
binding.callWithInvalidReceiver(() => {});
9393
}, /Invalid (pointer passed as )?argument/);
9494

9595
obj = binding.callConstructorWithArgs(testConstructor, 5, 6, 7);

test/globalObject/global_object_delete_property.cc

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,27 +5,27 @@ using namespace Napi;
55

66
Value DeletePropertyWithCStyleStringAsKey(const CallbackInfo& info) {
77
Object globalObject = info.Env().Global();
8-
String key = info[0].As<String>();
8+
String key = info[0].UnsafeAs<String>();
99
return Boolean::New(
1010
info.Env(), MaybeUnwrap(globalObject.Delete(key.Utf8Value().c_str())));
1111
}
1212

1313
Value DeletePropertyWithCppStyleStringAsKey(const CallbackInfo& info) {
1414
Object globalObject = info.Env().Global();
15-
String key = info[0].As<String>();
15+
String key = info[0].UnsafeAs<String>();
1616
return Boolean::New(info.Env(),
1717
MaybeUnwrap(globalObject.Delete(key.Utf8Value())));
1818
}
1919

2020
Value DeletePropertyWithInt32AsKey(const CallbackInfo& info) {
2121
Object globalObject = info.Env().Global();
22-
Number key = info[0].As<Number>();
22+
Number key = info[0].UnsafeAs<Number>();
2323
return Boolean::New(info.Env(),
2424
MaybeUnwrap(globalObject.Delete(key.Uint32Value())));
2525
}
2626

2727
Value DeletePropertyWithNapiValueAsKey(const CallbackInfo& info) {
2828
Object globalObject = info.Env().Global();
29-
Name key = info[0].As<Name>();
29+
Name key = info[0].UnsafeAs<Name>();
3030
return Boolean::New(info.Env(), MaybeUnwrap(globalObject.Delete(key)));
3131
}

test/globalObject/global_object_get_property.cc

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,25 +5,25 @@ using namespace Napi;
55

66
Value GetPropertyWithNapiValueAsKey(const CallbackInfo& info) {
77
Object globalObject = info.Env().Global();
8-
Name key = info[0].As<Name>();
8+
Name key = info[0].UnsafeAs<Name>();
99
return MaybeUnwrap(globalObject.Get(key));
1010
}
1111

1212
Value GetPropertyWithInt32AsKey(const CallbackInfo& info) {
1313
Object globalObject = info.Env().Global();
14-
Number key = info[0].As<Napi::Number>();
14+
Number key = info[0].UnsafeAs<Napi::Number>();
1515
return MaybeUnwrapOr(globalObject.Get(key.Uint32Value()), Value());
1616
}
1717

1818
Value GetPropertyWithCStyleStringAsKey(const CallbackInfo& info) {
1919
Object globalObject = info.Env().Global();
20-
String cStrkey = info[0].As<String>();
20+
String cStrkey = info[0].UnsafeAs<String>();
2121
return MaybeUnwrapOr(globalObject.Get(cStrkey.Utf8Value().c_str()), Value());
2222
}
2323

2424
Value GetPropertyWithCppStyleStringAsKey(const CallbackInfo& info) {
2525
Object globalObject = info.Env().Global();
26-
String cppStrKey = info[0].As<String>();
26+
String cppStrKey = info[0].UnsafeAs<String>();
2727
return MaybeUnwrapOr(globalObject.Get(cppStrKey.Utf8Value()), Value());
2828
}
2929

test/globalObject/global_object_has_own_property.cc

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ using namespace Napi;
55

66
Value HasPropertyWithCStyleStringAsKey(const CallbackInfo& info) {
77
Object globalObject = info.Env().Global();
8-
String key = info[0].As<String>();
8+
String key = info[0].UnsafeAs<String>();
99
return Boolean::New(
1010
info.Env(),
1111
MaybeUnwrapOr(globalObject.HasOwnProperty(key.Utf8Value().c_str()),
@@ -14,15 +14,15 @@ Value HasPropertyWithCStyleStringAsKey(const CallbackInfo& info) {
1414

1515
Value HasPropertyWithCppStyleStringAsKey(const CallbackInfo& info) {
1616
Object globalObject = info.Env().Global();
17-
String key = info[0].As<String>();
17+
String key = info[0].UnsafeAs<String>();
1818
return Boolean::New(
1919
info.Env(),
2020
MaybeUnwrapOr(globalObject.HasOwnProperty(key.Utf8Value()), false));
2121
}
2222

2323
Value HasPropertyWithNapiValueAsKey(const CallbackInfo& info) {
2424
Object globalObject = info.Env().Global();
25-
Name key = info[0].As<Name>();
25+
Name key = info[0].UnsafeAs<Name>();
2626
return Boolean::New(info.Env(),
2727
MaybeUnwrap(globalObject.HasOwnProperty(key)));
2828
}

test/globalObject/global_object_set_property.cc

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,28 +4,28 @@ using namespace Napi;
44

55
void SetPropertyWithCStyleStringAsKey(const CallbackInfo& info) {
66
Object globalObject = info.Env().Global();
7-
String key = info[0].As<String>();
7+
String key = info[0].UnsafeAs<String>();
88
Value value = info[1];
99
globalObject.Set(key.Utf8Value().c_str(), value);
1010
}
1111

1212
void SetPropertyWithCppStyleStringAsKey(const CallbackInfo& info) {
1313
Object globalObject = info.Env().Global();
14-
String key = info[0].As<String>();
14+
String key = info[0].UnsafeAs<String>();
1515
Value value = info[1];
1616
globalObject.Set(key.Utf8Value(), value);
1717
}
1818

1919
void SetPropertyWithInt32AsKey(const CallbackInfo& info) {
2020
Object globalObject = info.Env().Global();
21-
Number key = info[0].As<Number>();
21+
Number key = info[0].UnsafeAs<Number>();
2222
Value value = info[1];
2323
globalObject.Set(key.Uint32Value(), value);
2424
}
2525

2626
void SetPropertyWithNapiValueAsKey(const CallbackInfo& info) {
2727
Object globalObject = info.Env().Global();
28-
Name key = info[0].As<Name>();
28+
Name key = info[0].UnsafeAs<Name>();
2929
Value value = info[1];
3030
globalObject.Set(key, value);
31-
}
31+
}

0 commit comments

Comments
 (0)