Chromium Code Reviews| Index: third_party/WebKit/Source/devtools/front_end/sources/SourceMapNamesResolver.js |
| diff --git a/third_party/WebKit/Source/devtools/front_end/sources/SourceMapNamesResolver.js b/third_party/WebKit/Source/devtools/front_end/sources/SourceMapNamesResolver.js |
| index ccbe65f70e83c27a9cfc84890617a8d06ea6bfb3..63e590b5634f77af044083ec1cc6770653df0497 100644 |
| --- a/third_party/WebKit/Source/devtools/front_end/sources/SourceMapNamesResolver.js |
| +++ b/third_party/WebKit/Source/devtools/front_end/sources/SourceMapNamesResolver.js |
| @@ -5,7 +5,7 @@ |
| WebInspector.SourceMapNamesResolver = {}; |
| WebInspector.SourceMapNamesResolver._cachedMapSymbol = Symbol("cache"); |
| -WebInspector.SourceMapNamesResolver._cachedPromiseSymbol = Symbol("cache"); |
| +WebInspector.SourceMapNamesResolver._cachedPromiseSymbol = Symbol("cachePromise"); |
| /** |
| * @param {!WebInspector.DebuggerModel.Scope} scope |
| @@ -23,11 +23,11 @@ WebInspector.SourceMapNamesResolver._resolveScope = function(scope) |
| var startLocation = scope.startLocation(); |
| var endLocation = scope.endLocation(); |
| - var script = startLocation.script(); |
| - if (scope.type() === DebuggerAgent.ScopeType.Global || !startLocation || !endLocation || !script.sourceMapURL || script !== endLocation.script()) |
| + if (scope.type() === DebuggerAgent.ScopeType.Global || !startLocation || !endLocation || !startLocation.script().sourceMapURL || (startLocation.script() !== endLocation.script())) |
| return Promise.resolve(new Map()); |
| + var script = startLocation.script(); |
| var sourceMap = WebInspector.debuggerWorkspaceBinding.sourceMapForScript(script); |
| if (!sourceMap) |
| return Promise.resolve(new Map()); |
| @@ -117,6 +117,158 @@ WebInspector.SourceMapNamesResolver._resolveScope = function(scope) |
| } |
| /** |
| + * @param {!WebInspector.DebuggerModel.CallFrame} callFrame |
| + * @return {!Promise.<!Map<string, string>>} |
| + */ |
| +WebInspector.SourceMapNamesResolver._allVariablesInCallFrame = function(callFrame) |
| +{ |
| + var cached = callFrame[WebInspector.SourceMapNamesResolver._cachedMapSymbol]; |
| + if (cached) |
| + return Promise.resolve(cached); |
| + |
| + var promises = []; |
| + var scopeChain = callFrame.scopeChain(); |
| + for (var i = 0; i < scopeChain.length; ++i) |
| + promises.push(WebInspector.SourceMapNamesResolver._resolveScope(scopeChain[i])); |
| + |
| + return Promise.all(promises).then(mergeVariables); |
| + |
| + /** |
| + * @param {!Array<!Map<string, string>>} nameMappings |
| + * @return {!Map<string, string>} |
| + */ |
| + function mergeVariables(nameMappings) |
| + { |
| + var reverseMapping = new Map(); |
| + for (var map of nameMappings) { |
| + for (var compiledName of map.keys()) { |
| + var originalName = map.get(compiledName); |
| + if (!reverseMapping.has(originalName)) |
| + reverseMapping.set(originalName, compiledName); |
| + } |
| + } |
| + callFrame[WebInspector.SourceMapNamesResolver._cachedMapSymbol] = reverseMapping; |
| + return reverseMapping; |
| + } |
| +} |
| + |
| +/** |
| + * @param {!WebInspector.DebuggerModel.CallFrame} callFrame |
| + * @param {string} originalText |
| + * @param {!WebInspector.UISourceCode} uiSourceCode |
| + * @param {number} lineNumber |
| + * @param {number} startColumnNumber |
| + * @param {number} endColumnNumber |
| + * @return {!Promise<string>} |
| + */ |
| +WebInspector.SourceMapNamesResolver.resolveExpression = function(callFrame, originalText, uiSourceCode, lineNumber, startColumnNumber, endColumnNumber) |
| +{ |
| + if (!Runtime.experiments.isEnabled("resolveVariableNames")) |
| + return Promise.resolve(""); |
| + |
| + return WebInspector.SourceMapNamesResolver._allVariablesInCallFrame(callFrame).then(findCompiledName); |
| + |
| + /** |
| + * @param {!Map<string, string>} reverseMapping |
| + * @return {!Promise<string>} |
| + */ |
| + function findCompiledName(reverseMapping) |
| + { |
| + if (reverseMapping.has(originalText)) |
| + return Promise.resolve(reverseMapping.get(originalText) || ""); |
| + |
| + return WebInspector.SourceMapNamesResolver._resolveExpression(callFrame, uiSourceCode, lineNumber, startColumnNumber, endColumnNumber) |
| + } |
| +} |
| + |
| +/** |
| + * @param {!WebInspector.DebuggerModel.CallFrame} callFrame |
| + * @param {!WebInspector.UISourceCode} uiSourceCode |
| + * @param {number} lineNumber |
| + * @param {number} startColumnNumber |
| + * @param {number} endColumnNumber |
| + * @return {!Promise<string>} |
| + */ |
| +WebInspector.SourceMapNamesResolver._resolveExpression = function(callFrame, uiSourceCode, lineNumber, startColumnNumber, endColumnNumber) |
| +{ |
| + var target = callFrame.target(); |
| + var rawLocation = WebInspector.debuggerWorkspaceBinding.uiLocationToRawLocation(target, uiSourceCode, lineNumber, startColumnNumber); |
| + if (!rawLocation) |
| + return Promise.resolve(""); |
| + |
| + var script = rawLocation.script(); |
| + var sourceMap = WebInspector.debuggerWorkspaceBinding.sourceMapForScript(script); |
| + if (!sourceMap) |
| + return Promise.resolve(""); |
| + |
| + /** |
| + * @param {!{lineNumber: number, columnNumber: number}} position |
| + * @param {!WebInspector.SourceMap.Entry} mapping |
| + * @return {number} |
| + */ |
| + function comparator(position, mapping) |
| + { |
| + if (position.lineNumber !== mapping.sourceLineNumber) |
| + return position.lineNumber - mapping.sourceLineNumber; |
| + |
| + return position.columnNumber - mapping.sourceColumnNumber; |
| + } |
| + |
| + var mappings = sourceMap.reversedMappings(uiSourceCode.url()); |
| + var startIndex = mappings.lowerBound({lineNumber: lineNumber, columnNumber: startColumnNumber}, comparator); |
|
dgozman
2016/03/08 18:26:42
Let's move this to SourceMap.reverseMapTextRange.
sergeyv
2016/03/08 22:53:04
Done.
|
| + var endIndex = mappings.upperBound({lineNumber: lineNumber, columnNumber: endColumnNumber}, comparator); |
| + |
| + var startMapping = mappings[startIndex]; |
| + var endMapping = mappings[endIndex]; |
| + |
| + if (startMapping === endMapping) |
| + return Promise.resolve(""); |
| + |
| + return script.requestContent().then(onContent); |
| + |
| + /** |
| + * @param {?string} content |
| + * @return {string} |
| + */ |
| + function onContent(content) |
| + { |
| + if (!content) |
| + return ""; |
| + |
| + var textRange = new WebInspector.TextRange(startMapping.lineNumber, startMapping.columnNumber, endMapping.lineNumber, endMapping.columnNumber); |
| + var originalText = textRange.extract(content); |
| + var tokenizer = acorn.tokenizer(originalText, {ecmaVersion: 6}); |
| + try { |
| + var token = tokenizer.getToken(); |
| + while (token.type !== acorn.tokTypes.eof && WebInspector.AcornTokenizer.punctuator(token)) |
| + token = tokenizer.getToken(); |
| + |
| + var startIndex = token.start; |
| + var endIndex = token.end; |
| + while (token.type !== acorn.tokTypes.eof) { |
| + var isIdentifier = WebInspector.AcornTokenizer.identifier(token); |
| + var isThis = WebInspector.AcornTokenizer.keyword(token, "this"); |
| + var isString = token.type === acorn.tokTypes.string; |
| + if (!isThis && !isIdentifier && !isString) |
| + break; |
| + |
| + endIndex = token.end; |
| + token = tokenizer.getToken(); |
| + while (WebInspector.AcornTokenizer.punctuator(token, ".[]")) { |
| + if (WebInspector.AcornTokenizer.punctuator(token, "]")) |
| + endIndex = token.end; |
|
dgozman
2016/03/08 18:26:42
Let's not do this if current balance of [] is zero
sergeyv
2016/03/08 22:53:04
Done.
|
| + |
| + token = tokenizer.getToken(); |
| + } |
| + } |
| + return originalText.substring(startIndex, endIndex); |
| + } catch (e) { |
| + return ""; |
| + } |
| + } |
| +} |
| + |
| +/** |
| * @param {!WebInspector.DebuggerModel.Scope} scope |
| * @return {!WebInspector.RemoteObject} |
| */ |