Skip to content

Commit 67930ea

Browse files
committed
Store semantic diagnostics as well (for future tsc without build but incremental)
1 parent 69f65f5 commit 67930ea

File tree

1 file changed

+112
-6
lines changed

1 file changed

+112
-6
lines changed

src/compiler/builder.ts

Lines changed: 112 additions & 6 deletions
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,40 @@ 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+
undefined;
267+
return result;
268+
});
269+
}
270+
271+
function convertToDiagnosticRelatedInformation(diagnostic: ReusableDiagnosticRelatedInformation, newProgram: Program): DiagnosticRelatedInformation {
272+
const { file, messageText } = diagnostic;
273+
return {
274+
...diagnostic,
275+
file: file && newProgram.getSourceFileByPath(file),
276+
messageText: messageText === undefined || isString(messageText) ?
277+
messageText :
278+
convertToDiagnosticMessageChain(messageText, newProgram)
279+
};
280+
}
281+
282+
function convertToDiagnosticMessageChain(diagnostic: ReusableDiagnosticMessageChain, newProgram: Program): DiagnosticMessageChain {
283+
return {
284+
...diagnostic,
285+
next: diagnostic.next && convertToDiagnosticMessageChain(diagnostic.next, newProgram)
286+
};
287+
}
288+
228289
/**
229290
* Releases program and other related not needed properties
230291
*/
@@ -514,12 +575,13 @@ namespace ts {
514575
return diagnostics;
515576
}
516577

578+
export type ProgramBuildInfoDiagnostic = string | [string, ReadonlyArray<ReusableDiagnostic>];
517579
export interface ProgramBuildInfo {
518580
fileInfos: MapLike<BuilderState.FileInfo>;
519581
options: CompilerOptions;
520582
referencedMap?: MapLike<string[]>;
521583
exportedModulesMap?: MapLike<string[]>;
522-
semanticDiagnosticsPerFile?: string[];
584+
semanticDiagnosticsPerFile?: ProgramBuildInfoDiagnostic[];
523585
}
524586

525587
/**
@@ -555,15 +617,58 @@ namespace ts {
555617
}
556618

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

564635
return result;
565636
}
566637

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

0 commit comments

Comments
 (0)