Skip to content

Commit e238490

Browse files
committed
Introduce related spans into tsserver protocol
1 parent 9d42ab9 commit e238490

File tree

6 files changed

+102
-7
lines changed

6 files changed

+102
-7
lines changed

src/compiler/types.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4238,6 +4238,13 @@ namespace ts {
42384238
reportsUnnecessary?: {};
42394239
code: number;
42404240
source?: string;
4241+
relatedInformation?: DiagnosticRelatedInformation[];
4242+
}
4243+
export interface DiagnosticRelatedInformation {
4244+
file: SourceFile | undefined;
4245+
start: number | undefined;
4246+
length: number | undefined;
4247+
messageText: string | DiagnosticMessageChain;
42414248
}
42424249
export interface DiagnosticWithLocation extends Diagnostic {
42434250
file: SourceFile;

src/harness/unittests/tsserverProjectSystem.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -495,8 +495,8 @@ namespace ts.projectSystem {
495495
checkNthEvent(session, server.toEvent(eventName, diagnostics), 0, isMostRecent);
496496
}
497497

498-
function createDiagnostic(start: protocol.Location, end: protocol.Location, message: DiagnosticMessage, args: ReadonlyArray<string> = [], category = diagnosticCategoryName(message), reportsUnnecessary?: {}): protocol.Diagnostic {
499-
return { start, end, text: formatStringFromArgs(message.message, args), code: message.code, category, reportsUnnecessary, source: undefined };
498+
function createDiagnostic(start: protocol.Location, end: protocol.Location, message: DiagnosticMessage, args: ReadonlyArray<string> = [], category = diagnosticCategoryName(message), reportsUnnecessary?: {}, relatedInformation?: protocol.DiagnosticRelatedInformation[]): protocol.Diagnostic {
499+
return { start, end, text: formatStringFromArgs(message.message, args), code: message.code, category, reportsUnnecessary, relatedInformation, source: undefined };
500500
}
501501

502502
function checkCompleteEvent(session: TestSession, numberOfCurrentEvents: number, expectedSequenceId: number, isMostRecent = true): void {

src/server/protocol.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -465,6 +465,7 @@ namespace ts.server.protocol {
465465
code: number;
466466
/** May store more in future. For now, this will simply be `true` to indicate when a diagnostic is an unused-identifier diagnostic. */
467467
reportsUnnecessary?: {};
468+
relatedInformation?: DiagnosticRelatedInformation[];
468469
}
469470

470471
/**
@@ -2203,6 +2204,11 @@ namespace ts.server.protocol {
22032204

22042205
reportsUnnecessary?: {};
22052206

2207+
/**
2208+
* Any related spans the diagnostic may have, such as other locations relevant to an error, such as declarartion sites
2209+
*/
2210+
relatedInformation?: DiagnosticRelatedInformation[];
2211+
22062212
/**
22072213
* The error code of the diagnostic message.
22082214
*/
@@ -2221,6 +2227,23 @@ namespace ts.server.protocol {
22212227
fileName: string;
22222228
}
22232229

2230+
/**
2231+
* Represents additional spans returned with a diagnostic which are relevant to it
2232+
* Like DiagnosticWithLinePosition, this is provided in two forms:
2233+
* - start and length of the span
2234+
* - startLocation and endLocation a pair of Location objects storing the start/end line offset of the span
2235+
*/
2236+
export interface DiagnosticRelatedInformation {
2237+
/**
2238+
* Text of related or additional information.
2239+
*/
2240+
message: string;
2241+
/**
2242+
* Associated location
2243+
*/
2244+
span?: FileSpan;
2245+
}
2246+
22242247
export interface DiagnosticEventBody {
22252248
/**
22262249
* The file for which diagnostic information is reported.

src/server/session.ts

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,24 @@ namespace ts.server {
7676
code: diag.code,
7777
category: diagnosticCategoryName(diag),
7878
reportsUnnecessary: diag.reportsUnnecessary,
79-
source: diag.source
79+
source: diag.source,
80+
relatedInformation: map(diag.relatedInformation, formatRelatedInformation),
81+
};
82+
}
83+
84+
function formatRelatedInformation(info: DiagnosticRelatedInformation): protocol.DiagnosticRelatedInformation {
85+
if (!info.file) {
86+
return {
87+
message: flattenDiagnosticMessageText(info.messageText, "\n")
88+
};
89+
}
90+
return {
91+
span: {
92+
start: convertToLocation(getLineAndCharacterOfPosition(info.file, info.start!)),
93+
end: convertToLocation(getLineAndCharacterOfPosition(info.file, info.start! + info.length!)), // TODO: GH#18217
94+
file: info.file.fileName
95+
},
96+
message: flattenDiagnosticMessageText(info.messageText, "\n")
8097
};
8198
}
8299

@@ -92,8 +109,19 @@ namespace ts.server {
92109
const text = flattenDiagnosticMessageText(diag.messageText, "\n");
93110
const { code, source } = diag;
94111
const category = diagnosticCategoryName(diag);
95-
return includeFileName ? { start, end, text, code, category, source, reportsUnnecessary: diag.reportsUnnecessary, fileName: diag.file && diag.file.fileName } :
96-
{ start, end, text, code, category, reportsUnnecessary: diag.reportsUnnecessary, source };
112+
const common = {
113+
start,
114+
end,
115+
text,
116+
code,
117+
category,
118+
reportsUnnecessary: diag.reportsUnnecessary,
119+
source,
120+
relatedInformation: map(diag.relatedInformation, formatRelatedInformation),
121+
};
122+
return includeFileName
123+
? { ...common, fileName: diag.file && diag.file.fileName }
124+
: common;
97125
}
98126

99127
export interface PendingErrorCheck {
@@ -610,7 +638,8 @@ namespace ts.server {
610638
category: diagnosticCategoryName(d),
611639
code: d.code,
612640
startLocation: (d.file && convertToLocation(getLineAndCharacterOfPosition(d.file, d.start!)))!, // TODO: GH#18217
613-
endLocation: (d.file && convertToLocation(getLineAndCharacterOfPosition(d.file, d.start! + d.length!)))! // TODO: GH#18217
641+
endLocation: (d.file && convertToLocation(getLineAndCharacterOfPosition(d.file, d.start! + d.length!)))!, // TODO: GH#18217
642+
relatedInformation: map(d.relatedInformation, formatRelatedInformation)
614643
}));
615644
}
616645

@@ -638,7 +667,8 @@ namespace ts.server {
638667
source: d.source,
639668
startLocation: scriptInfo && scriptInfo.positionToLineOffset(d.start!), // TODO: GH#18217
640669
endLocation: scriptInfo && scriptInfo.positionToLineOffset(d.start! + d.length!),
641-
reportsUnnecessary: d.reportsUnnecessary
670+
reportsUnnecessary: d.reportsUnnecessary,
671+
relatedInformation: map(d.relatedInformation, formatRelatedInformation),
642672
});
643673
}
644674

tests/baselines/reference/api/tsserverlibrary.d.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2362,6 +2362,13 @@ declare namespace ts {
23622362
reportsUnnecessary?: {};
23632363
code: number;
23642364
source?: string;
2365+
relatedInformation?: DiagnosticRelatedInformation[];
2366+
}
2367+
interface DiagnosticRelatedInformation {
2368+
file: SourceFile | undefined;
2369+
start: number | undefined;
2370+
length: number | undefined;
2371+
messageText: string | DiagnosticMessageChain;
23652372
}
23662373
interface DiagnosticWithLocation extends Diagnostic {
23672374
file: SourceFile;
@@ -5838,6 +5845,7 @@ declare namespace ts.server.protocol {
58385845
code: number;
58395846
/** May store more in future. For now, this will simply be `true` to indicate when a diagnostic is an unused-identifier diagnostic. */
58405847
reportsUnnecessary?: {};
5848+
relatedInformation?: DiagnosticRelatedInformation[];
58415849
}
58425850
/**
58435851
* Response message for "projectInfo" request
@@ -7204,6 +7212,10 @@ declare namespace ts.server.protocol {
72047212
*/
72057213
category: string;
72067214
reportsUnnecessary?: {};
7215+
/**
7216+
* Any related spans the diagnostic may have, such as other locations relevant to an error, such as declarartion sites
7217+
*/
7218+
relatedInformation?: DiagnosticRelatedInformation[];
72077219
/**
72087220
* The error code of the diagnostic message.
72097221
*/
@@ -7219,6 +7231,22 @@ declare namespace ts.server.protocol {
72197231
*/
72207232
fileName: string;
72217233
}
7234+
/**
7235+
* Represents additional spans returned with a diagnostic which are relevant to it
7236+
* Like DiagnosticWithLinePosition, this is provided in two forms:
7237+
* - start and length of the span
7238+
* - startLocation and endLocation a pair of Location objects storing the start/end line offset of the span
7239+
*/
7240+
interface DiagnosticRelatedInformation {
7241+
/**
7242+
* Text of related or additional information.
7243+
*/
7244+
message: string;
7245+
/**
7246+
* Associated location
7247+
*/
7248+
span?: FileSpan;
7249+
}
72227250
interface DiagnosticEventBody {
72237251
/**
72247252
* The file for which diagnostic information is reported.

tests/baselines/reference/api/typescript.d.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2362,6 +2362,13 @@ declare namespace ts {
23622362
reportsUnnecessary?: {};
23632363
code: number;
23642364
source?: string;
2365+
relatedInformation?: DiagnosticRelatedInformation[];
2366+
}
2367+
interface DiagnosticRelatedInformation {
2368+
file: SourceFile | undefined;
2369+
start: number | undefined;
2370+
length: number | undefined;
2371+
messageText: string | DiagnosticMessageChain;
23652372
}
23662373
interface DiagnosticWithLocation extends Diagnostic {
23672374
file: SourceFile;

0 commit comments

Comments
 (0)