From c432c5f472748d12f87e443f69116415dc8f4250 Mon Sep 17 00:00:00 2001 From: roblou Date: Wed, 7 Dec 2016 15:35:35 -0800 Subject: [PATCH] Fix #141, sourcemap scope locations --- src/chrome/chromeDebugAdapter.ts | 13 ++++++++-- src/transformers/baseSourceMapTransformer.ts | 27 +++++++++++++++++++- src/transformers/lineNumberTransformer.ts | 27 +++++++++++++++++--- 3 files changed, 61 insertions(+), 6 deletions(-) diff --git a/src/chrome/chromeDebugAdapter.ts b/src/chrome/chromeDebugAdapter.ts index d7a28ee11..5881d955a 100644 --- a/src/chrome/chromeDebugAdapter.ts +++ b/src/chrome/chromeDebugAdapter.ts @@ -925,6 +925,10 @@ export abstract class ChromeDebugAdapter implements IDebugAdapter { public scopes(args: DebugProtocol.ScopesArguments): IScopesResponseBody { const currentFrame = this._frameHandles.get(args.frameId); + const currentScript = this._scriptsById.get(currentFrame.location.scriptId); + const currentScriptUrl = currentScript && currentScript.url; + const currentScriptPath = currentScriptUrl && this._pathTransformer.getClientPathFromTargetPath(currentScriptUrl); + const scopes = currentFrame.scopeChain.map((scope: Crdp.Debugger.Scope, i: number) => { // The first scope should include 'this'. Keep the RemoteObject reference for use by the variables request const thisObj = i === 0 && currentFrame.this; @@ -955,7 +959,13 @@ export abstract class ChromeDebugAdapter implements IDebugAdapter { }); } - return { scopes }; + const scopesResponse = { scopes }; + if (currentScriptPath) { + this._sourceMapTransformer.scopesResponse(currentScriptPath, scopesResponse); + this._lineColTransformer.scopeResponse(scopesResponse); + } + + return scopesResponse; } public variables(args: DebugProtocol.VariablesArguments): Promise { @@ -1216,7 +1226,6 @@ export abstract class ChromeDebugAdapter implements IDebugAdapter { return result + mappedSourcesStr; }); - } /** diff --git a/src/transformers/baseSourceMapTransformer.ts b/src/transformers/baseSourceMapTransformer.ts index 7e1664629..4e6b4818d 100644 --- a/src/transformers/baseSourceMapTransformer.ts +++ b/src/transformers/baseSourceMapTransformer.ts @@ -6,7 +6,7 @@ import * as path from 'path'; import {DebugProtocol} from 'vscode-debugprotocol'; import {ISetBreakpointsArgs, ILaunchRequestArgs, IAttachRequestArgs, - ISetBreakpointsResponseBody, IStackTraceResponseBody} from '../debugAdapterInterfaces'; + ISetBreakpointsResponseBody, IStackTraceResponseBody, IScopesResponseBody} from '../debugAdapterInterfaces'; import {MappedPosition, ISourcePathDetails} from '../sourceMaps/sourceMap'; import {SourceMaps} from '../sourceMaps/sourceMaps'; import * as utils from '../utils'; @@ -236,6 +236,31 @@ export class BaseSourceMapTransformer { } } + public scopesResponse(pathToGenerated: string, scopesResponse: IScopesResponseBody): void { + if (this._sourceMaps) { + scopesResponse.scopes.forEach(scope => this.mapScopeLocations(pathToGenerated, scope)); + } + } + + private mapScopeLocations(pathToGenerated: string, scope: DebugProtocol.Scope): void { + if (typeof scope.line !== 'number') { + return; + } + + const mappedStart = this._sourceMaps.mapToAuthored(pathToGenerated, scope.line, scope.column); + if (mappedStart) { + // Only apply changes if both mappings are found + const mappedEnd = this._sourceMaps.mapToAuthored(pathToGenerated, scope.endLine, scope.endColumn); + if (mappedEnd) { + scope.line = mappedStart.line; + scope.column = mappedStart.column; + + scope.endLine = mappedEnd.line; + scope.endColumn = mappedEnd.column; + } + } + } + public mapToGenerated(authoredPath: string, line: number, column: number): Promise { return this._preLoad.then(() => this._sourceMaps.mapToGenerated(authoredPath, line, column)); } diff --git a/src/transformers/lineNumberTransformer.ts b/src/transformers/lineNumberTransformer.ts index ed15df842..b07a130f6 100644 --- a/src/transformers/lineNumberTransformer.ts +++ b/src/transformers/lineNumberTransformer.ts @@ -5,7 +5,7 @@ import {DebugProtocol} from 'vscode-debugprotocol'; import {ChromeDebugSession} from '../chrome/chromeDebugSession'; -import {IDebugTransformer, ISetBreakpointsResponseBody, IStackTraceResponseBody} from '../debugAdapterInterfaces'; +import {IDebugTransformer, ISetBreakpointsResponseBody, IStackTraceResponseBody, IScopesResponseBody} from '../debugAdapterInterfaces'; /** * Converts from 1 based lines/cols on the client side to 0 based lines/cols on the target side @@ -30,15 +30,36 @@ export class LineColTransformer implements IDebugTransformer { this.convertDebuggerLocationToClient(bp); } + public scopeResponse(scopeResponse: IScopesResponseBody): void { + scopeResponse.scopes.forEach(scope => this.mapScopeLocations(scope)); + } + + private mapScopeLocations(scope: DebugProtocol.Scope): void { + this.convertDebuggerLocationToClient(scope); + + if (typeof scope.endLine === 'number') { + const endScope = { line: scope.endLine, column: scope.endColumn }; + this.convertDebuggerLocationToClient(endScope); + scope.endLine = endScope.line; + scope.endColumn = endScope.column; + } + } + private convertClientLocationToDebugger(location: { line?: number; column?: number }): void { - location.line = this.convertClientLineToDebugger(location.line); + if (typeof location.line === 'number') { + location.line = this.convertClientLineToDebugger(location.line); + } + if (typeof location.column === 'number') { location.column = this.convertClientColumnToDebugger(location.column); } } private convertDebuggerLocationToClient(location: { line?: number; column?: number }): void { - location.line = this.convertDebuggerLineToClient(location.line); + if (typeof location.line === 'number') { + location.line = this.convertDebuggerLineToClient(location.line); + } + if (typeof location.column === 'number') { location.column = this.convertDebuggerColumnToClient(location.column); }