Commit c211cb43 authored by Mathias Bynens's avatar Mathias Bynens Committed by V8 LUCI CQ

[inspector] Support printing RegExps with overridden `toString`

Prior to this patch, regular expression objects with a monkeypatched
`toString` were printed using the `toString` result value, rather than
actually representing the regular expression’s contents.

    const re = /./;
    re.toString = () => 'whoops!';
    console.log(re);
    // → logs 'whoops!'

Now that `v8::RegExp::GetSource` properly escapes special characters in
the source pattern [1], just like `RegExp#toString`, there is no longer
any reason to avoid it.

[1]: https://chromium-review.googlesource.com/c/v8/v8/+/2900737

Bug: v8:11693
Change-Id: I9a69cdb6813f76b669bdc24e4823c6d261f2ae73
Fixed: v8:11836
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2928188Reviewed-by: 's avatarPhilip Pfaffe <pfaffe@chromium.org>
Commit-Queue: Mathias Bynens <mathias@chromium.org>
Cr-Commit-Position: refs/heads/master@{#74862}
parent 85e5f795
...@@ -220,19 +220,22 @@ String16 descriptionForPrimitiveType(v8::Local<v8::Context> context, ...@@ -220,19 +220,22 @@ String16 descriptionForPrimitiveType(v8::Local<v8::Context> context,
return String16(); return String16();
} }
String16 descriptionForObject(v8::Isolate* isolate, String16 descriptionForRegExp(v8::Isolate* isolate,
v8::Local<v8::Object> object) {
return toProtocolString(isolate, object->GetConstructorName());
}
String16 descriptionForRegExp(v8::Local<v8::Context> context,
v8::Local<v8::RegExp> value) { v8::Local<v8::RegExp> value) {
v8::Isolate* isolate = context->GetIsolate(); String16Builder description;
v8::Local<v8::String> description; description.append('/');
if (!value->ToString(context).ToLocal(&description)) { description.append(toProtocolString(isolate, value->GetSource()));
return descriptionForObject(isolate, value); description.append('/');
} v8::RegExp::Flags flags = value->GetFlags();
return toProtocolString(isolate, description); if (flags & v8::RegExp::Flags::kHasIndices) description.append('d');
if (flags & v8::RegExp::Flags::kGlobal) description.append('g');
if (flags & v8::RegExp::Flags::kIgnoreCase) description.append('i');
if (flags & v8::RegExp::Flags::kLinear) description.append('l');
if (flags & v8::RegExp::Flags::kMultiline) description.append('m');
if (flags & v8::RegExp::Flags::kDotAll) description.append('s');
if (flags & v8::RegExp::Flags::kUnicode) description.append('u');
if (flags & v8::RegExp::Flags::kSticky) description.append('y');
return description.toString();
} }
enum class ErrorType { kNative, kClient }; enum class ErrorType { kNative, kClient };
...@@ -290,6 +293,11 @@ String16 descriptionForError(v8::Local<v8::Context> context, ...@@ -290,6 +293,11 @@ String16 descriptionForError(v8::Local<v8::Context> context,
return description + stackWithoutMessage; return description + stackWithoutMessage;
} }
String16 descriptionForObject(v8::Isolate* isolate,
v8::Local<v8::Object> object) {
return toProtocolString(isolate, object->GetConstructorName());
}
String16 descriptionForDate(v8::Local<v8::Context> context, String16 descriptionForDate(v8::Local<v8::Context> context,
v8::Local<v8::Date> date) { v8::Local<v8::Date> date) {
v8::Isolate* isolate = context->GetIsolate(); v8::Isolate* isolate = context->GetIsolate();
...@@ -1617,7 +1625,7 @@ std::unique_ptr<ValueMirror> ValueMirror::create(v8::Local<v8::Context> context, ...@@ -1617,7 +1625,7 @@ std::unique_ptr<ValueMirror> ValueMirror::create(v8::Local<v8::Context> context,
if (value->IsRegExp()) { if (value->IsRegExp()) {
return std::make_unique<ObjectMirror>( return std::make_unique<ObjectMirror>(
value, RemoteObject::SubtypeEnum::Regexp, value, RemoteObject::SubtypeEnum::Regexp,
descriptionForRegExp(context, value.As<v8::RegExp>())); descriptionForRegExp(isolate, value.As<v8::RegExp>()));
} }
if (value->IsProxy()) { if (value->IsProxy()) {
return std::make_unique<ObjectMirror>( return std::make_unique<ObjectMirror>(
......
...@@ -497,6 +497,18 @@ Running test: testRegExp ...@@ -497,6 +497,18 @@ Running test: testRegExp
type : object type : object
} }
} }
'var re = /./dgimsuy;
re.toString = () => 'foo';
re', returnByValue: false, generatePreview: false
{
result : {
className : RegExp
description : /./dgimsuy
objectId : <objectId>
subtype : regexp
type : object
}
}
'var re = new RegExp('\w+', 'g'); 'var re = new RegExp('\w+', 'g');
re.prop = 32; re.prop = 32;
re', returnByValue: false, generatePreview: true re', returnByValue: false, generatePreview: true
......
...@@ -230,6 +230,11 @@ InspectorTest.runAsyncTestSuite([ ...@@ -230,6 +230,11 @@ InspectorTest.runAsyncTestSuite([
InspectorTest.logMessage((await evaluate({ InspectorTest.logMessage((await evaluate({
expression: `new RegExp('foo/bar')` expression: `new RegExp('foo/bar')`
})).result); })).result);
InspectorTest.logMessage((await evaluate({
expression: `var re = /./dgimsuy;
re.toString = () => 'foo';
re`
})).result);
InspectorTest.logMessage((await evaluate({ InspectorTest.logMessage((await evaluate({
expression: `var re = new RegExp('\\w+', 'g'); expression: `var re = new RegExp('\\w+', 'g');
re.prop = 32; re.prop = 32;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment