[inspector] restore provisional breakpoints smarter
For breakpoints which are set by setBreakpointByUrl(url:..) backend calculates source hint on first related breakpoints resolved event and then uses this hint to adjust breakpoint position in later arrived scripts with the same url or on page reload. Doc: https://docs.google.com/a/google.com/document/d/1VtWo_-jelzEXSNbjESGTtruZngzXgbHLexfTzxNlnjE/edit?usp=sharing BUG=chromium:688776 R=pfeldman@chromium.org, alph@chromium.org Review-Url: https://codereview.chromium.org/2671193002 Cr-Commit-Position: refs/heads/master@{#43493}
This commit is contained in:
parent
d05dede4ce
commit
497dff7809
24
src/api.cc
24
src/api.cc
@ -9257,13 +9257,10 @@ bool debug::Script::GetPossibleBreakpoints(
|
||||
i::Handle<i::FixedArray>::cast(i::handle(script->line_ends(), isolate));
|
||||
CHECK(line_ends->length());
|
||||
|
||||
int start_offset = GetSourcePosition(start);
|
||||
int end_offset;
|
||||
if (end.IsEmpty()) {
|
||||
end_offset = GetSmiValue(line_ends, line_ends->length() - 1) + 1;
|
||||
} else {
|
||||
end_offset = GetSourcePosition(end);
|
||||
}
|
||||
int start_offset = GetSourceOffset(start);
|
||||
int end_offset = end.IsEmpty()
|
||||
? GetSmiValue(line_ends, line_ends->length() - 1) + 1
|
||||
: GetSourceOffset(end);
|
||||
if (start_offset >= end_offset) return true;
|
||||
|
||||
std::set<int> offsets;
|
||||
@ -9292,7 +9289,7 @@ bool debug::Script::GetPossibleBreakpoints(
|
||||
return true;
|
||||
}
|
||||
|
||||
int debug::Script::GetSourcePosition(const debug::Location& location) const {
|
||||
int debug::Script::GetSourceOffset(const debug::Location& location) const {
|
||||
i::Handle<i::Script> script = Utils::OpenHandle(this);
|
||||
if (script->type() == i::Script::TYPE_WASM) {
|
||||
// TODO(clemensh): Return the proper thing for wasm.
|
||||
@ -9318,6 +9315,17 @@ int debug::Script::GetSourcePosition(const debug::Location& location) const {
|
||||
return std::min(prev_line_offset + column + 1, line_offset);
|
||||
}
|
||||
|
||||
v8::debug::Location debug::Script::GetSourceLocation(int offset) const {
|
||||
i::Handle<i::Script> script = Utils::OpenHandle(this);
|
||||
if (script->type() == i::Script::TYPE_WASM) {
|
||||
// TODO(clemensh): Return the proper thing for wasm.
|
||||
return v8::debug::Location();
|
||||
}
|
||||
i::Script::PositionInfo info;
|
||||
i::Script::GetPositionInfo(script, offset, &info, i::Script::WITH_OFFSET);
|
||||
return debug::Location(info.line, info.column);
|
||||
}
|
||||
|
||||
debug::WasmScript* debug::WasmScript::Cast(debug::Script* script) {
|
||||
CHECK(script->IsWasm());
|
||||
return static_cast<WasmScript*>(script);
|
||||
|
@ -139,9 +139,8 @@ class V8_EXPORT_PRIVATE Script {
|
||||
const debug::Location& end,
|
||||
bool restrict_to_function,
|
||||
std::vector<debug::Location>* locations) const;
|
||||
|
||||
private:
|
||||
int GetSourcePosition(const debug::Location& location) const;
|
||||
int GetSourceOffset(const debug::Location& location) const;
|
||||
v8::debug::Location GetSourceLocation(int offset) const;
|
||||
};
|
||||
|
||||
// Specialization for wasm Scripts.
|
||||
|
@ -43,6 +43,7 @@ static const char pauseOnExceptionsState[] = "pauseOnExceptionsState";
|
||||
static const char asyncCallStackDepth[] = "asyncCallStackDepth";
|
||||
static const char blackboxPattern[] = "blackboxPattern";
|
||||
static const char debuggerEnabled[] = "debuggerEnabled";
|
||||
static const char skipAllPauses[] = "skipAllPauses";
|
||||
|
||||
// Breakpoint properties.
|
||||
static const char url[] = "url";
|
||||
@ -50,7 +51,7 @@ static const char isRegex[] = "isRegex";
|
||||
static const char lineNumber[] = "lineNumber";
|
||||
static const char columnNumber[] = "columnNumber";
|
||||
static const char condition[] = "condition";
|
||||
static const char skipAllPauses[] = "skipAllPauses";
|
||||
static const char hint[] = "hint";
|
||||
|
||||
} // namespace DebuggerAgentState
|
||||
|
||||
@ -59,6 +60,9 @@ static const char kDebuggerNotEnabled[] = "Debugger agent is not enabled";
|
||||
static const char kDebuggerNotPaused[] =
|
||||
"Can only perform operation while paused.";
|
||||
|
||||
static const size_t kBreakpointHintMaxLength = 128;
|
||||
static const intptr_t kBreakpointHintMaxSearchOffset = 80 * 10;
|
||||
|
||||
namespace {
|
||||
|
||||
void TranslateWasmStackTraceLocations(Array<CallFrame>* stackTrace,
|
||||
@ -119,6 +123,54 @@ std::unique_ptr<protocol::Debugger::Location> buildProtocolLocation(
|
||||
.build();
|
||||
}
|
||||
|
||||
String16 breakpointHint(const V8DebuggerScript& script,
|
||||
const ScriptBreakpoint& breakpoint) {
|
||||
int offset = script.offset(breakpoint.line_number, breakpoint.column_number);
|
||||
if (offset == V8DebuggerScript::kNoOffset) return String16();
|
||||
const String16& source = script.source();
|
||||
String16 hint =
|
||||
source.substring(offset, kBreakpointHintMaxLength).stripWhiteSpace();
|
||||
for (size_t i = 0; i < hint.length(); ++i) {
|
||||
if (hint[i] == '\r' || hint[i] == '\n' || hint[i] == ';') {
|
||||
return hint.substring(0, i);
|
||||
}
|
||||
}
|
||||
return hint;
|
||||
}
|
||||
|
||||
void adjustBreakpointLocation(const V8DebuggerScript& script,
|
||||
const String16& hint,
|
||||
ScriptBreakpoint* breakpoint) {
|
||||
if (hint.isEmpty()) return;
|
||||
intptr_t sourceOffset =
|
||||
script.offset(breakpoint->line_number, breakpoint->column_number);
|
||||
if (sourceOffset == V8DebuggerScript::kNoOffset) return;
|
||||
|
||||
intptr_t searchRegionOffset = std::max(
|
||||
sourceOffset - kBreakpointHintMaxSearchOffset, static_cast<intptr_t>(0));
|
||||
size_t offset = sourceOffset - searchRegionOffset;
|
||||
String16 searchArea = script.source().substring(
|
||||
searchRegionOffset, offset + kBreakpointHintMaxSearchOffset);
|
||||
|
||||
size_t nextMatch = searchArea.find(hint, offset);
|
||||
size_t prevMatch = searchArea.reverseFind(hint, offset);
|
||||
if (nextMatch == String16::kNotFound && prevMatch == String16::kNotFound) {
|
||||
return;
|
||||
}
|
||||
size_t bestMatch;
|
||||
if (nextMatch == String16::kNotFound) {
|
||||
bestMatch = prevMatch;
|
||||
} else if (prevMatch == String16::kNotFound) {
|
||||
bestMatch = nextMatch;
|
||||
} else {
|
||||
bestMatch = nextMatch - offset < offset - prevMatch ? nextMatch : prevMatch;
|
||||
}
|
||||
bestMatch += searchRegionOffset;
|
||||
v8::debug::Location hintPosition = script.location(bestMatch);
|
||||
if (hintPosition.IsEmpty()) return;
|
||||
breakpoint->line_number = hintPosition.GetLineNumber();
|
||||
breakpoint->column_number = hintPosition.GetColumnNumber();
|
||||
}
|
||||
} // namespace
|
||||
|
||||
V8DebuggerAgentImpl::V8DebuggerAgentImpl(
|
||||
@ -239,7 +291,7 @@ Response V8DebuggerAgentImpl::setSkipAllPauses(bool skip) {
|
||||
static std::unique_ptr<protocol::DictionaryValue>
|
||||
buildObjectForBreakpointCookie(const String16& url, int lineNumber,
|
||||
int columnNumber, const String16& condition,
|
||||
bool isRegex) {
|
||||
bool isRegex, const String16& hint) {
|
||||
std::unique_ptr<protocol::DictionaryValue> breakpointObject =
|
||||
protocol::DictionaryValue::create();
|
||||
breakpointObject->setString(DebuggerAgentState::url, url);
|
||||
@ -247,6 +299,9 @@ buildObjectForBreakpointCookie(const String16& url, int lineNumber,
|
||||
breakpointObject->setInteger(DebuggerAgentState::columnNumber, columnNumber);
|
||||
breakpointObject->setString(DebuggerAgentState::condition, condition);
|
||||
breakpointObject->setBoolean(DebuggerAgentState::isRegex, isRegex);
|
||||
if (!hint.isEmpty()) {
|
||||
breakpointObject->setString(DebuggerAgentState::hint, hint);
|
||||
}
|
||||
return breakpointObject;
|
||||
}
|
||||
|
||||
@ -293,20 +348,23 @@ Response V8DebuggerAgentImpl::setBreakpointByUrl(
|
||||
if (breakpointsCookie->get(breakpointId))
|
||||
return Response::Error("Breakpoint at specified location already exists.");
|
||||
|
||||
breakpointsCookie->setObject(
|
||||
breakpointId, buildObjectForBreakpointCookie(
|
||||
url, lineNumber, columnNumber, condition, isRegex));
|
||||
|
||||
String16 hint;
|
||||
ScriptBreakpoint breakpoint(String16(), lineNumber, columnNumber, condition);
|
||||
for (const auto& script : m_scripts) {
|
||||
if (!matches(m_inspector, script.second->sourceURL(), url, isRegex))
|
||||
continue;
|
||||
breakpoint.script_id = script.first;
|
||||
std::unique_ptr<protocol::Debugger::Location> location =
|
||||
resolveBreakpoint(breakpointId, breakpoint, UserBreakpointSource);
|
||||
resolveBreakpoint(breakpointId, breakpoint, UserBreakpointSource, hint);
|
||||
if (!isRegex) hint = breakpointHint(*script.second, breakpoint);
|
||||
if (location) (*locations)->addItem(std::move(location));
|
||||
}
|
||||
|
||||
breakpointsCookie->setObject(
|
||||
breakpointId,
|
||||
buildObjectForBreakpointCookie(url, lineNumber, columnNumber, condition,
|
||||
isRegex, hint));
|
||||
|
||||
*outBreakpointId = breakpointId;
|
||||
return Response::OK();
|
||||
}
|
||||
@ -325,8 +383,8 @@ Response V8DebuggerAgentImpl::setBreakpoint(
|
||||
m_breakpointIdToDebuggerBreakpointIds.end()) {
|
||||
return Response::Error("Breakpoint at specified location already exists.");
|
||||
}
|
||||
*actualLocation =
|
||||
resolveBreakpoint(breakpointId, breakpoint, UserBreakpointSource);
|
||||
*actualLocation = resolveBreakpoint(
|
||||
breakpointId, breakpoint, UserBreakpointSource, /* hint */ String16());
|
||||
if (!*actualLocation) return Response::Error("Could not resolve breakpoint");
|
||||
*outBreakpointId = breakpointId;
|
||||
return Response::OK();
|
||||
@ -457,7 +515,8 @@ bool V8DebuggerAgentImpl::isFunctionBlackboxed(const String16& scriptId,
|
||||
std::unique_ptr<protocol::Debugger::Location>
|
||||
V8DebuggerAgentImpl::resolveBreakpoint(const String16& breakpointId,
|
||||
const ScriptBreakpoint& breakpoint,
|
||||
BreakpointSource source) {
|
||||
BreakpointSource source,
|
||||
const String16& hint) {
|
||||
v8::HandleScope handles(m_isolate);
|
||||
DCHECK(enabled());
|
||||
// FIXME: remove these checks once crbug.com/520702 is resolved.
|
||||
@ -471,6 +530,8 @@ V8DebuggerAgentImpl::resolveBreakpoint(const String16& breakpointId,
|
||||
|
||||
// Translate from protocol location to v8 location for the debugger.
|
||||
ScriptBreakpoint translatedBreakpoint = breakpoint;
|
||||
adjustBreakpointLocation(*scriptIterator->second, hint,
|
||||
&translatedBreakpoint);
|
||||
m_debugger->wasmTranslation()->TranslateProtocolLocationToWasmScriptLocation(
|
||||
&translatedBreakpoint.script_id, &translatedBreakpoint.line_number,
|
||||
&translatedBreakpoint.column_number);
|
||||
@ -505,7 +566,7 @@ Response V8DebuggerAgentImpl::searchInContent(
|
||||
return Response::Error("No script for id: " + scriptId);
|
||||
|
||||
std::vector<std::unique_ptr<protocol::Debugger::SearchMatch>> matches =
|
||||
searchInTextByLinesImpl(m_session, it->second->source(m_isolate), query,
|
||||
searchInTextByLinesImpl(m_session, it->second->source(), query,
|
||||
optionalCaseSensitive.fromMaybe(false),
|
||||
optionalIsRegex.fromMaybe(false));
|
||||
*results = protocol::Array<protocol::Debugger::SearchMatch>::create();
|
||||
@ -538,7 +599,7 @@ Response V8DebuggerAgentImpl::setScriptSource(
|
||||
&m_pausedCallFrames, stackChanged, &compileError);
|
||||
if (!response.isSuccess() || compileError) return response;
|
||||
|
||||
it->second->setSource(newSource);
|
||||
it->second->setSource(newContent);
|
||||
std::unique_ptr<Array<CallFrame>> callFrames;
|
||||
response = currentCallFrames(&callFrames);
|
||||
if (!response.isSuccess()) return response;
|
||||
@ -583,8 +644,7 @@ Response V8DebuggerAgentImpl::getScriptSource(const String16& scriptId,
|
||||
ScriptsMap::iterator it = m_scripts.find(scriptId);
|
||||
if (it == m_scripts.end())
|
||||
return Response::Error("No script for id: " + scriptId);
|
||||
v8::HandleScope handles(m_isolate);
|
||||
*scriptSource = it->second->source(m_isolate);
|
||||
*scriptSource = it->second->source();
|
||||
return Response::OK();
|
||||
}
|
||||
|
||||
@ -993,7 +1053,7 @@ bool V8DebuggerAgentImpl::isPaused() const { return m_debugger->isPaused(); }
|
||||
void V8DebuggerAgentImpl::didParseSource(
|
||||
std::unique_ptr<V8DebuggerScript> script, bool success) {
|
||||
v8::HandleScope handles(m_isolate);
|
||||
String16 scriptSource = script->source(m_isolate);
|
||||
String16 scriptSource = script->source();
|
||||
if (!success) script->setSourceURL(findSourceURL(scriptSource, false));
|
||||
if (!success)
|
||||
script->setSourceMappingURL(findSourceMapURL(scriptSource, false));
|
||||
@ -1036,14 +1096,14 @@ void V8DebuggerAgentImpl::didParseSource(
|
||||
m_frontend.scriptParsed(
|
||||
scriptId, scriptURL, scriptRef->startLine(), scriptRef->startColumn(),
|
||||
scriptRef->endLine(), scriptRef->endColumn(), contextId,
|
||||
scriptRef->hash(m_isolate), std::move(executionContextAuxDataParam),
|
||||
scriptRef->hash(), std::move(executionContextAuxDataParam),
|
||||
isLiveEditParam, std::move(sourceMapURLParam), hasSourceURLParam,
|
||||
isModuleParam);
|
||||
else
|
||||
m_frontend.scriptFailedToParse(
|
||||
scriptId, scriptURL, scriptRef->startLine(), scriptRef->startColumn(),
|
||||
scriptRef->endLine(), scriptRef->endColumn(), contextId,
|
||||
scriptRef->hash(m_isolate), std::move(executionContextAuxDataParam),
|
||||
scriptRef->hash(), std::move(executionContextAuxDataParam),
|
||||
std::move(sourceMapURLParam), hasSourceURLParam, isModuleParam);
|
||||
|
||||
if (scriptURL.isEmpty() || !success) return;
|
||||
@ -1069,8 +1129,15 @@ void V8DebuggerAgentImpl::didParseSource(
|
||||
&breakpoint.column_number);
|
||||
breakpointObject->getString(DebuggerAgentState::condition,
|
||||
&breakpoint.condition);
|
||||
String16 hint;
|
||||
bool hasHint = breakpointObject->getString(DebuggerAgentState::hint, &hint);
|
||||
std::unique_ptr<protocol::Debugger::Location> location =
|
||||
resolveBreakpoint(cookie.first, breakpoint, UserBreakpointSource);
|
||||
resolveBreakpoint(cookie.first, breakpoint, UserBreakpointSource, hint);
|
||||
if (!hasHint) {
|
||||
hint = breakpointHint(*scriptRef, breakpoint);
|
||||
if (!hint.isEmpty())
|
||||
breakpointObject->setString(DebuggerAgentState::hint, hint);
|
||||
}
|
||||
if (location)
|
||||
m_frontend.breakpointResolved(cookie.first, std::move(location));
|
||||
}
|
||||
@ -1209,7 +1276,7 @@ void V8DebuggerAgentImpl::setBreakpointAt(const String16& scriptId,
|
||||
const String16& condition) {
|
||||
ScriptBreakpoint breakpoint(scriptId, lineNumber, columnNumber, condition);
|
||||
String16 breakpointId = generateBreakpointId(breakpoint, source);
|
||||
resolveBreakpoint(breakpointId, breakpoint, source);
|
||||
resolveBreakpoint(breakpointId, breakpoint, source, /* hint */ String16());
|
||||
}
|
||||
|
||||
void V8DebuggerAgentImpl::removeBreakpointAt(const String16& scriptId,
|
||||
|
@ -157,7 +157,8 @@ class V8DebuggerAgentImpl : public protocol::Debugger::Backend {
|
||||
void setPauseOnExceptionsImpl(int);
|
||||
|
||||
std::unique_ptr<protocol::Debugger::Location> resolveBreakpoint(
|
||||
const String16& breakpointId, const ScriptBreakpoint&, BreakpointSource);
|
||||
const String16& breakpointId, const ScriptBreakpoint&, BreakpointSource,
|
||||
const String16& hint);
|
||||
void removeBreakpointImpl(const String16& breakpointId);
|
||||
void clearBreakDetails();
|
||||
|
||||
|
@ -133,10 +133,9 @@ class ActualScript : public V8DebuggerScript {
|
||||
}
|
||||
|
||||
if (script->Source().ToLocal(&tmp)) {
|
||||
m_sourceObj.Reset(m_isolate, tmp);
|
||||
String16 source = toProtocolString(tmp);
|
||||
m_source = toProtocolString(tmp);
|
||||
// V8 will not count last line if script source ends with \n.
|
||||
if (source.length() > 1 && source[source.length() - 1] == '\n') {
|
||||
if (m_source.length() > 0 && m_source[m_source.length() - 1] == '\n') {
|
||||
m_endLine++;
|
||||
m_endColumn = 0;
|
||||
}
|
||||
@ -154,22 +153,10 @@ class ActualScript : public V8DebuggerScript {
|
||||
return m_sourceMappingURL;
|
||||
}
|
||||
|
||||
String16 source(v8::Isolate* isolate) const override {
|
||||
if (!m_sourceObj.IsEmpty())
|
||||
return toProtocolString(m_sourceObj.Get(isolate));
|
||||
return V8DebuggerScript::source(isolate);
|
||||
}
|
||||
|
||||
void setSourceMappingURL(const String16& sourceMappingURL) override {
|
||||
m_sourceMappingURL = sourceMappingURL;
|
||||
}
|
||||
|
||||
void setSource(v8::Local<v8::String> source) override {
|
||||
m_source = String16();
|
||||
m_sourceObj.Reset(m_isolate, source);
|
||||
m_hash = String16();
|
||||
}
|
||||
|
||||
bool getPossibleBreakpoints(
|
||||
const v8::debug::Location& start, const v8::debug::Location& end,
|
||||
bool restrictToFunction,
|
||||
@ -185,6 +172,17 @@ class ActualScript : public V8DebuggerScript {
|
||||
v8::debug::ResetBlackboxedStateCache(m_isolate, m_script.Get(m_isolate));
|
||||
}
|
||||
|
||||
int offset(int lineNumber, int columnNumber) const override {
|
||||
v8::HandleScope scope(m_isolate);
|
||||
return m_script.Get(m_isolate)->GetSourceOffset(
|
||||
v8::debug::Location(lineNumber, columnNumber));
|
||||
}
|
||||
|
||||
v8::debug::Location location(int offset) const override {
|
||||
v8::HandleScope scope(m_isolate);
|
||||
return m_script.Get(m_isolate)->GetSourceLocation(offset);
|
||||
}
|
||||
|
||||
private:
|
||||
String16 GetNameOrSourceUrl(v8::Local<v8::debug::Script> script) {
|
||||
v8::Local<v8::String> name;
|
||||
@ -194,7 +192,6 @@ class ActualScript : public V8DebuggerScript {
|
||||
}
|
||||
|
||||
String16 m_sourceMappingURL;
|
||||
v8::Global<v8::String> m_sourceObj;
|
||||
bool m_isLiveEdit = false;
|
||||
bool m_isModule = false;
|
||||
v8::Global<v8::debug::Script> m_script;
|
||||
@ -261,6 +258,14 @@ class WasmVirtualScript : public V8DebuggerScript {
|
||||
|
||||
void resetBlackboxedStateCache() override {}
|
||||
|
||||
int offset(int lineNumber, int columnNumber) const override {
|
||||
return kNoOffset;
|
||||
}
|
||||
|
||||
v8::debug::Location location(int offset) const override {
|
||||
return v8::debug::Location();
|
||||
}
|
||||
|
||||
private:
|
||||
static const String16& emptyString() {
|
||||
static const String16 singleEmptyString;
|
||||
@ -299,8 +304,8 @@ const String16& V8DebuggerScript::sourceURL() const {
|
||||
return m_sourceURL.isEmpty() ? m_url : m_sourceURL;
|
||||
}
|
||||
|
||||
const String16& V8DebuggerScript::hash(v8::Isolate* isolate) const {
|
||||
if (m_hash.isEmpty()) m_hash = calculateHash(source(isolate));
|
||||
const String16& V8DebuggerScript::hash() const {
|
||||
if (m_hash.isEmpty()) m_hash = calculateHash(source());
|
||||
DCHECK(!m_hash.isEmpty());
|
||||
return m_hash;
|
||||
}
|
||||
|
@ -59,8 +59,8 @@ class V8DebuggerScript {
|
||||
bool hasSourceURL() const { return !m_sourceURL.isEmpty(); }
|
||||
const String16& sourceURL() const;
|
||||
virtual const String16& sourceMappingURL() const = 0;
|
||||
virtual String16 source(v8::Isolate*) const { return m_source; }
|
||||
const String16& hash(v8::Isolate*) const;
|
||||
const String16& source() const { return m_source; }
|
||||
const String16& hash() const;
|
||||
int startLine() const { return m_startLine; }
|
||||
int startColumn() const { return m_startColumn; }
|
||||
int endLine() const { return m_endLine; }
|
||||
@ -71,8 +71,9 @@ class V8DebuggerScript {
|
||||
|
||||
void setSourceURL(const String16&);
|
||||
virtual void setSourceMappingURL(const String16&) = 0;
|
||||
virtual void setSource(v8::Local<v8::String> source) {
|
||||
m_source = toProtocolString(source);
|
||||
void setSource(const String16& source) {
|
||||
m_source = source;
|
||||
m_hash = String16();
|
||||
}
|
||||
|
||||
virtual bool getPossibleBreakpoints(
|
||||
@ -81,6 +82,10 @@ class V8DebuggerScript {
|
||||
std::vector<v8::debug::Location>* locations) = 0;
|
||||
virtual void resetBlackboxedStateCache() = 0;
|
||||
|
||||
static const int kNoOffset = -1;
|
||||
virtual int offset(int lineNumber, int columnNumber) const = 0;
|
||||
virtual v8::debug::Location location(int offset) const = 0;
|
||||
|
||||
protected:
|
||||
V8DebuggerScript(v8::Isolate*, String16 id, String16 url);
|
||||
|
||||
|
76
test/inspector/debugger/restore-breakpoint-expected.txt
Normal file
76
test/inspector/debugger/restore-breakpoint-expected.txt
Normal file
@ -0,0 +1,76 @@
|
||||
Checks that debugger agent uses source content to restore breakpoints.
|
||||
|
||||
Running test: testSameSource
|
||||
function foo() {
|
||||
#boo();
|
||||
}
|
||||
function foo() {
|
||||
#boo();
|
||||
}
|
||||
|
||||
Running test: testOneLineOffset
|
||||
function foo() {
|
||||
#boo();
|
||||
}
|
||||
function foo() {
|
||||
#boo();
|
||||
boo();
|
||||
}
|
||||
|
||||
Running test: testTwoSimilarLinesCloseToOriginalLocation1
|
||||
function foo() {
|
||||
|
||||
|
||||
#boo();
|
||||
}
|
||||
function foo() {
|
||||
#boo();
|
||||
|
||||
newCode();
|
||||
boo();
|
||||
|
||||
|
||||
|
||||
boo();
|
||||
}
|
||||
|
||||
Running test: testTwoSimilarLinesCloseToOriginalLocation2
|
||||
function foo() {
|
||||
|
||||
|
||||
#boo();
|
||||
}
|
||||
function foo() {
|
||||
boo();
|
||||
newLongCode();
|
||||
newCode();
|
||||
#boo();
|
||||
|
||||
|
||||
|
||||
boo();
|
||||
}
|
||||
|
||||
Running test: testHintIgnoreWhiteSpaces
|
||||
function foo() {
|
||||
|
||||
|
||||
|
||||
#boo();
|
||||
}
|
||||
function foo() {
|
||||
foo();
|
||||
|
||||
|
||||
#boo();
|
||||
}
|
||||
|
||||
Running test: testCheckOnlyLimitedOffsets
|
||||
function foo() {
|
||||
#boo();
|
||||
}
|
||||
function foo() {
|
||||
#newCode();
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;...
|
||||
boo();
|
||||
}
|
69
test/inspector/debugger/restore-breakpoint.js
Normal file
69
test/inspector/debugger/restore-breakpoint.js
Normal file
@ -0,0 +1,69 @@
|
||||
// Copyright 2017 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
print('Checks that debugger agent uses source content to restore breakpoints.');
|
||||
|
||||
Protocol.Debugger.enable();
|
||||
InspectorTest.runTestSuite([
|
||||
function testSameSource(next) {
|
||||
var source = 'function foo() {\nboo();\n}';
|
||||
test(source, source, { lineNumber: 1, columnNumber: 0 }, next);
|
||||
},
|
||||
|
||||
function testOneLineOffset(next) {
|
||||
var source = 'function foo() {\nboo();\n}';
|
||||
var newSource = 'function foo() {\nboo();\nboo();\n}';
|
||||
test(source, newSource, { lineNumber: 1, columnNumber: 0 }, next);
|
||||
},
|
||||
|
||||
function testTwoSimilarLinesCloseToOriginalLocation1(next) {
|
||||
var source = 'function foo() {\n\n\nboo();\n}';
|
||||
var newSource = 'function foo() {\nboo();\n\nnewCode();\nboo();\n\n\n\nboo();\n}';
|
||||
test(source, newSource, { lineNumber: 3, columnNumber: 0 }, next);
|
||||
},
|
||||
|
||||
function testTwoSimilarLinesCloseToOriginalLocation2(next) {
|
||||
var source = 'function foo() {\n\n\nboo();\n}';
|
||||
var newSource = 'function foo() {\nboo();\nnewLongCode();\nnewCode();\nboo();\n\n\n\nboo();\n}';
|
||||
test(source, newSource, { lineNumber: 3, columnNumber: 0 }, next);
|
||||
},
|
||||
|
||||
function testHintIgnoreWhiteSpaces(next) {
|
||||
var source = 'function foo() {\n\n\n\nboo();\n}';
|
||||
var newSource = 'function foo() {\nfoo();\n\n\nboo();\n}';
|
||||
test(source, newSource, { lineNumber: 1, columnNumber: 0 }, next);
|
||||
},
|
||||
|
||||
function testCheckOnlyLimitedOffsets(next) {
|
||||
var source = 'function foo() {\nboo();\n}';
|
||||
var longString = ';'.repeat(1000);
|
||||
var newSource = `function foo() {\nnewCode();\n${longString};\nboo();\n}`;
|
||||
test(source, newSource, { lineNumber: 1, columnNumber: 0 }, next);
|
||||
}
|
||||
]);
|
||||
|
||||
var finishedTests = 0;
|
||||
async function test(source, newSource, location, next) {
|
||||
var firstBreakpoint = true;
|
||||
Protocol.Debugger.onBreakpointResolved(message => {
|
||||
var lineNumber = message.params.location.lineNumber;
|
||||
var columnNumber = message.params.location.columnNumber;
|
||||
var currentSource = firstBreakpoint ? source : newSource;
|
||||
var lines = currentSource.split('\n');
|
||||
lines = lines.map(line => line.length > 80 ? line.substring(0, 77) + '...' : line);
|
||||
lines[lineNumber] = lines[lineNumber].slice(0, columnNumber) + '#' + lines[lineNumber].slice(columnNumber);
|
||||
InspectorTest.log(lines.join('\n'));
|
||||
firstBreakpoint = false;
|
||||
});
|
||||
|
||||
var sourceURL = `test${++finishedTests}.js`;
|
||||
await Protocol.Debugger.setBreakpointByUrl({
|
||||
url: sourceURL,
|
||||
lineNumber: location.lineNumber,
|
||||
columnNumber: location.columnNumber
|
||||
});
|
||||
await Protocol.Runtime.evaluate({ expression: `${source}\n//# sourceURL=${sourceURL}` });
|
||||
await Protocol.Runtime.evaluate({ expression: `${newSource}\n//# sourceURL=${sourceURL}` });
|
||||
next();
|
||||
}
|
Loading…
Reference in New Issue
Block a user