From 058a4ec2350a5397fb5825312f53ca86e16811a3 Mon Sep 17 00:00:00 2001 From: Tooru Fujisawa Date: Wed, 1 Apr 2015 18:34:03 +0900 Subject: [PATCH] Bug 1054755 - Part 3: Use IsRegExp in String.prototype.{contains,startsWith,endsWith}. r=till --- js/src/jsstr.cpp | 74 +++++++++++++++++--------- js/src/tests/ecma_6/String/IsRegExp.js | 24 +++++++++ 2 files changed, 72 insertions(+), 26 deletions(-) create mode 100644 js/src/tests/ecma_6/String/IsRegExp.js diff --git a/js/src/jsstr.cpp b/js/src/jsstr.cpp index 62db585fa7a3..5d04a884f143 100644 --- a/js/src/jsstr.cpp +++ b/js/src/jsstr.cpp @@ -1508,7 +1508,7 @@ RopeMatch(JSContext* cx, JSRope* text, JSLinearString* pat, int* match) return true; } -/* ES6 20121026 draft 15.5.4.24. */ +/* ES6 draft rc3 21.1.3.7. */ static bool str_contains(JSContext* cx, unsigned argc, Value* vp) { @@ -1520,11 +1520,23 @@ str_contains(JSContext* cx, unsigned argc, Value* vp) return false; // 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)); if (!searchStr) return false; - // Steps 6 and 7 + // Steps 9 and 10 uint32_t pos = 0; if (args.hasDefined(1)) { 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(); - // Step 9 + // Step 12 uint32_t start = Min(Max(pos, 0U), textLen); - // Steps 10 and 11 + // Steps 13 and 14 JSLinearString* text = str->ensureLinear(cx); if (!text) return false; @@ -1720,7 +1732,7 @@ HasSubstringAt(JSLinearString* text, JSLinearString* pat, size_t start) return EqualChars(pat->latin1Chars(nogc), textChars, patLen); } -/* ES6 20131108 draft 21.1.3.18. */ +/* ES6 draft rc3 21.1.3.18. */ bool js::str_startsWith(JSContext* cx, unsigned argc, Value* vp) { @@ -1731,19 +1743,24 @@ js::str_startsWith(JSContext* cx, unsigned argc, Value* vp) if (!str) return false; - // Step 4 - if (args.get(0).isObject() && IsObjectWithClass(args[0], ESClass_RegExp, cx)) { + // 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 5 and 6 + // Steps 7 and 8 RootedLinearString searchStr(cx, ArgToRootedString(cx, args, 0)); if (!searchStr) return false; - // Steps 7 and 8 + // Steps 9 and 10 uint32_t pos = 0; if (args.hasDefined(1)) { 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(); - // Step 10 + // Step 12 uint32_t start = Min(Max(pos, 0U), textLen); - // Step 11 + // Step 13 uint32_t searchLen = searchStr->length(); - // Step 12 + // Step 14 if (searchLen + start < searchLen || searchLen + start > textLen) { args.rval().setBoolean(false); return true; } - // Steps 13 and 14 + // Steps 15 and 16 JSLinearString* text = str->ensureLinear(cx); if (!text) return false; @@ -1781,7 +1798,7 @@ js::str_startsWith(JSContext* cx, unsigned argc, Value* vp) return true; } -/* ES6 20131108 draft 21.1.3.7. */ +/* ES6 draft rc3 21.1.3.6. */ static bool str_endsWith(JSContext* cx, unsigned argc, Value* vp) { @@ -1792,22 +1809,27 @@ str_endsWith(JSContext* cx, unsigned argc, Value* vp) if (!str) return false; - // Step 4 - if (args.get(0).isObject() && IsObjectWithClass(args[0], ESClass_RegExp, cx)) { + // 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 5 and 6 + // Steps 7 and 8 RootedLinearString searchStr(cx, ArgToRootedString(cx, args, 0)); if (!searchStr) return false; - // Step 7 + // Step 9 uint32_t textLen = str->length(); - // Steps 8 and 9 + // Steps 10 and 11 uint32_t pos = textLen; if (args.hasDefined(1)) { 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); - // Step 11 + // Step 13 uint32_t searchLen = searchStr->length(); - // Step 13 (reordered) + // Step 15 (reordered) if (searchLen > end) { args.rval().setBoolean(false); return true; } - // Step 12 + // Step 14 uint32_t start = end - searchLen; - // Steps 14 and 15 + // Steps 16 and 17 JSLinearString* text = str->ensureLinear(cx); if (!text) return false; diff --git a/js/src/tests/ecma_6/String/IsRegExp.js b/js/src/tests/ecma_6/String/IsRegExp.js new file mode 100644 index 000000000000..7be5479bbf7d --- /dev/null +++ b/js/src/tests/ecma_6/String/IsRegExp.js @@ -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);