Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

src: improve messages on CheckCast #1507

Merged
merged 2 commits into from
Jun 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 31 additions & 24 deletions napi-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,11 @@
////////////////////////////////////////////////////////////////////////////////

// Note: Do not include this file directly! Include "napi.h" instead.
// This should be a no-op and is intended for better IDE integration.
#include "napi.h"

#include <algorithm>
#include <cstdarg>
#include <cstring>
#if NAPI_HAS_THREADS
#include <mutex>
Expand Down Expand Up @@ -337,6 +340,18 @@ struct AccessorCallbackData {
void* data;
};

// Debugging-purpose C++-style variant of sprintf().
legendecas marked this conversation as resolved.
Show resolved Hide resolved
inline std::string StringFormat(const char* format, ...) {
std::string result;
va_list args;
va_start(args, format);
int len = vsnprintf(nullptr, 0, format, args);
result.resize(len);
vsnprintf(&result[0], len + 1, format, args);
va_end(args);
return result;
}

} // namespace details

#ifndef NODE_ADDON_API_DISABLE_DEPRECATED
Expand Down Expand Up @@ -805,8 +820,7 @@ inline void Boolean::CheckCast(napi_env env, napi_value value) {
napi_valuetype type;
napi_status status = napi_typeof(env, value, &type);
NAPI_CHECK(status == napi_ok, "Boolean::CheckCast", "napi_typeof failed");
NAPI_CHECK(
type == napi_boolean, "Boolean::CheckCast", "value is not napi_boolean");
NAPI_INTERNAL_CHECK_EQ(type, napi_boolean, "%d", "Boolean::CheckCast");
}

inline Boolean::Boolean() : Napi::Value() {}
Expand Down Expand Up @@ -842,8 +856,7 @@ inline void Number::CheckCast(napi_env env, napi_value value) {
napi_valuetype type;
napi_status status = napi_typeof(env, value, &type);
NAPI_CHECK(status == napi_ok, "Number::CheckCast", "napi_typeof failed");
NAPI_CHECK(
type == napi_number, "Number::CheckCast", "value is not napi_number");
NAPI_INTERNAL_CHECK_EQ(type, napi_number, "%d", "Number::CheckCast");
}

inline Number::Number() : Value() {}
Expand Down Expand Up @@ -938,8 +951,7 @@ inline void BigInt::CheckCast(napi_env env, napi_value value) {
napi_valuetype type;
napi_status status = napi_typeof(env, value, &type);
NAPI_CHECK(status == napi_ok, "BigInt::CheckCast", "napi_typeof failed");
NAPI_CHECK(
type == napi_bigint, "BigInt::CheckCast", "value is not napi_bigint");
NAPI_INTERNAL_CHECK_EQ(type, napi_bigint, "%d", "BigInt::CheckCast");
}

inline BigInt::BigInt() : Value() {}
Expand Down Expand Up @@ -1025,9 +1037,10 @@ inline void Name::CheckCast(napi_env env, napi_value value) {
napi_valuetype type;
napi_status status = napi_typeof(env, value, &type);
NAPI_CHECK(status == napi_ok, "Name::CheckCast", "napi_typeof failed");
NAPI_CHECK(type == napi_string || type == napi_symbol,
"Name::CheckCast",
"value is not napi_string or napi_symbol");
NAPI_INTERNAL_CHECK(type == napi_string || type == napi_symbol,
"Name::CheckCast",
"value is not napi_string or napi_symbol, got %d.",
type);
}

inline Name::Name() : Value() {}
Expand Down Expand Up @@ -1094,8 +1107,7 @@ inline void String::CheckCast(napi_env env, napi_value value) {
napi_valuetype type;
napi_status status = napi_typeof(env, value, &type);
NAPI_CHECK(status == napi_ok, "String::CheckCast", "napi_typeof failed");
NAPI_CHECK(
type == napi_string, "String::CheckCast", "value is not napi_string");
NAPI_INTERNAL_CHECK_EQ(type, napi_string, "%d", "String::CheckCast");
}

inline String::String() : Name() {}
Expand Down Expand Up @@ -1231,8 +1243,7 @@ inline void Symbol::CheckCast(napi_env env, napi_value value) {
napi_valuetype type;
napi_status status = napi_typeof(env, value, &type);
NAPI_CHECK(status == napi_ok, "Symbol::CheckCast", "napi_typeof failed");
NAPI_CHECK(
type == napi_symbol, "Symbol::CheckCast", "value is not napi_symbol");
NAPI_INTERNAL_CHECK_EQ(type, napi_symbol, "%d", "Symbol::CheckCast");
}

inline Symbol::Symbol() : Name() {}
Expand Down Expand Up @@ -1403,8 +1414,7 @@ inline void Object::CheckCast(napi_env env, napi_value value) {
napi_valuetype type;
napi_status status = napi_typeof(env, value, &type);
NAPI_CHECK(status == napi_ok, "Object::CheckCast", "napi_typeof failed");
NAPI_CHECK(
type == napi_object, "Object::CheckCast", "value is not napi_object");
NAPI_INTERNAL_CHECK_EQ(type, napi_object, "%d", "Object::CheckCast");
}

inline Object::Object() : TypeTaggable() {}
Expand Down Expand Up @@ -1814,9 +1824,7 @@ inline void External<T>::CheckCast(napi_env env, napi_value value) {
napi_valuetype type;
napi_status status = napi_typeof(env, value, &type);
NAPI_CHECK(status == napi_ok, "External::CheckCast", "napi_typeof failed");
NAPI_CHECK(type == napi_external,
"External::CheckCast",
"value is not napi_external");
NAPI_INTERNAL_CHECK_EQ(type, napi_external, "%d", "External::CheckCast");
}

template <typename T>
Expand Down Expand Up @@ -2270,12 +2278,13 @@ inline void TypedArrayOf<T>::CheckCast(napi_env env, napi_value value) {
"TypedArrayOf::CheckCast",
"napi_is_typedarray failed");

NAPI_CHECK(
NAPI_INTERNAL_CHECK(
(type == TypedArrayTypeForPrimitiveType<T>() ||
(type == napi_uint8_clamped_array && std::is_same<T, uint8_t>::value)),
"TypedArrayOf::CheckCast",
"Array type must match the template parameter. (Uint8 arrays may "
"optionally have the \"clamped\" array type.)");
"Array type must match the template parameter, (Uint8 arrays may "
"optionally have the \"clamped\" array type.), got %d.",
type);
}

template <typename T>
Expand Down Expand Up @@ -2456,9 +2465,7 @@ inline void Function::CheckCast(napi_env env, napi_value value) {
napi_valuetype type;
napi_status status = napi_typeof(env, value, &type);
NAPI_CHECK(status == napi_ok, "Function::CheckCast", "napi_typeof failed");
NAPI_CHECK(type == napi_function,
"Function::CheckCast",
"value is not napi_function");
NAPI_INTERNAL_CHECK_EQ(type, napi_function, "%d", "Function::CheckCast");
}

inline Function::Function() : Object() {}
Expand Down
20 changes: 20 additions & 0 deletions napi.h
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,26 @@ static_assert(sizeof(char16_t) == sizeof(wchar_t),
} \
} while (0)

// Internal check helper. Be careful that the formatted message length should be
// max 255 size and null terminated.
#define NAPI_INTERNAL_CHECK(expr, location, ...) \
do { \
if (!(expr)) { \
std::string msg = Napi::details::StringFormat(__VA_ARGS__); \
Napi::Error::Fatal(location, msg.c_str()); \
} \
} while (0)

#define NAPI_INTERNAL_CHECK_EQ(actual, expected, value_format, location) \
do { \
auto actual_value = (actual); \
NAPI_INTERNAL_CHECK(actual_value == (expected), \
location, \
"Expected " #actual " to be equal to " #expected \
", but got " value_format ".", \
actual_value); \
} while (0)

#define NAPI_FATAL_IF_FAILED(status, location, message) \
NAPI_CHECK((status) == napi_ok, location, message)

Expand Down