Bug 1613013 part 2. Change ThrowErrorMessage to be templated on the error number. r=peterv

This makes it easier to static_assert correct use.  It caught several bugs in
the next patch in this stack.

I had to disambiguate some calls to the templated ThrowDOMException that are
inside the binding_detail namespace, because otherwise they were trying to call
teh non-template function of the same name that's declared in binding_detail.

Differential Revision: https://phabricator.services.mozilla.com/D61522

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Boris Zbarsky 2020-02-06 20:40:36 +00:00
Родитель 747a4d9f0a
Коммит 09a1a6496e
7 изменённых файлов: 40 добавлений и 38 удалений

Просмотреть файл

@ -397,8 +397,8 @@ static bool ConvertKeyframeSequence(JSContext* aCx, dom::Document* aDocument,
// or null/undefined (which gets treated as a default {} dictionary
// value).
if (!value.isObject() && !value.isNullOrUndefined()) {
dom::ThrowErrorMessage(aCx, dom::MSG_NOT_OBJECT,
"Element of sequence<Keyframe> argument");
dom::ThrowErrorMessage<dom::MSG_NOT_OBJECT>(
aCx, "Element of sequence<Keyframe> argument");
return false;
}

Просмотреть файл

@ -1266,11 +1266,11 @@ void GetInterfaceImpl(JSContext* aCx, nsIInterfaceRequestor* aRequestor,
}
bool ThrowingConstructor(JSContext* cx, unsigned argc, JS::Value* vp) {
return ThrowErrorMessage(cx, MSG_ILLEGAL_CONSTRUCTOR);
return ThrowErrorMessage<MSG_ILLEGAL_CONSTRUCTOR>(cx);
}
bool ThrowConstructorWithoutNew(JSContext* cx, const char* name) {
return ThrowErrorMessage(cx, MSG_CONSTRUCTOR_WITHOUT_NEW, name);
return ThrowErrorMessage<MSG_CONSTRUCTOR_WITHOUT_NEW>(cx, name);
}
inline const NativePropertyHooks* GetNativePropertyHooksFromConstructorFunction(
@ -2457,7 +2457,7 @@ bool GetContentGlobalForJSImplementedObject(JSContext* cx,
}
if (!domImplVal.isObject()) {
ThrowErrorMessage(cx, MSG_NOT_OBJECT, "Value");
ThrowErrorMessage<MSG_NOT_OBJECT>(cx, "Value");
return false;
}
@ -2630,7 +2630,7 @@ bool ConvertJSValueToByteString(JSContext* cx, JS::Handle<JS::Value> v,
char badCharArray[6];
static_assert(sizeof(char16_t) <= 2, "badCharArray too small");
SprintfLiteral(badCharArray, "%d", badChar);
ThrowErrorMessage(cx, MSG_INVALID_BYTESTRING, index, badCharArray);
ThrowErrorMessage<MSG_INVALID_BYTESTRING>(cx, index, badCharArray);
return false;
}
} else {

Просмотреть файл

@ -1285,8 +1285,8 @@ inline bool EnumValueNotFound<true>(JSContext* cx, JS::HandleString str,
if (!deflated) {
return false;
}
return ThrowErrorMessage(cx, MSG_INVALID_ENUM_VALUE, sourceDescription,
deflated.get(), type);
return ThrowErrorMessage<MSG_INVALID_ENUM_VALUE>(cx, sourceDescription,
deflated.get(), type);
}
template <typename CharT>

Просмотреть файл

@ -23,7 +23,7 @@ bool CallbackInterface::GetCallableProperty(
JS::RootedString propId(cx, JSID_TO_STRING(aPropId));
JS::UniqueChars propName = JS_EncodeStringToUTF8(cx, propId);
nsPrintfCString description("Property '%s'", propName.get());
ThrowErrorMessage(cx, MSG_NOT_CALLABLE, description.get());
ThrowErrorMessage<MSG_NOT_CALLABLE>(cx, description.get());
return false;
}

Просмотреть файл

@ -4456,7 +4456,7 @@ class FailureFatalCastableObjectUnwrapper(CastableObjectUnwrapper):
isCallbackReturnValue, sourceDescription):
CastableObjectUnwrapper.__init__(
self, descriptor, source, mutableSource, target,
'ThrowErrorMessage(cx, MSG_DOES_NOT_IMPLEMENT_INTERFACE, "%s", "%s");\n'
'ThrowErrorMessage<MSG_DOES_NOT_IMPLEMENT_INTERFACE>(cx, "%s", "%s");\n'
'%s' % (sourceDescription, descriptor.interface.identifier.name,
exceptionCode),
exceptionCode,
@ -4766,25 +4766,25 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
def onFailureNotAnObject(failureCode):
return CGGeneric(
failureCode or
('ThrowErrorMessage(cx, MSG_NOT_OBJECT, "%s");\n'
('ThrowErrorMessage<MSG_NOT_OBJECT>(cx, "%s");\n'
'%s' % (firstCap(sourceDescription), exceptionCode)))
def onFailureBadType(failureCode, typeName):
return CGGeneric(
failureCode or
('ThrowErrorMessage(cx, MSG_DOES_NOT_IMPLEMENT_INTERFACE, "%s", "%s");\n'
('ThrowErrorMessage<MSG_DOES_NOT_IMPLEMENT_INTERFACE>(cx, "%s", "%s");\n'
'%s' % (firstCap(sourceDescription), typeName, exceptionCode)))
def onFailureIsShared(failureCode):
return CGGeneric(
failureCode or
('ThrowErrorMessage(cx, MSG_TYPEDARRAY_IS_SHARED, "%s");\n'
('ThrowErrorMessage<MSG_TYPEDARRAY_IS_SHARED>(cx, "%s");\n'
'%s' % (firstCap(sourceDescription), exceptionCode)))
def onFailureNotCallable(failureCode):
return CGGeneric(
failureCode or
('ThrowErrorMessage(cx, MSG_NOT_CALLABLE, "%s");\n'
('ThrowErrorMessage<MSG_NOT_CALLABLE>(cx, "%s");\n'
'%s' % (firstCap(sourceDescription), exceptionCode)))
# A helper function for handling default values. Takes a template
@ -4893,7 +4893,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
#pragma clang diagnostic ignored "-Wunreachable-code-return"
#endif // __clang__
if (($${passedToJSImpl}) && !CallerSubsumes($${val})) {
ThrowErrorMessage(cx, MSG_PERMISSION_DENIED_TO_PASS_ARG, "${sourceDescription}");
ThrowErrorMessage<MSG_PERMISSION_DENIED_TO_PASS_ARG>(cx, "${sourceDescription}");
$*{exceptionCode}
}
#ifdef __clang__
@ -4921,7 +4921,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
assert not isEnforceRange and not isClamp and not isAllowShared
if failureCode is None:
notSequence = ('ThrowErrorMessage(cx, MSG_NOT_SEQUENCE, "%s");\n'
notSequence = ('ThrowErrorMessage<MSG_NOT_SEQUENCE>(cx, "%s");\n'
"%s" % (firstCap(sourceDescription), exceptionCode))
else:
notSequence = failureCode
@ -5058,7 +5058,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
if type.isRecord():
assert not isEnforceRange and not isClamp and not isAllowShared
if failureCode is None:
notRecord = ('ThrowErrorMessage(cx, MSG_NOT_OBJECT, "%s");\n'
notRecord = ('ThrowErrorMessage<MSG_NOT_OBJECT>(cx, "%s");\n'
"%s" % (firstCap(sourceDescription), exceptionCode))
else:
notRecord = failureCode
@ -5407,7 +5407,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
$*{exceptionCode}
}
if (!done) {
ThrowErrorMessage(cx, MSG_NOT_IN_UNION, "${desc}", "${names}");
ThrowErrorMessage<MSG_NOT_IN_UNION>(cx, "${desc}", "${names}");
$*{exceptionCode}
}
""",
@ -6213,7 +6213,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
#pragma clang diagnostic ignored "-Wunreachable-code-return"
#endif // __clang__
if (($${passedToJSImpl}) && !CallerSubsumes($${val})) {
ThrowErrorMessage(cx, MSG_PERMISSION_DENIED_TO_PASS_ARG, "${sourceDescription}");
ThrowErrorMessage<MSG_PERMISSION_DENIED_TO_PASS_ARG>(cx, "${sourceDescription}");
$*{exceptionCode}
}
#ifdef __clang__
@ -6408,7 +6408,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
if lenientFloatCode is not None:
nonFiniteCode = lenientFloatCode
else:
nonFiniteCode = ('ThrowErrorMessage(cx, MSG_NOT_FINITE, "%s");\n'
nonFiniteCode = ('ThrowErrorMessage<MSG_NOT_FINITE>(cx, "%s");\n'
"%s" % (firstCap(sourceDescription), exceptionCode))
# We're appending to an if-block brace, so strip trailing whitespace
@ -8735,7 +8735,7 @@ class CGMethodCall(CGThing):
# Just throw; we have no idea what we're supposed to
# do with this.
caseBody.append(CGGeneric(
'return ThrowErrorMessage(cx, MSG_OVERLOAD_RESOLUTION_FAILED, "%d", "%d", "%s");\n' %
'return ThrowErrorMessage<MSG_OVERLOAD_RESOLUTION_FAILED>(cx, "%d", "%d", "%s");\n' %
(distinguishingIndex + 1, argCount, methodName)))
argCountCases.append(CGCase(str(argCount), CGList(caseBody)))
@ -8753,7 +8753,7 @@ class CGMethodCall(CGThing):
// header. Let's not worry about it.
nsAutoCString argCountStr;
argCountStr.AppendPrintf("%u", args.length());
return ThrowErrorMessage(cx, MSG_INVALID_OVERLOAD_ARGCOUNT, "${methodName}", argCountStr.get());
return ThrowErrorMessage<MSG_INVALID_OVERLOAD_ARGCOUNT>(cx, "${methodName}", argCountStr.get());
""",
methodName=methodName))))
overloadCGThings.append(
@ -9615,7 +9615,7 @@ class CGSpecializedForwardingSetter(CGSpecializedSetter):
}
if (!v.isObject()) {
return ThrowErrorMessage(cx, MSG_NOT_OBJECT, "${interface}.${attr}");
return ThrowErrorMessage<MSG_NOT_OBJECT>(cx, "${interface}.${attr}");
}
JS::Rooted<JSObject*> targetObj(cx, &v.toObject());
@ -10385,7 +10385,7 @@ def getUnionTypeTemplateVars(unionType, type, descriptorProvider,
body = body + fill(
"""
if (passedToJSImpl && !CallerSubsumes(obj)) {
ThrowErrorMessage(cx, MSG_PERMISSION_DENIED_TO_PASS_ARG, "${sourceDescription}");
ThrowErrorMessage<MSG_PERMISSION_DENIED_TO_PASS_ARG>(cx, "${sourceDescription}");
return false;
}
return true;
@ -13846,7 +13846,7 @@ class CGDictionary(CGThing):
body += dedent(
"""
if (!IsConvertibleToDictionary(val)) {
return ThrowErrorMessage(cx, MSG_NOT_DICTIONARY, sourceDescription);
return ThrowErrorMessage<MSG_NOT_DICTIONARY>(cx, sourceDescription);
}
""")
@ -14402,8 +14402,7 @@ class CGDictionary(CGThing):
// Don't error out if we have no cx. In that
// situation the caller is default-constructing us and we'll
// just assume they know what they're doing.
return ThrowErrorMessage(cx, MSG_MISSING_REQUIRED_DICTIONARY_MEMBER,
"%s");
return ThrowErrorMessage<MSG_MISSING_REQUIRED_DICTIONARY_MEMBER>(cx, "%s");
}
""" % self.getMemberSourceDescription(member))
conversionReplacements["convert"] = indent(conversionReplacements["convert"]).rstrip()
@ -16571,10 +16570,10 @@ class CGJSImplClass(CGBindingImplClass):
return false;
}
if (!args[0].isObject()) {
return ThrowErrorMessage(cx, MSG_NOT_OBJECT, "Argument 1 of ${ifaceName}._create");
return ThrowErrorMessage<MSG_NOT_OBJECT>(cx, "Argument 1 of ${ifaceName}._create");
}
if (!args[1].isObject()) {
return ThrowErrorMessage(cx, MSG_NOT_OBJECT, "Argument 2 of ${ifaceName}._create");
return ThrowErrorMessage<MSG_NOT_OBJECT>(cx, "Argument 2 of ${ifaceName}._create");
}
// GlobalObject will go through wrappers as needed for us, and
@ -18073,7 +18072,7 @@ class CGIterableMethodGenerator(CGGeneric):
CGGeneric.__init__(self, fill(
"""
if (!JS::IsCallable(arg0)) {
ThrowErrorMessage(cx, MSG_NOT_CALLABLE, "Argument 1 of ${ifaceName}.forEach");
ThrowErrorMessage<MSG_NOT_CALLABLE>(cx, "Argument 1 of ${ifaceName}.forEach");
return false;
}
JS::AutoValueArray<3> callArgs(cx);

Просмотреть файл

@ -75,10 +75,13 @@ namespace binding_detail {
void ThrowErrorMessage(JSContext* aCx, const unsigned aErrorNumber, ...);
} // namespace binding_detail
template <typename... Ts>
inline bool ThrowErrorMessage(JSContext* aCx, const ErrNum aErrorNumber,
Ts&&... aArgs) {
binding_detail::ThrowErrorMessage(aCx, static_cast<unsigned>(aErrorNumber),
template <ErrNum errorNumber, typename... Ts>
inline bool ThrowErrorMessage(JSContext* aCx, Ts&&... aArgs) {
#if defined(DEBUG) && (defined(__clang__) || defined(__GNUC__))
static_assert(ErrorFormatNumArgs[errorNumber] == sizeof...(aArgs),
"Pass in the right number of arguments");
#endif
binding_detail::ThrowErrorMessage(aCx, static_cast<unsigned>(errorNumber),
std::forward<Ts>(aArgs)...);
return false;
}

Просмотреть файл

@ -198,8 +198,8 @@ inline bool PrimitiveConversionTraits_EnforceRange(JSContext* cx,
"This can only be applied to integers!");
if (!mozilla::IsFinite(d)) {
return ThrowErrorMessage(cx, MSG_ENFORCE_RANGE_NON_FINITE,
TypeName<T>::value());
return ThrowErrorMessage<MSG_ENFORCE_RANGE_NON_FINITE>(
cx, TypeName<T>::value());
}
bool neg = (d < 0);
@ -207,8 +207,8 @@ inline bool PrimitiveConversionTraits_EnforceRange(JSContext* cx,
rounded = neg ? -rounded : rounded;
if (rounded < PrimitiveConversionTraits_Limits<T>::min() ||
rounded > PrimitiveConversionTraits_Limits<T>::max()) {
return ThrowErrorMessage(cx, MSG_ENFORCE_RANGE_OUT_OF_RANGE,
TypeName<T>::value());
return ThrowErrorMessage<MSG_ENFORCE_RANGE_OUT_OF_RANGE>(
cx, TypeName<T>::value());
}
*retval = static_cast<T>(rounded);