Skip to content

Commit 7106a58

Browse files
author
Andy
authored
Add type for diagnostics where location is defined (#23686)
* Add type for diagnostics where location is defined * getSemanticDiagnostics may return global diagnostics * Reduce array creation
1 parent 7fb3123 commit 7106a58

36 files changed

+149
-117
lines changed

src/compiler/binder.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ namespace ts {
158158
* If so, the node _must_ be in the current file (as that's the only way anything could have traversed to it to yield it as the error node)
159159
* This version of `createDiagnosticForNode` uses the binder's context to account for this, and always yields correct diagnostics even in these situations.
160160
*/
161-
function createDiagnosticForNode(node: Node, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number): Diagnostic {
161+
function createDiagnosticForNode(node: Node, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number): DiagnosticWithLocation {
162162
return createDiagnosticForNodeInSourceFile(getSourceFileOfNode(node) || file, node, message, arg0, arg1, arg2);
163163
}
164164

src/compiler/checker.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -313,11 +313,11 @@ namespace ts {
313313

314314
getSuggestionDiagnostics: file => {
315315
return (suggestionDiagnostics.get(file.fileName) || emptyArray).concat(getUnusedDiagnostics());
316-
function getUnusedDiagnostics(): ReadonlyArray<Diagnostic> {
316+
function getUnusedDiagnostics(): ReadonlyArray<DiagnosticWithLocation> {
317317
if (file.isDeclarationFile) return emptyArray;
318318

319319
checkSourceFile(file);
320-
const diagnostics: Diagnostic[] = [];
320+
const diagnostics: DiagnosticWithLocation[] = [];
321321
Debug.assert(!!(getNodeLinks(file).flags & NodeCheckFlags.TypeChecked));
322322
checkUnusedIdentifiers(getPotentiallyUnusedIdentifiers(file), (kind, diag) => {
323323
if (!unusedIsError(kind)) {
@@ -481,7 +481,7 @@ namespace ts {
481481

482482
const diagnostics = createDiagnosticCollection();
483483
// Suggestion diagnostics must have a file. Keyed by source file name.
484-
const suggestionDiagnostics = createMultiMap<Diagnostic>();
484+
const suggestionDiagnostics = createMultiMap<DiagnosticWithLocation>();
485485

486486
const enum TypeFacts {
487487
None = 0,
@@ -628,7 +628,7 @@ namespace ts {
628628
Local,
629629
Parameter,
630630
}
631-
type AddUnusedDiagnostic = (type: UnusedKind, diagnostic: Diagnostic) => void;
631+
type AddUnusedDiagnostic = (type: UnusedKind, diagnostic: DiagnosticWithLocation) => void;
632632

633633
const builtinGlobals = createSymbolTable();
634634
builtinGlobals.set(undefinedSymbol.escapedName, undefinedSymbol);
@@ -824,7 +824,7 @@ namespace ts {
824824
diagnostics.add(diagnostic);
825825
}
826826

827-
function addErrorOrSuggestion(isError: boolean, diagnostic: Diagnostic) {
827+
function addErrorOrSuggestion(isError: boolean, diagnostic: DiagnosticWithLocation) {
828828
if (isError) {
829829
diagnostics.add(diagnostic);
830830
}

src/compiler/core.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ namespace ts {
1414
return pathIsRelative(moduleName) || isRootedDiskPath(moduleName);
1515
}
1616

17-
export function sortAndDeduplicateDiagnostics(diagnostics: ReadonlyArray<Diagnostic>): Diagnostic[] {
18-
return sortAndDeduplicate(diagnostics, compareDiagnostics);
17+
export function sortAndDeduplicateDiagnostics<T extends Diagnostic>(diagnostics: ReadonlyArray<T>): T[] {
18+
return sortAndDeduplicate<T>(diagnostics, compareDiagnostics);
1919
}
2020
}
2121

@@ -1619,8 +1619,8 @@ namespace ts {
16191619
return localizedDiagnosticMessages && localizedDiagnosticMessages[message.key] || message.message;
16201620
}
16211621

1622-
export function createFileDiagnostic(file: SourceFile, start: number, length: number, message: DiagnosticMessage, ...args: (string | number)[]): Diagnostic;
1623-
export function createFileDiagnostic(file: SourceFile, start: number, length: number, message: DiagnosticMessage): Diagnostic {
1622+
export function createFileDiagnostic(file: SourceFile, start: number, length: number, message: DiagnosticMessage, ...args: (string | number)[]): DiagnosticWithLocation;
1623+
export function createFileDiagnostic(file: SourceFile, start: number, length: number, message: DiagnosticMessage): DiagnosticWithLocation {
16241624
Debug.assertGreaterThanOrEqual(start, 0);
16251625
Debug.assertGreaterThanOrEqual(length, 0);
16261626

src/compiler/parser.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -595,7 +595,7 @@ namespace ts {
595595
// tslint:enable variable-name
596596

597597
let sourceFile: SourceFile;
598-
let parseDiagnostics: Diagnostic[];
598+
let parseDiagnostics: DiagnosticWithLocation[];
599599
let syntaxCursor: IncrementalParser.SyntaxCursor;
600600

601601
let currentToken: SyntaxKind;

src/compiler/program.ts

Lines changed: 36 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -394,8 +394,8 @@ namespace ts {
394394
return resolutions;
395395
}
396396

397-
interface DiagnosticCache {
398-
perFile?: Map<Diagnostic[]>;
397+
interface DiagnosticCache<T extends Diagnostic> {
398+
perFile?: Map<T[]>;
399399
allDiagnostics?: Diagnostic[];
400400
}
401401

@@ -454,7 +454,7 @@ namespace ts {
454454

455455
export function getConfigFileParsingDiagnostics(configFileParseResult: ParsedCommandLine): ReadonlyArray<Diagnostic> {
456456
return configFileParseResult.options.configFile ?
457-
configFileParseResult.options.configFile.parseDiagnostics.concat(configFileParseResult.errors) :
457+
[...configFileParseResult.options.configFile.parseDiagnostics, ...configFileParseResult.errors] :
458458
configFileParseResult.errors;
459459
}
460460

@@ -517,8 +517,8 @@ namespace ts {
517517
let classifiableNames: UnderscoreEscapedMap<true>;
518518
let modifiedFilePaths: Path[] | undefined;
519519

520-
const cachedSemanticDiagnosticsForFile: DiagnosticCache = {};
521-
const cachedDeclarationDiagnosticsForFile: DiagnosticCache = {};
520+
const cachedSemanticDiagnosticsForFile: DiagnosticCache<Diagnostic> = {};
521+
const cachedDeclarationDiagnosticsForFile: DiagnosticCache<DiagnosticWithLocation> = {};
522522

523523
let resolvedTypeReferenceDirectives = createMap<ResolvedTypeReferenceDirective>();
524524
let fileProcessingDiagnostics = createDiagnosticCollection();
@@ -1313,10 +1313,10 @@ namespace ts {
13131313
return filesByName.get(path);
13141314
}
13151315

1316-
function getDiagnosticsHelper(
1316+
function getDiagnosticsHelper<T extends Diagnostic>(
13171317
sourceFile: SourceFile,
1318-
getDiagnostics: (sourceFile: SourceFile, cancellationToken: CancellationToken) => ReadonlyArray<Diagnostic>,
1319-
cancellationToken: CancellationToken): ReadonlyArray<Diagnostic> {
1318+
getDiagnostics: (sourceFile: SourceFile, cancellationToken: CancellationToken) => ReadonlyArray<T>,
1319+
cancellationToken: CancellationToken): ReadonlyArray<T> {
13201320
if (sourceFile) {
13211321
return getDiagnostics(sourceFile, cancellationToken);
13221322
}
@@ -1328,15 +1328,15 @@ namespace ts {
13281328
}));
13291329
}
13301330

1331-
function getSyntacticDiagnostics(sourceFile: SourceFile, cancellationToken: CancellationToken): ReadonlyArray<Diagnostic> {
1331+
function getSyntacticDiagnostics(sourceFile: SourceFile, cancellationToken: CancellationToken): ReadonlyArray<DiagnosticWithLocation> {
13321332
return getDiagnosticsHelper(sourceFile, getSyntacticDiagnosticsForFile, cancellationToken);
13331333
}
13341334

13351335
function getSemanticDiagnostics(sourceFile: SourceFile, cancellationToken: CancellationToken): ReadonlyArray<Diagnostic> {
13361336
return getDiagnosticsHelper(sourceFile, getSemanticDiagnosticsForFile, cancellationToken);
13371337
}
13381338

1339-
function getDeclarationDiagnostics(sourceFile: SourceFile, cancellationToken: CancellationToken): ReadonlyArray<Diagnostic> {
1339+
function getDeclarationDiagnostics(sourceFile: SourceFile, cancellationToken: CancellationToken): ReadonlyArray<DiagnosticWithLocation> {
13401340
const options = program.getCompilerOptions();
13411341
// collect diagnostics from the program only once if either no source file was specified or out/outFile is set (bundled emit)
13421342
if (!sourceFile || options.out || options.outFile) {
@@ -1347,7 +1347,7 @@ namespace ts {
13471347
}
13481348
}
13491349

1350-
function getSyntacticDiagnosticsForFile(sourceFile: SourceFile): ReadonlyArray<Diagnostic> {
1350+
function getSyntacticDiagnosticsForFile(sourceFile: SourceFile): ReadonlyArray<DiagnosticWithLocation> {
13511351
// For JavaScript files, we report semantic errors for using TypeScript-only
13521352
// constructs from within a JavaScript file as syntactic errors.
13531353
if (isSourceFileJavaScript(sourceFile)) {
@@ -1382,7 +1382,7 @@ namespace ts {
13821382
}
13831383
}
13841384

1385-
function getSemanticDiagnosticsForFile(sourceFile: SourceFile, cancellationToken: CancellationToken): Diagnostic[] {
1385+
function getSemanticDiagnosticsForFile(sourceFile: SourceFile, cancellationToken: CancellationToken): ReadonlyArray<Diagnostic> {
13861386
return getAndCacheDiagnostics(sourceFile, cancellationToken, cachedSemanticDiagnosticsForFile, getSemanticDiagnosticsForFileNoCache);
13871387
}
13881388

@@ -1403,15 +1403,22 @@ namespace ts {
14031403
// By default, only type-check .ts, .tsx, 'Deferred' and 'External' files (external files are added by plugins)
14041404
const includeBindAndCheckDiagnostics = sourceFile.scriptKind === ScriptKind.TS || sourceFile.scriptKind === ScriptKind.TSX ||
14051405
sourceFile.scriptKind === ScriptKind.External || isCheckJs || sourceFile.scriptKind === ScriptKind.Deferred;
1406-
const bindDiagnostics = includeBindAndCheckDiagnostics ? sourceFile.bindDiagnostics : emptyArray;
1406+
const bindDiagnostics: ReadonlyArray<Diagnostic> = includeBindAndCheckDiagnostics ? sourceFile.bindDiagnostics : emptyArray;
14071407
const checkDiagnostics = includeBindAndCheckDiagnostics ? typeChecker.getDiagnostics(sourceFile, cancellationToken) : emptyArray;
14081408
const fileProcessingDiagnosticsInFile = fileProcessingDiagnostics.getDiagnostics(sourceFile.fileName);
14091409
const programDiagnosticsInFile = programDiagnostics.getDiagnostics(sourceFile.fileName);
1410-
let diagnostics = bindDiagnostics.concat(checkDiagnostics, fileProcessingDiagnosticsInFile, programDiagnosticsInFile);
1411-
if (isCheckJs) {
1412-
diagnostics = concatenate(diagnostics, sourceFile.jsDocDiagnostics);
1410+
1411+
let diagnostics: Diagnostic[] | undefined;
1412+
for (const diags of [bindDiagnostics, checkDiagnostics, fileProcessingDiagnosticsInFile, programDiagnosticsInFile, isCheckJs ? sourceFile.jsDocDiagnostics : undefined]) {
1413+
if (diags) {
1414+
for (const diag of diags) {
1415+
if (shouldReportDiagnostic(diag)) {
1416+
diagnostics = append(diagnostics, diag);
1417+
}
1418+
}
1419+
}
14131420
}
1414-
return filter(diagnostics, shouldReportDiagnostic);
1421+
return diagnostics;
14151422
});
14161423
}
14171424

@@ -1440,9 +1447,9 @@ namespace ts {
14401447
return true;
14411448
}
14421449

1443-
function getJavaScriptSyntacticDiagnosticsForFile(sourceFile: SourceFile): Diagnostic[] {
1450+
function getJavaScriptSyntacticDiagnosticsForFile(sourceFile: SourceFile): DiagnosticWithLocation[] {
14441451
return runWithCancellationToken(() => {
1445-
const diagnostics: Diagnostic[] = [];
1452+
const diagnostics: DiagnosticWithLocation[] = [];
14461453
let parent: Node = sourceFile;
14471454
walk(sourceFile);
14481455

@@ -1610,20 +1617,20 @@ namespace ts {
16101617
}
16111618
}
16121619

1613-
function createDiagnosticForNodeArray(nodes: NodeArray<Node>, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number): Diagnostic {
1620+
function createDiagnosticForNodeArray(nodes: NodeArray<Node>, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number): DiagnosticWithLocation {
16141621
const start = nodes.pos;
16151622
return createFileDiagnostic(sourceFile, start, nodes.end - start, message, arg0, arg1, arg2);
16161623
}
16171624

16181625
// Since these are syntactic diagnostics, parent might not have been set
16191626
// this means the sourceFile cannot be infered from the node
1620-
function createDiagnosticForNode(node: Node, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number): Diagnostic {
1627+
function createDiagnosticForNode(node: Node, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number): DiagnosticWithLocation {
16211628
return createDiagnosticForNodeInSourceFile(sourceFile, node, message, arg0, arg1, arg2);
16221629
}
16231630
});
16241631
}
16251632

1626-
function getDeclarationDiagnosticsWorker(sourceFile: SourceFile | undefined, cancellationToken: CancellationToken): Diagnostic[] {
1633+
function getDeclarationDiagnosticsWorker(sourceFile: SourceFile, cancellationToken: CancellationToken): ReadonlyArray<DiagnosticWithLocation> {
16271634
return getAndCacheDiagnostics(sourceFile, cancellationToken, cachedDeclarationDiagnosticsForFile, getDeclarationDiagnosticsForFileNoCache);
16281635
}
16291636

@@ -1635,23 +1642,24 @@ namespace ts {
16351642
});
16361643
}
16371644

1638-
function getAndCacheDiagnostics(
1645+
function getAndCacheDiagnostics<T extends Diagnostic>(
16391646
sourceFile: SourceFile | undefined,
16401647
cancellationToken: CancellationToken,
1641-
cache: DiagnosticCache,
1642-
getDiagnostics: (sourceFile: SourceFile, cancellationToken: CancellationToken) => Diagnostic[]) {
1648+
cache: DiagnosticCache<T>,
1649+
getDiagnostics: (sourceFile: SourceFile, cancellationToken: CancellationToken) => T[],
1650+
): ReadonlyArray<T> {
16431651

16441652
const cachedResult = sourceFile
16451653
? cache.perFile && cache.perFile.get(sourceFile.path)
1646-
: cache.allDiagnostics;
1654+
: cache.allDiagnostics as T[];
16471655

16481656
if (cachedResult) {
16491657
return cachedResult;
16501658
}
16511659
const result = getDiagnostics(sourceFile, cancellationToken) || emptyArray;
16521660
if (sourceFile) {
16531661
if (!cache.perFile) {
1654-
cache.perFile = createMap<Diagnostic[]>();
1662+
cache.perFile = createMap<T[]>();
16551663
}
16561664
cache.perFile.set(sourceFile.path, result);
16571665
}
@@ -1661,7 +1669,7 @@ namespace ts {
16611669
return result;
16621670
}
16631671

1664-
function getDeclarationDiagnosticsForFile(sourceFile: SourceFile, cancellationToken: CancellationToken): Diagnostic[] {
1672+
function getDeclarationDiagnosticsForFile(sourceFile: SourceFile, cancellationToken: CancellationToken): ReadonlyArray<DiagnosticWithLocation> {
16651673
return sourceFile.isDeclarationFile ? [] : getDeclarationDiagnosticsWorker(sourceFile, cancellationToken);
16661674
}
16671675

src/compiler/transformer.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ namespace ts {
9090
let onSubstituteNode: TransformationContext["onSubstituteNode"] = (_, node) => node;
9191
let onEmitNode: TransformationContext["onEmitNode"] = (hint, node, callback) => callback(hint, node);
9292
let state = TransformationState.Uninitialized;
93-
const diagnostics: Diagnostic[] = [];
93+
const diagnostics: DiagnosticWithLocation[] = [];
9494

9595
// The transformation context is provided to each transformer as part of transformer
9696
// initialization.

src/compiler/transformers/declarations.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*@internal*/
22
namespace ts {
3-
export function getDeclarationDiagnostics(host: EmitHost, resolver: EmitResolver, file: SourceFile | undefined): Diagnostic[] {
3+
export function getDeclarationDiagnostics(host: EmitHost, resolver: EmitResolver, file: SourceFile | undefined): DiagnosticWithLocation[] {
44
if (file && isSourceFileJavaScript(file)) {
55
return []; // No declaration diagnostics for js for now
66
}

0 commit comments

Comments
 (0)