Bug 1054755 - Part 3: Use IsRegExp in String.prototype.{contains,startsWith,endsWith}. r=till

This commit is contained in:
Tooru Fujisawa 2015-04-01 18:34:03 +09:00
parent 1c0d394afc
commit 058a4ec235
2 changed files with 72 additions and 26 deletions

View File

@ -1508,7 +1508,7 @@ RopeMatch(JSContext* cx, JSRope* text, JSLinearString* pat, int* match)
return true; return true;
} }
/* ES6 20121026 draft 15.5.4.24. */ /* ES6 draft rc3 21.1.3.7. */
static bool static bool
str_contains(JSContext* cx, unsigned argc, Value* vp) str_contains(JSContext* cx, unsigned argc, Value* vp)
{ {
@ -1520,11 +1520,23 @@ str_contains(JSContext* cx, unsigned argc, Value* vp)
return false; return false;
// Steps 4 and 5 // Steps 4 and 5
bool isRegExp;
if (!IsRegExp(cx, args.get(0), &isRegExp))
return false;
// Step 6
if (isRegExp) {
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_INVALID_ARG_TYPE,
"first", "", "Regular Expression");
return false;
}
// Steps 7 and 8
RootedLinearString searchStr(cx, ArgToRootedString(cx, args, 0)); RootedLinearString searchStr(cx, ArgToRootedString(cx, args, 0));
if (!searchStr) if (!searchStr)
return false; return false;
// Steps 6 and 7 // Steps 9 and 10
uint32_t pos = 0; uint32_t pos = 0;
if (args.hasDefined(1)) { if (args.hasDefined(1)) {
if (args[1].isInt32()) { if (args[1].isInt32()) {
@ -1538,13 +1550,13 @@ str_contains(JSContext* cx, unsigned argc, Value* vp)
} }
} }
// Step 8 // Step 11
uint32_t textLen = str->length(); uint32_t textLen = str->length();
// Step 9 // Step 12
uint32_t start = Min(Max(pos, 0U), textLen); uint32_t start = Min(Max(pos, 0U), textLen);
// Steps 10 and 11 // Steps 13 and 14
JSLinearString* text = str->ensureLinear(cx); JSLinearString* text = str->ensureLinear(cx);
if (!text) if (!text)
return false; return false;
@ -1720,7 +1732,7 @@ HasSubstringAt(JSLinearString* text, JSLinearString* pat, size_t start)
return EqualChars(pat->latin1Chars(nogc), textChars, patLen); return EqualChars(pat->latin1Chars(nogc), textChars, patLen);
} }
/* ES6 20131108 draft 21.1.3.18. */ /* ES6 draft rc3 21.1.3.18. */
bool bool
js::str_startsWith(JSContext* cx, unsigned argc, Value* vp) js::str_startsWith(JSContext* cx, unsigned argc, Value* vp)
{ {
@ -1731,19 +1743,24 @@ js::str_startsWith(JSContext* cx, unsigned argc, Value* vp)
if (!str) if (!str)
return false; return false;
// Step 4 // Steps 4 and 5
if (args.get(0).isObject() && IsObjectWithClass(args[0], ESClass_RegExp, cx)) { bool isRegExp;
if (!IsRegExp(cx, args.get(0), &isRegExp))
return false;
// Step 6
if (isRegExp) {
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_INVALID_ARG_TYPE, JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_INVALID_ARG_TYPE,
"first", "", "Regular Expression"); "first", "", "Regular Expression");
return false; return false;
} }
// Steps 5 and 6 // Steps 7 and 8
RootedLinearString searchStr(cx, ArgToRootedString(cx, args, 0)); RootedLinearString searchStr(cx, ArgToRootedString(cx, args, 0));
if (!searchStr) if (!searchStr)
return false; return false;
// Steps 7 and 8 // Steps 9 and 10
uint32_t pos = 0; uint32_t pos = 0;
if (args.hasDefined(1)) { if (args.hasDefined(1)) {
if (args[1].isInt32()) { if (args[1].isInt32()) {
@ -1757,22 +1774,22 @@ js::str_startsWith(JSContext* cx, unsigned argc, Value* vp)
} }
} }
// Step 9 // Step 11
uint32_t textLen = str->length(); uint32_t textLen = str->length();
// Step 10 // Step 12
uint32_t start = Min(Max(pos, 0U), textLen); uint32_t start = Min(Max(pos, 0U), textLen);
// Step 11 // Step 13
uint32_t searchLen = searchStr->length(); uint32_t searchLen = searchStr->length();
// Step 12 // Step 14
if (searchLen + start < searchLen || searchLen + start > textLen) { if (searchLen + start < searchLen || searchLen + start > textLen) {
args.rval().setBoolean(false); args.rval().setBoolean(false);
return true; return true;
} }
// Steps 13 and 14 // Steps 15 and 16
JSLinearString* text = str->ensureLinear(cx); JSLinearString* text = str->ensureLinear(cx);
if (!text) if (!text)
return false; return false;
@ -1781,7 +1798,7 @@ js::str_startsWith(JSContext* cx, unsigned argc, Value* vp)
return true; return true;
} }
/* ES6 20131108 draft 21.1.3.7. */ /* ES6 draft rc3 21.1.3.6. */
static bool static bool
str_endsWith(JSContext* cx, unsigned argc, Value* vp) str_endsWith(JSContext* cx, unsigned argc, Value* vp)
{ {
@ -1792,22 +1809,27 @@ str_endsWith(JSContext* cx, unsigned argc, Value* vp)
if (!str) if (!str)
return false; return false;
// Step 4 // Steps 4 and 5
if (args.get(0).isObject() && IsObjectWithClass(args[0], ESClass_RegExp, cx)) { bool isRegExp;
if (!IsRegExp(cx, args.get(0), &isRegExp))
return false;
// Step 6
if (isRegExp) {
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_INVALID_ARG_TYPE, JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_INVALID_ARG_TYPE,
"first", "", "Regular Expression"); "first", "", "Regular Expression");
return false; return false;
} }
// Steps 5 and 6 // Steps 7 and 8
RootedLinearString searchStr(cx, ArgToRootedString(cx, args, 0)); RootedLinearString searchStr(cx, ArgToRootedString(cx, args, 0));
if (!searchStr) if (!searchStr)
return false; return false;
// Step 7 // Step 9
uint32_t textLen = str->length(); uint32_t textLen = str->length();
// Steps 8 and 9 // Steps 10 and 11
uint32_t pos = textLen; uint32_t pos = textLen;
if (args.hasDefined(1)) { if (args.hasDefined(1)) {
if (args[1].isInt32()) { if (args[1].isInt32()) {
@ -1821,22 +1843,22 @@ str_endsWith(JSContext* cx, unsigned argc, Value* vp)
} }
} }
// Step 10 // Step 12
uint32_t end = Min(Max(pos, 0U), textLen); uint32_t end = Min(Max(pos, 0U), textLen);
// Step 11 // Step 13
uint32_t searchLen = searchStr->length(); uint32_t searchLen = searchStr->length();
// Step 13 (reordered) // Step 15 (reordered)
if (searchLen > end) { if (searchLen > end) {
args.rval().setBoolean(false); args.rval().setBoolean(false);
return true; return true;
} }
// Step 12 // Step 14
uint32_t start = end - searchLen; uint32_t start = end - searchLen;
// Steps 14 and 15 // Steps 16 and 17
JSLinearString* text = str->ensureLinear(cx); JSLinearString* text = str->ensureLinear(cx);
if (!text) if (!text)
return false; return false;

View File

@ -0,0 +1,24 @@
var BUGNUMBER = 1054755;
var summary = 'String.prototype.{startsWith,endsWith,contains} should call IsRegExp.';
print(BUGNUMBER + ": " + summary);
for (var method of ["startsWith", "endsWith", "contains"]) {
for (var re of [/foo/, new RegExp()]) {
assertThrowsInstanceOf(() => "foo"[method](re), TypeError);
re[Symbol.match] = false;
"foo"[method](re);
}
for (var v1 of [true, 1, "bar", [], {}, Symbol.iterator]) {
assertThrowsInstanceOf(() => "foo"[method]({ [Symbol.match]: v1 }), TypeError);
}
for (var v2 of [false, 0, undefined, ""]) {
"foo"[method]({ [Symbol.match]: v2 });
}
}
if (typeof reportCompare === "function")
reportCompare(true, true);