Skip to content

Commit cd08a22

Browse files
authored
Clamp calculated sourcemap positions rather than throwing (#28583)
* Clamp calculated sourcemap positions rather than throwing, to allow the underlying file to drift out of date with the sourcemap without a crash * Clamp line as well
1 parent 12f3d0d commit cd08a22

File tree

3 files changed

+53
-4
lines changed

3 files changed

+53
-4
lines changed

src/compiler/scanner.ts

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -342,12 +342,29 @@ namespace ts {
342342
}
343343

344344
/* @internal */
345-
export function computePositionOfLineAndCharacter(lineStarts: ReadonlyArray<number>, line: number, character: number, debugText?: string): number {
345+
export function getPositionOfLineAndCharacterWithEdits(sourceFile: SourceFileLike, line: number, character: number): number {
346+
return computePositionOfLineAndCharacter(getLineStarts(sourceFile), line, character, sourceFile.text, /*allowEdits*/ true);
347+
}
348+
349+
/* @internal */
350+
export function computePositionOfLineAndCharacter(lineStarts: ReadonlyArray<number>, line: number, character: number, debugText?: string, allowEdits?: true): number {
346351
if (line < 0 || line >= lineStarts.length) {
347-
Debug.fail(`Bad line number. Line: ${line}, lineStarts.length: ${lineStarts.length} , line map is correct? ${debugText !== undefined ? arraysEqual(lineStarts, computeLineStarts(debugText)) : "unknown"}`);
352+
if (allowEdits) {
353+
// Clamp line to nearest allowable value
354+
line = line < 0 ? 0 : line >= lineStarts.length ? lineStarts.length - 1 : line;
355+
}
356+
else {
357+
Debug.fail(`Bad line number. Line: ${line}, lineStarts.length: ${lineStarts.length} , line map is correct? ${debugText !== undefined ? arraysEqual(lineStarts, computeLineStarts(debugText)) : "unknown"}`);
358+
}
348359
}
349360

350361
const res = lineStarts[line] + character;
362+
if (allowEdits) {
363+
// Clamp to nearest allowable values to allow the underlying to be edited without crashing (accuracy is lost, instead)
364+
// TODO: Somehow track edits between file as it was during the creation of sourcemap we have and the current file and
365+
// apply them to the computed position to improve accuracy
366+
return res > lineStarts[line + 1] ? lineStarts[line + 1] : typeof debugText === "string" && res > debugText.length ? debugText.length : res;
367+
}
351368
if (line < lineStarts.length - 1) {
352369
Debug.assert(res < lineStarts[line + 1]);
353370
}

src/compiler/sourcemap.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -608,7 +608,7 @@ namespace ts {
608608

609609
function processMapping(mapping: Mapping): MappedPosition {
610610
const generatedPosition = generatedFile !== undefined
611-
? getPositionOfLineAndCharacter(generatedFile, mapping.generatedLine, mapping.generatedCharacter)
611+
? getPositionOfLineAndCharacterWithEdits(generatedFile, mapping.generatedLine, mapping.generatedCharacter)
612612
: -1;
613613
let source: string | undefined;
614614
let sourcePosition: number | undefined;
@@ -617,7 +617,7 @@ namespace ts {
617617
const sourceFile = host.getSourceFileLike(sourceFilePath);
618618
source = map.sources[mapping.sourceIndex];
619619
sourcePosition = sourceFile !== undefined
620-
? getPositionOfLineAndCharacter(sourceFile, mapping.sourceLine, mapping.sourceCharacter)
620+
? getPositionOfLineAndCharacterWithEdits(sourceFile, mapping.sourceLine, mapping.sourceCharacter)
621621
: -1;
622622
}
623623
return {
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/// <reference path="../fourslash.ts" />
2+
3+
// @Filename: /node_modules/a/dist/index.d.ts
4+
////export declare class Foo {
5+
//// bar: any;
6+
////}
7+
//////# sourceMappingURL=index.d.ts.map
8+
9+
// @Filename: /node_modules/a/dist/index.d.ts.map
10+
////{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,qBAAa,GAAG;IACZ,GAAG,MAAC;CACP"}
11+
12+
// @Filename: /node_modules/a/src/index.ts
13+
////export class /*2*/Foo {
14+
////}
15+
////
16+
17+
// @Filename: /node_modules/a/package.json
18+
////{
19+
//// "name": "a",
20+
//// "version": "0.0.0",
21+
//// "private": true,
22+
//// "main": "dist",
23+
//// "types": "dist"
24+
////}
25+
26+
// @Filename: /index.ts
27+
////import { Foo/*1*/ } from "a";
28+
29+
goTo.file("/index.ts");
30+
31+
goTo.marker("1");
32+
verify.goToDefinitionIs("2"); // getDefinitionAndBoundSpan

0 commit comments

Comments
 (0)