Bug 1220457 - Show deprecation warning for non-standard RegExp.multiline. r=till
authorTooru Fujisawa <arai_a@mac.com>
Sun, 01 Nov 2015 20:55:15 +0900
changeset 276832 5ac90824efedaa33efdce5acc42d61fa0bdb7dc8
parent 276831 edc36eaff15ff316dbc6cbcea906aca974f987d9
child 276833 7347f089d50864cc0617d77a6748b6f4785403e6
push id29810
push usercbook@mozilla.com
push dateFri, 18 Dec 2015 14:24:54 +0000
treeherdermozilla-central@c5cb194cc9cb [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstill
bugs1220457
milestone46.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1220457 - Show deprecation warning for non-standard RegExp.multiline. r=till
js/src/builtin/RegExp.cpp
js/src/jit-test/tests/basic/regexp-multiline-warning.js
js/src/js.msg
js/src/jscompartment.cpp
js/src/jscompartment.h
js/src/vm/Xdr.h
--- a/js/src/builtin/RegExp.cpp
+++ b/js/src/builtin/RegExp.cpp
@@ -605,18 +605,16 @@ const JSFunctionSpec js::regexp_methods[
         CallArgs args = CallArgsFromVp(argc, vp);                               \
         RegExpStatics* res = cx->global()->getRegExpStatics(cx);                \
         if (!res)                                                               \
             return false;                                                       \
         code;                                                                   \
     }
 
 DEFINE_STATIC_GETTER(static_input_getter,        return res->createPendingInput(cx, args.rval()))
-DEFINE_STATIC_GETTER(static_multiline_getter,    args.rval().setBoolean(res->multiline());
-                                                 return true)
 DEFINE_STATIC_GETTER(static_lastMatch_getter,    return res->createLastMatch(cx, args.rval()))
 DEFINE_STATIC_GETTER(static_lastParen_getter,    return res->createLastParen(cx, args.rval()))
 DEFINE_STATIC_GETTER(static_leftContext_getter,  return res->createLeftContext(cx, args.rval()))
 DEFINE_STATIC_GETTER(static_rightContext_getter, return res->createRightContext(cx, args.rval()))
 
 DEFINE_STATIC_GETTER(static_paren1_getter,       STATIC_PAREN_GETTER_CODE(1))
 DEFINE_STATIC_GETTER(static_paren2_getter,       STATIC_PAREN_GETTER_CODE(2))
 DEFINE_STATIC_GETTER(static_paren3_getter,       STATIC_PAREN_GETTER_CODE(3))
@@ -651,23 +649,56 @@ static_input_setter(JSContext* cx, unsig
         return false;
 
     res->setPendingInput(str);
     args.rval().setString(str);
     return true;
 }
 
 static bool
+WarnOnceAboutRegExpMultiline(JSContext* cx)
+{
+    if (!cx->compartment()->warnedAboutRegExpMultiline) {
+        if (!JS_ReportErrorFlagsAndNumber(cx, JSREPORT_WARNING, GetErrorMessage, nullptr,
+                                          JSMSG_DEPRECATED_REGEXP_MULTILINE))
+        {
+            return false;
+        }
+        cx->compartment()->warnedAboutRegExpMultiline = true;
+    }
+
+    return true;
+}
+
+static bool
+static_multiline_getter(JSContext* cx, unsigned argc, Value* vp)
+{
+    CallArgs args = CallArgsFromVp(argc, vp);
+    RegExpStatics* res = cx->global()->getRegExpStatics(cx);
+    if (!res)
+        return false;
+
+    if (!WarnOnceAboutRegExpMultiline(cx))
+        return false;
+
+    args.rval().setBoolean(res->multiline());
+    return true;
+}
+
+static bool
 static_multiline_setter(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     RegExpStatics* res = cx->global()->getRegExpStatics(cx);
     if (!res)
         return false;
 
+    if (!WarnOnceAboutRegExpMultiline(cx))
+        return false;
+
     bool b = ToBoolean(args.get(0));
     res->setMultiline(cx, b);
     args.rval().setBoolean(b);
     return true;
 }
 
 const JSPropertySpec js::regexp_static_props[] = {
     JS_PSGS("input", static_input_getter, static_input_setter,
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/regexp-multiline-warning.js
@@ -0,0 +1,23 @@
+// RegExp.multiline access should be warned once and only once.
+
+function testWarn(code) {
+  enableLastWarning();
+  var g = newGlobal();
+  g.code = code;
+  g.eval('eval(code)');
+  var warning = getLastWarning();
+  assertEq(warning !== null, true, "warning should be caught for " + code);
+  assertEq(warning.name, "SyntaxError");
+
+  clearLastWarning();
+  g.eval('eval(code)');
+  warning = getLastWarning();
+  assertEq(warning, null, "warning should not be caught for 2nd ocurrence");
+  disableLastWarning();
+}
+
+testWarn("var a = RegExp.multiline;");
+testWarn("RegExp.multiline = true;");
+
+testWarn("var a = RegExp['$*'];");
+testWarn("RegExp['$*'] = true;");
--- a/js/src/js.msg
+++ b/js/src/js.msg
@@ -439,16 +439,17 @@ MSG_DEF(JSMSG_INVALID_LANGUAGE_TAG,    1
 MSG_DEF(JSMSG_INVALID_LOCALES_ELEMENT, 0, JSEXN_TYPEERR, "invalid element in locales argument")
 MSG_DEF(JSMSG_INVALID_LOCALE_MATCHER,  1, JSEXN_RANGEERR, "invalid locale matcher in supportedLocalesOf(): {0}")
 MSG_DEF(JSMSG_INVALID_OPTION_VALUE,    2, JSEXN_RANGEERR, "invalid value {1} for option {0}")
 MSG_DEF(JSMSG_INVALID_TIME_ZONE,       1, JSEXN_RANGEERR, "invalid time zone in DateTimeFormat(): {0}")
 MSG_DEF(JSMSG_UNDEFINED_CURRENCY,      0, JSEXN_TYPEERR, "undefined currency in NumberFormat() with currency style")
 
 // RegExp
 MSG_DEF(JSMSG_BAD_CLASS_RANGE,         0, JSEXN_SYNTAXERR, "invalid range in character class")
+MSG_DEF(JSMSG_DEPRECATED_REGEXP_MULTILINE, 0, JSEXN_SYNTAXERR, "RegExp.multiline is deprecated. Use m flag instead")
 MSG_DEF(JSMSG_ESCAPE_AT_END_OF_REGEXP, 0, JSEXN_SYNTAXERR, "\\ at end of pattern")
 MSG_DEF(JSMSG_INVALID_GROUP,           0, JSEXN_SYNTAXERR, "invalid regexp group")
 MSG_DEF(JSMSG_MISSING_PAREN,           0, JSEXN_SYNTAXERR, "unterminated parenthetical")
 MSG_DEF(JSMSG_NEWREGEXP_FLAGGED,       0, JSEXN_TYPEERR, "can't supply flags when constructing one RegExp from another")
 MSG_DEF(JSMSG_NOTHING_TO_REPEAT,       0, JSEXN_SYNTAXERR, "nothing to repeat")
 MSG_DEF(JSMSG_NUMBERS_OUT_OF_ORDER,    0, JSEXN_SYNTAXERR, "numbers out of order in {} quantifier.")
 MSG_DEF(JSMSG_TOO_MANY_PARENS,         0, JSEXN_INTERNALERR, "too many parentheses in regular expression")
 MSG_DEF(JSMSG_UNMATCHED_RIGHT_PAREN,   0, JSEXN_SYNTAXERR, "unmatched ) in regular expression")
--- a/js/src/jscompartment.cpp
+++ b/js/src/jscompartment.cpp
@@ -45,16 +45,17 @@ JSCompartment::JSCompartment(Zone* zone,
     zone_(zone),
     runtime_(zone->runtimeFromMainThread()),
     principals_(nullptr),
     isSystem_(false),
     isSelfHosting(false),
     marked(true),
     warnedAboutFlagsArgument(false),
     warnedAboutExprClosure(false),
+    warnedAboutRegExpMultiline(false),
     addonId(options.addonIdOrNull()),
 #ifdef DEBUG
     firedOnNewGlobalObject(false),
 #endif
     global_(nullptr),
     enterCompartmentDepth(0),
     performanceMonitoring(runtime_),
     data(nullptr),
--- a/js/src/jscompartment.h
+++ b/js/src/jscompartment.h
@@ -273,16 +273,17 @@ struct JSCompartment
   private:
     JSPrincipals*                principals_;
     bool                         isSystem_;
   public:
     bool                         isSelfHosting;
     bool                         marked;
     bool                         warnedAboutFlagsArgument;
     bool                         warnedAboutExprClosure;
+    bool                         warnedAboutRegExpMultiline;
 
     // A null add-on ID means that the compartment is not associated with an
     // add-on.
     JSAddonId*                   const addonId;
 
 #ifdef DEBUG
     bool                         firedOnNewGlobalObject;
 #endif
--- a/js/src/vm/Xdr.h
+++ b/js/src/vm/Xdr.h
@@ -24,21 +24,21 @@ namespace js {
  * versions.  If deserialization fails, the data should be invalidated if
  * possible.
  *
  * When you change this, run make_opcode_doc.py and copy the new output into
  * this wiki page:
  *
  *  https://developer.mozilla.org/en-US/docs/SpiderMonkey/Internals/Bytecode
  */
-static const uint32_t XDR_BYTECODE_VERSION_SUBTRAHEND = 333;
+static const uint32_t XDR_BYTECODE_VERSION_SUBTRAHEND = 334;
 static const uint32_t XDR_BYTECODE_VERSION =
     uint32_t(0xb973c0de - XDR_BYTECODE_VERSION_SUBTRAHEND);
 
-static_assert(JSErr_Limit == 420,
+static_assert(JSErr_Limit == 421,
               "GREETINGS, POTENTIAL SUBTRAHEND INCREMENTER! If you added or "
               "removed MSG_DEFs from js.msg, you should increment "
               "XDR_BYTECODE_VERSION_SUBTRAHEND and update this assertion's "
               "expected JSErr_Limit value.");
 
 class XDRBuffer {
   public:
     explicit XDRBuffer(JSContext* cx)