Skip to content

Commit 6c5ae93

Browse files
committed
Store semantic diagnostics as well (for future tsc without build but incremental)
1 parent 6e1e1e7 commit 6c5ae93

File tree

1 file changed

+110
-6
lines changed

1 file changed

+110
-6
lines changed

src/compiler/builder.ts

+110-6
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,33 @@
11
/*@internal*/
22
namespace ts {
3+
export interface ReusableDiagnostic extends ReusableDiagnosticRelatedInformation {
4+
/** May store more in future. For now, this will simply be `true` to indicate when a diagnostic is an unused-identifier diagnostic. */
5+
reportsUnnecessary?: {};
6+
source?: string;
7+
relatedInformation?: ReusableDiagnosticRelatedInformation[];
8+
}
9+
10+
export interface ReusableDiagnosticRelatedInformation {
11+
category: DiagnosticCategory;
12+
code: number;
13+
file: Path | undefined;
14+
start: number | undefined;
15+
length: number | undefined;
16+
messageText: string | ReusableDiagnosticMessageChain;
17+
}
18+
19+
export interface ReusableDiagnosticMessageChain {
20+
messageText: string;
21+
category: DiagnosticCategory;
22+
code: number;
23+
next?: ReusableDiagnosticMessageChain;
24+
}
25+
326
export interface ReusableBuilderProgramState extends ReusableBuilderState {
427
/**
528
* Cache of semantic diagnostics for files with their Path being the key
629
*/
7-
semanticDiagnosticsPerFile?: ReadonlyMap<ReadonlyArray<Diagnostic>> | undefined;
30+
semanticDiagnosticsPerFile?: ReadonlyMap<ReadonlyArray<ReusableDiagnostic> | ReadonlyArray<Diagnostic>> | undefined;
831
/**
932
* The map has key by source file's path that has been changed
1033
*/
@@ -46,6 +69,10 @@ namespace ts {
4669
* Current index to retrieve pending affected file
4770
*/
4871
affectedFilesPendingEmitIndex?: number | undefined;
72+
/*
73+
* true if semantic diagnostics are ReusableDiagnostic instead of Diagnostic
74+
*/
75+
hasReusableDiagnostic?: true;
4976
}
5077

5178
/**
@@ -200,7 +227,7 @@ namespace ts {
200227
// Unchanged file copy diagnostics
201228
const diagnostics = oldState!.semanticDiagnosticsPerFile!.get(sourceFilePath);
202229
if (diagnostics) {
203-
state.semanticDiagnosticsPerFile!.set(sourceFilePath, diagnostics);
230+
state.semanticDiagnosticsPerFile!.set(sourceFilePath, oldState!.hasReusableDiagnostic ? convertToDiagnostics(diagnostics as ReadonlyArray<ReusableDiagnostic>, newProgram) : diagnostics as ReadonlyArray<Diagnostic>);
204231
if (!state.semanticDiagnosticsFromOldState) {
205232
state.semanticDiagnosticsFromOldState = createMap<true>();
206233
}
@@ -225,6 +252,39 @@ namespace ts {
225252
return state;
226253
}
227254

255+
function convertToDiagnostics(diagnostics: ReadonlyArray<ReusableDiagnostic>, newProgram: Program): ReadonlyArray<Diagnostic> {
256+
if (!diagnostics.length) return emptyArray;
257+
return diagnostics.map(diagnostic => {
258+
const result: Diagnostic = convertToDiagnosticRelatedInformation(diagnostic, newProgram);
259+
result.reportsUnnecessary = diagnostic.reportsUnnecessary;
260+
result.source = diagnostic.source;
261+
const { relatedInformation } = diagnostic;
262+
result.relatedInformation = relatedInformation &&
263+
relatedInformation.length ?
264+
relatedInformation.map(r => convertToDiagnosticRelatedInformation(r, newProgram)) :
265+
emptyArray;
266+
return result;
267+
});
268+
}
269+
270+
function convertToDiagnosticRelatedInformation(diagnostic: ReusableDiagnosticRelatedInformation, newProgram: Program): DiagnosticRelatedInformation {
271+
const { file, messageText } = diagnostic;
272+
return {
273+
...diagnostic,
274+
file: file && newProgram.getSourceFileByPath(file),
275+
messageText: messageText === undefined || isString(messageText) ?
276+
messageText :
277+
convertToDiagnosticMessageChain(messageText, newProgram)
278+
};
279+
}
280+
281+
function convertToDiagnosticMessageChain(diagnostic: ReusableDiagnosticMessageChain, newProgram: Program): DiagnosticMessageChain {
282+
return {
283+
...diagnostic,
284+
next: diagnostic.next && convertToDiagnosticMessageChain(diagnostic.next, newProgram)
285+
};
286+
}
287+
228288
/**
229289
* Releases program and other related not needed properties
230290
*/
@@ -514,12 +574,13 @@ namespace ts {
514574
return diagnostics;
515575
}
516576

577+
export type ProgramBuildInfoDiagnostic = string | [string, ReadonlyArray<ReusableDiagnostic>];
517578
export interface ProgramBuildInfo {
518579
fileInfos: MapLike<BuilderState.FileInfo>;
519580
options: CompilerOptions;
520581
referencedMap?: MapLike<string[]>;
521582
exportedModulesMap?: MapLike<string[]>;
522-
semanticDiagnosticsPerFile?: string[];
583+
semanticDiagnosticsPerFile?: ProgramBuildInfoDiagnostic[];
523584
}
524585

525586
/**
@@ -555,15 +616,57 @@ namespace ts {
555616
}
556617

557618
if (state.semanticDiagnosticsPerFile) {
558-
const semanticDiagnosticsPerFile: string[] = [];
619+
const semanticDiagnosticsPerFile: ProgramBuildInfoDiagnostic[] = [];
559620
// Currently not recording actual errors since those mean no emit for tsc --build
560-
state.semanticDiagnosticsPerFile.forEach((_value, key) => semanticDiagnosticsPerFile.push(key));
621+
state.semanticDiagnosticsPerFile.forEach((value, key) => semanticDiagnosticsPerFile.push(
622+
value.length ?
623+
[
624+
key,
625+
state.hasReusableDiagnostic ?
626+
value as ReadonlyArray<ReusableDiagnostic> :
627+
convertToReusableDiagnostics(value as ReadonlyArray<Diagnostic>)
628+
] :
629+
key
630+
));
561631
result.semanticDiagnosticsPerFile = semanticDiagnosticsPerFile;
562632
}
563633

564634
return result;
565635
}
566636

637+
function convertToReusableDiagnostics(diagnostics: ReadonlyArray<Diagnostic>): ReadonlyArray<ReusableDiagnostic> {
638+
Debug.assert(!!diagnostics.length);
639+
return diagnostics.map(diagnostic => {
640+
const result: ReusableDiagnostic = convertToReusableDiagnosticRelatedInformation(diagnostic);
641+
result.reportsUnnecessary = diagnostic.reportsUnnecessary;
642+
result.source = diagnostic.source;
643+
const { relatedInformation } = diagnostic;
644+
result.relatedInformation = relatedInformation &&
645+
relatedInformation.length ?
646+
relatedInformation.map(r => convertToReusableDiagnosticRelatedInformation(r)) :
647+
emptyArray;
648+
return result;
649+
});
650+
}
651+
652+
function convertToReusableDiagnosticRelatedInformation(diagnostic: DiagnosticRelatedInformation): ReusableDiagnosticRelatedInformation {
653+
const { file, messageText } = diagnostic;
654+
return {
655+
...diagnostic,
656+
file: file && file.path,
657+
messageText: messageText === undefined || isString(messageText) ?
658+
messageText :
659+
convertToReusableDiagnosticMessageChain(messageText)
660+
};
661+
}
662+
663+
function convertToReusableDiagnosticMessageChain(diagnostic: DiagnosticMessageChain): ReusableDiagnosticMessageChain {
664+
return {
665+
...diagnostic,
666+
next: diagnostic.next && convertToReusableDiagnosticMessageChain(diagnostic.next)
667+
};
668+
}
669+
567670
export enum BuilderProgramKind {
568671
SemanticDiagnosticsBuilderProgram,
569672
EmitAndSemanticDiagnosticsBuilderProgram
@@ -868,7 +971,8 @@ namespace ts {
868971
compilerOptions: program.options,
869972
referencedMap: getMapOfReferencedSet(program.referencedMap),
870973
exportedModulesMap: getMapOfReferencedSet(program.exportedModulesMap),
871-
semanticDiagnosticsPerFile: program.semanticDiagnosticsPerFile && arrayToMap(program.semanticDiagnosticsPerFile, identity, () => emptyArray)
974+
semanticDiagnosticsPerFile: program.semanticDiagnosticsPerFile && arrayToMap(program.semanticDiagnosticsPerFile, value => isString(value) ? value : value[0], value => isString(value) ? emptyArray : value[1]),
975+
hasReusableDiagnostic: true
872976
};
873977
return {
874978
getState: () => state,

0 commit comments

Comments
 (0)